Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented HTC Vive (SteamVR/OpenVR) #19

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "space_view3d_virtual_reality/lib/hmd_sdk_bridge"]
path = space_view3d_virtual_reality/lib/hmd_sdk_bridge
url = ../hmd_sdk_bridge_build
url = ../hmd_sdk_bridge
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment on that matter.

16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Virtual Reality Viewport
Addon to bring virtual reality devices to the Blender viewport.
Add-on to bring virtual reality devices to the Blender viewport.

This is work in progress, use at your own risk.

Expand All @@ -13,10 +13,13 @@ Oculus Legacy (Linux, Mac, Windows)
Oculus (Windows)
* Oculus 0.7 runtime

Note
====
* Windows 64 builds are not working at the moment, use 32 bits instead
* Extended Mode is the only supported mode
HTC Vive (Windows)
* OpenVR 0.9.20 runtime

Current Known Issues
====================
HTC Vive: TODO: Fix Blender crash on OpenVR when stopping. (Pausing works).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any clues on why you are getting this crash? Do you have a segfault or it isreally simply a freeze?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • note to self: to test oculus 64 bits with this change

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did fix this crash on the commit https://github.com/cedeon/hmd_sdk_bridge/commit/e70a76e2929385eb5a55d8bf6941d83a576b6f49 . It was simply a missing return statement. I need to remove this from the readme.



How to Use
==========
Expand Down Expand Up @@ -79,8 +82,9 @@ Roadmap
Credits
=======
* Oculus SDK 0.5 wrapper by https://github.com/jherico/python-ovrsdk
* Oculus SDK 0.7 bridge: Dalai Felinto and Djalma Lucio @ Visgraf / IMPA
* Oculus SDK 0.7 bridge: Dalai Felinto and Djalma Lucio @ Visgraf / IMPA
* Blender Addon - Dalai Felinto - http://www.dalaifelinto.com
* OpenVR Implementation by William Culver (@cedeon)

Acknowledgements
================
Expand Down
1 change: 1 addition & 0 deletions space_view3d_virtual_reality/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class VirtualRealityPreferences(bpy.types.AddonPreferences):
description="Library to use for the display",
items=(("OCULUS", "Oculus", "Oculus - oculus.com"),
("OCULUS_LEGACY", "Oculus Legacy", "Oculus 0.5 - oculus.com"),
("VIVE", "HTC Vive", "OpenVR"),
("DEBUG", "Debug", "Debug backend - no real HMD"),
),
default="OCULUS_LEGACY",
Expand Down
13 changes: 12 additions & 1 deletion space_view3d_virtual_reality/hmd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ def HMD(display_backend, context, error_callback):
"""
from .oculus import Oculus
from .oculus_legacy import OculusLegacy
from .openvr import OpenVR
from .debug import Debug

displays = {
'OCULUS':Oculus,
'OCULUS_LEGACY':OculusLegacy,
'VIVE':OpenVR,
'DEBUG':Debug,
}

Expand Down Expand Up @@ -63,6 +65,7 @@ class HMD_Base:
"_modelview_matrix",
"_near",
"_far",
"_status",
}

def __init__(self, name, is_direct_mode, context, error_callback):
Expand All @@ -79,6 +82,7 @@ def __init__(self, name, is_direct_mode, context, error_callback):
self._eye_orientation_raw = [[1.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0]]
self._eye_position_raw = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
self._scale = self._calculateScale(context)
self._status = "Uninitialized"

self._updateViewClipping(context)

Expand Down Expand Up @@ -118,6 +122,14 @@ def projection_matrix(self):
def modelview_matrix(self):
return self._modelview_matrix[self._current_eye]

@property
def status(self):
return self._status

@status.setter
def status(self, value):
self._status = value

def setEye(self, eye):
self._current_eye = int(bool(eye))

Expand Down Expand Up @@ -295,4 +307,3 @@ def _convertMatrixTo4x4(self, value):
matrix[3] = value[12:16]

return matrix.transposed()

4 changes: 3 additions & 1 deletion space_view3d_virtual_reality/hmd/oculus.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def init(self, context):
if not self._setup():
raise Exception("Failed to setup Oculus")

# set status to okay.
self.status = "HMD Initialized"

except Exception as E:
self.error("init", E, True)
self._hmd = None
Expand Down Expand Up @@ -128,4 +131,3 @@ def quit(self):
"""
self._hmd = None
return super(Oculus, self).quit()

141 changes: 141 additions & 0 deletions space_view3d_virtual_reality/hmd/openvr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""
OpenVR Compatible (HTC Vive)
=============

