Explorar el Código

Fix lens flares in VR

James Urquhart hace 9 años
padre
commit
c6d2456a7c

+ 41 - 30
Engine/source/T3D/lightFlareData.cpp

@@ -33,6 +33,7 @@
 #include "gfx/gfxOcclusionQuery.h"
 #include "gfx/gfxDrawUtil.h"
 #include "gfx/gfxTextureManager.h"
+#include "gfx/sim/debugDraw.h"
 #include "renderInstance/renderPassManager.h"
 #include "T3D/gameBase/gameConnection.h"
 #include "T3D/gameBase/processList.h"
@@ -275,12 +276,10 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
    // is on scren at all... if not then return
    // the last result.
    const Point3F &lightPos = flareState->lightMat.getPosition();  
-   const RectI &viewport = GFX->getViewport();
-   MatrixF projMatrix;
-   state->getCameraFrustum().getProjectionMatrix(&projMatrix);
-   if( state->isReflectPass() )
-      projMatrix = state->getSceneManager()->getNonClipProjection();
-   bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix );
+   const RectI &viewport = RectI(Point2I(0, 0), GFX->getViewport().extent);
+
+   MatrixF camProjMatrix = projMatrix = state->getSceneManager()->getNonClipProjection();
+   bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), camProjMatrix );
 
    // It is onscreen, so raycast as a simple occlusion test.
    const LightInfo *lightInfo = flareState->lightInfo;
@@ -297,7 +296,7 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
       // Always treat light as onscreen if using HOQ
       // it will be faded out if offscreen anyway.
       onScreen = true;
-	  needsRaycast = false;
+      needsRaycast = false;
 
       // Test the hardware queries for rendered pixels.
       U32 pixels = 0, fullPixels = 0;
@@ -400,63 +399,75 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
    return lightVisible;
 }
 
-void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flareState )
+void LightFlareData::prepRender(SceneRenderState *state, LightFlareState *flareState)
 {
-   PROFILE_SCOPE( LightFlareData_prepRender );
+   PROFILE_SCOPE(LightFlareData_prepRender);
 
    const LightInfo *lightInfo = flareState->lightInfo;
 
-   if (  mIsZero( flareState->fullBrightness ) ||
-         mIsZero( lightInfo->getBrightness() ) )
-      return;
+   if (mIsZero(flareState->fullBrightness) ||
+       mIsZero(lightInfo->getBrightness()))
+   return;
 
    // Figure out the element count to render.
    U32 elementCount = mElementCount;
    const bool isReflectPass = state->isReflectPass();
-   if ( isReflectPass )
+   if (isReflectPass)
    {
       // Then we don't render anything this pass.
-      if ( !mRenderReflectPass )
+      if (!mRenderReflectPass)
          return;
 
       // Find the zero distance elements which make 
       // up the corona of the light flare.
       elementCount = 0.0f;
-      for ( U32 i=0; i < mElementCount; i++ )
-         if ( mIsZero( mElementDist[i] ) )
-            elementCount++;
+      for (U32 i = 0; i < mElementCount; i++)
+         if (mIsZero(mElementDist[i]))
+      elementCount++;
    }
 
    // Better have something to render.
-   if ( elementCount == 0 )
+   if (elementCount == 0)
       return;
-  
+
    U32 visDelta = U32_MAX;
    F32 occlusionFade = 1.0f;
    Point3F lightPosSS;
-   bool lightVisible = _testVisibility( state, flareState, &visDelta, &occlusionFade, &lightPosSS );
-   
+   bool lightVisible = _testVisibility(state, flareState, &visDelta, &occlusionFade, &lightPosSS);
+
+   //DebugDrawer::get()->drawBox(flareState->lightMat.getPosition() + Point3F(-0.5, -0.5, -0.5) * 4, flareState->lightMat.getPosition() + Point3F(0.5, 0.5, 0.5) * 4, ColorI::BLUE);
+
    // We can only skip rendering if the light is not 
    // visible, and it has elapsed the fade out time.
-   if (  mIsZero( occlusionFade ) ||
-         !lightVisible && visDelta > FadeOutTime )
+   if (mIsZero(occlusionFade) ||
+      !lightVisible && visDelta > FadeOutTime)
       return;
 
    const RectI &viewport = GFX->getViewport();
-   Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f );
+   Point3F oneOverViewportExtent(1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f);
 
-   // Really convert it to screen space.
-   lightPosSS.x -= viewport.point.x;
-   lightPosSS.y -= viewport.point.y;
    lightPosSS *= oneOverViewportExtent;
-   lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
+   lightPosSS = (lightPosSS * 2.0f) - Point3F::One;
    lightPosSS.y = -lightPosSS.y;
    lightPosSS.z = 0.0f;
 
+   // Determine the center of the current projection so we can converge there
+   Point3F centerProj(0);
+   {
+      MatrixF camProjMatrix = state->getSceneManager()->getNonClipProjection();
+      Point3F outCenterPos;
+      RectI centerViewport = RectI(Point2I(0, 0), viewport.extent);
+      MathUtils::mProjectWorldToScreen(Point3F(0,state->getSceneManager()->getNearClip(),0), &outCenterPos, centerViewport, MatrixF::Identity, camProjMatrix);
+      centerProj = outCenterPos;
+      centerProj *= oneOverViewportExtent;
+      centerProj = (centerProj * 2.0f) - Point3F::One;
+      centerProj.y = -centerProj.y;
+      centerProj.z = 0.0f;
+   }
+
    // Take any projection offset into account so that the point where the flare's
    // elements converge is at the 'eye' point rather than the center of the viewport.
-   const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset();
-   Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) );
+   Point3F flareVec( centerProj - lightPosSS );
    const F32 flareLength = flareVec.len();
    if ( flareLength > 0.0f )
       flareVec *= 1.0f / flareLength;

+ 2 - 2
Engine/source/environment/scatterSky.cpp

@@ -667,11 +667,11 @@ void ScatterSky::prepRenderImage( SceneRenderState *state )
       mFlareState.scale = mFlareScale;
       mFlareState.lightInfo = mLight;
 
-      Point3F lightPos = state->getCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f;
+      Point3F lightPos = state->getDiffuseCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f;
       mFlareState.lightMat.identity();
       mFlareState.lightMat.setPosition( lightPos );
 
-      F32 dist = ( lightPos - state->getCameraPosition( ) ).len( );
+      F32 dist = ( lightPos - state->getDiffuseCameraPosition( ) ).len( );
       F32 coronaScale = 0.5f;
       F32 screenRadius = GFX->getViewport( ).extent.y * coronaScale * 0.5f;
       mFlareState.worldRadius = screenRadius * dist / state->getWorldToScreenScale( ).y;

+ 1 - 1
Engine/source/math/util/frustum.cpp

@@ -216,7 +216,7 @@ void Frustum::setNearFarDist( F32 nearDist, F32 farDist )
    // Recalculate the frustum.
    MatrixF xfm( mTransform );
 
-   const F32 CENTER_EPSILON = 0.01;
+   const F32 CENTER_EPSILON = 0.001;
    F32 centerX = mNearLeft + (mNearRight - mNearLeft) * 0.5;
    F32 centerY = mNearBottom + (mNearTop - mNearBottom) * 0.5;
    if ((centerX > CENTER_EPSILON || centerX < -CENTER_EPSILON) || (centerY > CENTER_EPSILON || centerY < -CENTER_EPSILON) )