Przeglądaj źródła

Added basic Oculus Rift support module, added manual projection matrix mode for Camera, added a way to set projection matrix manually in Renderer

Ivan Safrin 12 lat temu
rodzic
commit
92e34b684a

+ 5 - 0
Core/Contents/Include/PolyCamera.h

@@ -57,6 +57,10 @@ namespace Polycode {
 
 			/** ProjectionMode: Perspective projection, with bounds set by edges of frustum. */
 			static const int PERSPECTIVE_FRUSTUM = 5;
+        
+            /** ProjectionMode: Manual matrix projection. */
+            static const int MANUAL_MATRIX = 6;
+        
 
 			/**
 			* Constructor.
@@ -191,6 +195,7 @@ namespace Polycode {
             virtual void applyClone(Entity *clone, bool deepClone, bool ignoreEditorOnly) const;
 			
 			Matrix4 getProjectionMatrix();
+            void setProjectionMatrix(Matrix4 matrix);
 			
 			Polycode::Rectangle getViewport();
 			

+ 1 - 0
Core/Contents/Include/PolyGLRenderer.h

@@ -132,6 +132,7 @@ namespace Polycode {
 		void drawArrays(int drawType);		
 				
 		void setProjectionOrtho(Number xSize=0.0f, Number ySize=0.0f, Number near=-256.0f, Number far=256.0f, bool centered = false);
+        void setProjectionMatrix(Matrix4 matrix);
 		void setPerspectiveDefaults();
 		
 		void enableBackfaceCulling(bool val);

+ 1 - 0
Core/Contents/Include/PolyRenderer.h

@@ -118,6 +118,7 @@ namespace Polycode {
 		virtual void loadIdentity() = 0;		
 		virtual void setProjectionOrtho(Number xSize=0.0f, Number ySize=0.0f, Number near=-256.0f, Number far=256.0f, bool centered = false) = 0;
 		virtual void setPerspectiveDefaults() = 0;
+        virtual void setProjectionMatrix(Matrix4 matrix) = 0;
 		
 		virtual void setTexture(Texture *texture) = 0;		
 		virtual void enableBackfaceCulling(bool val) = 0;

+ 11 - 2
Core/Contents/Source/PolyCamera.cpp

@@ -329,7 +329,7 @@ void Camera::setPostFilter(Material *shaderMaterial) {
 		
 	this->filterShaderMaterial = shaderMaterial;
 	if(!originalSceneTexture) {
-		renderer->createRenderTextures(&originalSceneTexture, &zBufferSceneTexture, CoreServices::getInstance()->getCore()->getXRes(), CoreServices::getInstance()->getCore()->getYRes(), shaderMaterial->fp16RenderTargets);
+        CoreServices::getInstance()->getRenderer()->createRenderTextures(&originalSceneTexture, &zBufferSceneTexture, CoreServices::getInstance()->getCore()->getXRes(), CoreServices::getInstance()->getCore()->getYRes(), shaderMaterial->fp16RenderTargets);
 	}
 	
 	for(int i=0; i < shaderMaterial->getNumShaders(); i++) {
@@ -443,6 +443,10 @@ void Camera::setProjectionMode(int mode) {
 	projectionMode = mode;
 }
 
+void Camera::setProjectionMatrix(Matrix4 matrix) {
+    projectionMatrix = matrix;
+}
+
 void Camera::doCameraTransform() {
 	
     viewport = renderer->getViewport();
@@ -469,10 +473,15 @@ void Camera::doCameraTransform() {
 		case ORTHO_SIZE_VIEWPORT:
 			renderer->setProjectionOrtho(viewport.w / renderer->getBackingResolutionScaleX(), viewport.h / renderer->getBackingResolutionScaleY(), !topLeftOrtho);
 		break;
+		case MANUAL_MATRIX:
+            renderer->setProjectionMatrix(projectionMatrix);
+        break;
 	}
 	renderer->setExposureLevel(exposureLevel);
 
-	projectionMatrix = renderer->getProjectionMatrix();
+    if(projectionMode != MANUAL_MATRIX) {
+        projectionMatrix = renderer->getProjectionMatrix();
+    }
 
 	if(matrixDirty) {
 		rebuildTransformMatrix();

+ 10 - 0
Core/Contents/Source/PolyGLRenderer.cpp

@@ -566,6 +566,16 @@ void OpenGLRenderer::setProjectionOrtho(Number xSize, Number ySize, Number _near
 	glLoadIdentity();
 }
 
+void OpenGLRenderer::setProjectionMatrix(Matrix4 matrix) {
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    
+	glLoadMatrixd(matrix.ml);
+    
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+}
+
 void OpenGLRenderer::enableBackfaceCulling(bool val) {
 	if(val)
 		glEnable(GL_CULL_FACE);

+ 161 - 0
Modules/Contents/OculusVR/PolycodeOVR.cpp

@@ -0,0 +1,161 @@
+/*
+ Copyright (C) 2014 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#include "PolycodeOVR.h"
+
+PolycodeOVR::PolycodeOVR(Scene *parentScene) {
+    
+    this->parentScene = parentScene;
+    
+    cameraRoot = new Entity();
+    
+    leftCamera = new Camera(parentScene);
+    rightCamera = new Camera(parentScene);
+    
+    leftCamera->setClippingPlanes(0.001, 100.0);
+    leftCamera->frustumCulling = false;
+    rightCamera->setClippingPlanes(0.001, 100.0);
+    rightCamera->frustumCulling = false;
+    
+    cameraRoot->addChild(leftCamera);
+    cameraRoot->addChild(rightCamera);
+    
+    initOVR();
+}
+
+void PolycodeOVR::initOVR() {
+    OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
+    
+    pManager = *OVR::DeviceManager::Create();
+    pHMD     = *pManager->EnumerateDevices<OVR::HMDDevice>().CreateDevice();
+    
+    if(!pHMD) {
+        Logger::log("Could not detect Oculus device\n");
+        return;
+    }
+    
+    pSensor = *pHMD->GetSensor();
+    if (!pSensor) {
+        Logger::log("Could not get Oculus sensor\n");
+        return;
+    }
+    
+    SFusion = new OVR::SensorFusion();
+    SFusion->AttachToSensor(pSensor);
+    
+    OVR::HMDInfo hmd;
+    if (!pHMD->GetDeviceInfo(&hmd)) {
+        Logger::log("Unable to get Oculus device information.\n");
+        return;
+    }
+    
+    leftTexture = new SceneRenderTexture(parentScene, leftCamera, hmd.HResolution/2, hmd.VResolution);
+    rightTexture = new SceneRenderTexture(parentScene, rightCamera, hmd.HResolution/2, hmd.VResolution);
+    
+    float halfScreenDistance = (hmd.VScreenSize / 2);
+    float yfov = 2.0f * atan(halfScreenDistance/hmd.EyeToScreenDistance);
+    
+//    leftCamera->setFOV(yfov);
+//    rightCamera->setFOV(yfov);
+    
+    float aspectRatio = float(hmd.HResolution * 0.5f) / float(hmd.VResolution);
+    
+    float viewCenter             = hmd.HScreenSize * 0.25f;
+    float eyeProjectionShift     = viewCenter - hmd.LensSeparationDistance*0.5f;
+    float projectionCenterOffset = 4.0f * eyeProjectionShift / hmd.HScreenSize;
+    
+    OVR::Matrix4f projCenter = OVR::Matrix4f::PerspectiveRH(yfov, aspectRatio, 0.3f, 1000.0f);
+    OVR::Matrix4f projLeft   = OVR::Matrix4f::Translation(projectionCenterOffset, 0, 0) * projCenter;
+    OVR::Matrix4f projRight  = OVR::Matrix4f::Translation(-projectionCenterOffset, 0, 0) * projCenter;
+    
+    Matrix4 projLeftPolycode(projLeft.M[0][0], projLeft.M[1][0], projLeft.M[2][0], projLeft.M[3][0],
+                             projLeft.M[0][1], projLeft.M[1][1], projLeft.M[2][1], projLeft.M[3][1],
+                             projLeft.M[0][2], projLeft.M[1][2], projLeft.M[2][2], projLeft.M[3][2],
+                             projLeft.M[0][3], projLeft.M[1][3], projLeft.M[2][3], projLeft.M[3][3]);
+    
+    leftCamera->setProjectionMode(Camera::MANUAL_MATRIX);
+    leftCamera->setProjectionMatrix(projLeftPolycode);
+    
+
+    Matrix4 projRightPolycode(projRight.M[0][0], projRight.M[1][0], projRight.M[2][0], projRight.M[3][0],
+                              projRight.M[0][1], projRight.M[1][1], projRight.M[2][1], projRight.M[3][1],
+                              projRight.M[0][2], projRight.M[1][2], projRight.M[2][2], projRight.M[3][2],
+                              projRight.M[0][3], projRight.M[1][3], projRight.M[2][3], projRight.M[3][3]);
+    
+    rightCamera->setProjectionMode(Camera::MANUAL_MATRIX);
+    rightCamera->setProjectionMatrix(projRightPolycode);
+    
+    
+    float    halfIPD  = hmd.InterpupillaryDistance * 0.5f;
+    
+    Number scale = 1.0;
+    
+    leftCamera->setPosition(-halfIPD, 0.0, 0.0);
+    rightCamera->setPosition(halfIPD, 0.0, 0.0);
+    
+    leftCamera->setPostFilterByName("VRCorrect");
+    leftCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "screenCenter")->setVector2(Vector2(0.5, 0.5));
+    leftCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "lensCenter")->setVector2(Vector2(0.5, 0.5));
+    leftCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "scale")->setVector2(Vector2(0.5f / scale, 0.5f * aspectRatio / scale));
+    leftCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "scaleIn")->setVector2(Vector2(2.0f, 2.0f / aspectRatio));
+    leftCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_COLOR, "hmdWarpParam")->setColor(Color(hmd.DistortionK[0], hmd.DistortionK[1], hmd.DistortionK[2], hmd.DistortionK[3]));
+
+    
+    rightCamera->setPostFilterByName("VRCorrect");
+    rightCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "screenCenter")->setVector2(Vector2(0.5, 0.5));
+    rightCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "lensCenter")->setVector2(Vector2(0.5, 0.5));
+    rightCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "scale")->setVector2(Vector2(0.5f / scale, 0.5f * aspectRatio / scale));
+    rightCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_VECTOR2, "scaleIn")->setVector2(Vector2(2.0f, 2.0f / aspectRatio));
+    rightCamera->getLocalShaderOptions()[0]->addParam(ProgramParam::PARAM_COLOR, "hmdWarpParam")->setColor(Color(hmd.DistortionK[0], hmd.DistortionK[1], hmd.DistortionK[2], hmd.DistortionK[3]));
+    
+}
+
+Texture *PolycodeOVR::getLeftTexture() {
+    return leftTexture->getTargetTexture();
+}
+
+Texture *PolycodeOVR::getRightTexture() {
+    return rightTexture->getTargetTexture();
+}
+
+void PolycodeOVR::Update() {
+    Quaternion q;
+    OVR::Quatf ovrQ = SFusion->GetOrientation();
+    q.set(ovrQ.w, ovrQ.x, ovrQ.y, ovrQ.z);
+    cameraRoot->setRotationByQuaternion(q);
+}
+
+Entity *PolycodeOVR::getCameraRoot() {
+    return cameraRoot;
+}
+
+PolycodeOVR::~PolycodeOVR() {
+    if(cameraRoot->getParentEntity()) {
+        cameraRoot->getParentEntity()->removeChild(cameraRoot);
+    }
+    delete cameraRoot;
+    delete leftCamera;
+    delete rightCamera;
+    delete SFusion;
+    delete leftTexture;
+    delete rightTexture;
+}

+ 57 - 0
Modules/Contents/OculusVR/PolycodeOVR.h

@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2014 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+ #include "OVR.h"
+ #include "Polycode.h"
+
+using namespace Polycode;
+
+class PolycodeOVR {
+    public:
+        PolycodeOVR(Scene *parentScene);
+        ~PolycodeOVR();
+    
+        void initOVR();
+    
+        Texture *getLeftTexture();
+        Texture *getRightTexture();
+    
+        void Update();
+        Entity *getCameraRoot();
+    
+    protected:
+    
+        OVR::Ptr<OVR::DeviceManager> pManager;
+        OVR::Ptr<OVR::HMDDevice>     pHMD;
+        OVR::Ptr<OVR::SensorDevice> pSensor;
+        OVR::SensorFusion *SFusion;
+    
+        Entity *cameraRoot;
+    
+        SceneRenderTexture *leftTexture;
+        SceneRenderTexture *rightTexture;
+    
+        Scene *parentScene; 
+    
+        Camera *leftCamera;
+        Camera *rightCamera;
+};

+ 22 - 0
Modules/Contents/OculusVR/Resources/VRCorrect.frag

@@ -0,0 +1,22 @@
+uniform vec2 scale;
+uniform vec2 screenCenter;
+uniform vec2 lensCenter;
+uniform vec2 scaleIn;
+uniform vec4 hmdWarpParam;
+
+uniform sampler2D screenColorBuffer;
+
+void main()
+{
+
+	vec2 theta = (gl_TexCoord[0].st - lensCenter) * scaleIn;
+
+	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);
+	vec2 tc = (lensCenter + scale * rvector);
+
+	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, 0.0, 1.0);
+	else
+		gl_FragColor = texture2D(screenColorBuffer, tc);
+}

+ 18 - 0
Modules/Contents/OculusVR/Resources/VRCorrect.mat

@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+<polycode>	
+	<shaders>
+		<shader type="glsl" name="VRCorrect" screen="true">
+			<vp source="default/ScreenShader.vert"/>
+			<fp source="VRCorrect.frag"/>
+		</shader>							
+	</shaders>
+	<materials>								
+		<material name="VRCorrect" screen="true">
+			<shader name="VRCorrect">
+				<targettextures>			
+					<targettexture mode="color" name="screenColorBuffer"/>			
+				</targettextures>			
+			</shader>
+		</material>			
+	</materials>
+</polycode>