OpenVR Compatible head mounted display
It uses a python wrapper to connect with the SDK
"""

from . import HMD_Base

from ..lib import (
checkModule,
)

class OpenVR(HMD_Base):
def __init__(self, context, error_callback):
super(OpenVR, self).__init__('OpenVR', True, context, error_callback)
checkModule('hmd_sdk_bridge')

def _getHMDClass(self):
"""
This is the python interface to the DLL file in hmd_sdk_bridge.
"""
from bridge.hmd.openvr import HMD
return HMD

@property
def projection_matrix(self):
if self._current_eye:
matrix = self._hmd.getProjectionMatrixRight(self._near, self._far)
else:
matrix = self._hmd.getProjectionMatrixLeft(self._near, self._far)

self.projection_matrix = matrix
return super(OpenVR, self).projection_matrix

@projection_matrix.setter
def projection_matrix(self, value):
self._projection_matrix[self._current_eye] = \
self._convertMatrixTo4x4(value)


def init(self, context):
"""
Initialize device

:return: return True if the device was properly initialized
:rtype: bool
"""
try:
HMD = self._getHMDClass()
self._hmd = HMD()

# bail out early if we didn't initialize properly
if self._hmd.get_state_bool() == False:
raise Exception(self._hmd.get_status())

# Tell the user our status at this point.
self.status = "HMD Init OK. Make sure lighthouses running else no display."

# gather arguments from HMD
self.setEye(0)
self.width = self._hmd.width_left
self.height = self._hmd.height_left

self.setEye(1)
self.width = self._hmd.width_right
self.height = self._hmd.height_right

# initialize FBO
if not super(OpenVR, self).init():
raise Exception("Failed to initialize HMD")

# send it back to HMD
if not self._setup():
raise Exception("Failed to setup OpenVR Compatible HMD")

except Exception as E:
self.error("OpenVR.init", E, True)
self._hmd = None
return False

else:
return True

def _setup(self):
return self._hmd.setup(self._color_texture[0], self._color_texture[1])

def loop(self, context):
"""
Get fresh tracking data
"""
try:
data = self._hmd.update()

self._eye_orientation_raw[0] = data[0]
self._eye_orientation_raw[1] = data[2]
self._eye_position_raw[0] = data[1]
self._eye_position_raw[1] = data[3]

# update matrices
super(OpenVR, self).loop(context)

except Exception as E:
self.error("OpenVR.loop", E, False)
return False

#if VERBOSE:
# print("Left Eye Orientation Raw: " + str(self._eye_orientation_raw[0]))
# print("Right Eye Orientation Raw: " + str(self._eye_orientation_raw[1]))

return True

def frameReady(self):
"""
The frame is ready to be sent to the device
"""
try:
self._hmd.frameReady()

except Exception as E:
self.error("OpenVR.frameReady", E, False)
return False

return True

def reCenter(self):
"""
Re-center the HMD device

:return: return True if success
:rtype: bool
"""
return self._hmd.reCenter()

def quit(self):
"""
Garbage collection
"""
self._hmd = None
return super(OpenVR, self).quit()
2 changes: 1 addition & 1 deletion space_view3d_virtual_reality/lib/hmd_sdk_bridge
7 changes: 5 additions & 2 deletions space_view3d_virtual_reality/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def invoke(self, context, event):
return {'CANCELLED'}

if self.init(context):
print('Running Modal...')
return {'RUNNING_MODAL'}
else:
# quit right away
Expand Down Expand Up @@ -249,7 +250,8 @@ def init(self, context):
self._hash_master = hash(context.area)

# setup modal
self._timer = wm.event_timer_add(1.0 / 75.0, context.window) # 75 Hz
# TODO: check: cedeon changed to: 90Hz
self._timer = wm.event_timer_add(1.0 / 90.0, context.window) # 90 Hz
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may need to be an option per HMD. I will need to check how does the Oculus behave with this change.

self._handle_pre = bpy.types.SpaceView3D.draw_handler_add(self._draw_callback_pre, (context,), 'WINDOW', 'PRE_VIEW')
self._handle_post = bpy.types.SpaceView3D.draw_handler_add(self._draw_callback_post, (context,), 'WINDOW', 'POST_VIEW')
self._handle_pixel = bpy.types.SpaceView3D.draw_handler_add(self._draw_callback_pixel, (context,), 'WINDOW', 'POST_PIXEL')
Expand All @@ -267,6 +269,8 @@ def _init(self, context):
if not self._hmd.init(context):
self.report({'ERROR'}, "Error initializing device")
return False
else:
self.report({'INFO'}, self._hmd.status )

# get the data from device
color_texture = [0, 0]
Expand Down Expand Up @@ -784,4 +788,3 @@ def unregister():
del bpy.types.WindowManager.virtual_reality
bpy.utils.unregister_class(VirtualRealityInfo)
bpy.utils.unregister_class(VirtualRealityCommandInfo)