From e51d9e15d907496d8be6693524fbfc1c6d79653a Mon Sep 17 00:00:00 2001 From: kaetemi Date: Wed, 26 Jun 2013 08:00:19 +0200 Subject: [PATCH] Render from multiple cameras, see #43 --- code/nel/include/nel/3d/stereo_ovr.h | 27 ++++++ code/nel/src/3d/stereo_ovr.cpp | 97 ++++++++++++++++++- .../bin/snowballs_client_default.cfg | 2 +- code/snowballs2/client/src/camera.cpp | 26 +++-- code/snowballs2/client/src/camera.h | 4 + .../client/src/snowballs_client.cpp | 52 ++++++---- 6 files changed, 177 insertions(+), 31 deletions(-) diff --git a/code/nel/include/nel/3d/stereo_ovr.h b/code/nel/include/nel/3d/stereo_ovr.h index 3858b046e..89e6759d7 100644 --- a/code/nel/include/nel/3d/stereo_ovr.h +++ b/code/nel/include/nel/3d/stereo_ovr.h @@ -49,11 +49,15 @@ // NeL includes #include +#include +#include // Project includes namespace NL3D { +class UCamera; + struct CStereoDeviceInfo { public: @@ -80,6 +84,20 @@ public: CStereoOVR(const CStereoDeviceInfo &deviceInfo); virtual ~CStereoOVR(); + /// Gets the required screen resolution for this device + virtual void getScreenResolution(uint &width, uint &height); + /// Set latest camera position etcetera + virtual void updateCamera(const NL3D::UCamera *camera); + + /// Is there a next pass + virtual bool nextPass(); + /// Gets the current viewport + virtual const NL3D::CViewport &getCurrentViewport(); + /// Gets the current camera frustum + virtual void getCurrentFrustum(NL3D::UCamera *camera); + /// Gets the current camera matrix + virtual void getCurrentMatrix(NL3D::UCamera *camera); + virtual NLMISC::CQuat getOrientation(); static void listDevices(std::vector &devicesOut); @@ -87,10 +105,19 @@ public: static bool isLibraryInUse(); static void releaseLibrary(); + /// Calculates internal camera information based on the reference camera + void initCamera(const NL3D::UCamera *camera); + bool isDeviceCreated(); private: CStereoOVRDevicePtr *m_DevicePtr; + int m_Stage; + CViewport m_LeftViewport; + CViewport m_RightViewport; + CFrustum m_LeftFrustum; + CFrustum m_RightFrustum; + CMatrix m_CameraMatrix; }; /* class CStereoOVR */ diff --git a/code/nel/src/3d/stereo_ovr.cpp b/code/nel/src/3d/stereo_ovr.cpp index 44daae9ef..32d5bffb7 100644 --- a/code/nel/src/3d/stereo_ovr.cpp +++ b/code/nel/src/3d/stereo_ovr.cpp @@ -51,6 +51,7 @@ // NeL includes // #include +#include // Project includes @@ -142,9 +143,10 @@ public: OVR::Ptr HMDDevice; OVR::Ptr SensorDevice; OVR::SensorFusion SensorFusion; + OVR::HMDInfo HMDInfo; }; -CStereoOVR::CStereoOVR(const CStereoDeviceInfo &deviceInfo) +CStereoOVR::CStereoOVR(const CStereoDeviceInfo &deviceInfo) : m_Stage(2) { ++s_DeviceCounter; m_DevicePtr = new CStereoOVRDevicePtr(); @@ -155,11 +157,30 @@ CStereoOVR::CStereoOVR(const CStereoDeviceInfo &deviceInfo) if (m_DevicePtr->HMDDevice) { + m_DevicePtr->HMDDevice->GetDeviceInfo(&m_DevicePtr->HMDInfo); + nldebug("OVR: HScreenSize: %f, VScreenSize: %f", m_DevicePtr->HMDInfo.HScreenSize, m_DevicePtr->HMDInfo.VScreenSize); + nldebug("OVR: VScreenCenter: %f", m_DevicePtr->HMDInfo.VScreenCenter); + nldebug("OVR: EyeToScreenDistance: %f", m_DevicePtr->HMDInfo.EyeToScreenDistance); + nldebug("OVR: LensSeparationDistance: %f", m_DevicePtr->HMDInfo.LensSeparationDistance); + nldebug("OVR: InterpupillaryDistance: %f", m_DevicePtr->HMDInfo.InterpupillaryDistance); + nldebug("OVR: HResolution: %i, VResolution: %i", m_DevicePtr->HMDInfo.HResolution, m_DevicePtr->HMDInfo.VResolution); + nldebug("OVR: DistortionK[0]: %f, DistortionK[1]: %f", m_DevicePtr->HMDInfo.DistortionK[0], m_DevicePtr->HMDInfo.DistortionK[1]); + nldebug("OVR: DistortionK[2]: %f, DistortionK[3]: %f", m_DevicePtr->HMDInfo.DistortionK[2], m_DevicePtr->HMDInfo.DistortionK[3]); + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 160 NL3D::CStereoOVR::CStereoOVR : OVR: HScreenSize: 0.149760, VScreenSize: 0.093600 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 161 NL3D::CStereoOVR::CStereoOVR : OVR: VScreenCenter: 0.046800 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 162 NL3D::CStereoOVR::CStereoOVR : OVR: EyeToScreenDistance: 0.041000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 163 NL3D::CStereoOVR::CStereoOVR : OVR: LensSeparationDistance: 0.063500 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 164 NL3D::CStereoOVR::CStereoOVR : OVR: InterpupillaryDistance: 0.064000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 165 NL3D::CStereoOVR::CStereoOVR : OVR: HResolution: 1280, VResolution: 800 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 166 NL3D::CStereoOVR::CStereoOVR : OVR: DistortionK[0]: 1.000000, DistortionK[1]: 0.220000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 167 NL3D::CStereoOVR::CStereoOVR : OVR: DistortionK[2]: 0.240000, DistortionK[3]: 0.000000 m_DevicePtr->SensorDevice = m_DevicePtr->HMDDevice->GetSensor(); m_DevicePtr->SensorFusion.AttachToSensor(m_DevicePtr->SensorDevice); m_DevicePtr->SensorFusion.SetGravityEnabled(true); m_DevicePtr->SensorFusion.SetPredictionEnabled(true); m_DevicePtr->SensorFusion.SetYawCorrectionEnabled(true); + m_LeftViewport.init(0.f, 0.f, 0.5f, 1.0f); + m_RightViewport.init(0.5f, 0.f, 0.5f, 1.0f); } } @@ -177,6 +198,74 @@ CStereoOVR::~CStereoOVR() --s_DeviceCounter; } +void CStereoOVR::getScreenResolution(uint &width, uint &height) +{ + width = m_DevicePtr->HMDInfo.HResolution; + height = m_DevicePtr->HMDInfo.VResolution; +} + +void CStereoOVR::initCamera(const NL3D::UCamera *camera) +{ + float ar = (float)m_DevicePtr->HMDInfo.HResolution / ((float)m_DevicePtr->HMDInfo.VResolution * 2.0f); + float fov = 2.0f * atanf((m_DevicePtr->HMDInfo.VScreenSize / 2.0f) / m_DevicePtr->HMDInfo.EyeToScreenDistance); //(float)NLMISC::Pi/2.f; // 2.0f * atanf(m_DevicePtr->HMDInfo.VScreenSize / 2.0f * m_DevicePtr->HMDInfo.EyeToScreenDistance); + m_LeftFrustum.initPerspective(fov, ar, camera->getFrustum().Near, camera->getFrustum().Far); + m_RightFrustum = m_LeftFrustum; + float viewCenter = m_DevicePtr->HMDInfo.HScreenSize * 0.25f; + float eyeProjectionShift = viewCenter - m_DevicePtr->HMDInfo.LensSeparationDistance * 0.5f; + float projectionCenterOffset = 4.0f * eyeProjectionShift / m_DevicePtr->HMDInfo.HScreenSize; + nldebug("OVR: projectionCenterOffset = %f", projectionCenterOffset); + projectionCenterOffset *= (m_LeftFrustum.Left - m_LeftFrustum.Right) * 0.5f; // made this up ... + m_LeftFrustum.Left += projectionCenterOffset; + m_LeftFrustum.Right += projectionCenterOffset; + m_RightFrustum.Left -= projectionCenterOffset; + m_RightFrustum.Right -= projectionCenterOffset; +} + +void CStereoOVR::updateCamera(const NL3D::UCamera *camera) +{ + if (camera->getFrustum().Near != m_LeftFrustum.Near + || camera->getFrustum().Far != m_LeftFrustum.Far) + CStereoOVR::initCamera(camera); + m_CameraMatrix = camera->getMatrix(); +} + +bool CStereoOVR::nextPass() +{ + switch (m_Stage) + { + case 0: + ++m_Stage; + return true; + case 1: + ++m_Stage; + return false; + case 2: + m_Stage = 0; + return true; + } +} + +const NL3D::CViewport &CStereoOVR::getCurrentViewport() +{ + if (m_Stage) return m_RightViewport; + else return m_LeftViewport; +} + +void CStereoOVR::getCurrentFrustum(NL3D::UCamera *camera) +{ + if (m_Stage) camera->setFrustum(m_RightFrustum); + else camera->setFrustum(m_LeftFrustum); +} + +void CStereoOVR::getCurrentMatrix(NL3D::UCamera *camera) +{ + CMatrix translate; + if (m_Stage) translate.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * -0.5f, 0.f, 0.f)); + else translate.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * 0.5f, 0.f, 0.f)); + camera->setTransformMode(NL3D::UTransformable::DirectMatrix); + camera->setMatrix(m_CameraMatrix * translate); // or switch? +} + NLMISC::CQuat CStereoOVR::getOrientation() { OVR::Quatf quatovr = m_DevicePtr->SensorFusion.GetPredictedOrientation(); @@ -225,7 +314,11 @@ void CStereoOVR::listDevices(std::vector &devicesOut) CStereoOVR *CStereoOVR::createDevice(const CStereoDeviceInfo &deviceInfo) { - return new CStereoOVR(deviceInfo); + CStereoOVR *stereo = new CStereoOVR(deviceInfo); + if (stereo->isDeviceCreated()) + return stereo; + delete stereo; + return NULL; } bool CStereoOVR::isLibraryInUse() diff --git a/code/snowballs2/bin/snowballs_client_default.cfg b/code/snowballs2/bin/snowballs_client_default.cfg index 758bd8483..9d1429f83 100755 --- a/code/snowballs2/bin/snowballs_client_default.cfg +++ b/code/snowballs2/bin/snowballs_client_default.cfg @@ -52,7 +52,7 @@ ScreenHeight = 800; ScreenDepth = 32; // If 1, run in fullscreen mode, 0 for windowed -ScreenFull = 0; +ScreenFull = 1; // Start position of the player (the z is always 0) StartPoint = { 1840.0, -970.0, 0.0 }; diff --git a/code/snowballs2/client/src/camera.cpp b/code/snowballs2/client/src/camera.cpp index f1a76e552..1911f9694 100644 --- a/code/snowballs2/client/src/camera.cpp +++ b/code/snowballs2/client/src/camera.cpp @@ -64,13 +64,13 @@ UVisualCollisionEntity *CamCollisionEntity = NULL; static UInstance Snow = NULL; // The sky 3D objects -static UScene *SkyScene = NULL; -static UCamera SkyCamera = NULL; +UScene *SkyScene = NULL; +UCamera SkyCamera = NULL; static UInstance Sky = NULL; static UCloudScape *Clouds = NULL; -static CStereoOVR *s_StereoHMD = NULL; +CStereoOVR *StereoHMD = NULL; // // Functions @@ -111,7 +111,7 @@ void initCamera() if (deviceInfo) { nlinfo("Create HMD device!"); - s_StereoHMD = CStereoOVR::createDevice(*deviceInfo); + StereoHMD = CStereoOVR::createDevice(*deviceInfo); } } @@ -129,6 +129,13 @@ void initCamera() CamCollisionEntity = VisualCollisionManager->createEntity(); CamCollisionEntity->setCeilMode(true); + if (StereoHMD) + { + StereoHMD->nextPass(); // test + + StereoHMD->initCamera(&Camera); + } + // Create the snowing particle system Snow = Scene->createInstance("snow.ps"); // And setup it @@ -159,16 +166,16 @@ void releaseCamera() Scene->deleteInstance(Snow); VisualCollisionManager->deleteEntity(CamCollisionEntity); - delete s_StereoHMD; - s_StereoHMD = NULL; + delete StereoHMD; + StereoHMD = NULL; CStereoOVR::releaseLibrary(); } void updateCamera() { - if (s_StereoHMD) + if (StereoHMD) { - NLMISC::CQuat hmdOrient = s_StereoHMD->getOrientation(); + NLMISC::CQuat hmdOrient = StereoHMD->getOrientation(); NLMISC::CMatrix camMatrix = Camera.getMatrix(); NLMISC::CMatrix hmdMatrix; hmdMatrix.setRot(hmdOrient); @@ -217,7 +224,8 @@ void updateSky() // Must clear ZBuffer For incoming rendering. Driver->clearZBuffer(); - Clouds->render(); + if (!StereoHMD) // Cloudscape not supported (fix Viewport please) + Clouds->render(); } } /* namespace SBCLIENT */ diff --git a/code/snowballs2/client/src/camera.h b/code/snowballs2/client/src/camera.h index c7718c653..5eae47c53 100644 --- a/code/snowballs2/client/src/camera.h +++ b/code/snowballs2/client/src/camera.h @@ -30,6 +30,7 @@ namespace NL3D { class UVisualCollisionEntity; + class CStereoOVR; }; namespace SBCLIENT { @@ -39,7 +40,10 @@ namespace SBCLIENT { // extern NL3D::UCamera Camera; +extern NL3D::UCamera SkyCamera; extern NL3D::UVisualCollisionEntity *CamCollisionEntity; +extern NL3D::CStereoOVR *StereoHMD; +extern NL3D::UScene *SkyScene; // // External functions diff --git a/code/snowballs2/client/src/snowballs_client.cpp b/code/snowballs2/client/src/snowballs_client.cpp index e0f044174..5ed15b9d7 100644 --- a/code/snowballs2/client/src/snowballs_client.cpp +++ b/code/snowballs2/client/src/snowballs_client.cpp @@ -51,6 +51,7 @@ #if SBCLIENT_DEV_STEREO # include #endif /* #if SBCLIENT_DEV_STEREO */ +#include // Project includes #include "pacs.h" @@ -709,6 +710,7 @@ void loopIngame() // 09. Update Camera (depends on entities) updateCamera(); + StereoHMD->updateCamera(&Camera); // 10. Update Interface (login, ui, etc) // ... @@ -729,17 +731,28 @@ void loopIngame() else { // call all 3d render thingies - Driver->clearBuffers(CRGBA(127, 0, 0)); // if you see red, there's a problem with bloom or stereo render + // Driver->clearBuffers(CRGBA(127, 0, 0)); // if you see red, there's a problem with bloom or stereo render + + // 01. Render Driver (background color) + // BLOOM CBloomEffect::instance().initBloom(); // start bloom effect (just before the first scene element render) + Driver->clearBuffers(CRGBA(0, 0, 127)); // clear all buffers, if you see this blue there's a problem with scene rendering + #if SBCLIENT_DEV_STEREO _StereoRender->calculateCameras(Camera.getObjectPtr()); // calculate modified matrices for the current camera for (uint cameraId = 0; cameraId < _StereoRender->getCameraCount(); ++cameraId) { _StereoRender->getCamera(cameraId, Camera.getObjectPtr()); // get the matrix details for this camera -#endif /* #if SBCLIENT_DEV_STEREO */ - // 01. Render Driver (background color) - CBloomEffect::instance().initBloom(); // start bloom effect (just before the first scene element render) - Driver->clearBuffers(CRGBA(0, 0, 127)); // clear all buffers, if you see this blue there's a problem with scene rendering +#endif /* #if SBCLIENT_DEV_STEREO */ + while (StereoHMD->nextPass()) + { + const CViewport &vp = StereoHMD->getCurrentViewport(); + Driver->setViewport(vp); + Scene->setViewport(vp); + SkyScene->setViewport(vp); + StereoHMD->getCurrentFrustum(&Camera); + StereoHMD->getCurrentFrustum(&SkyCamera); + StereoHMD->getCurrentMatrix(&Camera); // 02. Render Sky (sky scene) updateSky(); // Render the sky scene before the main scene @@ -749,10 +762,10 @@ void loopIngame() // 05. Render Effects (flare) updateLensFlare(); // Render the lens flare - CBloomEffect::instance().endBloom(); // end the actual bloom effect visible in the scene + // BLOOM CBloomEffect::instance().endBloom(); // end the actual bloom effect visible in the scene // 06. Render Interface 3D (player names) - CBloomEffect::instance().endInterfacesDisplayBloom(); // end bloom effect system after drawing the 3d interface (z buffer related) + // BLOOM CBloomEffect::instance().endInterfacesDisplayBloom(); // end bloom effect system after drawing the 3d interface (z buffer related) #if SBCLIENT_DEV_STEREO _StereoRender->copyBufferToTexture(cameraId); // copy current buffer to the active stereorender texture @@ -761,19 +774,20 @@ void loopIngame() _StereoRender->render(); // render everything together in the current mode #endif /* #if SBCLIENT_DEV_STEREO */ - // 07. Render Interface 2D (chatboxes etc, optionally does have 3d) - updateCompass(); // Update the compass - updateRadar(); // Update the radar - updateGraph(); // Update the radar - if (ShowCommands) updateCommands(); // Update the commands panel - updateAnimation(); - renderEntitiesNames(); // Render the name on top of the other players - updateInterface(); // Update interface - renderInformation(); - update3dLogo(); + // 07. Render Interface 2D (chatboxes etc, optionally does have 3d) + updateCompass(); // Update the compass + updateRadar(); // Update the radar + updateGraph(); // Update the radar + if (ShowCommands) updateCommands(); // Update the commands panel + updateAnimation(); + renderEntitiesNames(); // Render the name on top of the other players + updateInterface(); // Update interface + renderInformation(); + update3dLogo(); - // 08. Render Debug (stuff for dev) - // ... + // 08. Render Debug (stuff for dev) + // ... + } // 09. Render Buffer Driver->swapBuffers();