From 9e23a689ae4e9e3791bd6b6adae9f98f1aa7ef81 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 1 Aug 2014 15:44:12 +0200 Subject: [PATCH] Project GUI into space --- code/nel/include/nel/3d/stereo_hmd.h | 3 + code/nel/include/nel/3d/stereo_ovr.h | 22 ++- code/nel/src/3d/stereo_ovr.cpp | 226 +++++++++++++++++++++------ code/ryzom/client/src/main_loop.cpp | 20 ++- 4 files changed, 215 insertions(+), 56 deletions(-) diff --git a/code/nel/include/nel/3d/stereo_hmd.h b/code/nel/include/nel/3d/stereo_hmd.h index 95c159cfd..3276e78fe 100644 --- a/code/nel/include/nel/3d/stereo_hmd.h +++ b/code/nel/include/nel/3d/stereo_hmd.h @@ -53,6 +53,9 @@ public: /// Get the HMD orientation virtual NLMISC::CQuat getOrientation() const = 0; + /// Set the GUI reference + virtual void setInterfaceMatrix(const NL3D::CMatrix &matrix) = 0; + /// Get GUI center (1 = width, 1 = height, 0 = center) virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const = 0; diff --git a/code/nel/include/nel/3d/stereo_ovr.h b/code/nel/include/nel/3d/stereo_ovr.h index b92830b36..a215ff8b6 100644 --- a/code/nel/include/nel/3d/stereo_ovr.h +++ b/code/nel/include/nel/3d/stereo_ovr.h @@ -123,6 +123,9 @@ public: /// Get the HMD orientation virtual NLMISC::CQuat getOrientation() const; + /// Set the GUI reference + virtual void setInterfaceMatrix(const NL3D::CMatrix &matrix); + /// Get GUI center (1 = width, 1 = height, 0 = center) virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const; @@ -134,21 +137,23 @@ public: /// Set the scale of the game in units per meter virtual void setScale(float s); + /// Calculates internal camera information based on the reference camera + void initCamera(uint cid, const NL3D::UCamera *camera); + /// Render GUI + void renderGUI(); + + /// Checks if the device used by this class was actually created + bool isDeviceCreated(); static void listDevices(std::vector &devicesOut); static bool isLibraryInUse(); static void releaseLibrary(); - - /// Calculates internal camera information based on the reference camera - void initCamera(uint cid, const NL3D::UCamera *camera); - /// Checks if the device used by this class was actually created - bool isDeviceCreated(); - private: CStereoOVRDevicePtr *m_DevicePtr; int m_Stage; int m_SubStage; + CViewport m_RegularViewport; CViewport m_LeftViewport; CViewport m_RightViewport; CFrustum m_ClippingFrustum[NL_STEREO_MAX_USER_CAMERAS]; @@ -156,12 +161,13 @@ private: CFrustum m_RightFrustum[NL_STEREO_MAX_USER_CAMERAS]; CFrustum m_OriginalFrustum[NL_STEREO_MAX_USER_CAMERAS]; CMatrix m_CameraMatrix[NL_STEREO_MAX_USER_CAMERAS]; + CMatrix m_InterfaceCameraMatrix; mutable bool m_OrientationCached; mutable NLMISC::CQuat m_OrientationCache; UDriver *m_Driver; - NLMISC::CSmartPtr m_BarrelTex; - NL3D::CTextureUser *m_BarrelTexU; + NL3D::CTextureUser *m_SceneTexture; NL3D::UMaterial m_BarrelMat; + NL3D::CTextureUser *m_GUITexture; NLMISC::CQuadUV m_BarrelQuadLeft; NLMISC::CQuadUV m_BarrelQuadRight; NLMISC::CRefPtr m_PixelProgram; diff --git a/code/nel/src/3d/stereo_ovr.cpp b/code/nel/src/3d/stereo_ovr.cpp index e7816587b..789d48926 100644 --- a/code/nel/src/3d/stereo_ovr.cpp +++ b/code/nel/src/3d/stereo_ovr.cpp @@ -169,7 +169,7 @@ public: OVR::HMDInfo HMDInfo; }; -CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_BarrelTexU(NULL), m_PixelProgram(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f) +CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_SceneTexture(NULL), m_GUITexture(NULL), m_PixelProgram(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f) { ++s_DeviceCounter; m_DevicePtr = new CStereoOVRDevicePtr(); @@ -213,9 +213,6 @@ CStereoOVR::~CStereoOVR() m_BarrelMat.getObjectPtr()->setTexture(0, NULL); m_Driver->deleteMaterial(m_BarrelMat); } - delete m_BarrelTexU; - m_BarrelTexU = NULL; - m_BarrelTex = NULL; // CSmartPtr delete m_PixelProgram; m_PixelProgram = NULL; @@ -340,7 +337,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) { m_Driver = driver; - m_BarrelTex = new CTextureBloom(); // lol bloom + /*m_BarrelTex = new CTextureBloom(); // lol bloom m_BarrelTex->setRenderTarget(true); m_BarrelTex->setReleasable(false); m_BarrelTex->resize(m_DevicePtr->HMDInfo.HResolution, m_DevicePtr->HMDInfo.VResolution); @@ -348,7 +345,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) m_BarrelTex->setWrapS(ITexture::Clamp); m_BarrelTex->setWrapT(ITexture::Clamp); drvInternal->setupTexture(*m_BarrelTex); - m_BarrelTexU = new CTextureUser(m_BarrelTex); + m_BarrelTexU = new CTextureUser(m_BarrelTex);*/ m_BarrelMat = m_Driver->createMaterial(); m_BarrelMat.initUnlit(); @@ -361,7 +358,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) barrelMat->setZWrite(false); barrelMat->setZFunc(CMaterial::always); barrelMat->setDoubleSided(true); - barrelMat->setTexture(0, m_BarrelTex); + // barrelMat->setTexture(0, m_BarrelTex); m_BarrelQuadLeft.V0 = CVector(0.f, 0.f, 0.5f); m_BarrelQuadLeft.V1 = CVector(0.5f, 0.f, 0.5f); @@ -373,7 +370,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) m_BarrelQuadRight.V2 = CVector(1.f, 1.f, 0.5f); m_BarrelQuadRight.V3 = CVector(0.5f, 1.f, 0.5f); - nlassert(!drvInternal->isTextureRectangle(m_BarrelTex)); // not allowed + // nlassert(!drvInternal->isTextureRectangle(m_BarrelTex)); // not allowed m_BarrelQuadLeft.Uv0 = CUV(0.f, 0.f); m_BarrelQuadLeft.Uv1 = CUV(0.5f, 0.f); @@ -448,53 +445,59 @@ bool CStereoOVR::nextPass() // Do not allow weird stuff. uint32 width, height; m_Driver->getWindowSize(width, height); - nlassert(width == m_DevicePtr->HMDInfo.HResolution); - nlassert(height == m_DevicePtr->HMDInfo.VResolution); + // nlassert(width == m_DevicePtr->HMDInfo.HResolution); + // nlassert(height == m_DevicePtr->HMDInfo.VResolution); if (m_Driver->getPolygonMode() == UDriver::Filled) { - switch (m_Stage) + switch (m_Stage) // Previous stage { case 0: - ++m_Stage; - m_SubStage = 0; - // stage 1: - // (initBloom) - // clear buffer - // draw scene left - return true; - case 1: - ++m_Stage; + m_Stage += 2; m_SubStage = 0; // stage 2: - // draw scene right + // draw interface 2d (onto render target) return true; case 2: ++m_Stage; m_SubStage = 0; // stage 3: - // (endBloom) - // draw interface 3d left + // (initBloom) + // clear buffer + // draw scene left return true; case 3: ++m_Stage; m_SubStage = 0; // stage 4: - // draw interface 3d right + // draw scene right return true; case 4: ++m_Stage; m_SubStage = 0; // stage 5: - // (endInterfacesDisplayBloom) - // draw interface 2d left + // (endBloom) + // draw interface 3d left return true; case 5: ++m_Stage; m_SubStage = 0; // stage 6: - // draw interface 2d right + // draw interface 3d right return true; + /*case 6: + ++m_Stage; + m_SubStage = 0; + // stage 7: + // (endInterfacesDisplayBloom) + // draw interface 2d left + return true; + case 7: + ++m_Stage; + m_SubStage = 0; + // stage 8: + // draw interface 2d right + return true;*/ case 6: m_Stage = 0; m_SubStage = 0; @@ -526,26 +529,30 @@ bool CStereoOVR::nextPass() const NL3D::CViewport &CStereoOVR::getCurrentViewport() const { - if (m_Stage % 2) return m_LeftViewport; + if (m_Stage == 2) return m_RegularViewport; + else if (m_Stage % 2) return m_LeftViewport; else return m_RightViewport; } const NL3D::CFrustum &CStereoOVR::getCurrentFrustum(uint cid) const { - if (m_Stage % 2) return m_LeftFrustum[cid]; + if (m_Stage == 2) return m_OriginalFrustum[cid]; + else if (m_Stage % 2) return m_LeftFrustum[cid]; else return m_RightFrustum[cid]; } void CStereoOVR::getCurrentFrustum(uint cid, NL3D::UCamera *camera) const { - if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]); + if (m_Stage == 2) camera->setFrustum(m_OriginalFrustum[cid]); + else if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]); else camera->setFrustum(m_RightFrustum[cid]); } void CStereoOVR::getCurrentMatrix(uint cid, NL3D::UCamera *camera) const { CMatrix translate; - if (m_Stage % 2) translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f)); + if (m_Stage == 2) { } + else if (m_Stage % 2) translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f)); else translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * 0.5f, 0.f, 0.f)); CMatrix mat = m_CameraMatrix[cid] * translate; if (camera->getTransformMode() == NL3D::UTransformable::RotQuat) @@ -564,7 +571,7 @@ bool CStereoOVR::wantClear() { switch (m_Stage) { - case 1: + case 3: m_SubStage = 1; return true; } @@ -575,8 +582,8 @@ bool CStereoOVR::wantScene() { switch (m_Stage) { - case 1: - case 2: + case 3: + case 4: m_SubStage = 2; return true; } @@ -587,8 +594,8 @@ bool CStereoOVR::wantInterface3D() { switch (m_Stage) { - case 3: - case 4: + case 5: + case 6: m_SubStage = 3; return true; } @@ -599,37 +606,163 @@ bool CStereoOVR::wantInterface2D() { switch (m_Stage) { - case 5: - case 6: + case 2: m_SubStage = 4; return true; } return m_Driver->getPolygonMode() != UDriver::Filled; } - /// Returns non-NULL if a new render target was set bool CStereoOVR::beginRenderTarget() { // render target always set before driver clear // nlassert(m_SubStage <= 1); - if (m_Driver && m_Stage == 1 && (m_Driver->getPolygonMode() == UDriver::Filled)) + + // Set GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) { - static_cast(m_Driver)->setRenderTarget(*m_BarrelTexU, 0, 0, 0, 0); + nlassert(!m_GUITexture); + uint32 width, height; + m_Driver->getWindowSize(width, height); + m_GUITexture = m_Driver->getRenderTargetManager().getRenderTarget(width, height, true, UTexture::RGBA8888); + static_cast(m_Driver)->setRenderTarget(*m_GUITexture); + m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 0, 0)); return true; } + + // Begin 3D scene render target + if (m_Driver && m_Stage == 3 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + nlassert(!m_SceneTexture); + uint32 width, height; + m_Driver->getWindowSize(width, height); // Temporary limitation, TODO: scaling! + m_SceneTexture = m_Driver->getRenderTargetManager().getRenderTarget(width, height); + static_cast(m_Driver)->setRenderTarget(*m_SceneTexture); + return true; + } + return false; } +void CStereoOVR::setInterfaceMatrix(const NL3D::CMatrix &matrix) +{ + m_InterfaceCameraMatrix = matrix; +} + +void CStereoOVR::renderGUI() +{ + + /*CMatrix mat; + mat.translate(m_InterfaceCameraMatrix.getPos()); + CVector dir = m_InterfaceCameraMatrix.getJ(); + dir.z = 0; + dir.normalize(); + if (dir.y < 0) + mat.rotateZ(float(NLMISC::Pi+asin(dir.x))); + else + mat.rotateZ(float(NLMISC::Pi+NLMISC::Pi-asin(dir.x))); + m_Driver->setModelMatrix(mat);*/ + m_Driver->setModelMatrix(m_InterfaceCameraMatrix); + + { + nlassert(m_GUITexture); + + NLMISC::CQuadUV quad; + + NL3D::UMaterial umat = m_Driver->createMaterial(); + umat.initUnlit(); + umat.setColor(NLMISC::CRGBA::White); + umat.setDoubleSided(true); + umat.setBlend(true); + umat.setAlphaTest(false); + NL3D::CMaterial *mat = umat.getObjectPtr(); + mat->setShader(NL3D::CMaterial::Normal); + mat->setBlendFunc(CMaterial::one, CMaterial::TBlend::invsrcalpha); + mat->setZWrite(false); + // mat->setZFunc(CMaterial::always); // Not nice + mat->setDoubleSided(true); + mat->setTexture(0, m_GUITexture->getITexture()); + + // user options + float height = 6.0f; + float distance = 3.0f; + + uint32 winw, winh; + m_Driver->getWindowSize(winw, winh); + float width = height * (float)winw / (float)winh; + + NLMISC::CQuadUV quadUV; + quadUV.V0 = CVector(-(width * 0.5f), distance, -(height * 0.5f)); + quadUV.V1 = CVector((width * 0.5f), distance, -(height * 0.5f)); + quadUV.V2 = CVector((width * 0.5f), distance, (height * 0.5f)); + quadUV.V3 = CVector(-(width * 0.5f), distance, (height * 0.5f)); + quadUV.Uv0 = CUV(0.f, 0.f); + quadUV.Uv1 = CUV(1.f, 0.f); + quadUV.Uv2 = CUV(1.f, 1.f); + quadUV.Uv3 = CUV(0.f, 1.f); + + m_Driver->drawQuad(quadUV, umat); + + m_Driver->deleteMaterial(umat); + } + + { + NLMISC::CLine line(NLMISC::CVector(0, 3, -3), NLMISC::CVector(0, 3, 3)); + + NL3D::UMaterial mat = m_Driver->createMaterial(); + mat.setZWrite(false); + mat.setZFunc(UMaterial::always); + mat.setDoubleSided(true); + mat.setColor(NLMISC::CRGBA::Red); + mat.setBlend(false); + + m_Driver->drawLine(line, mat); + + m_Driver->deleteMaterial(mat); + } +} + /// Returns true if a render target was fully drawn bool CStereoOVR::endRenderTarget() { // after rendering of course // nlassert(m_SubStage > 1); + + // End GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // End GUI render target + nlassert(m_GUITexture); + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); + } + + // End of 3D Interface pass left + if (m_Driver && m_Stage == 5 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + } + + // End of 3D Interface pass right + if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_GUITexture); + m_GUITexture = NULL; + } + + // End 3D scene render target if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) // set to 4 to turn off distortion of 2d gui { - CTextureUser cu; - (static_cast(m_Driver))->setRenderTarget(cu); + nlassert(m_SceneTexture); + + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); bool fogEnabled = m_Driver->fogEnabled(); m_Driver->enableFog(false); @@ -640,7 +773,7 @@ bool CStereoOVR::endRenderTarget() m_Driver->getWindowSize(width, height); NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr(); - barrelMat->setTexture(0, m_BarrelTex); + barrelMat->setTexture(0, m_SceneTexture->getITexture()); drvInternal->activePixelProgram(m_PixelProgram); @@ -705,8 +838,13 @@ bool CStereoOVR::endRenderTarget() drvInternal->activePixelProgram(NULL); m_Driver->enableFog(fogEnabled); + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture); + m_SceneTexture = NULL; + return true; } + return false; } diff --git a/code/ryzom/client/src/main_loop.cpp b/code/ryzom/client/src/main_loop.cpp index 36c918ca5..e6a9c50a0 100644 --- a/code/ryzom/client/src/main_loop.cpp +++ b/code/ryzom/client/src/main_loop.cpp @@ -1386,8 +1386,20 @@ bool mainLoop() MainCam.setRotQuat(View.currentViewQuat()); if (StereoHMD) { + CMatrix camMatrix; + camMatrix.translate(MainCam.getMatrix().getPos()); + CVector dir = MainCam.getMatrix().getJ(); + dir.z = 0; + dir.normalize(); + if (dir.y < 0) + camMatrix.rotateZ(float(NLMISC::Pi+asin(dir.x))); + else + camMatrix.rotateZ(float(NLMISC::Pi+NLMISC::Pi-asin(dir.x))); + + StereoHMD->setInterfaceMatrix(camMatrix); + NLMISC::CQuat hmdOrient = StereoHMD->getOrientation(); - NLMISC::CMatrix camMatrix = MainCam.getMatrix(); + // NLMISC::CMatrix camMatrix = MainCam.getMatrix(); NLMISC::CMatrix hmdMatrix; hmdMatrix.setRot(hmdOrient); NLMISC::CMatrix posMatrix; // minimal head modeling, will be changed in the future @@ -1645,7 +1657,7 @@ bool mainLoop() { if (Render) { - if (ClientCfg.Bloom) + if (!StereoDisplay && ClientCfg.Bloom) // NO VR BLOOMZ { nlassert(bloomStage == 0); // set bloom parameters before applying bloom effect @@ -1695,7 +1707,7 @@ bool mainLoop() // Render if (Render) { - if (ClientCfg.Bloom && bloomStage == 1) + if (!StereoDisplay && ClientCfg.Bloom && bloomStage == 1) // NO VR BLOOMZ { // End the actual bloom effect visible in the scene. if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); @@ -1822,7 +1834,7 @@ bool mainLoop() // special case in OpenGL : all scene has been display in render target, // now, final texture is display with a quad - if (!ClientCfg.Light && ClientCfg.Bloom && Render && bloomStage == 2) + if (!StereoDisplay && !ClientCfg.Light && ClientCfg.Bloom && Render && bloomStage == 2) // NO VR BLOOMZ { // End bloom effect system after drawing the 3d interface (z buffer related). if (StereoDisplay) Driver->setViewport(NL3D::CViewport());