Explorar o código

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.
DavidWyand-GG %!s(int64=12) %!d(string=hai) anos
pai
achega
2fc5adb536

+ 15 - 15
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;

+ 130 - 52
Engine/source/scene/reflector.cpp

@@ -546,7 +546,12 @@ void PlaneReflector::updateReflection( const ReflectParams &params )
    // 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,42 +567,7 @@ void PlaneReflector::updateReflection( const ReflectParams &params )
    mLastDir = params.query->cameraMatrix.getForwardVector();
    mLastPos = params.query->cameraMatrix.getPosition();
 
-   if ( objectSpace )
-   {
-      // set up camera transform relative to object
-      MatrixF invObjTrans = mObject->getRenderTransform();
-      invObjTrans.inverse();
-      MatrixF relCamTrans = invObjTrans * params.query->cameraMatrix;
-
-      MatrixF camReflectTrans = getCameraReflection( relCamTrans );
-      MatrixF camTrans = mObject->getRenderTransform() * camReflectTrans;
-      camTrans.inverse();
-
-      GFX->setWorldMatrix( camTrans );
-
-      // use relative reflect transform for modelview since clip plane is in object space
-      camTrans = camReflectTrans;
-      camTrans.inverse();
-
-      // set new projection matrix
-      gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
-      MatrixF clipProj = getFrustumClipProj( camTrans );
-      GFX->setProjectionMatrix( clipProj );
-   }    
-   else
-   {
-      MatrixF camTrans = params.query->cameraMatrix;
-
-      // set world mat from new camera view
-      MatrixF camReflectTrans = getCameraReflection( camTrans );
-      camReflectTrans.inverse();
-      GFX->setWorldMatrix( camReflectTrans );
-
-      // set new projection matrix
-      gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
-      MatrixF clipProj = getFrustumClipProj( camReflectTrans );
-      GFX->setProjectionMatrix( clipProj );
-   }   
+   setGFXMatrices( params.query->cameraMatrix );
 
    // Adjust the detail amount
    F32 detailAdjustBackup = TSShapeInstance::smDetailAdjust;
@@ -611,19 +581,9 @@ void PlaneReflector::updateReflection( const ReflectParams &params )
    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 );
+   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
@@ -634,10 +594,90 @@ void PlaneReflector::updateReflection( const ReflectParams &params )
    // 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();
+   ColorF clearColor = gClientSceneGraph->getAmbientLightColor();
    GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, clearColor, 1.0f, 0 );
 
-   gClientSceneGraph->renderSceneNoLights( &reflectRenderState, objTypeFlag );
+   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();
 
@@ -651,7 +691,45 @@ void PlaneReflector::updateReflection( const ReflectParams &params )
    mIsRendering = false;
 }
 
-MatrixF PlaneReflector::getCameraReflection( MatrixF &camTrans )
+void PlaneReflector::setGFXMatrices( const MatrixF &camTrans )
+{
+   if ( objectSpace )
+   {
+      // set up camera transform relative to object
+      MatrixF invObjTrans = mObject->getRenderTransform();
+      invObjTrans.inverse();
+      MatrixF relCamTrans = invObjTrans * camTrans;
+
+      MatrixF camReflectTrans = getCameraReflection( relCamTrans );
+      MatrixF camTrans = mObject->getRenderTransform() * camReflectTrans;
+      camTrans.inverse();
+
+      GFX->setWorldMatrix( camTrans );
+
+      // use relative reflect transform for modelview since clip plane is in object space
+      camTrans = camReflectTrans;
+      camTrans.inverse();
+
+      // set new projection matrix
+      gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
+      MatrixF clipProj = getFrustumClipProj( camTrans );
+      GFX->setProjectionMatrix( clipProj );
+   }    
+   else
+   {
+      // set world mat from new camera view
+      MatrixF camReflectTrans = getCameraReflection( camTrans );
+      camReflectTrans.inverse();
+      GFX->setWorldMatrix( camReflectTrans );
+
+      // set new projection matrix
+      gClientSceneGraph->setNonClipProjection( (MatrixF&) GFX->getProjectionMatrix() );
+      MatrixF clipProj = getFrustumClipProj( camReflectTrans );
+      GFX->setProjectionMatrix( clipProj );
+   }   
+}
+
+MatrixF PlaneReflector::getCameraReflection( const MatrixF &camTrans )
 {
    Point3F normal = refplane;
 

+ 4 - 1
Engine/source/scene/reflector.h

@@ -202,8 +202,11 @@ public:
    virtual F32 calcScore( const ReflectParams &params );
    virtual void updateReflection( const ReflectParams &params ); 
 
+   /// 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 );