From 2fc5adb536536655dafcea778532c3de321bb386 Mon Sep 17 00:00:00 2001 From: DavidWyand-GG Date: Fri, 25 Oct 2013 01:57:38 -0400 Subject: [PATCH] PlaneReflector Support for Side-by-Side Rendering - The PlaneReflector class now supports side-by-side rendering. This does mean that while in this rendering style that all planar reflections are rendered twice, as reflection is a screen space effect from the eye point of view. - Planar reflections now work in the Oculus Rift. - Modified GuiTSCtrl::onRender() to move up where the rendering style is defined to just before the reflection manager has its turn. --- Engine/source/gui/3d/guiTSControl.cpp | 30 ++-- Engine/source/scene/reflector.cpp | 190 ++++++++++++++++++-------- Engine/source/scene/reflector.h | 5 +- 3 files changed, 153 insertions(+), 72 deletions(-) diff --git a/Engine/source/gui/3d/guiTSControl.cpp b/Engine/source/gui/3d/guiTSControl.cpp index 95dc960c3..4e42dbf84 100644 --- a/Engine/source/gui/3d/guiTSControl.cpp +++ b/Engine/source/gui/3d/guiTSControl.cpp @@ -316,6 +316,21 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect) return; } + // Set up the appropriate render style + U32 prevRenderStyle = GFX->getCurrentRenderStyle(); + Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset(); + Point3F prevEyeOffset = GFX->getStereoEyeOffset(); + if(mRenderStyle == RenderStyleStereoSideBySide) + { + GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide); + GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset); + GFX->setStereoEyeOffset(mLastCameraQuery.eyeOffset); + } + else + { + GFX->setCurrentRenderStyle(GFXDevice::RS_Standard); + } + if ( mReflectPriority > 0 ) { // Get the total reflection priority. @@ -338,21 +353,6 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect) mLastCameraQuery.cameraMatrix.mul(rotMat); } - // Set up the appropriate render style - U32 prevRenderStyle = GFX->getCurrentRenderStyle(); - Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset(); - Point3F prevEyeOffset = GFX->getStereoEyeOffset(); - if(mRenderStyle == RenderStyleStereoSideBySide) - { - GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide); - GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset); - GFX->setStereoEyeOffset(mLastCameraQuery.eyeOffset); - } - else - { - GFX->setCurrentRenderStyle(GFXDevice::RS_Standard); - } - // set up the camera and viewport stuff: F32 wwidth; F32 wheight; diff --git a/Engine/source/scene/reflector.cpp b/Engine/source/scene/reflector.cpp index df2e7f580..91a29f99b 100644 --- a/Engine/source/scene/reflector.cpp +++ b/Engine/source/scene/reflector.cpp @@ -546,7 +546,12 @@ void PlaneReflector::updateReflection( const ReflectParams ¶ms ) // store current matrices GFXTransformSaver saver; - F32 aspectRatio = F32( params.viewportExtent.x ) / F32( params.viewportExtent.y ); + Point2I viewport(params.viewportExtent); + if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) + { + viewport.x *= 0.5f; + } + F32 aspectRatio = F32( viewport.x ) / F32( viewport.y ); Frustum frustum; frustum.set(false, params.query->fov, aspectRatio, params.query->nearPlane, params.query->farPlane); @@ -562,12 +567,138 @@ void PlaneReflector::updateReflection( const ReflectParams ¶ms ) mLastDir = params.query->cameraMatrix.getForwardVector(); mLastPos = params.query->cameraMatrix.getPosition(); + setGFXMatrices( params.query->cameraMatrix ); + + // Adjust the detail amount + F32 detailAdjustBackup = TSShapeInstance::smDetailAdjust; + TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust; + + + if(reflectTarget.isNull()) + reflectTarget = GFX->allocRenderToTextureTarget(); + reflectTarget->attachTexture( GFXTextureTarget::Color0, reflectTex ); + reflectTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff ); + GFX->pushActiveRenderTarget(); + GFX->setActiveRenderTarget( reflectTarget ); + + U32 objTypeFlag = -1; + SceneCameraState reflectCameraState = SceneCameraState::fromGFX(); + LIGHTMGR->registerGlobalLights( &reflectCameraState.getFrustum(), false ); + + // Since we can sometime be rendering a reflection for 1 or 2 frames before + // it gets updated do to the lag associated with getting the results from + // a HOQ we can sometimes see into parts of the reflection texture that + // have nothing but clear color ( eg. under the water ). + // To make this look less crappy use the ambient color of the sun. + // + // In the future we may want to fix this instead by having the scatterSky + // render a skirt or something in its lower half. + // + ColorF clearColor = gClientSceneGraph->getAmbientLightColor(); + GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, clearColor, 1.0f, 0 ); + + if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) + { + // Store previous values + RectI originalVP = GFX->getViewport(); + + Point2F projOffset = GFX->getCurrentProjectionOffset(); + Point3F eyeOffset = GFX->getStereoEyeOffset(); + + // Render left half of display + RectI leftVP = originalVP; + leftVP.extent.x *= 0.5; + GFX->setViewport(leftVP); + + MatrixF leftWorldTrans(true); + leftWorldTrans.setPosition(Point3F(eyeOffset.x, eyeOffset.y, eyeOffset.z)); + MatrixF leftWorld(params.query->cameraMatrix); + leftWorld.mulL(leftWorldTrans); + + Frustum gfxFrustum = GFX->getFrustum(); + gfxFrustum.setProjectionOffset(Point2F(projOffset.x, projOffset.y)); + GFX->setFrustum(gfxFrustum); + + setGFXMatrices( leftWorld ); + + SceneCameraState cameraStateLeft = SceneCameraState::fromGFX(); + SceneRenderState renderStateLeft( gClientSceneGraph, SPT_Reflect, cameraStateLeft ); + renderStateLeft.setSceneRenderStyle(SRS_SideBySide); + renderStateLeft.setSceneRenderField(0); + renderStateLeft.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); + renderStateLeft.setDiffuseCameraTransform( params.query->cameraMatrix ); + renderStateLeft.disableAdvancedLightingBins(true); + + gClientSceneGraph->renderSceneNoLights( &renderStateLeft, objTypeFlag ); + + // Render right half of display + RectI rightVP = originalVP; + rightVP.extent.x *= 0.5; + rightVP.point.x += rightVP.extent.x; + GFX->setViewport(rightVP); + + MatrixF rightWorldTrans(true); + rightWorldTrans.setPosition(Point3F(-eyeOffset.x, eyeOffset.y, eyeOffset.z)); + MatrixF rightWorld(params.query->cameraMatrix); + rightWorld.mulL(rightWorldTrans); + + gfxFrustum = GFX->getFrustum(); + gfxFrustum.setProjectionOffset(Point2F(-projOffset.x, projOffset.y)); + GFX->setFrustum(gfxFrustum); + + setGFXMatrices( rightWorld ); + + SceneCameraState cameraStateRight = SceneCameraState::fromGFX(); + SceneRenderState renderStateRight( gClientSceneGraph, SPT_Reflect, cameraStateRight ); + renderStateRight.setSceneRenderStyle(SRS_SideBySide); + renderStateRight.setSceneRenderField(1); + renderStateRight.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); + renderStateRight.setDiffuseCameraTransform( params.query->cameraMatrix ); + renderStateRight.disableAdvancedLightingBins(true); + + gClientSceneGraph->renderSceneNoLights( &renderStateRight, objTypeFlag ); + + // Restore previous values + gfxFrustum.clearProjectionOffset(); + GFX->setFrustum(gfxFrustum); + GFX->setViewport(originalVP); + } + else + { + SceneRenderState reflectRenderState + ( + gClientSceneGraph, + SPT_Reflect, + SceneCameraState::fromGFX() + ); + + reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); + reflectRenderState.setDiffuseCameraTransform( params.query->cameraMatrix ); + reflectRenderState.disableAdvancedLightingBins(true); + + gClientSceneGraph->renderSceneNoLights( &reflectRenderState, objTypeFlag ); + } + + LIGHTMGR->unregisterAllLights(); + + // Clean up. + reflectTarget->resolve(); + GFX->popActiveRenderTarget(); + + // Restore detail adjust amount. + TSShapeInstance::smDetailAdjust = detailAdjustBackup; + + mIsRendering = false; +} + +void PlaneReflector::setGFXMatrices( const MatrixF &camTrans ) +{ if ( objectSpace ) { // set up camera transform relative to object MatrixF invObjTrans = mObject->getRenderTransform(); invObjTrans.inverse(); - MatrixF relCamTrans = invObjTrans * params.query->cameraMatrix; + MatrixF relCamTrans = invObjTrans * camTrans; MatrixF camReflectTrans = getCameraReflection( relCamTrans ); MatrixF camTrans = mObject->getRenderTransform() * camReflectTrans; @@ -586,8 +717,6 @@ void PlaneReflector::updateReflection( const ReflectParams ¶ms ) } else { - MatrixF camTrans = params.query->cameraMatrix; - // set world mat from new camera view MatrixF camReflectTrans = getCameraReflection( camTrans ); camReflectTrans.inverse(); @@ -598,60 +727,9 @@ void PlaneReflector::updateReflection( const ReflectParams ¶ms ) MatrixF clipProj = getFrustumClipProj( camReflectTrans ); GFX->setProjectionMatrix( clipProj ); } - - // Adjust the detail amount - F32 detailAdjustBackup = TSShapeInstance::smDetailAdjust; - TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust; - - - if(reflectTarget.isNull()) - reflectTarget = GFX->allocRenderToTextureTarget(); - reflectTarget->attachTexture( GFXTextureTarget::Color0, reflectTex ); - reflectTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff ); - GFX->pushActiveRenderTarget(); - GFX->setActiveRenderTarget( reflectTarget ); - - SceneRenderState reflectRenderState - ( - gClientSceneGraph, - SPT_Reflect, - SceneCameraState::fromGFX() - ); - - reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial ); - reflectRenderState.setDiffuseCameraTransform( params.query->cameraMatrix ); - reflectRenderState.disableAdvancedLightingBins(true); - - U32 objTypeFlag = -1; - LIGHTMGR->registerGlobalLights( &reflectRenderState.getFrustum(), false ); - - // Since we can sometime be rendering a reflection for 1 or 2 frames before - // it gets updated do to the lag associated with getting the results from - // a HOQ we can sometimes see into parts of the reflection texture that - // have nothing but clear color ( eg. under the water ). - // To make this look less crappy use the ambient color of the sun. - // - // In the future we may want to fix this instead by having the scatterSky - // render a skirt or something in its lower half. - // - ColorF clearColor = reflectRenderState.getAmbientLightColor(); - GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, clearColor, 1.0f, 0 ); - - gClientSceneGraph->renderSceneNoLights( &reflectRenderState, objTypeFlag ); - - LIGHTMGR->unregisterAllLights(); - - // Clean up. - reflectTarget->resolve(); - GFX->popActiveRenderTarget(); - - // Restore detail adjust amount. - TSShapeInstance::smDetailAdjust = detailAdjustBackup; - - mIsRendering = false; } -MatrixF PlaneReflector::getCameraReflection( MatrixF &camTrans ) +MatrixF PlaneReflector::getCameraReflection( const MatrixF &camTrans ) { Point3F normal = refplane; diff --git a/Engine/source/scene/reflector.h b/Engine/source/scene/reflector.h index 25c6399a8..bc5dca698 100644 --- a/Engine/source/scene/reflector.h +++ b/Engine/source/scene/reflector.h @@ -202,8 +202,11 @@ public: virtual F32 calcScore( const ReflectParams ¶ms ); virtual void updateReflection( const ReflectParams ¶ms ); + /// Set up the GFX matrices + void setGFXMatrices( const MatrixF &camTrans ); + /// Set up camera matrix for a reflection on the plane - MatrixF getCameraReflection( MatrixF &camTrans ); + MatrixF getCameraReflection( const MatrixF &camTrans ); /// Oblique frustum clipping - use near plane of zbuffer as a clip plane MatrixF getFrustumClipProj( MatrixF &modelview );