1
\$\begingroup\$

So after fixing all my lighting and shadow problems that my new terrain system showed me that I had I have an issue with my shadow maps, I have had it since my XNA days but because of my world setup, field of view and no shadow jittering fix I couldn't really see it.

I'm 90% sure its to do with the way I fix the shadow jittering, this peace of code is really old and I have never really been able to fix it. It comes from this page and I never really did much with it other than drop it in and it worked so I moved on to other parts of the engine.

Here is a pic so u can see what is going on, easier than you guys trying to work out what "a strange black peace of my shadow map". enter image description here

It looks to me like there is a problem with the way the frustum is clipped but I'm not really sure so here is the light view projection code with the jitter fix, if I turn the jitter fix off then it fixes the problem but I'm left with jittery shadows.

VB.net

Private Function CreateLightViewProjectionMatrix(CASCADE_SHADOW_RESOLUTION As Single, lightDir As Vector3, minZ As Single, maxZ As Single, index As Integer, ByRef _Camera As Camera, frustumCornersWS As Vector3(), frustumCornersVS As Vector3(), _directionalClippingPlanes As Plane()) As Matrix


    Dim splitFrustumCornersVS As Vector3() = New Vector3(7) {}
    For i As Integer = 0 To 3
        splitFrustumCornersVS(i) = frustumCornersVS(i + 4) * (minZ / _Camera.FarClip)
    Next

    For i As Integer = 4 To 7
        splitFrustumCornersVS(i) = frustumCornersVS(i) * (maxZ / _Camera.FarClip)
    Next

    Dim cameraMat As Matrix = _Camera.Transform


    For i As Integer = 0 To frustumCornersWS.Length - 1
        Vector3.Transform(splitFrustumCornersVS(i), cameraMat, frustumCornersWS(i))
    Next


    Dim cameraUpVector As Vector3 = Vector3.Up
    If Math.Abs(Vector3.Dot(cameraUpVector, lightDir)) > 0.9F Then
        cameraUpVector = Vector3.ForwardRH
    End If

    Dim lightRotation As Matrix = Matrix.LookAtRH(Vector3.Zero, -lightDir, cameraUpVector)


    For i As Integer = 0 To frustumCornersWS.Length - 1
        Vector3.Transform(frustumCornersWS(i), lightRotation, frustumCornersWS(i))
    Next


    Dim mins As Vector3 = frustumCornersWS(0), maxes As Vector3 = frustumCornersWS(0)
    For i As Integer = 1 To frustumCornersWS.Length - 1
        Dim p As Vector3 = frustumCornersWS(i)
        If p.X < mins.X Then
            mins.X = p.X
        End If
        If p.Y < mins.Y Then
            mins.Y = p.Y
        End If
        If p.Z < mins.Z Then
            mins.Z = p.Z
        End If
        If p.X > maxes.X Then
            maxes.X = p.X
        End If
        If p.Y > maxes.Y Then
            maxes.Y = p.Y
        End If
        If p.Z > maxes.Z Then
            maxes.Z = p.Z
        End If
    Next


    Dim minsVS As Vector3 = splitFrustumCornersVS(0), maxesVS As Vector3 = splitFrustumCornersVS(0)
    For i As Integer = 1 To splitFrustumCornersVS.Length - 1
        Dim p As Vector3 = splitFrustumCornersVS(i)
        If p.X < minsVS.X Then
            minsVS.X = p.X
        End If
        If p.Y < minsVS.Y Then
            minsVS.Y = p.Y
        End If
        If p.Z < minsVS.Z Then
            minsVS.Z = p.Z
        End If
        If p.X > maxesVS.X Then
            maxesVS.X = p.X
        End If
        If p.Y > maxesVS.Y Then
            maxesVS.Y = p.Y
        End If
        If p.Z > maxesVS.Z Then
            maxesVS.Z = p.Z
        End If
    Next
    Dim _lightBox As New BoundingBox(mins, maxes)


    If fixShadowJittering Then

        Dim diagonalLength As Single = (frustumCornersWS(0) - frustumCornersWS(6)).Length()

        Dim worldsUnitsPerTexel As Single = diagonalLength / CType(CASCADE_SHADOW_RESOLUTION , Single)
        Dim vBorderOffset As Vector3 = (New Vector3(diagonalLength, diagonalLength, diagonalLength) - (_lightBox.Maximum - _lightBox.Minimum)) * 0.5F
        _lightBox.Maximum += vBorderOffset
        _lightBox.Minimum -= vBorderOffset

        _lightBox.Minimum /= worldsUnitsPerTexel
        _lightBox.Minimum.X = CType(Math.Floor(_lightBox.Minimum.X), Single)
        _lightBox.Minimum.Y = CType(Math.Floor(_lightBox.Minimum.Y), Single)
        _lightBox.Minimum.Z = CType(Math.Floor(_lightBox.Minimum.Z), Single)
        _lightBox.Minimum *= worldsUnitsPerTexel

        _lightBox.Maximum /= worldsUnitsPerTexel
        _lightBox.Maximum.X = CType(Math.Floor(_lightBox.Maximum.X), Single)
        _lightBox.Maximum.Y = CType(Math.Floor(_lightBox.Maximum.Y), Single)
        _lightBox.Maximum.Z = CType(Math.Floor(_lightBox.Maximum.Z), Single)
        _lightBox.Maximum *= worldsUnitsPerTexel
    End If

    Dim boxSize As Vector3 = _lightBox.Maximum - _lightBox.Minimum
    If boxSize.X = 0 OrElse boxSize.Y = 0 OrElse boxSize.Z = 0 Then
        boxSize = Vector3.One
    End If
    Dim halfBoxSize As Vector3 = boxSize * 0.5F

         Dim lightPosition As Vector3 = _lightBox.Minimum + halfBoxSize
    lightPosition.Z = _lightBox.Minimum.Z

          lightPosition = Vector3.Transform(lightPosition, Matrix.Invert(lightRotation))

           Dim lightView As Matrix = Matrix.LookAtRH(lightPosition, lightPosition - lightDir, cameraUpVector)


    Dim lightProjection As Matrix = Matrix.OrthoRH(boxSize.X, boxSize.Y, -boxSize.Z, 0)

    Dim lightDirVS As Vector3 = Vector3.TransformNormal(-lightDir, _Camera.EyeTransform)

    Return lightView * lightProjection
