Transforming a split frustum from NDC to world space

Started by
2 comments, last by Digitalfragment 8 years, 5 months ago

Hi, I'm trying to implement cascaded shadow maps in my Direct3D project and I've been struggling with this issue for a few days now. What I'm trying to do is calculate the current view frustum splits in world space by manually constructing frustum splits in NDC space and transforming them with the current inverse viewprojection matrix. I've managed to create the frustums in NDC space, using these values for the first frustum;



/// NDC Frustum points (xyzw)
LTN:-1.000000  1.000000  0.100000  1.000000
RTN: 1.000000  1.000000  0.100000  1.000000
LBN:-1.000000 -1.000000  0.100000  1.000000
RBN: 1.000000 -1.000000  0.100000  1.000000
LTF:-1.000000  1.000000  0.215443  1.000000
RTF: 1.000000  1.000000  0.215443  1.000000
LBF:-1.000000 -1.000000  0.215443  1.000000
RBF: 1.000000 -1.000000  0.215443  1.000000

LTN means LeftTopNear, LBF means LeftBottomFar and so on. The data for the second and third frustum are similar, but with the different z-values for the far planes (0.464159 for the second frustum and 1.0 for the last one)

Here's the code that is supposed to transform and normalize the frustum points:


/// m_viewProjection verified to be correct
XMMATRIX invViewProjection = XMMatrixInverse(nullptr, m_viewProjection);

/// GFX_SHADOW_CASCADE_COUNT is set to 3
for (unsigned short i = 0; i < Config::GFX_SHADOW_CASCADE_COUNT; i++)
{
  for (int j = 0; j < 8; j++)
  {
    m_frustumsWorld[i].point[j] = XMVector4Transform(m_frustumsNDC[i].point[j], invViewProjection);
    m_frustumsWorld[i].point[j] /= m_frustumsWorld[i].point[j].m128_f32[3];			
  }
}

The problem seems to occur when I do the transform. The last frustum (with NDC z-far distance of 1.0) seems to get transformed right with a world z-value corresponding to 100% of the max view distance, but the other two doesn't. Their transformed values puts them extremly close to the camera, not ~21% and ~46% of the max view distance which is what I'm looking for. I've spent days trying to figure out whats wrong appreciate any help I can get!

Advertisement

Here the code to compute the 8 corners of the camera frustum in world-space :


void CCameraComponent::ComputeFrustumCornerPoints( CVector3* Points ) const
{
  // Get property values.
  const float NearClipPlane = GetNearClipPlane();
  const float FarClipPlane = GetFarClipPlane();

  // Compute the projection inverse scale factor.
  const float ScaleXInv = 1.0f / m_ProjectionMatrix( 0, 0 );
  const float ScaleYInv = 1.0f / m_ProjectionMatrix( 1, 1 );

  // Compute corners in view space.
  CVector3 CornersVS[ 8 ];
  const float NearX = ScaleXInv * NearClipPlane;
  const float NearY = ScaleYInv * NearClipPlane;
  CornersVS[ 0 ] = CVector3( -NearX, +NearY, NearClipPlane );
  CornersVS[ 1 ] = CVector3( +NearX, +NearY, NearClipPlane );
  CornersVS[ 2 ] = CVector3( +NearX, -NearY, NearClipPlane );
  CornersVS[ 3 ] = CVector3( -NearX, -NearY, NearClipPlane );
  const float FarX = ScaleXInv * FarClipPlane;
  const float FarY = ScaleYInv * FarClipPlane;
  CornersVS[ 4 ] = CVector3( -FarX, +FarY, FarClipPlane );
  CornersVS[ 5 ] = CVector3( +FarX, +FarY, FarClipPlane );
  CornersVS[ 6 ] = CVector3( +FarX, -FarY, FarClipPlane );
  CornersVS[ 7 ] = CVector3( -FarX, -FarY, FarClipPlane );

  // Compute the inverse of the view matrix.
  const CMatrix4 InverseViewMatrix = m_ViewMatrix.Inversed();

  // Compute the world space corners.
  for( UInt32 i = 0; i < 8; ++i )
    Points[ i ] = InverseViewMatrix.TransformPoint( CornersVS[ i ] );
}

Thanks so much Alundra, your solution with constructing the corners in view space works much better. Still curious as to why the original solution didn't work though!

Thanks so much Alundra, your solution with constructing the corners in view space works much better. Still curious as to why the original solution didn't work though!

The reason why is would be this (To quote Eric Lengyel)
Z is nonlinear because perspective-correct rasterization requires linear interpolation of 1/z -- linear interpolation of z itself does not produce the correct results.

http://www.gamedev.net/topic/539378-why-non-linear-depth-buffer/#entry4483438

This topic is closed to new replies.

Advertisement