Rubrik: Grafik und Font · DirectX | VB-Versionen: VB5, VB6 | 13.12.02 |
Sichtbarkeitstest in D3D Frustum culling ist eine äußerst beliebte und sinnvolle Technik um zu überprüfen ob ein Objekt im Blickfeld ist. | ||
Autor: Marius Schmidt | Bewertung: | Views: 14.290 |
www.matrixvb.da.ru | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Bei der Programmierung von 3D-Anwendungen ist es äußerst sinnvoll die Rechenzeit nur für Objekte zu verwenden, die der Nutzer später auch sehen wird. Deshalb muss man heraus finden, ob ein Objekt im Blickfeld liegt oder nicht.
Um solch einen Test durchzuführen, überprüft man lediglich ein paar Eckpunkte des Objektes, da eine Überprüfung des gesamten Objektes zu kompliziert wäre. Normalerweise benutzt man hierzu sogenannte "Bounding Boxes". Diese Boxen werden ganz einfach durch den minimalen und den maximalen X/Y/Z-Wert des Objektes beschrieben.
Hier folgt nun der Code zur Berechnung des Blickfeldes und zur Überprüfung ob eine "Bounding Box" im Blickfeld liegt:
Option Explicit ' Deklarationen ' Das berechnete Blickfeld setzt sich aus den ' 6 Seiten zusammen Private Frustum(5) As D3DPLANE ' Wir speichern uns den Index für jede Seite in ' einer Aufzählung. So ist es später einfacher ' die Seiten zu identifizieren Private Enum FrustumSide FS_RIGHT = 0 ' RECHTE Seite FS_LEFT = 1 ' LINKE Seite FS_BOTTOM = 2 ' UNTERE Seite FS_TOP = 3 ' OBERE Seite FS_BACK = 4 ' HINTERE Seite FS_FRONT = 5 ' VORDERE Seite End Enum ' Diese Matrix wird aus der Projektions- und ' Blickfeld-Matrix multipliziert Dim matClip As D3DMATRIX
' Funktion zum Berechnen das Blickfelds Public Sub CalculateFrustum() ' matView = Blickfeld-Matrix ' matProj = Projektions-Matrix D3DXMatrixMultiply matClip, matView, matProj ' Die nachfolgenden Berechnungen sind etwas ' kompliziert. Man muss sich schon ziemlich gut mit ' Matrizen-Berechnung auskennen, um die Berechnungen ' zu verstehen. Wir müssen nur wissen, dass hier das ' Blickfeld aus einer Matrix in die Planes ' konvertiert wird ' Rechts With Frustum(FS_RIGHT) .a = matClip.m14 - matClip.m11 .b = matClip.m24 - matClip.m21 .c = matClip.m34 - matClip.m31 .d = matClip.m44 - matClip.m41 End With D3DXPlaneNormalize Frustum(FS_RIGHT), Frustum(FS_RIGHT) ' Links With Frustum(FS_LEFT) .a = matClip.m14 + matClip.m11 .b = matClip.m24 + matClip.m21 .c = matClip.m34 + matClip.m31 .d = matClip.m44 + matClip.m41 End With D3DXPlaneNormalize Frustum(FS_LEFT), Frustum(FS_LEFT) ' Unten With Frustum(FS_BOTTOM) .a = matClip.m14 + matClip.m12 .b = matClip.m24 + matClip.m22 .c = matClip.m34 + matClip.m32 .d = matClip.m44 + matClip.m42 End With D3DXPlaneNormalize Frustum(FS_BOTTOM), Frustum(FS_BOTTOM) ' Oben With Frustum(FS_TOP) .a = matClip.m14 - matClip.m12 .b = matClip.m24 - matClip.m22 .c = matClip.m34 - matClip.m32 .d = matClip.m44 - matClip.m42 End With D3DXPlaneNormalize Frustum(FS_TOP), Frustum(FS_TOP) ' Hinten With Frustum(FS_BACK) .a = matClip.m14 - matClip.m13 .b = matClip.m24 - matClip.m23 .c = matClip.m34 - matClip.m33 .d = matClip.m44 - matClip.m43 End With D3DXPlaneNormalize Frustum(FS_BACK), Frustum(FS_BACK) ' Vorne With Frustum(FS_FRONT) .a = matClip.m14 + matClip.m13 .b = matClip.m24 + matClip.m23 .c = matClip.m34 + matClip.m33 .d = matClip.m44 + matClip.m43 End With D3DXPlaneNormalize Frustum(FS_FRONT), Frustum(FS_FRONT) End Sub
' Überprüft ob eine Box im Blickfeld der Kamera ist ' (indem die maximalen und minimalen Werte der Box ' übergeben werden) Public Function BoxInFrustum(Max As D3DVECTOR, _ Min As D3DVECTOR) As Boolean Dim i As Integer ' Alle 6 Planes testen For i = 0 To 5 ' PlaneDorCoord führt eine PLANE-Gleichung durch, ' die Formel dafür lautet: ' ------------------------- ' A * x + B * y + C * z + D ' ------------------------- ' Die Großbuchstaben stehen hiebrei für die Werte ' aus D3DPLANE, die Kleinbuchstaben für die ' Vertex-Koordinate, die wir testen möchten BoxInFrustum = True If D3DXPlaneDotCoord(Frustum(i), Max) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Min.x, Max.y, Max.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Max.x, Min.y, Max.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Min.x, Min.y, Max.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Max.x, Max.y, Min.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Min.x, Max.y, Min.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), _ MakeVector(Max.x, Min.y, Min.z)) <= 0 Or _ D3DXPlaneDotCoord(Frustum(i), Min) <= 0 Then BoxInFrustum = False: Exit For End If Next Ic End Function
' Hilfsgunktion um einen Vektor zu erstellen Public Function MakeVector(x As Single, _ y As Single, z As Single) As D3DVECTOR With MakeVector .x = x .y = y .z = z End With End Function
Diese Funktionen habe ich von einem C++ OGL Sample von gametutorials.com in VB übersetzt. Nach meinen Erfahrungen ist diese Methode um einiges schneller als die D3DXVec3Unproject-Methode, da das Blickfeld vorberechnet wird.