diff --git a/CMakeLists.txt b/CMakeLists.txt index e3c5450..802ff4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,12 +6,22 @@ PROJECT(OsgOculusViewer) SET(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -# Show relative paths options -OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths in makefiles and projects." ON) +# Check if we are doing out of source builds +STRING(COMPARE NOTEQUAL ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} CMAKE_OUT_OF_SOURCE_BUILD) + +# Relative paths can be trouble when doing out of source builds +IF(CMAKE_OUT_OF_SOURCE_BUILD) + SET(DEFAULT_RELATIVE_PATHS OFF) +ELSE() + SET(DEFAULT_RELATIVE_PATHS ON) +ENDIF() + +# Show relative paths options +OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths in makefiles and projects." ${DEFAULT_RELATIVE_PATHS}) MARK_AS_ADVANCED(CMAKE_USE_RELATIVE_PATHS) -# Build example viewer -OPTION(BUILD_EXAMPLE "Enable to build viewer example" ON) +# Build example viewers +OPTION(BUILD_EXAMPLES "Enable to build viewer examples" ON) IF (WIN32) @@ -20,18 +30,28 @@ IF (WIN32) IF(NOT OSG_DIR) MESSAGE(FATAL_ERROR "Error: OpenSceneGraph not found.") ENDIF(NOT OSG_DIR) - + # Where to find OpenSceneGraph third party dependencies - SET(OSG_THIRD_PARTY_DIR CACHE PATH "Path where to find the OpenSceneGraph third party dependencies") + SET(OSG_THIRD_PARTY_DIR $ENV{OSG_THIRD_PARTY_DIR} CACHE PATH "Path where to find the OpenSceneGraph third party dependencies") IF(NOT OSG_THIRD_PARTY_DIR) MESSAGE(FATAL_ERROR "Error: OpenSceneGraph 3rd Party Directory not found.") ENDIF(NOT OSG_THIRD_PARTY_DIR) - + # Where to find Oculus SDK SET(OCULUS_SDK_ROOT_DIR $ENV{OCULUS_SDK_ROOT_DIR} CACHE PATH "Path where to find the Oculus SDK") IF(NOT OCULUS_SDK_ROOT_DIR) MESSAGE(FATAL_ERROR "Error: Oculus SDK not found.") ENDIF(NOT OCULUS_SDK_ROOT_DIR) + + IF(MSVC) + OPTION(VISUAL_STUDIO_EXPRESS "Building with Visual Studio Express" OFF) + IF(VISUAL_STUDIO_EXPRESS) + # If building with Visual Studio Express we must specify location of ATL include directory and libraries + # These are not included in then Visual Studio Express install, but must be installed separately via Windows Driver Kit + SET(ATL_INCLUDE_DIR CACHE PATH "Path where to find the ATL include directory") + SET(ATL_LIBRARY_DIR CACHE PATH "Path where to find the ATL libries directory") + ENDIF(VISUAL_STUDIO_EXPRESS) + ENDIF(MSVC) ENDIF(WIN32) #Solution @@ -45,20 +65,31 @@ FIND_PACKAGE( OpenGL REQUIRED ) FIND_PACKAGE( OpenSceneGraph REQUIRED osgViewer osgDB osgGA) FIND_PACKAGE( OculusSDK REQUIRED ) +# Oculus SDK dependencies for Mac OSX +IF (APPLE) + FIND_LIBRARY (CORE_FOUNDATION CoreFoundation) + FIND_LIBRARY (CORE_GRAPHICS CoreGraphics) + FIND_LIBRARY (IOKIT IOKit) +ENDIF (APPLE) + INCLUDE_DIRECTORIES(BEFORE ${OPENGL_INCLUDE_DIR} ${OPENSCENEGRAPH_INCLUDE_DIR} ${OCULUS_SDK_INCLUDE_DIRS} ) +IF(VISUAL_STUDIO_EXPRESS) + INCLUDE_DIRECTORIES(BEFORE + ${ATL_INCLUDE_DIR} + ) +ENDIF(VISUAL_STUDIO_EXPRESS) + # osgViewer::ViewConfig concept requires osg 3.2 or later IF(NOT OPENSCENEGRAPH_VERSION VERSION_EQUAL 3.2.0 AND NOT OPENSCENEGRAPH_VERSION VERSION_GREATER 3.2.0) SET (USE_VIEW_CONFIG OFF) - SET (BUILD_DEPRECATED ON) ELSE() SET (USE_VIEW_CONFIG ON) - OPTION(BUILD_DEPRECATED "Enable to build deprecated version as well" OFF) ENDIF() ############################################################################### @@ -68,18 +99,18 @@ IF(MSVC) # Make sure we use minimal windows.h library without min max macros SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"WIN32_LEAN_AND_MEAN\"") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D \"NOMINMAX\"") - + # Use Link Time Code Generation - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG") - - IF(MSVC80) - # Detech 64-bit portability Issues - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wp64") - ENDIF(MSVC80) - + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG") + + # Add ATL libraries for Visual Studio Express builds + IF(VISUAL_STUDIO_EXPRESS) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LIBPATH:${ATL_LIBRARY_DIR}") + ENDIF(VISUAL_STUDIO_EXPRESS) + OPTION(BUILD_MULTI_PROCESSOR_COMPILATION "Use multiple processors when compiling" ON) MARK_AS_ADVANCED(BUILD_MULTI_PROCESSOR_COMPILATION) - + IF(BUILD_MULTI_PROCESSOR_COMPILATION) # Set multi processor build SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") @@ -95,9 +126,16 @@ IF(UNIX) IF(CMAKE_COMPILER_IS_GNUCC) ADD_DEFINITIONS(-Wall -ansi -pedantic -Wextra) IF (WARNINGS_AS_ERRORS) - ADD_DEFINITIONS(-Werror) + ADD_DEFINITIONS(-Werror) ENDIF(WARNINGS_AS_ERRORS) ENDIF(CMAKE_COMPILER_IS_GNUCC) + IF (APPLE) + # set standard lib, clang defaults to c++0x + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++98") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98 -stdlib=libstdc++ -Wno-overloaded-virtual -Wno-conversion") + set(WARNING_CFLAGS "") + ENDIF() ENDIF(UNIX) ############################################################################### diff --git a/README.md b/README.md index 463b357..0165f4d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ OsgOculusViewer An OsgViewer with support for the Oculus Rift -Last tested against Oculus SDK 0.2.5 +Last tested against Oculus SDK 0.4.1 Beta To be able to use the osgViewer::ViewConfig version you will need to use OpenSceneGraph 3.2.0 or later. @@ -13,6 +13,8 @@ License Source code is licensed according to the 3-clause license BSD-license. See license.txt for complete licensing information. +**NOTE** By linking to the Oculus SDK libraries you must adhere to the terms of the Oculus SDK License Agreement. + Contributors ------------ @@ -21,3 +23,5 @@ Björn Blissing Jan Ciger Nico Kruithof + +Daniel Sjölie diff --git a/cmake/FindOculusSDK.cmake b/cmake/FindOculusSDK.cmake index dfd0ec3..22d44b1 100644 --- a/cmake/FindOculusSDK.cmake +++ b/cmake/FindOculusSDK.cmake @@ -4,6 +4,7 @@ # OCULUS_SDK_INCLUDE_DIRS - where to find OVR.h, etc. # OCULUS_SDK_LIBRARIES - List of libraries when using OculusSDK. # OCULUS_SDK_FOUND - True if OculusSDK found. +# OCULUS_SDK_VERSION - Version of the OculusSDK if found IF (DEFINED ENV{OCULUS_SDK_ROOT_DIR}) SET(OCULUS_SDK_ROOT_DIR "$ENV{OCULUS_SDK_ROOT_DIR}") @@ -20,29 +21,80 @@ FIND_PATH(OCULUS_SDK_INCLUDE_DIRS NAMES OVR.h HINTS # Determine architecture IF(CMAKE_SIZEOF_VOID_P MATCHES "8") - SET(OCULUS_SDK_LIB_ARCH "x86_64" CACHE STRING "library location") + IF(UNIX) + SET(_OCULUS_SDK_LIB_ARCH "x86_64") + ENDIF() + IF(MSVC) + SET(_OCULUS_SDK_LIB_ARCH "x64") + ENDIF() ELSE() - SET(OCULUS_SDK_LIB_ARCH "i386" CACHE STRING "library location") + IF(UNIX) + SET(_OCULUS_SDK_LIB_ARCH "i386") + ENDIF() + IF(MSVC) + SET(_OCULUS_SDK_LIB_ARCH "Win32") + ENDIF() ENDIF() -MARK_AS_ADVANCED(OCULUS_SDK_LIB_ARCH) + +MARK_AS_ADVANCED(_OCULUS_SDK_LIB_ARCH) # Append "d" to debug libs on windows platform IF (WIN32) SET(CMAKE_DEBUG_POSTFIX d) ENDIF() +# Determine the compiler version for Visual Studio +IF (MSVC) + # Visual Studio 2010 + IF(MSVC10) + SET(_OCULUS_MSVC_DIR "VS2010") + ENDIF() + # Visual Studio 2012 + IF(MSVC11) + SET(_OCULUS_MSVC_DIR "VS2012") + ENDIF() + # Visual Studio 2013 + IF(MSVC12) + SET(_OCULUS_MSVC_DIR "VS2013") + ENDIF() +ENDIF() + +# Try to ascertain the version of the SDK +IF(OCULUS_SDK_INCLUDE_DIRS) + SET(_OCULUS_VERSION_FILE "${OCULUS_SDK_INCLUDE_DIRS}/OVR_Version.h") + + IF(EXISTS "${_OCULUS_VERSION_FILE}") + FILE(STRINGS "${_OCULUS_VERSION_FILE}" _OCULUS_VERSION_FILE_CONTENTS REGEX "#define OVR_[A-Z]+_VERSION[ \t]+[0-9]+") + + STRING(REGEX REPLACE ".*#define OVR_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" OCULUS_SDK_VERSION_MAJOR ${_OCULUS_VERSION_FILE_CONTENTS}) + STRING(REGEX REPLACE ".*#define OVR_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" OCULUS_SDK_VERSION_MINOR ${_OCULUS_VERSION_FILE_CONTENTS}) + STRING(REGEX REPLACE ".*#define OVR_BUILD_VERSION[ \t]+([0-9]+).*" "\\1" OCULUS_SDK_VERSION_BUILD ${_OCULUS_VERSION_FILE_CONTENTS}) + + SET(OCULUS_SDK_VERSION "${OCULUS_SDK_VERSION_MAJOR}.${OCULUS_SDK_VERSION_MINOR}.${OCULUS_SDK_VERSION_BUILD}" CACHE INTERNAL "The version of Oculus SDK which was detected") + ENDIF() +ENDIF() + +# Locate Oculus license file +SET(_OCULUS_SDK_LICENSE_FILE "${OCULUS_SDK_ROOT_DIR}/LICENSE.txt") +IF(EXISTS "${_OCULUS_SDK_LICENSE_FILE}") + SET(OCULUS_SDK_LICENSE_FILE "${_OCULUS_SDK_LICENSE_FILE}" CACHE INTERNAL "The location of the Oculus SDK license file") +ENDIF() + # Look for the library. -FIND_LIBRARY(OCULUS_SDK_LIBRARY NAMES libovr ovr HINTS ${OCULUS_SDK_ROOT_DIR} - ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Win32 - ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Release/${OCULUS_SDK_LIB_ARCH} +FIND_LIBRARY(OCULUS_SDK_LIBRARY NAMES libovr libovr64 ovr HINTS ${OCULUS_SDK_ROOT_DIR} + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/${_OCULUS_SDK_LIB_ARCH}/${_OCULUS_MSVC_DIR} + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Mac/Release + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Release/${_OCULUS_SDK_LIB_ARCH} ) # This will find release lib on Linux if no debug is available - on Linux this is no problem and avoids # having to compile in debug when not needed -FIND_LIBRARY(OCULUS_SDK_LIBRARY_DEBUG NAMES libovr${CMAKE_DEBUG_POSTFIX} ovr${CMAKE_DEBUG_POSTFIX} ovr HINTS - ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Win32 - ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Debug/${OCULUS_SDK_LIB_ARCH} - ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Release/${OCULUS_SDK_LIB_ARCH} +FIND_LIBRARY(OCULUS_SDK_LIBRARY_DEBUG NAMES libovr${CMAKE_DEBUG_POSTFIX} libovr64${CMAKE_DEBUG_POSTFIX} ovr${CMAKE_DEBUG_POSTFIX} ovr libovr HINTS + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/${_OCULUS_SDK_LIB_ARCH}/${_OCULUS_MSVC_DIR} + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Mac/Debug + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Mac/Release + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Debug/${_OCULUS_SDK_LIB_ARCH} + ${OCULUS_SDK_ROOT_DIR}/LibOVR/Lib/Linux/Release/${_OCULUS_SDK_LIB_ARCH} ) MARK_AS_ADVANCED(OCULUS_SDK_LIBRARY) diff --git a/license.txt b/license.txt index a183c9d..d46e7b5 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2013, Swedish National Road and Transport Research Institute +Copyright (c) 2013-2014, Swedish National Road and Transport Research Institute All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af35b79..c94f371 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,153 +1,162 @@ # Target name SET(TARGET_LIBRARYNAME OsgOculus) -SET(TARGET_LIBRARYNAME_DEPRECATED OsgOculus_deprecated) -SET(TARGET_TARGETNAME OsgOculusViewer) -SET(TARGET_TARGETNAME_DEPRECATED OsgOculusViewer_deprecated) +SET(TARGET_TARGETNAME_VIEW_CONFIG OculusViewConfigExample) +SET(TARGET_TARGETNAME_VIEWER OculusViewerExample) +SET(TARGET_TARGETNAME_COMPOSITE_VIEWER OculusCompositeViewerExample) -# Target source files +# Source files for library SET(TARGET_SRC + oculusviewer.cpp oculusdevice.cpp oculuseventhandler.cpp oculusviewconfig.cpp ) -# Target header files +# Header files for library SET(TARGET_H + oculusviewer.h oculusdevice.h oculuseventhandler.h oculusviewconfig.h ) -# Target source files -SET(TARGET_DEPRECATED_SRC - oculusdevice.cpp - hmdcamera.cpp -) -# Target header files -SET(TARGET_DEPRECATED_H - oculusdevice.cpp - hmdcamera.h -) +# Add view config if available +IF (USE_VIEW_CONFIG) + SET(TARGET_SRC ${TARGET_SRC} + oculusviewconfig.cpp + ) + + SET(TARGET_H ${TARGET_H} + oculusviewconfig.h + ) +ENDIF() ##################################################################### # Create library ##################################################################### -IF(USE_VIEW_CONFIG) - ADD_LIBRARY(${TARGET_LIBRARYNAME} ${TARGET_SRC} ${TARGET_H}) - - ##################################################################### - # Linker options - ##################################################################### +ADD_LIBRARY(${TARGET_LIBRARYNAME} ${TARGET_SRC} ${TARGET_H}) - # Link to open gl libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OPENGL_LIBRARIES} ) +##################################################################### +# Linker options +##################################################################### - # Link to OpenSceneGraph libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OPENSCENEGRAPH_LIBRARIES} ) +# Link to open gl libs +TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OPENGL_LIBRARIES} ) + +# Link to OpenSceneGraph libs +TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OPENSCENEGRAPH_LIBRARIES} ) + +# Link to Oculus libs +TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OCULUS_SDK_LIBRARIES} ) + +# Link to libraries needed for Oculus on Visual Studio +IF(MSVC) + TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} winmm.lib ws2_32.lib) +ENDIF(MSVC) + +# Link to libraries needed for Oculus on Linux and Mac +IF(UNIX) + # Oculus SDK dependencies for Mac OSX + IF (APPLE) + TARGET_LINK_LIBRARIES ( + ${TARGET_LIBRARYNAME} + ${CORE_FOUNDATION} + ${CORE_GRAPHICS} + ${IOKIT} + ) + ELSE(APPLE) + # Oculus SDK dependencies for Linux + TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} pthread udev X11 Xinerama) + ENDIF(APPLE) +ENDIF(UNIX) - # Link to Oculus libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} ${OCULUS_SDK_LIBRARIES} ) +##################################################################### +# Create executable +##################################################################### +IF(BUILD_EXAMPLES) + ADD_EXECUTABLE(${TARGET_TARGETNAME_VIEWER} viewerexample.cpp) + TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME_VIEWER} ${TARGET_LIBRARYNAME}) - # Link to libraries needed for Oculus on Windows - IF(WIN32) - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} winmm.lib ) - ENDIF(WIN32) + ADD_EXECUTABLE(${TARGET_TARGETNAME_COMPOSITE_VIEWER} compositeviewerexample.cpp) + TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME_COMPOSITE_VIEWER} ${TARGET_LIBRARYNAME}) - # Link to libraries needed for Oculus on Linux - IF(UNIX) - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME} pthread udev X11 Xinerama) - ENDIF(UNIX) - - ##################################################################### - # Create executable - ##################################################################### - IF(BUILD_EXAMPLE) - ADD_EXECUTABLE(${TARGET_TARGETNAME} osgoculusviewer.cpp) - TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME} ${TARGET_LIBRARYNAME}) - ENDIF(BUILD_EXAMPLE) -ENDIF() + INSTALL(TARGETS ${TARGET_TARGETNAME_VIEWER} ${TARGET_TARGETNAME_COMPOSITE_VIEWER} RUNTIME DESTINATION bin) + + IF (USE_VIEW_CONFIG) + ADD_EXECUTABLE(${TARGET_TARGETNAME_VIEW_CONFIG} viewconfigexample.cpp) + TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME_VIEW_CONFIG} ${TARGET_LIBRARYNAME}) + INSTALL(TARGETS ${TARGET_TARGETNAME_VIEW_CONFIG} RUNTIME DESTINATION bin) + ENDIF() + +ENDIF(BUILD_EXAMPLES) -IF (BUILD_DEPRECATED) - ADD_LIBRARY(${TARGET_LIBRARYNAME_DEPRECATED} ${TARGET_DEPRECATED_SRC} ${TARGET_DEPRECATED_H}) - ##################################################################### - # Linker options - ##################################################################### - - # Link to open gl libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME_DEPRECATED} ${OPENGL_LIBRARIES} ) - - # Link to OpenSceneGraph libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME_DEPRECATED} ${OPENSCENEGRAPH_LIBRARIES} ) - - # Link to Oculus libs - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME_DEPRECATED} ${OCULUS_SDK_LIBRARIES} ) - - # Link to libraries needed for Oculus on Windows - IF(WIN32) - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME_DEPRECATED} winmm.lib ) - ENDIF(WIN32) - - # Link to libraries needed for Oculus on Linux - IF(UNIX) - TARGET_LINK_LIBRARIES(${TARGET_LIBRARYNAME_DEPRECATED} pthread udev X11 Xinerama) - ENDIF(UNIX) - - ##################################################################### - # Create executable - ##################################################################### - IF(BUILD_EXAMPLE) - ADD_EXECUTABLE(${TARGET_TARGETNAME_DEPRECATED} osgoculusviewer_deprecated.cpp) - TARGET_LINK_LIBRARIES(${TARGET_TARGETNAME_DEPRECATED} ${TARGET_LIBRARYNAME_DEPRECATED}) - ENDIF(BUILD_EXAMPLE) -ENDIF() #################################################################### -# Copy shaders if we are doing out of source builds +# Create user file for correct environment string ##################################################################### -STRING(COMPARE NOTEQUAL ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} CMAKE_OUT_OF_SOURCE_BUILD) -IF (CMAKE_OUT_OF_SOURCE_BUILD) - CONFIGURE_FILE(warp.vert warp.vert COPYONLY) - CONFIGURE_FILE(warpWithChromeAb.frag warpWithChromeAb.frag COPYONLY) - CONFIGURE_FILE(warpWithoutChromeAb.frag warpWithoutChromeAb.frag COPYONLY) -ENDIF() +IF(MSVC) + IF (OPENSCENEGRAPH_FOUND) + # Build path + SET(USERFILE_ENVIRONMENT_DEBUG "PATH=") + SET(USERFILE_ENVIRONMENT_RELEASE "PATH=") + + # Add OpenSceneGraph to path + IF (EXISTS "${OSG_DIR}/bin") + SET(OSG_BIN_DIR "${OSG_DIR}/bin" CACHE PATH "Path where to find OpenSceneGraph binaries") + ELSE (EXISTS "${OSG_DIR}/bin") + SET (OSG_BIN_DIR CACHE PATH "Path where to find OpenSceneGraph binaries") + ENDIF(EXISTS "${OSG_DIR}/bin") + SET(USERFILE_ENVIRONMENT_DEBUG "${USERFILE_ENVIRONMENT_DEBUG}${OSG_BIN_DIR}") + SET(USERFILE_ENVIRONMENT_RELEASE "${USERFILE_ENVIRONMENT_RELEASE}${OSG_BIN_DIR}") + + IF (OSG_THIRD_PARTY_DIR) + # Add third party to path + SET(USERFILE_ENVIRONMENT_DEBUG "${USERFILE_ENVIRONMENT_DEBUG};${OSG_THIRD_PARTY_DIR}/bin") + SET(USERFILE_ENVIRONMENT_RELEASE "${USERFILE_ENVIRONMENT_RELEASE};${OSG_THIRD_PARTY_DIR}/bin") + ELSE (OSG_THIRD_PARTY_DIR) + MESSAGE("Warning: OpenSceneGraph 3rd Party Directory not found.") + ENDIF(OSG_THIRD_PARTY_DIR) + + # For visual studio 2010 (MSVC10), 2012 (MSVC11) and 2013 (MSVC12) + IF(MSVC10 OR MSVC11 OR MSVC12) + CONFIGURE_FILE(osgoculusviewer.vcxproj.template ${TARGET_TARGETNAME_VIEWER}.vcxproj.user @ONLY) + CONFIGURE_FILE(osgoculusviewer.vcxproj.template ${TARGET_TARGETNAME_COMPOSITE_VIEWER}.vcxproj.user @ONLY) + IF (USE_VIEW_CONFIG) + CONFIGURE_FILE(osgoculusviewer.vcxproj.template ${TARGET_TARGETNAME_VIEW_CONFIG}.vcxproj.user @ONLY) + ENDIF() + ENDIF() + + ENDIF (OPENSCENEGRAPH_FOUND) +ENDIF(MSVC) #################################################################### -# Create user file for correct environment string +# Install library ##################################################################### + +INSTALL(FILES ${TARGET_H} DESTINATION include) + +INSTALL(TARGETS ${TARGET_LIBRARYNAME} + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +INSTALL(FILES "${PROJECT_SOURCE_DIR}/README.md" DESTINATION . RENAME readme.txt) +INSTALL(FILES "${PROJECT_SOURCE_DIR}/license.txt" DESTINATION . RENAME license_osgoculus.txt) +INSTALL(FILES ${OCULUS_SDK_LICENSE_FILE} DESTINATION . RENAME license_oculus.txt) + +SET(CPACK_PACKAGE_NAME "${TARGET_LIBRARYNAME}-SDK-v") +SET(CPACK_PACKAGE_VERSION_MAJOR "${OCULUS_SDK_VERSION_MAJOR}") +SET(CPACK_PACKAGE_VERSION_MINOR "${OCULUS_SDK_VERSION_MINOR}") +SET(CPACK_PACKAGE_VERSION_PATCH "${OCULUS_SDK_VERSION_BUILD}") +SET(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md") +SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/license.txt") + + IF(WIN32) - IF(MSVC) - IF (OPENSCENEGRAPH_FOUND) - # Build path - SET(USERFILE_ENVIRONMENT_DEBUG "PATH=") - SET(USERFILE_ENVIRONMENT_RELEASE "PATH=") - - # Add OpenSceneGraph to path - IF (EXISTS "${OSG_DIR}/bin") - SET(OSG_BIN_DIR "${OSG_DIR}/bin" CACHE PATH "Path where to find OpenSceneGraph binaries") - ELSE (EXISTS "${OSG_DIR}/bin") - SET (OSG_BIN_DIR CACHE PATH "Path where to find OpenSceneGraph binaries") - ENDIF(EXISTS "${OSG_DIR}/bin") - SET(USERFILE_ENVIRONMENT_DEBUG "${USERFILE_ENVIRONMENT_DEBUG}${OSG_BIN_DIR}") - SET(USERFILE_ENVIRONMENT_RELEASE "${USERFILE_ENVIRONMENT_RELEASE}${OSG_BIN_DIR}") - - IF (OSG_THIRD_PARTY_DIR) - # Add third party to path - SET(USERFILE_ENVIRONMENT_DEBUG "${USERFILE_ENVIRONMENT_DEBUG};${OSG_THIRD_PARTY_DIR}/bin") - SET(USERFILE_ENVIRONMENT_RELEASE "${USERFILE_ENVIRONMENT_RELEASE};${OSG_THIRD_PARTY_DIR}/bin") - ELSE (OSG_THIRD_PARTY_DIR) - MESSAGE("Warning: OpenSceneGraph 3rd Party Directory not found.") - ENDIF(OSG_THIRD_PARTY_DIR) - - # For visual studio 2010 (MSVC10), 2012 (MSVC11) and 2013 (MSVC12) - IF(MSVC10 OR MSVC11 OR MSVC12) - IF (USE_VIEW_CONFIG) - CONFIGURE_FILE(osgoculusviewer.vcxproj.template ${TARGET_TARGETNAME}.vcxproj.user @ONLY) - ENDIF() - IF (BUILD_DEPRECATED) - CONFIGURE_FILE(osgoculusviewer.vcxproj.template ${TARGET_TARGETNAME_DEPRECATED}.vcxproj.user @ONLY) - ENDIF() - ENDIF() + SET(CPACK_GENERATOR "ZIP") +ELSEIF(UNIX) + SET(CPACK_GENERATOR "TGZ;TBZ2;TZ") +ENDIF() - ENDIF (OPENSCENEGRAPH_FOUND) - ENDIF(MSVC) -ENDIF(WIN32) +# Pack files to package +INCLUDE(CPack) diff --git a/src/compositeviewerexample.cpp b/src/compositeviewerexample.cpp new file mode 100644 index 0000000..c06f517 --- /dev/null +++ b/src/compositeviewerexample.cpp @@ -0,0 +1,162 @@ +/* +* compositeviewerexample.cpp +* +* Created on: Jul 03, 2013 +* Author: Bjorn Blissing +*/ +#include "oculusdevice.h" +#include "oculuseventhandler.h" + +#include + +#include +#include + + +int main( int argc, char** argv ) +{ + float nearClip = 0.01f; + float farClip = 10000.0f; + bool useTimewarp = true; + osg::ref_ptr oculusDevice = new OculusDevice(nearClip, farClip, useTimewarp); + // use an ArgumentParser object to manage the program arguments. + osg::ArgumentParser arguments(&argc,argv); + // read the scene from the list of file specified command line arguments. + osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); + + // if not loaded assume no arguments passed in, try use default cow model instead. + if (!loadedModel) loadedModel = osgDB::readNodeFile("cow.osgt"); + + // Still no loaded model, then exit + if (!loadedModel) return 0; + + // Calculate the texture size + const int textureWidth = oculusDevice->renderTargetWidth()/2; + const int textureHeight = oculusDevice->renderTargetHeight(); + // Setup textures for the RTT cameras + osg::ref_ptr textureLeft = new osg::Texture2D; + textureLeft->setTextureSize(textureWidth, textureHeight); + textureLeft->setInternalFormat(GL_RGBA); + osg::ref_ptr textureRight = new osg::Texture2D; + textureRight->setTextureSize(textureWidth, textureHeight); + textureRight->setInternalFormat(GL_RGBA); + // Initialize RTT cameras for each eye + osg::ref_ptr leftEyeRTTCamera = oculusDevice->createRTTCamera(textureLeft, OculusDevice::LEFT, osg::Camera::ABSOLUTE_RF); + leftEyeRTTCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); + leftEyeRTTCamera->addChild( loadedModel ); + osg::ref_ptr rightEyeRTTCamera = oculusDevice->createRTTCamera(textureRight, OculusDevice::RIGHT, osg::Camera::ABSOLUTE_RF); + rightEyeRTTCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); + rightEyeRTTCamera->addChild( loadedModel ); + // Create HUD cameras for each eye + osg::ref_ptr leftCameraWarp = oculusDevice->createWarpOrthoCamera(0.0, 1.0, 0.0, 1.0); + osg::ref_ptr rightCameraWarp = oculusDevice->createWarpOrthoCamera(0.0, 1.0, 0.0, 1.0); + + // Create shader program + osg::ref_ptr program = oculusDevice->createShaderProgram(); + + // Create distortionMesh for each camera + osg::ref_ptr leftDistortionMesh = oculusDevice->distortionMesh(OculusDevice::LEFT, program, 0, 0, textureWidth, textureHeight, true); + leftCameraWarp->addChild(leftDistortionMesh); + osg::ref_ptr rightDistortionMesh = oculusDevice->distortionMesh(OculusDevice::RIGHT, program, 0, 0, textureWidth, textureHeight, true); + rightCameraWarp->addChild(rightDistortionMesh); + + // Add pre draw camera to handle time warp + leftCameraWarp->setPreDrawCallback(new WarpCameraPreDrawCallback(oculusDevice)); + rightCameraWarp->setPreDrawCallback(new WarpCameraPreDrawCallback(oculusDevice)); + + // Attach shaders to each distortion mesh + osg::ref_ptr leftEyeStateSet = leftDistortionMesh->getOrCreateStateSet(); + osg::ref_ptr rightEyeStateSet = rightDistortionMesh->getOrCreateStateSet(); + + oculusDevice->applyShaderParameters(leftEyeStateSet, program, textureLeft, OculusDevice::LEFT); + oculusDevice->applyShaderParameters(rightEyeStateSet, program, textureRight, OculusDevice::RIGHT); + + // Create Trackball manipulator + osg::ref_ptr cameraManipulator = new osgGA::TrackballManipulator; + const osg::BoundingSphere& bs = loadedModel->getBound(); + + if (bs.valid()) { + // Adjust view to object view + cameraManipulator->setHomePosition(osg::Vec3(0, bs.radius()*1.5, 0), osg::Vec3(0, 0, 0), osg::Vec3(0, 0, 1)); + } + + // Add cameras to groups + osg::ref_ptr leftRoot = new osg::Group; + osg::ref_ptr rightRoot = new osg::Group; + leftRoot->addChild(leftEyeRTTCamera); + leftRoot->addChild(leftCameraWarp); + rightRoot->addChild(rightEyeRTTCamera); + rightRoot->addChild(rightCameraWarp); + + osg::ref_ptr traits = oculusDevice->graphicsContextTraits(); + osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits); + + // Attach a callback to detect swap + osg::ref_ptr swapCallback = new OculusSwapCallback(oculusDevice); + gc->setSwapCallback(swapCallback); + + // Create a composite viewer + osgViewer::CompositeViewer viewer(arguments); + + // Create views and attach camera groups to them + osg::ref_ptr leftView = new osgViewer::View; + leftView->setName("LeftEyeView"); + viewer.addView(leftView); + leftView->setSceneData(leftRoot); + leftView->getCamera()->setName("LeftEyeCamera"); + leftView->getCamera()->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); + leftView->getCamera()->setViewport(new osg::Viewport(0, 0, oculusDevice->screenResolutionWidth() / 2, oculusDevice->screenResolutionHeight())); + leftView->getCamera()->setGraphicsContext(gc); + // Add statistics view to only one view + leftView->addEventHandler(new osgViewer::StatsHandler); + // Add Oculus Keyboard Handler to only one view + leftView->addEventHandler(new OculusEventHandler(oculusDevice)); + leftView->setCameraManipulator(cameraManipulator); + osg::ref_ptr rightView = new osgViewer::View; + rightView->setName("RightEyeView"); + viewer.addView(rightView); + rightView->setSceneData(rightRoot); + rightView->getCamera()->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); + rightView->getCamera()->setName("RightEyeCamera"); + rightView->getCamera()->setViewport(new osg::Viewport(oculusDevice->screenResolutionWidth() / 2, 0, oculusDevice->screenResolutionWidth() / 2, oculusDevice->screenResolutionHeight())); + rightView->getCamera()->setGraphicsContext(gc); + rightView->setCameraManipulator(cameraManipulator); + + // Realize viewer + if (!viewer.isRealized()) { + viewer.realize(); + } + + // Create matrix for camera position and orientation & position (from HMD) + osg::Matrix cameraManipulatorViewMatrix; + osg::Matrix hmdMatrix; + // Get the view matrix for each eye for later use + osg::Matrix leftEyeViewMatrix = oculusDevice->viewMatrixLeft(); + osg::Matrix rightEyeViewMatrix = oculusDevice->viewMatrixRight(); + // Set the projection matrix for each eye + leftEyeRTTCamera->setProjectionMatrix(oculusDevice->projectionMatrixLeft()); + rightEyeRTTCamera->setProjectionMatrix(oculusDevice->projectionMatrixRight()); + + // Start Viewer + while (!viewer.done()) { + // Update the pose + oculusDevice->updatePose(swapCallback->frameIndex()); + + osg::Vec3 position = oculusDevice->position(); + osg::Quat orientation = oculusDevice->orientation(); + + hmdMatrix.makeRotate(orientation); + hmdMatrix.preMultTranslate(position); + + leftEyeViewMatrix = oculusDevice->viewMatrixLeft(); + rightEyeViewMatrix = oculusDevice->viewMatrixRight(); + // Get camera matrix from manipulator + cameraManipulatorViewMatrix = cameraManipulator->getInverseMatrix(); + leftEyeRTTCamera->setViewMatrix(leftEyeViewMatrix*cameraManipulatorViewMatrix*hmdMatrix); + rightEyeRTTCamera->setViewMatrix(rightEyeViewMatrix*cameraManipulatorViewMatrix*hmdMatrix); + + viewer.frame(); + } + + return 0; +} \ No newline at end of file diff --git a/src/hmdcamera.cpp b/src/hmdcamera.cpp deleted file mode 100644 index fb83193..0000000 --- a/src/hmdcamera.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * HMDCamera.cpp - * - * Created on: Jun 30, 2013 - * Author: Jan Ciger - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "hmdcamera.h" -#include "oculusdevice.h" - - -HMDCamera::HMDCamera(osgViewer::View* view, osg::ref_ptr dev) : osg::Group(), - m_configured(false), - m_useChromaticAberrationCorrection(false), - m_view(view), - m_device(dev) -{ -} - - -HMDCamera::~HMDCamera() -{ -} - -void HMDCamera::traverse(osg::NodeVisitor& nv) -{ - if (!m_configured) { - configure(); - } - - // Get orientation from oculus sensor - osg::Quat orient = m_device->getOrientation(); - // Nasty hack to update the view offset for each of the slave cameras - // There doesn't seem to be an accessor for this, fortunately the offsets are public - m_view->findSlaveForCamera(m_cameraRTTLeft.get())->_viewOffset.setRotate(orient); - m_view->findSlaveForCamera(m_cameraRTTRight.get())->_viewOffset.setRotate(orient); - osg::Group::traverse(nv); -} - -osg::Camera* HMDCamera::createRTTCamera(osg::Texture* texture, osg::GraphicsContext* gc) const -{ - osg::ref_ptr camera = new osg::Camera; - camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); - camera->setClearMask( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - camera->setDrawBuffer(GL_FRONT); - camera->setReadBuffer(GL_FRONT); - camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); - camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setAllowEventFocus(false); - camera->setGraphicsContext(gc); - camera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - if ( texture ) { - texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); - texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); - camera->setViewport(0, 0, texture->getTextureWidth(), texture->getTextureHeight()); - camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, 0, false, 4, 4); - } - - return camera.release(); -} - -osg::Camera* HMDCamera::createHUDCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc) const -{ - osg::ref_ptr camera = new osg::Camera; - camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); - camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); - camera->setClearMask( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - camera->setRenderOrder(osg::Camera::POST_RENDER); - camera->setAllowEventFocus(false); - camera->setGraphicsContext(gc); - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setProjectionMatrix(osg::Matrix::ortho2D(left, right, bottom, top)); - camera->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); - return camera.release(); -} - -osg::Geode* HMDCamera::createHUDQuad( float width, float height, float scale ) const -{ - osg::Geometry* geom = osg::createTexturedQuadGeometry(osg::Vec3(), - osg::Vec3(width, 0.0f, 0.0f), - osg::Vec3(0.0f, height, 0.0f), - 0.0f, 0.0f, width*scale, height*scale ); - osg::ref_ptr quad = new osg::Geode; - quad->addDrawable( geom ); - int values = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED; - quad->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), values ); - quad->getOrCreateStateSet()->setMode( GL_LIGHTING, values ); - return quad.release(); -} - -void HMDCamera::applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, - osg::Texture2D* texture, OculusDevice::EyeSide eye) const { - stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - stateSet->setAttributeAndModes( program, osg::StateAttribute::ON ); - stateSet->addUniform( new osg::Uniform("WarpTexture", 0) ); - stateSet->addUniform( new osg::Uniform("LensCenter", m_device->lensCenter(eye))); - stateSet->addUniform( new osg::Uniform("ScreenCenter", m_device->screenCenter())); - stateSet->addUniform( new osg::Uniform("Scale", m_device->scale())); - stateSet->addUniform( new osg::Uniform("ScaleIn", m_device->scaleIn())); - stateSet->addUniform( new osg::Uniform("HmdWarpParam", m_device->warpParameters())); - stateSet->addUniform( new osg::Uniform("ChromAbParam", m_device->chromAbParameters())); -} - -void HMDCamera::configure() -{ - const int textureWidth = m_device->scaleFactor() * m_device->hScreenResolution()/2; - const int textureHeight = m_device->scaleFactor() * m_device->vScreenResolution(); - - // master projection matrix - m_view->getCamera()->setProjectionMatrix(m_device->projectionCenterMatrix()); - m_view->setName("Oculus"); - osg::ref_ptr mainCamera = m_view->getCamera(); - mainCamera->setName("Main"); - // Disable scene rendering for main camera - mainCamera->setCullMask(~m_sceneNodeMask); - - osg::ref_ptr textureLeft = new osg::Texture2D; - textureLeft->setTextureSize( textureWidth, textureHeight ); - textureLeft->setInternalFormat( GL_RGBA ); - osg::ref_ptr textureRight = new osg::Texture2D; - textureRight->setTextureSize( textureWidth, textureHeight ); - textureRight->setInternalFormat( GL_RGBA ); - - osg::ref_ptr gc = mainCamera->getGraphicsContext(); - // Create render to texture cameras - m_cameraRTTLeft = createRTTCamera(textureLeft, gc.get()); - m_cameraRTTRight = createRTTCamera(textureRight, gc.get()); - m_cameraRTTLeft->setName("LeftRTT"); - m_cameraRTTRight->setName("RightRTT"); - m_cameraRTTLeft->setCullMask(m_sceneNodeMask); - m_cameraRTTRight->setCullMask(m_sceneNodeMask); - - - // Create HUD cameras for each eye - osg::ref_ptr cameraHUDLeft = createHUDCamera(0.0, 1.0, 0.0, 1.0, gc.get()); - cameraHUDLeft->setName("LeftHUD"); - cameraHUDLeft->setViewport(new osg::Viewport(0, 0, m_device->hScreenResolution() / 2.0f, m_device->vScreenResolution())); - osg::ref_ptr cameraHUDRight = createHUDCamera(0.0, 1.0, 0.0, 1.0, gc.get()); - cameraHUDRight->setName("RightHUD"); - cameraHUDRight->setViewport(new osg::Viewport(m_device->hScreenResolution() / 2.0f, 0, - m_device->hScreenResolution() / 2.0f, m_device->vScreenResolution())); - // Create quads on each camera - osg::ref_ptr leftQuad = createHUDQuad(1.0f, 1.0f); - cameraHUDLeft->addChild(leftQuad); - osg::ref_ptr rightQuad = createHUDQuad(1.0f, 1.0f); - cameraHUDRight->addChild(rightQuad); - - // Set up shaders from the Oculus SDK documentation - osg::ref_ptr program = new osg::Program; - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX); - vertexShader->loadShaderSourceFromFile(osgDB::findDataFile("warp.vert")); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT); - - // Fragment shader with or without correction for chromatic aberration - if (m_useChromaticAberrationCorrection) { - fragmentShader->loadShaderSourceFromFile(osgDB::findDataFile("warpWithChromeAb.frag")); - } else { - fragmentShader->loadShaderSourceFromFile(osgDB::findDataFile("warpWithoutChromeAb.frag")); - } - - program->addShader(vertexShader); - program->addShader(fragmentShader); - - // Attach shaders to each HUD - osg::StateSet* leftEyeStateSet = leftQuad->getOrCreateStateSet(); - osg::StateSet* rightEyeStateSet = rightQuad->getOrCreateStateSet(); - applyShaderParameters(leftEyeStateSet, program.get(), textureLeft.get(), OculusDevice::LEFT_EYE); - applyShaderParameters(rightEyeStateSet, program.get(), textureRight.get(), OculusDevice::RIGHT_EYE); - - // Add cameras as slaves, specifying offsets for the projection - m_view->addSlave(m_cameraRTTLeft.get(), m_device->projectionOffsetMatrix(OculusDevice::LEFT_EYE), - m_device->viewMatrix(OculusDevice::LEFT_EYE), - true); - m_view->addSlave(m_cameraRTTRight.get(), m_device->projectionOffsetMatrix(OculusDevice::RIGHT_EYE), - m_device->viewMatrix(OculusDevice::RIGHT_EYE), - true); - m_view->addSlave(cameraHUDLeft, false); - m_view->addSlave(cameraHUDRight, false); - m_configured = true; -} diff --git a/src/hmdcamera.h b/src/hmdcamera.h deleted file mode 100644 index a0773c8..0000000 --- a/src/hmdcamera.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * HMDCamera.h - * - * Created on: Jun 30, 2013 - * Author: Jan Ciger - */ - -#ifndef _OSG_HMDCAMERA_H_ -#define _OSG_HMDCAMERA_H_ - -#include - -#include "oculusdevice.h" - -namespace osgViewer { - class View; - class NodeVisitor; -} - -class HMDCamera: public osg::Group { - public: - HMDCamera(osgViewer::View* view, osg::ref_ptr dev); - virtual void traverse(osg::NodeVisitor& nv); - void setChromaticAberrationCorrection(bool correctionEnabled) { m_useChromaticAberrationCorrection = correctionEnabled; } - void setSceneNodeMask(osg::Node::NodeMask nodeMask) { m_sceneNodeMask = nodeMask; } - protected: - ~HMDCamera(); - virtual void configure(); - - osg::Camera* createRTTCamera(osg::Texture* tex, osg::GraphicsContext* gc) const; - osg::Camera* createHUDCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc) const; - osg::Geode* createHUDQuad(float width, float height, float scale = 1.0f) const; - void applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, - osg::Texture2D* texture, OculusDevice::EyeSide eye) const; - bool m_configured; - bool m_useChromaticAberrationCorrection; - osg::observer_ptr m_view; - osg::observer_ptr m_cameraRTTLeft, m_cameraRTTRight; - osg::observer_ptr m_device; - osg::Node::NodeMask m_sceneNodeMask; -}; - -#endif /* _OSG_HMDCAMERA_H_ */ diff --git a/src/oculusdevice.cpp b/src/oculusdevice.cpp index 50f3a10..21818fb 100644 --- a/src/oculusdevice.cpp +++ b/src/oculusdevice.cpp @@ -7,279 +7,596 @@ #include "oculusdevice.h" - -OculusDevice::OculusDevice() : - m_deviceManager(0), m_hmdDevice(0), m_sensor(0), m_hmdInfo(0), m_sensorFusion(0), - m_useCustomScaleFactor(false), m_customScaleFactor(1.0f), - m_nearClip(0.3f), m_farClip(5000.0f), m_predictionDelta(0.03f) +#include + +const std::string OculusDevice::m_warpVertexShaderSource( + "#version 110\n" + + "uniform vec2 EyeToSourceUVScale;\n" + "uniform vec2 EyeToSourceUVOffset;\n" + + "attribute vec2 Position;\n" + "attribute vec4 Color;\n" + "attribute vec2 TexCoord0;\n" + "attribute vec2 TexCoord1;\n" + "attribute vec2 TexCoord2;\n" + + "varying vec4 oColor;\n" + "varying vec2 oTexCoord0;\n" + "varying vec2 oTexCoord1;\n" + "varying vec2 oTexCoord2;\n" + + "void main()\n" + "{\n" + " gl_Position.x = Position.x;\n" + " gl_Position.y = Position.y;\n" + " gl_Position.z = 0.5;\n" + " gl_Position.w = 1.0;\n" + " // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).\n" + " // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)\n" + " oTexCoord0 = TexCoord0 * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " oTexCoord0.y = 1.0-oTexCoord0.y;\n" + " oTexCoord1 = TexCoord1 * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " oTexCoord1.y = 1.0-oTexCoord1.y;\n" + " oTexCoord2 = TexCoord2 * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " oTexCoord2.y = 1.0-oTexCoord2.y;\n" + " oColor = Color; // Used for vignette fade.\n" + "}\n" +); + +const std::string OculusDevice::m_warpWithTimewarpVertexShaderSource( + "#version 110\n" + + "uniform vec2 EyeToSourceUVScale;\n" + "uniform vec2 EyeToSourceUVOffset;\n" + "uniform mat4 EyeRotationStart;\n" + "uniform mat4 EyeRotationEnd;\n" + + "attribute vec2 Position;\n" + "attribute vec4 Color;\n" + "attribute vec2 TexCoord0;\n" + "attribute vec2 TexCoord1;\n" + "attribute vec2 TexCoord2;\n" + + "varying vec4 oColor;\n" + "varying vec2 oTexCoord0;\n" + "varying vec2 oTexCoord1;\n" + "varying vec2 oTexCoord2;\n" + + "void main()\n" + "{\n" + " gl_Position.x = Position.x;\n" + " gl_Position.y = Position.y;\n" + " gl_Position.z = 0.0;\n" + " gl_Position.w = 1.0;\n" + + " // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).\n" + " // These are now real world vectors in direction(x, y, 1) relative to the eye of the HMD.\n" + " vec3 TanEyeAngleR = vec3 ( TexCoord0.x, TexCoord0.y, 1.0 );\n" + " vec3 TanEyeAngleG = vec3 ( TexCoord1.x, TexCoord1.y, 1.0 );\n" + " vec3 TanEyeAngleB = vec3 ( TexCoord2.x, TexCoord2.y, 1.0 );\n" + + " mat3 EyeRotation;\n" + " EyeRotation[0] = mix ( EyeRotationStart[0], EyeRotationEnd[0], Color.a ).xyz;\n" + " EyeRotation[1] = mix ( EyeRotationStart[1], EyeRotationEnd[1], Color.a ).xyz;\n" + " EyeRotation[2] = mix ( EyeRotationStart[2], EyeRotationEnd[2], Color.a ).xyz;\n" + " vec3 TransformedR = EyeRotation * TanEyeAngleR;\n" + " vec3 TransformedG = EyeRotation * TanEyeAngleG;\n" + " vec3 TransformedB = EyeRotation * TanEyeAngleB;\n" + + " // Project them back onto the Z=1 plane of the rendered images.\n" + " float RecipZR = 1.0 / TransformedR.z;\n" + " float RecipZG = 1.0 / TransformedG.z;\n" + " float RecipZB = 1.0 / TransformedB.z;\n" + " vec2 FlattenedR = vec2 ( TransformedR.x * RecipZR, TransformedR.y * RecipZR );\n" + " vec2 FlattenedG = vec2 ( TransformedG.x * RecipZG, TransformedG.y * RecipZG );\n" + " vec2 FlattenedB = vec2 ( TransformedB.x * RecipZB, TransformedB.y * RecipZB );\n" + + " // These are now still in TanEyeAngle space.\n" + " // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)\n" + " vec2 SrcCoordR = FlattenedR * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " vec2 SrcCoordG = FlattenedG * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " vec2 SrcCoordB = FlattenedB * EyeToSourceUVScale + EyeToSourceUVOffset;\n" + " oTexCoord0 = SrcCoordR;\n" + " oTexCoord0.y = 1.0-oTexCoord0.y;\n" + " oTexCoord1 = SrcCoordG;\n" + " oTexCoord1.y = 1.0-oTexCoord1.y;\n" + " oTexCoord2 = SrcCoordB;\n" + " oTexCoord2.y = 1.0-oTexCoord2.y;\n" + " oColor = vec4(Color.r, Color.r, Color.r, Color.r); // Used for vignette fade.\n" + "}\n" +); + +const std::string OculusDevice::m_warpFragmentShaderSource( + "#version 110\n" + " \n" + "uniform sampler2D Texture;\n" + " \n" + "varying vec4 oColor;\n" + "varying vec2 oTexCoord0;\n" + "varying vec2 oTexCoord1;\n" + "varying vec2 oTexCoord2;\n" + " \n" + "void main()\n" + "{\n" + " gl_FragColor.r = oColor.r * texture2D(Texture, oTexCoord0).r;\n" + " gl_FragColor.g = oColor.g * texture2D(Texture, oTexCoord1).g;\n" + " gl_FragColor.b = oColor.b * texture2D(Texture, oTexCoord2).b;\n" + " gl_FragColor.a = 1.0;\n" + "}\n" +); + +OculusDevice::OculusDevice(float nearClip, float farClip, bool useTimewarp) : m_hmdDevice(0), + m_nearClip(nearClip), m_farClip(farClip), + m_useTimeWarp(useTimewarp), + m_position(osg::Vec3(0.0f, 0.0f, 0.0f)), + m_orientation(osg::Quat(0.0f, 0.0f, 0.0f, 1.0f)) { - // Init Oculus HMD - OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All)); - m_deviceManager = *OVR::DeviceManager::Create(); - m_hmdDevice = *m_deviceManager->EnumerateDevices().CreateDevice(); + ovr_Initialize(); + + // Enumerate HMD devices + int numberOfDevices = ovrHmd_Detect(); + osg::notify(osg::DEBUG_INFO) << "Number of connected devices: " << numberOfDevices << std::endl; + + // Get first available HMD + m_hmdDevice = ovrHmd_Create(0); + + // If no HMD is found try an emulated device + if (!m_hmdDevice) { + osg::notify(osg::WARN) << "Warning: No device could be found. Creating emulated device " << std::endl; + m_hmdDevice = ovrHmd_CreateDebug(ovrHmd_DK1); + ovrHmd_ResetFrameTiming(m_hmdDevice, 0); + } if (m_hmdDevice) { - m_hmdInfo = new OVR::HMDInfo; + // Print out some information about the HMD + osg::notify(osg::ALWAYS) << "Product: " << m_hmdDevice->ProductName << std::endl; + osg::notify(osg::ALWAYS) << "Manufacturer: " << m_hmdDevice->Manufacturer << std::endl; + osg::notify(osg::ALWAYS) << "VendorId: " << m_hmdDevice->VendorId << std::endl; + osg::notify(osg::ALWAYS) << "ProductId: " << m_hmdDevice->ProductId << std::endl; + osg::notify(osg::ALWAYS) << "SerialNumber: " << m_hmdDevice->SerialNumber << std::endl; + osg::notify(osg::ALWAYS) << "FirmwareVersion: " << m_hmdDevice->FirmwareMajor << "." << m_hmdDevice->FirmwareMinor << std::endl; + + // Get more details about the HMD. + m_resolution = m_hmdDevice->Resolution; + + // Compute recommended render texture size + float pixelsPerDisplayPixel = 1.0f; // Decrease this value to scale the size on render texture on lower performance hardware. Values above 1.0 is unnecessary. - if (!m_hmdDevice->GetDeviceInfo(m_hmdInfo)) { - osg::notify(osg::FATAL) << "Error: Unable to get device info" << std::endl; - } else { - m_sensor = *m_hmdDevice->GetSensor(); - } - } else { - osg::notify(osg::WARN) << "Warning: Unable to find HMD Device, will use default renderpath instead." << std::endl; + ovrSizei recommenedLeftTextureSize = ovrHmd_GetFovTextureSize(m_hmdDevice, ovrEye_Left, m_hmdDevice->DefaultEyeFov[0], pixelsPerDisplayPixel); + ovrSizei recommenedRightTextureSize = ovrHmd_GetFovTextureSize(m_hmdDevice, ovrEye_Right, m_hmdDevice->DefaultEyeFov[1], pixelsPerDisplayPixel); + + // Compute size of render target + m_renderTargetSize.w = recommenedLeftTextureSize.w + recommenedRightTextureSize.w; + m_renderTargetSize.h = osg::maximum(recommenedLeftTextureSize.h, recommenedRightTextureSize.h); + + // Initialize ovrEyeRenderDesc struct. + m_eyeRenderDesc[0] = ovrHmd_GetRenderDesc(m_hmdDevice, ovrEye_Left, m_hmdDevice->DefaultEyeFov[0]); + m_eyeRenderDesc[1] = ovrHmd_GetRenderDesc(m_hmdDevice, ovrEye_Right, m_hmdDevice->DefaultEyeFov[1]); - // Try to connect to sensor only, used for emulated devices - m_sensor = *m_deviceManager->EnumerateDevices().CreateDevice(); - } + ovrVector3f leftEyeAdjust = m_eyeRenderDesc[0].ViewAdjust; + m_leftEyeAdjust.set(leftEyeAdjust.x, leftEyeAdjust.y, leftEyeAdjust.z); + ovrVector3f rightEyeAdjust = m_eyeRenderDesc[1].ViewAdjust; + m_rightEyeAdjust.set(rightEyeAdjust.x, rightEyeAdjust.y, rightEyeAdjust.z); - // Attach sensor - if (m_sensor) { - m_sensorFusion = new OVR::SensorFusion; - m_sensorFusion->AttachToSensor(m_sensor); - m_sensorFusion->SetPredictionEnabled(true); - // Get default sensor prediction delta - m_predictionDelta = m_sensorFusion->GetPredictionDelta(); - } else { - osg::notify(osg::WARN) << "Warning: Unable to connect to tracker sensor." << std::endl; + bool isRightHanded = true; + + ovrMatrix4f leftEyeProjectionMatrix = ovrMatrix4f_Projection(m_eyeRenderDesc[0].Fov, m_nearClip, m_farClip, isRightHanded); + // Transpose matrix + m_leftEyeProjectionMatrix.set(leftEyeProjectionMatrix.M[0][0], leftEyeProjectionMatrix.M[1][0], leftEyeProjectionMatrix.M[2][0], leftEyeProjectionMatrix.M[3][0], + leftEyeProjectionMatrix.M[0][1], leftEyeProjectionMatrix.M[1][1], leftEyeProjectionMatrix.M[2][1], leftEyeProjectionMatrix.M[3][1], + leftEyeProjectionMatrix.M[0][2], leftEyeProjectionMatrix.M[1][2], leftEyeProjectionMatrix.M[2][2], leftEyeProjectionMatrix.M[3][2], + leftEyeProjectionMatrix.M[0][3], leftEyeProjectionMatrix.M[1][3], leftEyeProjectionMatrix.M[2][3], leftEyeProjectionMatrix.M[3][3]); + + ovrMatrix4f rightEyeProjectionMatrix = ovrMatrix4f_Projection(m_eyeRenderDesc[1].Fov, m_nearClip, m_farClip, isRightHanded); + // Transpose matrix + m_rightEyeProjectionMatrix.set(rightEyeProjectionMatrix.M[0][0], rightEyeProjectionMatrix.M[1][0], rightEyeProjectionMatrix.M[2][0], rightEyeProjectionMatrix.M[3][0], + rightEyeProjectionMatrix.M[0][1], rightEyeProjectionMatrix.M[1][1], rightEyeProjectionMatrix.M[2][1], rightEyeProjectionMatrix.M[3][1], + rightEyeProjectionMatrix.M[0][2], rightEyeProjectionMatrix.M[1][2], rightEyeProjectionMatrix.M[2][2], rightEyeProjectionMatrix.M[3][2], + rightEyeProjectionMatrix.M[0][3], rightEyeProjectionMatrix.M[1][3], rightEyeProjectionMatrix.M[2][3], rightEyeProjectionMatrix.M[3][3]); + + // Start the sensor which provides the Rift’s pose and motion. + ovrHmd_ConfigureTracking(m_hmdDevice, ovrTrackingCap_Orientation | + ovrTrackingCap_MagYawCorrection | + ovrTrackingCap_Position, 0); + + beginFrameTiming(); } } OculusDevice::~OculusDevice() { - if (m_sensorFusion) { - // Detach sensor - m_sensorFusion->AttachToSensor(NULL); - delete m_sensorFusion; - m_sensorFusion = NULL; - } - - delete m_hmdInfo; - m_hmdInfo = NULL; - m_sensor.Clear(); - m_hmdDevice.Clear(); - m_deviceManager.Clear(); - - // Do a nice shutdown of the Oculus HMD - if (OVR::System::IsInitialized()) { - OVR::System::Destroy(); - } + ovrHmd_Destroy(m_hmdDevice); + ovr_Shutdown(); } -unsigned int OculusDevice::hScreenResolution() const +unsigned int OculusDevice::screenResolutionWidth() const { - if (m_hmdInfo) { - return m_hmdInfo->HResolution; - } - - // Default value from dev kit - return 1280; + return m_hmdDevice->Resolution.w; } -unsigned int OculusDevice::vScreenResolution() const +unsigned int OculusDevice::screenResolutionHeight() const { - if (m_hmdInfo) { - return m_hmdInfo->VResolution; - } + return m_hmdDevice->Resolution.h; +} + - // Default value from dev kit - return 800; +unsigned int OculusDevice::renderTargetWidth() const +{ + return m_renderTargetSize.w; } -float OculusDevice::hScreenSize() const +unsigned int OculusDevice::renderTargetHeight() const { - if (m_hmdInfo) { - return m_hmdInfo->HScreenSize; - } + return m_renderTargetSize.h; +} - // Default value from dev kit - return 0.14976f; +osg::Matrix OculusDevice::projectionMatrixCenter() const +{ + osg::Matrix projectionMatrixCenter; + projectionMatrixCenter = m_leftEyeProjectionMatrix.operator*(0.5)+m_rightEyeProjectionMatrix.operator*(0.5); + return projectionMatrixCenter; } -float OculusDevice::vScreenSize() const +osg::Matrix OculusDevice::projectionMatrixLeft() const { - if (m_hmdInfo) { - return m_hmdInfo->VScreenSize; - } + return m_leftEyeProjectionMatrix; +} - // Default value from dev kit - return 0.0936f; +osg::Matrix OculusDevice::projectionMatrixRight() const +{ + return m_rightEyeProjectionMatrix; } -float OculusDevice::vScreenCenter() const +osg::Matrix OculusDevice::projectionOffsetMatrixLeft() const { - if (m_hmdInfo) { - return m_hmdInfo->VScreenCenter; - } + osg::Matrix projectionOffsetMatrix; + float offset = m_leftEyeProjectionMatrix(2, 0); + projectionOffsetMatrix.makeTranslate(osg::Vec3(-offset, 0.0, 0.0)); + return projectionOffsetMatrix; +} - return vScreenSize()*0.5f; +osg::Matrix OculusDevice::projectionOffsetMatrixRight() const +{ + osg::Matrix projectionOffsetMatrix; + float offset = m_rightEyeProjectionMatrix(2, 0); + projectionOffsetMatrix.makeTranslate(osg::Vec3(-offset, 0.0, 0.0)); + return projectionOffsetMatrix; } -float OculusDevice::eyeToScreenDistance() const +osg::Matrix OculusDevice::viewMatrixLeft() const { - if (m_hmdInfo) { - return m_hmdInfo->EyeToScreenDistance; - } + osg::Matrix viewMatrix; + viewMatrix.makeTranslate(m_leftEyeAdjust); + return viewMatrix; +} - // Default value from dev kit - return 0.041f; +osg::Matrix OculusDevice::viewMatrixRight() const +{ + osg::Matrix viewMatrix; + viewMatrix.makeTranslate(m_rightEyeAdjust); + return viewMatrix; } -float OculusDevice::lensSeparationDistance() const +void OculusDevice::updatePose(unsigned int frameIndex) { - if (m_hmdInfo) { - return m_hmdInfo->LensSeparationDistance; + // Ask the API for the times when this frame is expected to be displayed. + m_frameTiming = ovrHmd_GetFrameTiming(m_hmdDevice, frameIndex); + + // Query the HMD for the current tracking state. + ovrTrackingState ts = ovrHmd_GetTrackingState(m_hmdDevice, m_frameTiming.ScanoutMidpointSeconds); + if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { + ovrPoseStatef headpose = ts.HeadPose; + ovrPosef pose = headpose.ThePose; + m_position.set(-pose.Position.x, -pose.Position.y, -pose.Position.z); + m_orientation.set(pose.Orientation.x, pose.Orientation.y, pose.Orientation.z, -pose.Orientation.w); + + // Get head pose for both eyes (used for time warp + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; ++eyeIndex) { + ovrEyeType eye = m_hmdDevice->EyeRenderOrder[eyeIndex]; + m_headPose[eye] = ovrHmd_GetEyePose(m_hmdDevice, eye); + } } +} - // Default value from dev kit - return 0.0635f; +void OculusDevice::resetSensorOrientation() const { + ovrHmd_RecenterPose(m_hmdDevice); } +int OculusDevice::renderOrder(Eye eye) const { + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; ++eyeIndex) { + ovrEyeType ovrEye = m_hmdDevice->EyeRenderOrder[eyeIndex]; + if (ovrEye == ovrEye_Left && eye == LEFT) { + return eyeIndex; + } + if (ovrEye == ovrEye_Right && eye == RIGHT) { + return eyeIndex; + } + } + return 0; +} -float OculusDevice::interpupillaryDistance() const -{ - if (m_hmdInfo) { - return m_hmdInfo->InterpupillaryDistance; +osg::Geode* OculusDevice::distortionMesh(Eye eye, osg::Program* program, int x, int y, int w, int h, bool splitViewport) { + osg::ref_ptr geode = new osg::Geode; + // Allocate & generate distortion mesh vertices. + ovrDistortionMesh meshData; + ovrHmd_CreateDistortionMesh(m_hmdDevice, m_eyeRenderDesc[eye].Eye, m_eyeRenderDesc[eye].Fov, ovrDistortionCap_Chromatic | ovrDistortionCap_TimeWarp, &meshData); + + // Now parse the vertex data and create a render ready vertex buffer from it + ovrDistortionVertex* ov = meshData.pVertexData; + osg::Vec2Array* positionArray = new osg::Vec2Array; + osg::Vec4Array* colorArray = new osg::Vec4Array; + osg::Vec2Array* textureRArray = new osg::Vec2Array; + osg::Vec2Array* textureGArray = new osg::Vec2Array; + osg::Vec2Array* textureBArray = new osg::Vec2Array; + + for (unsigned vertNum = 0; vertNum < meshData.VertexCount; ++vertNum) + { + if (splitViewport) { + // Positions need to be scaled and translated if we are using one viewport per eye + if (eye == LEFT) { + positionArray->push_back(osg::Vec2f(2 * ov[vertNum].ScreenPosNDC.x + 1.0, ov[vertNum].ScreenPosNDC.y)); + } + else if (eye == RIGHT) { + positionArray->push_back(osg::Vec2f(2 * ov[vertNum].ScreenPosNDC.x - 1.0, ov[vertNum].ScreenPosNDC.y)); + } + } + else { + positionArray->push_back(osg::Vec2f(ov[vertNum].ScreenPosNDC.x, ov[vertNum].ScreenPosNDC.y)); + } + + colorArray->push_back(osg::Vec4f(ov[vertNum].VignetteFactor, ov[vertNum].VignetteFactor, ov[vertNum].VignetteFactor, ov[vertNum].TimeWarpFactor)); + textureRArray->push_back(osg::Vec2f(ov[vertNum].TanEyeAnglesR.x, ov[vertNum].TanEyeAnglesR.y)); + textureGArray->push_back(osg::Vec2f(ov[vertNum].TanEyeAnglesG.x, ov[vertNum].TanEyeAnglesG.y)); + textureBArray->push_back(osg::Vec2f(ov[vertNum].TanEyeAnglesB.x, ov[vertNum].TanEyeAnglesB.y)); + } + + // Get triangle indicies + osg::UShortArray* indexArray = new osg::UShortArray; + unsigned short* index = meshData.pIndexData; + for (unsigned indexNum = 0; indexNum < meshData.IndexCount; ++indexNum) { + indexArray->push_back(index[indexNum]); } - // Default value from dev kit, typical values for average human male - return 0.064f; + // Deallocate the mesh data + ovrHmd_DestroyDistortionMesh(&meshData); + + osg::ref_ptr geometry = new osg::Geometry; + osg::ref_ptr drawElement = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, indexArray->size(), (GLushort*) indexArray->getDataPointer()); + geometry->addPrimitiveSet(drawElement); + + GLuint positionLoc = 0; + GLuint colorLoc = 1; + GLuint texCoord0Loc = 2; + GLuint texCoord1Loc = 3; + GLuint texCoord2Loc = 4; + + program->addBindAttribLocation("Position", positionLoc); + geometry->setVertexAttribArray(positionLoc, positionArray); + geometry->setVertexAttribBinding(positionLoc, osg::Geometry::BIND_PER_VERTEX); + + program->addBindAttribLocation("Color", colorLoc); + geometry->setVertexAttribArray(colorLoc, colorArray); + geometry->setVertexAttribBinding(colorLoc, osg::Geometry::BIND_PER_VERTEX); + + program->addBindAttribLocation("TexCoord0", texCoord0Loc); + geometry->setVertexAttribArray(texCoord0Loc, textureRArray); + geometry->setVertexAttribBinding(texCoord0Loc, osg::Geometry::BIND_PER_VERTEX); + + program->addBindAttribLocation("TexCoord1", texCoord1Loc); + geometry->setVertexAttribArray(texCoord1Loc, textureGArray); + geometry->setVertexAttribBinding(texCoord1Loc, osg::Geometry::BIND_PER_VERTEX); + + program->addBindAttribLocation("TexCoord2", texCoord2Loc); + geometry->setVertexAttribArray(texCoord2Loc, textureBArray); + geometry->setVertexAttribBinding(texCoord2Loc, osg::Geometry::BIND_PER_VERTEX); + + // Compute UV scale and offset + ovrRecti eyeRenderViewport; + eyeRenderViewport.Pos.x = x; + eyeRenderViewport.Pos.y = y; + eyeRenderViewport.Size.w = w; + eyeRenderViewport.Size.h = h; + ovrSizei renderTargetSize; + renderTargetSize.w = m_renderTargetSize.w / 2; + renderTargetSize.h = m_renderTargetSize.h; + ovrHmd_GetRenderScaleAndOffset(m_eyeRenderDesc[eye].Fov, renderTargetSize, eyeRenderViewport, m_UVScaleOffset[eye]); + geode->addDrawable(geometry); + return geode.release(); } -osg::Matrix OculusDevice::viewMatrix(EyeSide eye) const -{ - osg::Matrix viewMatrix; +osg::Vec2f OculusDevice::eyeToSourceUVScale(Eye eye) const { + osg::Vec2f uvScale(m_UVScaleOffset[eye][0].x, m_UVScaleOffset[eye][0].y); + return uvScale; +} +osg::Vec2f OculusDevice::eyeToSourceUVOffset(Eye eye) const { + osg::Vec2f uvOffset(m_UVScaleOffset[eye][1].x, m_UVScaleOffset[eye][1].y); + return uvOffset; +} - if (eye == LEFT_EYE) { - viewMatrix.makeTranslate(osg::Vec3f(halfIPD(), 0.0f, 0.0f)); - } else if (eye == RIGHT_EYE) { - viewMatrix.makeTranslate(osg::Vec3f(-halfIPD(), 0.0f, 0.0f)); - } else { - viewMatrix.makeTranslate(osg::Vec3f(0.0f, 0.0f, 0.0f)); - } +osg::Matrixf OculusDevice::eyeRotationStart(Eye eye) const { + osg::Matrixf rotationStart; + + ovrMatrix4f rotationMatrix = m_timeWarpMatrices[eye][0]; + // Transpose matrix + rotationStart.set(rotationMatrix.M[0][0], rotationMatrix.M[1][0], rotationMatrix.M[2][0], rotationMatrix.M[3][0], + rotationMatrix.M[0][1], rotationMatrix.M[1][1], rotationMatrix.M[2][1], rotationMatrix.M[3][1], + rotationMatrix.M[0][2], rotationMatrix.M[1][2], rotationMatrix.M[2][2], rotationMatrix.M[3][2], + rotationMatrix.M[0][3], rotationMatrix.M[1][3], rotationMatrix.M[2][3], rotationMatrix.M[3][3]); + + return rotationStart; +} - return viewMatrix; +osg::Matrixf OculusDevice::eyeRotationEnd(Eye eye) const { + osg::Matrixf rotationEnd; + + ovrMatrix4f rotationMatrix = m_timeWarpMatrices[eye][1]; + // Transpose matrix + rotationEnd.set(rotationMatrix.M[0][0], rotationMatrix.M[1][0], rotationMatrix.M[2][0], rotationMatrix.M[3][0], + rotationMatrix.M[0][1], rotationMatrix.M[1][1], rotationMatrix.M[2][1], rotationMatrix.M[3][1], + rotationMatrix.M[0][2], rotationMatrix.M[1][2], rotationMatrix.M[2][2], rotationMatrix.M[3][2], + rotationMatrix.M[0][3], rotationMatrix.M[1][3], rotationMatrix.M[2][3], rotationMatrix.M[3][3]); + + return rotationEnd; } -osg::Matrix OculusDevice::projectionMatrix(EyeSide eye) const -{ - osg::Matrixf projectionMatrix = projectionOffsetMatrix(eye); - projectionMatrix.preMult(projectionCenterMatrix()); - return projectionMatrix; +void OculusDevice::beginFrameTiming(unsigned int frameIndex) { + m_frameTiming = ovrHmd_BeginFrameTiming(m_hmdDevice, frameIndex); } -osg::Matrix OculusDevice::projectionCenterMatrix() const -{ - osg::Matrix projectionMatrix; - float halfScreenDistance = vScreenSize() * 0.5f * distortionScale(); - float yFov = (180.0f/3.14159f) * 2.0f * atan(halfScreenDistance / eyeToScreenDistance()); - projectionMatrix.makePerspective(yFov, aspectRatio(), m_nearClip, m_farClip); - return projectionMatrix; +void OculusDevice::endFrameTiming() const { + ovrHmd_EndFrameTiming(m_hmdDevice); } -osg::Matrix OculusDevice::projectionOffsetMatrix(EyeSide eye) const -{ - osg::Matrix projectionMatrix; - float eyeProjectionShift = viewCenter() - lensSeparationDistance()*0.5f; - float projectionCenterOffset = 4.0f * eyeProjectionShift / hScreenSize(); - - if (eye == LEFT_EYE) { - projectionMatrix.makeTranslate(osg::Vec3d(projectionCenterOffset, 0, 0)); - } else if (eye == RIGHT_EYE) { - projectionMatrix.makeTranslate(osg::Vec3d(-projectionCenterOffset, 0, 0)); - } else { - projectionMatrix.makeIdentity(); - } +void OculusDevice::waitTillTime() { + // Wait till time-warp point to reduce latency. + ovr_WaitTillTime(m_frameTiming.TimewarpPointSeconds); - return projectionMatrix; + // Get time warp properties + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; ++eyeIndex) { + ovrHmd_GetEyeTimewarpMatrices(m_hmdDevice, (ovrEyeType)eyeIndex, m_headPose[eyeIndex], m_timeWarpMatrices[eyeIndex]); + } } -osg::Vec2f OculusDevice::lensCenter(EyeSide eye) const +osg::Camera* OculusDevice::createRTTCamera(osg::Texture* texture, OculusDevice::Eye eye, osg::Transform::ReferenceFrame referenceFrame, osg::GraphicsContext* gc) const { - if (eye == LEFT_EYE) { - return osg::Vec2f(1.0f-lensSeparationDistance()/hScreenSize(), 0.5f); - } else if (eye == RIGHT_EYE) { - return osg::Vec2f(lensSeparationDistance()/hScreenSize(), 0.5f); + osg::ref_ptr camera = new osg::Camera; + camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); + camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + camera->setDrawBuffer(GL_FRONT); + camera->setReadBuffer(GL_FRONT); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + camera->setRenderOrder(osg::Camera::PRE_RENDER, renderOrder(eye)); + camera->setAllowEventFocus(false); + camera->setReferenceFrame(referenceFrame); + + if (gc) { + camera->setGraphicsContext(gc); } - return osg::Vec2f(0.5f, 0.5f); -} + if (texture) { + texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); + texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); + camera->setViewport(0, 0, texture->getTextureWidth(), texture->getTextureHeight()); + camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, 0, false, 4, 4); + } -osg::Vec2f OculusDevice::screenCenter() const -{ - return osg::Vec2f(0.5f, 0.5f); + return camera.release(); } -osg::Vec2f OculusDevice::scale() const +osg::Camera* OculusDevice::createWarpOrthoCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc) const { - float scaleFactor = 1.0f/distortionScale(); - return osg::Vec2f(0.5*scaleFactor, 0.5f*scaleFactor*aspectRatio()); + osg::ref_ptr camera = new osg::Camera; + camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); + camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + camera->setRenderOrder(osg::Camera::POST_RENDER); + camera->setAllowEventFocus(false); + + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); + camera->setProjectionMatrix(osg::Matrix::ortho2D(left, right, bottom, top)); + camera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + if (gc) { + camera->setGraphicsContext(gc); + } + return camera.release(); } -osg::Vec2f OculusDevice::scaleIn() const -{ - return osg::Vec2f(2.0f, 2.0f/aspectRatio()); -} +osg::Program* OculusDevice::createShaderProgram() const { + // Set up shaders from the Oculus SDK documentation + osg::ref_ptr program = new osg::Program; + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX); -osg::Vec4f OculusDevice::warpParameters() const -{ - if (m_hmdInfo) { - return osg::Vec4f(m_hmdInfo->DistortionK[0], m_hmdInfo->DistortionK[1], m_hmdInfo->DistortionK[2], m_hmdInfo->DistortionK[3]); + if (m_useTimeWarp) { + vertexShader->setShaderSource(m_warpWithTimewarpVertexShaderSource); + } + else { + vertexShader->setShaderSource(m_warpVertexShaderSource); } - // Default values from devkit - return osg::Vec4f(1.0f, 0.22f, 0.24f, 0.0f); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT); + fragmentShader->setShaderSource(m_warpFragmentShaderSource); + program->addShader(vertexShader); + program->addShader(fragmentShader); + return program.release(); } -osg::Vec4f OculusDevice::chromAbParameters() const -{ - if (m_hmdInfo) { - return osg::Vec4f(m_hmdInfo->ChromaAbCorrection[0], m_hmdInfo->ChromaAbCorrection[1], m_hmdInfo->ChromaAbCorrection[2], m_hmdInfo->ChromaAbCorrection[3]); +void OculusDevice::applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, osg::Texture2D* texture, OculusDevice::Eye eye) const { + stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateSet->setAttributeAndModes(program, osg::StateAttribute::ON); + stateSet->addUniform(new osg::Uniform("Texture", 0)); + stateSet->addUniform(new osg::Uniform("EyeToSourceUVScale", eyeToSourceUVScale(eye))); + stateSet->addUniform(new osg::Uniform("EyeToSourceUVOffset", eyeToSourceUVOffset(eye))); + + // Uniforms needed for time warp + if (m_useTimeWarp) { + osg::ref_ptr eyeRotationStart = new osg::Uniform("EyeRotationStart", this->eyeRotationStart(eye)); + osg::ref_ptr eyeRotationEnd = new osg::Uniform("EyeRotationEnd", this->eyeRotationEnd(eye)); + stateSet->addUniform(eyeRotationStart); + stateSet->addUniform(eyeRotationEnd); + eyeRotationStart->setUpdateCallback(new EyeRotationCallback(EyeRotationCallback::START, this, eye)); + eyeRotationEnd->setUpdateCallback(new EyeRotationCallback(EyeRotationCallback::END, this, eye)); } - - // Default values from devkit - return osg::Vec4f(0.996f, -0.004f, 1.014f, 0.0f); } -osg::Quat OculusDevice::getOrientation() const -{ - // Create identity quaternion - osg::Quat osgQuat(0.0f, 0.0f, 0.0f, 1.0f); +osg::GraphicsContext::Traits* OculusDevice::graphicsContextTraits() const { + // Create screen with match the Oculus Rift resolution + osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); - if (m_sensorFusion && m_sensorFusion->IsAttachedToSensor()) { - OVR::Quatf quat; - - if (m_sensorFusion->IsPredictionEnabled()) { - quat = m_sensorFusion->GetPredictedOrientation(m_predictionDelta); - } else { - quat = m_sensorFusion->GetOrientation(); - } - - osgQuat.set(quat.x, quat.y, quat.z, -quat.w); + if (!wsi) { + osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot create windows." << std::endl; + return 0; } - return osgQuat; + // Get the screen identifiers set in environment variable DISPLAY + osg::GraphicsContext::ScreenIdentifier si; + si.readDISPLAY(); + + // If displayNum has not been set, reset it to 0. + if (si.displayNum < 0) si.displayNum = 0; + + // If screenNum has not been set, reset it to 0. + if (si.screenNum < 0) si.screenNum = 0; + + unsigned int width, height; + wsi->getScreenResolution(si, width, height); + + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->hostName = si.hostName; + traits->screenNum = si.screenNum; + traits->displayNum = si.displayNum; + traits->windowDecoration = false; + traits->x = m_hmdDevice->WindowsPos.x; + traits->y = m_hmdDevice->WindowsPos.y; + traits->width = screenResolutionWidth(); + traits->height = screenResolutionHeight(); + traits->doubleBuffer = true; + traits->sharedContext = 0; + traits->vsync = true; // VSync should always be enabled for Oculus Rift applications + + return traits.release(); } -void OculusDevice::setSensorPredictionEnabled(bool prediction) +void WarpCameraPreDrawCallback::operator()(osg::RenderInfo&) const { - if (m_sensorFusion) { - m_sensorFusion->SetPredictionEnabled(prediction); - } + // Wait till time - warp point to reduce latency. + m_device->waitTillTime(); } -float OculusDevice::distortionScale() const -{ - // Disable distortion scale calculation and use user suppied value instead - if (m_useCustomScaleFactor) { - return m_customScaleFactor; - } +void OculusSwapCallback::swapBuffersImplementation(osg::GraphicsContext *gc) { + // Run the default system swapBufferImplementation + gc->swapBuffersImplementation(); + // End frame timing when swap buffer is done + m_device->endFrameTiming(); + // Start a new frame with incremented frame index + m_device->beginFrameTiming(++m_frameIndex); +} - float lensShift = hScreenSize() * 0.25f - lensSeparationDistance() * 0.5f; - float lensViewportShift = 4.0f * lensShift / hScreenSize(); - float fitRadius = fabs(-1 - lensViewportShift); - float rsq = fitRadius*fitRadius; - osg::Vec4f k = warpParameters(); - float scale = (k[0] + k[1] * rsq + k[2] * rsq * rsq + k[3] * rsq * rsq * rsq); - return scale; +void EyeRotationCallback::operator() (osg::Uniform* uniform, osg::NodeVisitor*) { + if (m_mode == START) { + uniform->set(m_device->eyeRotationStart(m_eye)); + } + else if (m_mode == END) { + uniform->set(m_device->eyeRotationEnd(m_eye)); + } } \ No newline at end of file diff --git a/src/oculusdevice.h b/src/oculusdevice.h index f681bc7..178955e 100644 --- a/src/oculusdevice.h +++ b/src/oculusdevice.h @@ -8,74 +8,139 @@ #ifndef _OSG_OCULUSDEVICE_H_ #define _OSG_OCULUSDEVICE_H_ -#include -#include +// Include the OculusVR SDK +#include "OVR.h" +#include +#include -class OculusDevice : public osg::Referenced { +// Forward declaration +class WarpCameraPreDrawCallback; +class OculusSwapCallback; +class EyeRotationCallback; +class OculusDevice : public osg::Referenced { + friend class WarpCameraPreDrawCallback; + friend class OculusSwapCallback; + friend class EyeRotationCallback; + public: - OculusDevice(); - - enum EyeSide { - CENTER_EYE = 0, - LEFT_EYE = 1, - RIGHT_EYE = 2 + enum Eye + { + LEFT = 0, + RIGHT = 1, + COUNT = 2 }; + OculusDevice(float nearClip, float farClip, bool useTimewarp); - unsigned int hScreenResolution() const; - unsigned int vScreenResolution() const; - float hScreenSize() const; - float vScreenSize() const; - float vScreenCenter() const; - float eyeToScreenDistance() const; - float lensSeparationDistance() const; - float interpupillaryDistance() const; + unsigned int screenResolutionWidth() const; + unsigned int screenResolutionHeight() const; - osg::Matrix viewMatrix(EyeSide eye = CENTER_EYE) const; - osg::Matrix projectionMatrix(EyeSide eye = CENTER_EYE) const; - osg::Matrix projectionOffsetMatrix(EyeSide eye = CENTER_EYE) const; - osg::Matrix projectionCenterMatrix() const; + unsigned int renderTargetWidth() const; + unsigned int renderTargetHeight() const; - osg::Vec2f lensCenter(EyeSide eye = CENTER_EYE) const; - osg::Vec2f screenCenter() const; - osg::Vec4f warpParameters() const; - osg::Vec4f chromAbParameters() const; - osg::Vec2f scale() const; - osg::Vec2f scaleIn() const; + osg::Matrix projectionMatrixCenter() const; + osg::Matrix projectionMatrixLeft() const; + osg::Matrix projectionMatrixRight() const; - float scaleFactor() const { return distortionScale(); } + osg::Matrix projectionOffsetMatrixLeft() const; + osg::Matrix projectionOffsetMatrixRight() const; - float aspectRatio() const { return float (hScreenResolution()/2) / float (vScreenResolution()); } - osg::Quat getOrientation() const; + osg::Matrix viewMatrixLeft() const; + osg::Matrix viewMatrixRight() const; - void setNearClip(float nearClip) { m_nearClip = nearClip; } - void setFarClip(float farclip) { m_farClip = farclip; } + float nearClip() const { return m_nearClip; } + float farClip() const { return m_farClip; } + bool useTimewarp() const { return m_useTimeWarp; } - void setSensorPredictionEnabled(bool prediction); - void setSensorPredictionDelta(float delta) { m_predictionDelta = delta; } - void setCustomScaleFactor(const float& customScaleFactor) { m_useCustomScaleFactor = true; m_customScaleFactor = customScaleFactor; } - - void resetSensorOrientation() { if (m_sensorFusion) m_sensorFusion->Reset(); } + void resetSensorOrientation() const; + void updatePose(unsigned int frameIndex = 0); + + osg::Vec3 position() const { return m_position; } + osg::Quat orientation() const { return m_orientation; } + + osg::Geode* distortionMesh(Eye eye, osg::Program* program, int x, int y, int w, int h, bool splitViewport=false); + osg::Camera* createRTTCamera(osg::Texture* texture, OculusDevice::Eye eye, osg::Transform::ReferenceFrame referenceFrame, osg::GraphicsContext* gc = 0) const; + osg::Camera* createWarpOrthoCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc=0) const; + osg::Program* createShaderProgram() const; + void applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, osg::Texture2D* texture, OculusDevice::Eye eye) const; + osg::GraphicsContext::Traits* graphicsContextTraits() const; protected: ~OculusDevice(); // Since we inherit from osg::Referenced we must make destructor protected - float viewCenter() const { return hScreenSize() * 0.25f; } - float halfIPD() const { return interpupillaryDistance() * 0.5f; } - float distortionScale() const; - - OVR::Ptr m_deviceManager; - OVR::Ptr m_hmdDevice; - OVR::Ptr m_sensor; - OVR::HMDInfo* m_hmdInfo; - OVR::SensorFusion* m_sensorFusion; - bool m_useCustomScaleFactor; - float m_customScaleFactor; + + int renderOrder(Eye eye) const; + osg::Matrixf eyeRotationStart(Eye eye) const; + osg::Matrixf eyeRotationEnd(Eye eye) const; + osg::Vec2f eyeToSourceUVScale(Eye eye) const; + osg::Vec2f eyeToSourceUVOffset(Eye eye) const; + + void beginFrameTiming(unsigned int frameIndex = 0); + void endFrameTiming() const; + void waitTillTime(); + + static const std::string m_warpVertexShaderSource; + static const std::string m_warpWithTimewarpVertexShaderSource; + static const std::string m_warpFragmentShaderSource; + + ovrHmd m_hmdDevice; + ovrSizei m_resolution; + ovrSizei m_renderTargetSize; + ovrEyeRenderDesc m_eyeRenderDesc[2]; + ovrVector2f m_UVScaleOffset[2][2]; + ovrFrameTiming m_frameTiming; + ovrPosef m_headPose[2]; + ovrMatrix4f m_timeWarpMatrices[2][2]; + + osg::Matrixf m_leftEyeProjectionMatrix; + osg::Matrixf m_rightEyeProjectionMatrix; + osg::Vec3f m_leftEyeAdjust; + osg::Vec3f m_rightEyeAdjust; + + osg::Vec3 m_position; + osg::Quat m_orientation; + float m_nearClip; float m_farClip; - float m_predictionDelta; + bool m_useTimeWarp; private: OculusDevice(const OculusDevice&); // Do not allow copy + OculusDevice& operator=(const OculusDevice&); // Do not allow assignment operator. +}; + +class WarpCameraPreDrawCallback : public osg::Camera::DrawCallback +{ +public: + WarpCameraPreDrawCallback(osg::ref_ptr device) : m_device(device) {} + virtual void operator()(osg::RenderInfo& renderInfo) const; +protected: + osg::observer_ptr m_device; +}; + +class OculusSwapCallback : public osg::GraphicsContext::SwapCallback { +public: + OculusSwapCallback(osg::ref_ptr device) : m_device(device), m_frameIndex(0) {} + void swapBuffersImplementation(osg::GraphicsContext *gc); + int frameIndex() const { return m_frameIndex; } +private: + osg::observer_ptr m_device; + int m_frameIndex; +}; + +class EyeRotationCallback : public osg::Uniform::Callback +{ +public: + enum Mode + { + START, + END + }; + EyeRotationCallback(const Mode mode, const OculusDevice* device, const OculusDevice::Eye& eye) : m_mode(mode), m_device(device), m_eye(eye) {} + virtual void operator() (osg::Uniform* uniform, osg::NodeVisitor* nv); +protected: + const Mode m_mode; + const OculusDevice* m_device; + const OculusDevice::Eye m_eye; }; #endif /* _OSG_OCULUSDEVICE_H_ */ diff --git a/src/oculuseventhandler.cpp b/src/oculuseventhandler.cpp index d7a3154..fb65c2d 100644 --- a/src/oculuseventhandler.cpp +++ b/src/oculuseventhandler.cpp @@ -6,6 +6,7 @@ */ #include "oculuseventhandler.h" +#include "oculusdevice.h" bool OculusEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& ad) { @@ -16,7 +17,7 @@ bool OculusEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActio switch(ea.getKey()) { case osgGA::GUIEventAdapter::KEY_R: - m_oculusViewConfig->resetSensorOrientation(); + m_oculusDevice->resetSensorOrientation(); return osgGA::GUIEventHandler::handle(ea, ad); break; default: diff --git a/src/oculuseventhandler.h b/src/oculuseventhandler.h index ce6c6fa..e8a2cc5 100644 --- a/src/oculuseventhandler.h +++ b/src/oculuseventhandler.h @@ -10,15 +10,16 @@ #include -#include "oculusviewconfig.h" +// Forward declaration +class OculusDevice; class OculusEventHandler : public osgGA::GUIEventHandler { public: - OculusEventHandler(osg::ref_ptr viewConfig) : m_oculusViewConfig(viewConfig) {} + OculusEventHandler(osg::ref_ptr device) : m_oculusDevice(device) {} virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&); protected: - osg::ref_ptr m_oculusViewConfig; + osg::ref_ptr m_oculusDevice; }; diff --git a/src/oculusviewconfig.cpp b/src/oculusviewconfig.cpp index b334bb2..e2be9c3 100644 --- a/src/oculusviewconfig.cpp +++ b/src/oculusviewconfig.cpp @@ -4,135 +4,23 @@ * Created on: Sept 26, 2013 * Author: Bjorn Blissing & Jan Ciger */ -#include -#include -#include -#include -#include - -#include -#include - -#include - #include "oculusviewconfig.h" -#include "oculusdevice.h" - -osg::Camera* OculusViewConfig::createRTTCamera(osg::Texture* texture, osg::GraphicsContext* gc) const -{ - osg::ref_ptr camera = new osg::Camera; - camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); - camera->setClearMask( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - camera->setDrawBuffer(GL_FRONT); - camera->setReadBuffer(GL_FRONT); - camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); - camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setAllowEventFocus(false); - camera->setGraphicsContext(gc); - camera->setReferenceFrame(osg::Camera::RELATIVE_RF); - - if ( texture ) { - texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); - texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR); - camera->setViewport(0, 0, texture->getTextureWidth(), texture->getTextureHeight()); - camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, 0, false, 4, 4); - } - - return camera.release(); -} - -osg::Camera* OculusViewConfig::createHUDCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc) const -{ - osg::ref_ptr camera = new osg::Camera; - camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f)); - camera->setClearMask( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - camera->setRenderOrder(osg::Camera::POST_RENDER); - camera->setAllowEventFocus(false); - camera->setGraphicsContext(gc); - camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); - camera->setProjectionMatrix(osg::Matrix::ortho2D(left, right, bottom, top)); - camera->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); - return camera.release(); -} -osg::Geode* OculusViewConfig::createHUDQuad( float width, float height, float scale ) const -{ - osg::Geometry* geom = osg::createTexturedQuadGeometry(osg::Vec3(), - osg::Vec3(width, 0.0f, 0.0f), - osg::Vec3(0.0f, height, 0.0f), - 0.0f, 0.0f, width*scale, height*scale ); - osg::ref_ptr quad = new osg::Geode; - quad->addDrawable( geom ); - int values = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED; - quad->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), values ); - quad->getOrCreateStateSet()->setMode( GL_LIGHTING, values ); - return quad.release(); -} - -void OculusViewConfig::applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, - osg::Texture2D* texture, OculusDevice::EyeSide eye) const { - stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - stateSet->setAttributeAndModes( program, osg::StateAttribute::ON ); - stateSet->addUniform( new osg::Uniform("WarpTexture", 0) ); - stateSet->addUniform( new osg::Uniform("LensCenter", m_device->lensCenter(eye))); - stateSet->addUniform( new osg::Uniform("ScreenCenter", m_device->screenCenter())); - stateSet->addUniform( new osg::Uniform("Scale", m_device->scale())); - stateSet->addUniform( new osg::Uniform("ScaleIn", m_device->scaleIn())); - stateSet->addUniform( new osg::Uniform("HmdWarpParam", m_device->warpParameters())); - stateSet->addUniform( new osg::Uniform("ChromAbParam", m_device->chromAbParameters())); -} +#include "oculuseventhandler.h" void OculusViewConfig::configure(osgViewer::View& view) const { - m_device->setNearClip(m_nearClip); - m_device->setFarClip(m_farClip); - m_device->setSensorPredictionEnabled(m_useSensorPrediction); - m_device->setSensorPredictionDelta(m_predictionDelta); - - if (m_useCustomScaleFactor) { - m_device->setCustomScaleFactor(m_customScaleFactor); - } - - // Create screen with match the Oculus Rift resolution - osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); - - if (!wsi) { - osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<getScreenResolution(si, width, height); - - osg::ref_ptr traits = new osg::GraphicsContext::Traits; - traits->hostName = si.hostName; - traits->screenNum = si.screenNum; - traits->displayNum = si.displayNum; - traits->windowDecoration = false; - traits->x = 0; - traits->y = 0; - traits->width = m_device->hScreenResolution(); - traits->height = m_device->vScreenResolution(); - traits->doubleBuffer = true; - traits->sharedContext = 0; - traits->vsync = true; // VSync should always be enabled for Oculus Rift applications - // Create a graphic context based on our desired traits + osg::ref_ptr traits = m_device->graphicsContextTraits(); osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits); if (!gc) { osg::notify(osg::NOTICE) << "Error, GraphicsWindow has not been created successfully" << std::endl; return; } + + // Attach a callback to detect swap + osg::ref_ptr swapCallback = new OculusSwapCallback(m_device); + gc->setSwapCallback(swapCallback); osg::ref_ptr camera = view.getCamera(); camera->setName("Main"); @@ -143,10 +31,10 @@ void OculusViewConfig::configure(osgViewer::View& view) const camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); // Disable automatic computation of near and far plane on main camera, will propagate to slave cameras camera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); - const int textureWidth = m_device->scaleFactor() * m_device->hScreenResolution()/2; - const int textureHeight = m_device->scaleFactor() * m_device->vScreenResolution(); + const int textureWidth = m_device->renderTargetWidth()/2; + const int textureHeight = m_device->renderTargetHeight(); // master projection matrix - camera->setProjectionMatrix(m_device->projectionCenterMatrix()); + camera->setProjectionMatrix(m_device->projectionMatrixCenter()); // Create textures for RTT cameras osg::ref_ptr textureLeft = new osg::Texture2D; textureLeft->setTextureSize( textureWidth, textureHeight ); @@ -155,70 +43,58 @@ void OculusViewConfig::configure(osgViewer::View& view) const textureRight->setTextureSize( textureWidth, textureHeight ); textureRight->setInternalFormat( GL_RGBA ); // Create RTT cameras and attach textures - osg::ref_ptr cameraRTTLeft = createRTTCamera(textureLeft, gc); - osg::ref_ptr cameraRTTRight = createRTTCamera(textureRight, gc); + osg::ref_ptr cameraRTTLeft = m_device->createRTTCamera(textureLeft, OculusDevice::LEFT, osg::Camera::RELATIVE_RF, gc); + osg::ref_ptr cameraRTTRight = m_device->createRTTCamera(textureRight, OculusDevice::RIGHT, osg::Camera::RELATIVE_RF, gc); cameraRTTLeft->setName("LeftRTT"); cameraRTTRight->setName("RightRTT"); cameraRTTLeft->setCullMask(m_sceneNodeMask); cameraRTTRight->setCullMask(m_sceneNodeMask); - // Create HUD cameras for left eye - osg::ref_ptr cameraHUDLeft = createHUDCamera(0.0, 1.0, 0.0, 1.0, gc); - cameraHUDLeft->setName("LeftHUD"); - cameraHUDLeft->setViewport(new osg::Viewport(0, 0, - m_device->hScreenResolution() / 2.0f, m_device->vScreenResolution())); - // Create HUD cameras for right eye - osg::ref_ptr cameraHUDRight = createHUDCamera(0.0, 1.0, 0.0, 1.0, gc); - cameraHUDRight->setName("RightHUD"); - cameraHUDRight->setViewport(new osg::Viewport(m_device->hScreenResolution() / 2.0f, 0, - m_device->hScreenResolution() / 2.0f, m_device->vScreenResolution())); - // Create quads for each camera - osg::ref_ptr leftQuad = createHUDQuad(1.0f, 1.0f); - cameraHUDLeft->addChild(leftQuad); - osg::ref_ptr rightQuad = createHUDQuad(1.0f, 1.0f); - cameraHUDRight->addChild(rightQuad); - - // Set up shaders from the Oculus SDK documentation - osg::ref_ptr program = new osg::Program; - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX); - vertexShader->loadShaderSourceFromFile(osgDB::findDataFile("warp.vert")); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT); - - // Fragment shader with or without correction for chromatic aberration - if (m_useChromaticAberrationCorrection) { - fragmentShader->loadShaderSourceFromFile(osgDB::findDataFile("warpWithChromeAb.frag")); - } else { - fragmentShader->loadShaderSourceFromFile(osgDB::findDataFile("warpWithoutChromeAb.frag")); - } - - program->addShader(vertexShader); - program->addShader(fragmentShader); - - // Attach shaders to each HUD - osg::StateSet* leftEyeStateSet = leftQuad->getOrCreateStateSet(); - osg::StateSet* rightEyeStateSet = rightQuad->getOrCreateStateSet(); - applyShaderParameters(leftEyeStateSet, program.get(), textureLeft.get(), OculusDevice::LEFT_EYE); - applyShaderParameters(rightEyeStateSet, program.get(), textureRight.get(), OculusDevice::RIGHT_EYE); + // Create warp ortho camera + osg::ref_ptr cameraWarp = m_device->createWarpOrthoCamera(0.0, 1.0, 0.0, 1.0, gc); + cameraWarp->setName("WarpOrtho"); + cameraWarp->setViewport(new osg::Viewport(0, 0, m_device->screenResolutionWidth(), m_device->screenResolutionHeight())); + + // Create shader program + osg::ref_ptr program = m_device->createShaderProgram(); + + // Create distortionMesh for each camera + osg::ref_ptr leftDistortionMesh = m_device->distortionMesh(OculusDevice::LEFT, program, 0, 0, textureWidth, textureHeight); + cameraWarp->addChild(leftDistortionMesh); + + osg::ref_ptr rightDistortionMesh = m_device->distortionMesh(OculusDevice::RIGHT, program, 0, 0, textureWidth, textureHeight); + cameraWarp->addChild(rightDistortionMesh); + + // Add pre draw camera to handle time warp + cameraWarp->setPreDrawCallback(new WarpCameraPreDrawCallback(m_device)); + + // Attach shaders to each distortion mesh + osg::ref_ptr leftEyeStateSet = leftDistortionMesh->getOrCreateStateSet(); + osg::ref_ptr rightEyeStateSet = rightDistortionMesh->getOrCreateStateSet(); + + m_device->applyShaderParameters(leftEyeStateSet, program.get(), textureLeft.get(), OculusDevice::LEFT); + m_device->applyShaderParameters(rightEyeStateSet, program.get(), textureRight.get(), OculusDevice::RIGHT); + // Add RTT cameras as slaves, specifying offsets for the projection view.addSlave(cameraRTTLeft, - m_device->projectionOffsetMatrix(OculusDevice::LEFT_EYE), - m_device->viewMatrix(OculusDevice::LEFT_EYE), + m_device->projectionOffsetMatrixLeft(), + m_device->viewMatrixLeft(), true); view.addSlave(cameraRTTRight, - m_device->projectionOffsetMatrix(OculusDevice::RIGHT_EYE), - m_device->viewMatrix(OculusDevice::RIGHT_EYE), + m_device->projectionOffsetMatrixRight(), + m_device->viewMatrixRight(), true); - // Add HUD cameras as slaves - view.addSlave(cameraHUDLeft, false); - view.addSlave(cameraHUDRight, false); - + // Add warp camera as slave + view.addSlave(cameraWarp, false); view.setName("Oculus"); + // Connect main camera to node callback that get HMD orientation - if (m_useOrientations) { - camera->setDataVariance(osg::Object::DYNAMIC); - camera->setUpdateCallback(new OculusViewConfigOrientationCallback(cameraRTTLeft, cameraRTTRight, m_device)); - } + camera->setDataVariance(osg::Object::DYNAMIC); + camera->setUpdateCallback(new OculusViewConfigOrientationCallback(cameraRTTLeft, cameraRTTRight, m_device, swapCallback)); + + // Add Oculus keyboard handler + view.addEventHandler(new OculusEventHandler(m_device)); } void OculusViewConfigOrientationCallback::operator() (osg::Node* node, osg::NodeVisitor* nv) @@ -227,12 +103,21 @@ void OculusViewConfigOrientationCallback::operator() (osg::Node* node, osg::Node osg::View* view = mainCamera->getView(); if (view) { - osg::Quat orient = m_device.get()->getOrientation(); + m_device.get()->updatePose(m_swapCallback->frameIndex()); + osg::Vec3 position = m_device.get()->position(); + osg::Quat orientation = m_device.get()->orientation(); + osg::Matrix viewOffsetLeft = m_device.get()->viewMatrixLeft(); + osg::Matrix viewOffsetRight = m_device.get()->viewMatrixRight(); + viewOffsetLeft.preMultTranslate(position); + viewOffsetRight.preMultTranslate(position); + viewOffsetLeft.postMultRotate(orientation); + viewOffsetRight.postMultRotate(orientation); // Nasty hack to update the view offset for each of the slave cameras // There doesn't seem to be an accessor for this, fortunately the offsets are public - view->findSlaveForCamera(m_cameraRTTLeft.get())->_viewOffset.setRotate(orient); - view->findSlaveForCamera(m_cameraRTTRight.get())->_viewOffset.setRotate(orient); + view->findSlaveForCamera(m_cameraRTTLeft.get())->_viewOffset = viewOffsetLeft; + view->findSlaveForCamera(m_cameraRTTRight.get())->_viewOffset = viewOffsetRight; } traverse(node, nv); } + diff --git a/src/oculusviewconfig.h b/src/oculusviewconfig.h index 9c59c80..f265f82 100644 --- a/src/oculusviewconfig.h +++ b/src/oculusviewconfig.h @@ -13,49 +13,18 @@ class OculusViewConfig : public osgViewer::ViewConfig { public: - OculusViewConfig() : osgViewer::ViewConfig(), + OculusViewConfig(float nearClip=0.01f, float farClip=10000.0f, bool useTimewarp=true) : osgViewer::ViewConfig(), m_configured(false), - m_useChromaticAberrationCorrection(true), - m_useOrientations(true), - m_useSensorPrediction(true), - m_useCustomScaleFactor(false), - m_customScaleFactor(1.25f), - m_nearClip(0.3f), - m_farClip(5000.0f), - m_predictionDelta(0.03f), m_sceneNodeMask(0x1), m_device(0) { - m_device = new OculusDevice; + m_device = new OculusDevice(nearClip, farClip, useTimewarp); } - void setEnableOrientationsFromHMD(bool useOrientations) { m_useOrientations = useOrientations; } - void setEnableChromaticAberrationCorrection(bool correctionEnabled) { m_useChromaticAberrationCorrection = correctionEnabled; } - void setNearClip(float nearClip) { m_nearClip = nearClip; } - void setFarClip(float farclip) { m_farClip = farclip; } - void setSensorPredictionEnabled(bool prediction); - void setSensorPredictionDelta(float delta) { m_predictionDelta = delta; } - void resetSensorOrientation() { if (m_device) m_device->resetSensorOrientation(); } - void setUseDefaultScaleFactor(bool useDefault) { m_useCustomScaleFactor = !useDefault; } - void setCustomScaleFactor(const float& customScaleFactor) { m_useCustomScaleFactor = true; m_customScaleFactor = customScaleFactor; } void setSceneNodeMask(osg::Node::NodeMask nodeMask) { m_sceneNodeMask = nodeMask; } virtual void configure(osgViewer::View& view) const; protected: ~OculusViewConfig() {}; - osg::Camera* createRTTCamera(osg::Texture* tex, osg::GraphicsContext* gc) const; - osg::Camera* createHUDCamera(double left, double right, double bottom, double top, osg::GraphicsContext* gc) const; - osg::Geode* createHUDQuad( float width, float height, float scale = 1.0f ) const; - void applyShaderParameters(osg::StateSet* stateSet, osg::Program* program, - osg::Texture2D* texture, OculusDevice::EyeSide eye) const; - bool m_configured; - bool m_useOrientations; - bool m_useChromaticAberrationCorrection; - bool m_useSensorPrediction; - bool m_useCustomScaleFactor; - float m_customScaleFactor; - float m_nearClip; - float m_farClip; - float m_predictionDelta; osg::Node::NodeMask m_sceneNodeMask; osg::ref_ptr m_device; @@ -63,11 +32,15 @@ class OculusViewConfig : public osgViewer::ViewConfig { class OculusViewConfigOrientationCallback : public osg::NodeCallback { public: - OculusViewConfigOrientationCallback(osg::ref_ptr rttLeft, osg::ref_ptr rttRight, osg::observer_ptr device) : m_cameraRTTLeft(rttLeft), m_cameraRTTRight(rttRight), m_device(device) {}; + OculusViewConfigOrientationCallback(osg::ref_ptr rttLeft, + osg::ref_ptr rttRight, + osg::ref_ptr device, + osg::ref_ptr swapCallback) : m_cameraRTTLeft(rttLeft), m_cameraRTTRight(rttRight), m_device(device), m_swapCallback(swapCallback) {}; virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); protected: osg::observer_ptr m_cameraRTTLeft, m_cameraRTTRight; osg::observer_ptr m_device; + osg::observer_ptr m_swapCallback; }; #endif /* _OSG_OCULUSVIEWCONFIG_H_ */ \ No newline at end of file diff --git a/src/oculusviewer.cpp b/src/oculusviewer.cpp new file mode 100644 index 0000000..cc85f1a --- /dev/null +++ b/src/oculusviewer.cpp @@ -0,0 +1,109 @@ +/* + * oculusviewer.cpp + * + * Created on: Jun 30, 2013 + * Author: Jan Ciger & Björn Blissing + */ + +#include "oculusviewer.h" + +#include + +void OculusViewer::traverse(osg::NodeVisitor& nv) +{ + if (!m_configured) { + configure(); + } + + if (m_configured) { + m_device.get()->updatePose(m_swapCallback->frameIndex()); + osg::Vec3 position = m_device.get()->position(); + osg::Quat orientation = m_device.get()->orientation(); + osg::Matrix viewOffsetLeft = m_device.get()->viewMatrixLeft(); + osg::Matrix viewOffsetRight = m_device.get()->viewMatrixRight(); + viewOffsetLeft.preMultTranslate(position); + viewOffsetRight.preMultTranslate(position); + viewOffsetLeft.postMultRotate(orientation); + viewOffsetRight.postMultRotate(orientation); + // Nasty hack to update the view offset for each of the slave cameras + // There doesn't seem to be an accessor for this, fortunately the offsets are public + m_view->findSlaveForCamera(m_cameraRTTLeft.get())->_viewOffset = viewOffsetLeft; + m_view->findSlaveForCamera(m_cameraRTTRight.get())->_viewOffset = viewOffsetRight; + } + osg::Group::traverse(nv); +} + +void OculusViewer::configure() +{ + osg::ref_ptr gc = m_view->getCamera()->getGraphicsContext(); + + // Attach a callback to detect swap + m_swapCallback = new OculusSwapCallback(m_device); + gc->setSwapCallback(m_swapCallback); + + osg::ref_ptr camera = m_view->getCamera(); + camera->setName("Main"); + + // Disable scene rendering for main camera + camera->setCullMask(~m_sceneNodeMask); + + const int textureWidth = m_device->renderTargetWidth()/2; + const int textureHeight = m_device->renderTargetHeight(); + // master projection matrix + camera->setProjectionMatrix(m_device->projectionMatrixCenter()); + // Create textures for RTT cameras + osg::ref_ptr textureLeft = new osg::Texture2D; + textureLeft->setTextureSize(textureWidth, textureHeight); + textureLeft->setInternalFormat(GL_RGBA); + osg::ref_ptr textureRight = new osg::Texture2D; + textureRight->setTextureSize(textureWidth, textureHeight); + textureRight->setInternalFormat(GL_RGBA); + // Create RTT cameras and attach textures + m_cameraRTTLeft = m_device->createRTTCamera(textureLeft, OculusDevice::LEFT, osg::Camera::RELATIVE_RF, gc); + m_cameraRTTRight = m_device->createRTTCamera(textureRight, OculusDevice::RIGHT, osg::Camera::RELATIVE_RF, gc); + m_cameraRTTLeft->setName("LeftRTT"); + m_cameraRTTRight->setName("RightRTT"); + m_cameraRTTLeft->setCullMask(m_sceneNodeMask); + m_cameraRTTRight->setCullMask(m_sceneNodeMask); + + // Create warp ortho camera + osg::ref_ptr cameraWarp = m_device->createWarpOrthoCamera(0.0, 1.0, 0.0, 1.0, gc); + cameraWarp->setName("WarpOrtho"); + cameraWarp->setViewport(new osg::Viewport(0, 0, m_device->screenResolutionWidth(), m_device->screenResolutionHeight())); + + // Create shader program + osg::ref_ptr program = m_device->createShaderProgram(); + + // Create distortionMesh for each camera + osg::ref_ptr leftDistortionMesh = m_device->distortionMesh(OculusDevice::LEFT, program, 0, 0, textureWidth, textureHeight); + cameraWarp->addChild(leftDistortionMesh); + + osg::ref_ptr rightDistortionMesh = m_device->distortionMesh(OculusDevice::RIGHT, program, 0, 0, textureWidth, textureHeight); + cameraWarp->addChild(rightDistortionMesh); + + // Add pre draw camera to handle time warp + cameraWarp->setPreDrawCallback(new WarpCameraPreDrawCallback(m_device)); + + // Attach shaders to each distortion mesh + osg::StateSet* leftEyeStateSet = leftDistortionMesh->getOrCreateStateSet(); + osg::StateSet* rightEyeStateSet = rightDistortionMesh->getOrCreateStateSet(); + + m_device->applyShaderParameters(leftEyeStateSet, program.get(), textureLeft.get(), OculusDevice::LEFT); + m_device->applyShaderParameters(rightEyeStateSet, program.get(), textureRight.get(), OculusDevice::RIGHT); + + // Add RTT cameras as slaves, specifying offsets for the projection + m_view->addSlave(m_cameraRTTLeft.get(), + m_device->projectionOffsetMatrixLeft(), + m_device->viewMatrixLeft(), + true); + m_view->addSlave(m_cameraRTTRight.get(), + m_device->projectionOffsetMatrixRight(), + m_device->viewMatrixRight(), + true); + + // Add warp camera as slave + m_view->addSlave(cameraWarp, false); + m_view->setName("Oculus"); + + m_configured = true; +} diff --git a/src/oculusviewer.h b/src/oculusviewer.h new file mode 100644 index 0000000..86db60a --- /dev/null +++ b/src/oculusviewer.h @@ -0,0 +1,44 @@ +/* + * oculusviewer.h + * + * Created on: Jun 30, 2013 + * Author: Jan Ciger & Björn Blissing + */ + +#ifndef _OSG_OCULUSVIEWER_H_ +#define _OSG_OCULUSVIEWER_H_ + +#include + +#include "oculusdevice.h" + +// Forward declaration +namespace osgViewer { + class View; +} + +class OculusViewer : public osg::Group { + public: + OculusViewer(osgViewer::View* view, osg::ref_ptr dev) : osg::Group(), + m_configured(false), + m_view(view), + m_cameraRTTLeft(0), m_cameraRTTRight(0), + m_device(dev), + m_swapCallback(0), + m_sceneNodeMask(0x1) {}; + virtual void traverse(osg::NodeVisitor& nv); + void setSceneNodeMask(osg::Node::NodeMask nodeMask) { m_sceneNodeMask = nodeMask; } + protected: + ~OculusViewer() {}; + virtual void configure(); + + bool m_configured; + + osg::observer_ptr m_view; + osg::observer_ptr m_cameraRTTLeft, m_cameraRTTRight; + osg::observer_ptr m_device; + osg::ref_ptr m_swapCallback; + osg::Node::NodeMask m_sceneNodeMask; +}; + +#endif /* _OSG_OCULUSVIEWER_H_ */ diff --git a/src/osgoculusviewer.cpp b/src/viewconfigexample.cpp similarity index 88% rename from src/osgoculusviewer.cpp rename to src/viewconfigexample.cpp index ca0f79a..c8176f6 100644 --- a/src/osgoculusviewer.cpp +++ b/src/viewconfigexample.cpp @@ -1,5 +1,5 @@ /* - * main.cpp + * viewconfigexample.cpp * * Created on: Jul 03, 2013 * Author: Bjorn Blissing @@ -7,8 +7,6 @@ #include #include -#include -#include #include "oculuseventhandler.h" #include "oculusviewconfig.h" @@ -31,15 +29,16 @@ int main( int argc, char** argv ) loadedModel->setNodeMask(sceneNodeMask); // Create Oculus View Config - osg::ref_ptr oculusViewConfig = new OculusViewConfig; + float nearClip = 0.01f; + float farClip = 10000.0f; + bool useTimewarp = true; + osg::ref_ptr oculusViewConfig = new OculusViewConfig(nearClip, farClip, useTimewarp); // Set the node mask used for scene oculusViewConfig->setSceneNodeMask(sceneNodeMask); // Create viewer osgViewer::Viewer viewer(arguments); // Add statistics handler viewer.addEventHandler(new osgViewer::StatsHandler); - // Add Oculus keyboard handler - viewer.addEventHandler(new OculusEventHandler(oculusViewConfig)); // Apply view config viewer.apply(oculusViewConfig); // Add loaded model to viewer diff --git a/src/osgoculusviewer_deprecated.cpp b/src/viewerexample.cpp similarity index 52% rename from src/osgoculusviewer_deprecated.cpp rename to src/viewerexample.cpp index b0d38f5..a4b4c4a 100644 --- a/src/osgoculusviewer_deprecated.cpp +++ b/src/viewerexample.cpp @@ -1,29 +1,16 @@ /* - * main.cpp + * viewerexample.cpp * * Created on: Jul 03, 2013 * Author: Bjorn Blissing */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include #include -#include -#include -#include "oculusdevice.h" -#include "hmdcamera.h" +#include "oculusviewer.h" +#include "oculuseventhandler.h" + int main( int argc, char** argv ) { @@ -48,42 +35,13 @@ int main( int argc, char** argv ) } // Open the HMD - osg::ref_ptr oculusDevice = new OculusDevice(); - oculusDevice->setCustomScaleFactor(1.25f); - - // Create screen with match the Oculus Rift resolution - osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); - - if (!wsi) { - osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<getScreenResolution(si, width, height); + float nearClip = 0.01f; + float farClip = 10000.0f; + bool useTimewarp = true; + osg::ref_ptr oculusDevice = new OculusDevice(nearClip, farClip, useTimewarp); - osg::ref_ptr traits = new osg::GraphicsContext::Traits; - traits->hostName = si.hostName; - traits->screenNum = si.screenNum; - traits->displayNum = si.displayNum; - traits->windowDecoration = false; - traits->x = 0; - traits->y = 0; - traits->width = oculusDevice->hScreenResolution(); - traits->height = oculusDevice->vScreenResolution(); - traits->doubleBuffer = true; - traits->sharedContext = 0; - traits->vsync = true; // VSync should always be enabled for Oculus Rift applications + // Get the suggested context traits + osg::ref_ptr traits = oculusDevice->graphicsContextTraits(); // Create a graphic context based on our desired traits osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits); @@ -110,13 +68,14 @@ int main( int argc, char** argv ) osg::Node::NodeMask sceneNodeMask = loadedModel->getNodeMask() & ~0x1; loadedModel->setNodeMask(sceneNodeMask); - osg::ref_ptr hmd_camera = new HMDCamera(&viewer, oculusDevice); - hmd_camera->setChromaticAberrationCorrection(true); - hmd_camera->setSceneNodeMask(sceneNodeMask); - hmd_camera->addChild(loadedModel); - viewer.setSceneData(hmd_camera); + osg::ref_ptr oculusViewer = new OculusViewer(&viewer, oculusDevice); + oculusViewer->setSceneNodeMask(sceneNodeMask); + oculusViewer->addChild(loadedModel); + viewer.setSceneData(oculusViewer); // Add statistics handler viewer.addEventHandler(new osgViewer::StatsHandler); + // Add Oculus Keyboard Handler to only one view + viewer.addEventHandler(new OculusEventHandler(oculusDevice)); // Start Viewer viewer.run(); return 0; diff --git a/src/warp.vert b/src/warp.vert deleted file mode 100644 index f93f8e8..0000000 --- a/src/warp.vert +++ /dev/null @@ -1,7 +0,0 @@ -varying vec2 Texcoord; - -void main( void ) -{ - gl_Position = ftransform(); - Texcoord = gl_MultiTexCoord0.xy; -} diff --git a/src/warpWithChromeAb.frag b/src/warpWithChromeAb.frag deleted file mode 100644 index f710751..0000000 --- a/src/warpWithChromeAb.frag +++ /dev/null @@ -1,38 +0,0 @@ -uniform sampler2D WarpTexture; -uniform vec2 LensCenter; -uniform vec2 ScreenCenter; -uniform vec2 Scale; -uniform vec2 ScaleIn; -uniform vec4 HmdWarpParam; -uniform vec4 ChromAbParam; - -varying vec2 Texcoord; - -void main(void) -{ - vec2 theta = (Texcoord - LensCenter) * ScaleIn; // Scales texture coordinates to [-1, 1] - float rSq = theta.x * theta.x + theta.y * theta.y; - vec2 theta1 = theta * ( HmdWarpParam.x + - HmdWarpParam.y * rSq + - HmdWarpParam.z * rSq * rSq + - HmdWarpParam.w * rSq * rSq * rSq); - // Detect whether blue texture coordinates are out of range since these will scaled out the furthest. - vec2 thetaBlue = theta1 * (ChromAbParam.z + ChromAbParam.w * rSq); - vec2 tcBlue = LensCenter + Scale * thetaBlue; - - if (any(bvec2(clamp(tcBlue, ScreenCenter - vec2(0.5, 0.5), ScreenCenter + vec2(0.5, 0.5)) - tcBlue))) { - gl_FragColor = vec4(0, 0, 0, 0); - return; - } - - // Now do blue texture lookup. - float blue = texture2D(WarpTexture, tcBlue).b; - // Do green lookup (no scaling). - vec2 tcGreen = LensCenter + Scale * theta1; - float green = texture2D(WarpTexture, tcGreen).g; - // Do red scale and lookup. - vec2 thetaRed = theta1 * (ChromAbParam.x + ChromAbParam.y * rSq); - vec2 tcRed = LensCenter + Scale * thetaRed; - float red = texture2D(WarpTexture, tcRed).r; - gl_FragColor = vec4(red, green, blue, 1); -} diff --git a/src/warpWithoutChromeAb.frag b/src/warpWithoutChromeAb.frag deleted file mode 100644 index abc7917..0000000 --- a/src/warpWithoutChromeAb.frag +++ /dev/null @@ -1,31 +0,0 @@ -uniform sampler2D WarpTexture; -uniform vec2 LensCenter; -uniform vec2 ScreenCenter; -uniform vec2 Scale; -uniform vec2 ScaleIn; -uniform vec4 HmdWarpParam; - -varying vec2 Texcoord; - -// Scales input texture coordinates for distortion. -vec2 HmdWarp(vec2 texCoord) -{ - vec2 theta = (texCoord - LensCenter) * ScaleIn; // Scales texture coordinates to [-1, 1] - float rSq = theta.x * theta.x + theta.y * theta.y; - vec2 rvector= theta * ( HmdWarpParam.x + - HmdWarpParam.y * rSq + - HmdWarpParam.z * rSq * rSq + - HmdWarpParam.w * rSq * rSq * rSq); - return LensCenter + Scale * rvector; -} - -void main(void) -{ - vec2 tc = HmdWarp(Texcoord); - - if (any(bvec2(clamp(tc, ScreenCenter - vec2(0.5, 0.5), ScreenCenter + vec2(0.5, 0.5)) - tc))) { - gl_FragColor = vec4(0, 0, 0, 0); - } else { - gl_FragColor = texture2D(WarpTexture, tc); - } -}