View Frustum Culling

Man stelle sich vor, die Kamera steht mittig auf einem Terrain, umringt von tausenden Objekten. Ohne Optimierung würden jedesmal alle Vertexdaten zur Verarbeitung an die GPU geschickt.

Mit Frustum Culling werden nur noch Objekte verarbeitet, die sich auch wirklich im Sichtfeld der Kamera befinden. Alles was ausserhalb des Kamera-Frustums liegt fällt raus.

Aus der frame-aktuellen ViewProjektionMatrix (View x Projection) lassen sich alle sechs Planes (Near, Far, Left, Right, Top, Bottom) extrahieren. Anhand der Plane-Normalen lässt sich über ein Dot-Produkt ermitteln ob sich ein Punkt vor oder hinter der Plane befindet. Liegt der Testpunkt vor allen Planes, befindet er sich innerhalb des Frustums. Damit die Berechnung des Dot-Produkts richtig funktioniert, ist es wichtig die Planes zu normalisieren.


View Frustum Planes

'Build the view frustum planes
'
Public Sub Update(ViewProjection As Matrix)
  With ViewProjection
    '#Far Plane
    _Plane(0) = New Plane(.M14 - .M13, .M24 - .M23, .M34 - .M33, .M44 - .M43)
    '#Near Plane
    _Plane(1) = New Plane(.M13, .M23, .M33, .M43)
    '#Left Plane
    _Plane(2) = New Plane(.M14 + .M11, .M24 + .M21, .M34 + .M31, .M44 + .M41)
    '#Right Plane
    _Plane(3) = New Plane(.M14 - .M11, .M24 - .M21, .M34 - .M31, .M44 - .M41)
    '#Top Plane
    _Plane(4) = New Plane(.M14 - .M12, .M24 - .M22, .M34 - .M32, .M44 - .M42)
    '#Bottom Plane
    _Plane(5) = New Plane(.M14 + .M12, .M24 + .M22, .M34 + .M32, .M44 + .M42)
  End With
  
  '#Normalize Planes
  For i = 0 To 5
    _Plane(i) = Plane.Normalize(_Plane(i))
  Next
End Sub

'Test if Point is in Frustum
'
Public Function PointInFrustum(ByVal Point As Vector3, Optional Radius As Single = 0) As Boolean
  Dim vec4 As New Vector4(Point.X, Point.Y, Point.Z, 1)
     For Each p In _Plane
       If Plane.Dot(p, vec4) < -Radius Then Return False
     Next
  Return True
End Function

Bounding Test
Eine BoundingBox besteht aus 8 Punkten. Jeder einzelne Punkt wird gegen alle Planes getestet. Bei einem positiven Ergebnis wird die Schleife frühzeitig verlassen. Eine BoundingSphere ist wesentlich günstiger. Beim Test wird nur der Center benötigt um das Ergebnis gegen den Radius zu testen.

'BoundingBox Test
'
Public Function BoundingBoxInFrustum(Bounding As BoundingBox) As Boolean
  For Each v In Bounding.GetCorners
    If PointInFrustum(v) Then Return True
  Next
  Return False
End Function
'

'BoundingSphere Test
'
Public Function BoundingSphereInFrustum(Bounding As BoundingSphere) As Boolean
  Return PointInFrustum(Bounding.Center, Bounding.Radius)
End Function

Camera Bounding
Alle Objekte hinter der NearPlane werden durch das Culling verworfen. Dies kann in manchen Situationen jedoch unerwünscht sein. Um Objekte für Schatten oder Höhenberechnung dennoch zu erfassen, wird ein Bounding um die Kameraposition erstellt. Damit lässt sich auf einfache Weise ein Sphere-Sphere-Test realisieren der einen bestimmten Radius abdeckt.

'Sphere Intersection
'
Return BoundingSphere.Intersects(Camera.Bounding, Obj.Bounding)
'
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s