用VR观看LoL,这到底是如何实现的
2016-11-20 20:52
621 查看
前段时间,网上出现了一段使用HTC vive观看LoL的视频,相关链接在这里。这是由一位名叫Fire-Proof的大神开发完成的,并且大神公布了源代码。作为一名程序员,对牛掰的代码自然充满了好奇,用VR观看LoL,这到底是如何实现的呢?
查看代码发现,程序完全使用Python开发(再次感受到Python的强大),包含的代码并不多,一共也就10几个文件。
首先查看main.py。在最下方定义了
程序创建了一个名为MainDialog的对话框,让我们看一下MainDialog中有些什么(代码有删减)
对话框创建了一个start按钮,并将该按钮的点击事件绑定到了
看来玄机在
在
该方法会首先来检测VR控制器是否触发,并获取VR头显的位置信息,根据这些数据来更新LoL的画面信息。其中访问VR设备是通过调用openvr库来实现的,并在OpenVR.py中做了进一步的封装。那么更新LoL画面如何实现呢,答案是修改LoL进程的内存。
在LeagueOfLegends.py中,封装了修改LoL进程内存的方法,例如执行self.lol.x = 520,实际上执行的是下面的代码
而更底层的实现是通过memorpy目录中的相关代码来实现的。那么如何知道应该修改哪些内存位置呢(毕竟直接修改内存一个不慎可能进程就挂了)。涉及到画面信息的内存位置都是通过一个
HOW TO: Find base addr
1) Move screen to lowest y coord
2) Scan for float = 520
3) Move screen to highest y coord
4) Scan for float = 14765
5) Select the address that will updated the camera pos when changed
6) Right click this address and click “find out what accesses this address”
7) Select an element and press more information
8) Copy the value which is listed at the end of the string “The value of the pointer needed to find this …”
9) Search for this this value as an 8-bit hex value
10) Now search for the first address found
11) You should now have found a “green” address, select this and double click the address
12) You should now be able to see a string similar to “League of Legends.exe”+13D4280 <– base addr
看起来作者是通过某些内存查看软件(例如IDA)来进行分析得到的内存地址(在此膜拜大神)。
了解了这些,基本就明白程序的技术原理了,剩下的部分感兴趣的同学可以自行查看源码,当然有条件可以上设备体验一番。
查看代码发现,程序完全使用Python开发(再次感受到Python的强大),包含的代码并不多,一共也就10几个文件。
首先查看main.py。在最下方定义了
start_app方法
def start_app(): app = QApplication(sys.argv) tray_icon = MainDialog() tray_icon.show() app.exec_()
程序创建了一个名为MainDialog的对话框,让我们看一下MainDialog中有些什么(代码有删减)
class MainDialog(QDialog, Ui_MainDialog): def __init__(self, parent=None): super(MainDialog, self).__init__(parent) self.spectate = None self.spectate_started = False self.setupUi(self) self.lol_watcher = ProcessWatcher(b"League of Legends") self.lol_watcher.running.connect(self.lol_watcher_update, Qt.QueuedConnection) self.lol_watcher.start() self.vorpx_watcher = ProcessWatcher(b"vorpControl") self.vorpx_watcher.running.connect(self.vorpx_watcher_update,Qt.QueuedConnection) self.vorpx_watcher.start() self.pushButtonStart.clicked.connect(self.toggle_spectate) def toggle_spectate(self): if self.spectate_started: self.pushButtonStart.setText("Start") self.stop_spectate() self.spectate_started = False else: self.pushButtonStart.setText("Stop") self.start_spectate() self.spectate_started = True def start_spectate(self): if self.spectate is None: self.spectate = SpectateThread() self.spectate.error.connect(self.spectate_error, Qt.QueuedConnection) self.spectate.start()
对话框创建了一个start按钮,并将该按钮的点击事件绑定到了
toggle_spectate方法上,该方法会调用
start_spectate方法,并最终通过
SpectateThread创建了一个线程。继续查看
SpectateThread(代码有删减)
class SpectateThread(QThread): def __init__(self): super(SpectateThread, self).__init__() self.spectate = None def run(self, *args, **kwargs): self.spectate = VRSpectate() self.spectate.run()
看来玄机在
VRSpectate方法中。在查看
VRSpectate之前,注意到
MainDailog中开启了两个线程来检测”League of Legends”进程和”vorpControl”进程。前一个很好理解,观看LoL自然需要”League of Legends”进程,那这个”vorpControl”进程又是什么鬼呢?这是vorpX软件的运行进程,用来将非VR游戏的画面转换成VR模式并同步到头显设备中。看到这里是不是有种被欺骗的感觉,通过VR观看LoL是通过软件来实现的?答案确实如此,Python程序并不负责转换LoL的画面到VR设备上,它只是不停的检测VR头显和控制器的状态,并以此调整LoL的画面,这样就可以通过转动头部或触发控制器来以不同的视角观看LoL画面(比如站立时鸟瞰整个战场,蹲下来观看局部战场)。
在
VRSepecate的
run方法中,会不停的调用
_next_frame方法来更新画面
def _next_frame(self): self.scale = self.z_offset controller_frame = self.vr.controller_frame() # Camera movement if len(controller_frame) == 2: if all(controller_frame.button_pressed("trigger")): self.yaw_offset += self.prev_controller_frame.relative_rotation - controller_frame.relative_rotation self.z_offset += (self.prev_controller_frame.relative_distance - controller_frame.relative_distance) * self.z_offset * 2 self._move_offset(self.prev_controller_frame.position(), controller_frame.position()) elif any(controller_frame.button_pressed("trigger")): active_controller = [i for i, x in enumerate(controller_frame.button_pressed("trigger")) if x][0] self._move_offset(self.prev_controller_frame.position(active_controller), controller_frame.position(active_controller)) if len(controller_frame) == 1: if any(controller_frame.button_pressed("trigger")): self._move_offset(self.prev_controller_frame.position(), controller_frame.position(), update_z=True) self.prev_controller_frame = controller_frame pos = self.vr.hmd.position() self.lol.yaw = pos.yaw + self.yaw_offset self.lol.pitch = pos.pitch*-1 self.lol.x = (pos.x*self.scale) + self.x_offset self.lol.y = (pos.y*self.scale) + self.y_offset self.lol.z = (pos.z*self.scale) + self.z_offset
该方法会首先来检测VR控制器是否触发,并获取VR头显的位置信息,根据这些数据来更新LoL的画面信息。其中访问VR设备是通过调用openvr库来实现的,并在OpenVR.py中做了进一步的封装。那么更新LoL画面如何实现呢,答案是修改LoL进程的内存。
在LeagueOfLegends.py中,封装了修改LoL进程内存的方法,例如执行self.lol.x = 520,实际上执行的是下面的代码
@x.setter def x(self, val): self._x.write(val, type="float")
而更底层的实现是通过memorpy目录中的相关代码来实现的。那么如何知道应该修改哪些内存位置呢(毕竟直接修改内存一个不慎可能进程就挂了)。涉及到画面信息的内存位置都是通过一个
cam_base_address进行偏移得到的,作者给出了
cam_base_address的搜索方法:
HOW TO: Find base addr
1) Move screen to lowest y coord
2) Scan for float = 520
3) Move screen to highest y coord
4) Scan for float = 14765
5) Select the address that will updated the camera pos when changed
6) Right click this address and click “find out what accesses this address”
7) Select an element and press more information
8) Copy the value which is listed at the end of the string “The value of the pointer needed to find this …”
9) Search for this this value as an 8-bit hex value
10) Now search for the first address found
11) You should now have found a “green” address, select this and double click the address
12) You should now be able to see a string similar to “League of Legends.exe”+13D4280 <– base addr
看起来作者是通过某些内存查看软件(例如IDA)来进行分析得到的内存地址(在此膜拜大神)。
了解了这些,基本就明白程序的技术原理了,剩下的部分感兴趣的同学可以自行查看源码,当然有条件可以上设备体验一番。
相关文章推荐
- QQ游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
- QQ 游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
- 写给VR手游开发小白的教程:(六)Cardboard如何实现沉浸式VR体验之构造双眼
- 做视频直播时如何实现对观看直播的用户做登记?
- 如何做电脑游戏桌面录屏直播实现手机直接观看
- QQ游戏到底是如何实现百万人同时在线并保持游戏高效率的呢
- UnityVR.05如何实现VR第一人称射击行为
- 写给VR手游开发小白的教程:(七)Cardboard如何实现沉浸式VR体验之扭曲矫正和FOV匹配
- 如何减轻拔牙的疼痛?研究人员建议用VR观看沿海场景
- QQ 游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
- c中的gets 与scanf到底有什么差 ,如何实现键盘输入及屏幕显示
- PROFINET如何实现“一网到底”?
- 写给VR手游开发小白的教程:(八)最终篇:Cardboard如何实现沉浸式VR体验之头部跟踪和Gaze的实现
- Unix编程学习笔记--------系统调用的疑问????? 到底什么是系统调用???? 系统调用是如何实现的???
- QQ 游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
- Java HashMap到底是如何实现的,结合源代码分析
- 教你如何用php实现LOL数据远程获取
- Java中Thread类的join方法到底是如何实现等待
- TextView 的新特性,Autosizing 到底是如何实现的? | 源码分析
- VR、AR、MR、CR到底如何区分