End Function 

Just the jitter fixing code:

   If fixShadowJittering Then

        Dim diagonalLength As Single = (frustumCornersWS(0) - frustumCornersWS(6)).Length()

        Dim worldsUnitsPerTexel As Single = diagonalLength / CType(CASCADE_SHADOW_RESOLUTION , Single)
        Dim vBorderOffset As Vector3 = (New Vector3(diagonalLength, diagonalLength, diagonalLength) - (_lightBox.Maximum - _lightBox.Minimum)) * 0.5F
        _lightBox.Maximum += vBorderOffset
        _lightBox.Minimum -= vBorderOffset

        _lightBox.Minimum /= worldsUnitsPerTexel
        _lightBox.Minimum.X = CType(Math.Floor(_lightBox.Minimum.X), Single)
        _lightBox.Minimum.Y = CType(Math.Floor(_lightBox.Minimum.Y), Single)
        _lightBox.Minimum.Z = CType(Math.Floor(_lightBox.Minimum.Z), Single)
        _lightBox.Minimum *= worldsUnitsPerTexel

        _lightBox.Maximum /= worldsUnitsPerTexel
        _lightBox.Maximum.X = CType(Math.Floor(_lightBox.Maximum.X), Single)
        _lightBox.Maximum.Y = CType(Math.Floor(_lightBox.Maximum.Y), Single)
        _lightBox.Maximum.Z = CType(Math.Floor(_lightBox.Maximum.Z), Single)
        _lightBox.Maximum *= worldsUnitsPerTexel
    End If
\$\endgroup\$

0

You must log in to answer this question.

Browse other questions tagged .