Normalen - Interpolation für 3D Modelle
Übersicht

![]() |
NoobodyBetreff: Normalen - Interpolation für 3D Modelle |
![]() Antworten mit Zitat ![]() |
---|---|---|
Nach Lektüre eines kleinen Artikels auf Gamasutra habe ich eine Funktion für die Interpolation von 3D - Modellen geschrieben.
Ist wohl einer der kompliziertesten Codes, der je aus meiner Feder floss ![]() Die Funktion geht alle Dreiecke des Ursprungsmodells durch und verfeinert das Modell, indem es das Dreieck 'wölbt'. Wie genau diese Wölbung aussieht, wird durch die Vertexnormalen der drei anliegenden Vertices bestimmt. Wofür ist das gut? Nun, das wird ganz praktisch, wenn man verschieden detaillierte Ausführungen eines Modells in seinem Spiel verwenden will, um nahe Objekte mit hoher und ferne Objekte mit niedriger Polygonzahl rendern zu lassen. Wenn man die Vertexnormalen geschickt setzt, kann man mit der Funktion eine detailliertere Version des Meshes aus dem Low-Poly-Mesh generieren lassen. Dadurch braucht man nicht immer mehrere verschiedene Modelldateien zu seinem Spiel beilegen, sondern erstellt alles beim Start des Programms auf Basis eines einzigen Modells. Wie fein das generierte Mesh sein soll, kann durch den Parameter LOD der Interpolationsfunktion festelegt werden. Je höher der Wert, desto mehr Polygone. Beim Aufruf von SetNormals im Beispielcode (Zeile 19) kann man den letzten Parameter von 1 auf höhere Werte abändern, um die Interpolation noch zu verstärken - ergibt einen tollen visuellen Effekt. Der Code demonstriert die Funktionsweise des Algorithmus anhand den Primitiven von Blitz (Würfel, Kegel, Kugel etc.) Code: [AUSKLAPPEN] Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer() Dim Vertices( 0, 0 ) ;Vertexarray Local Cam = CreateCamera() ;Kamera PositionEntity Cam, 0, 0, -5 Local Light = CreateLight( 2 ) ;Beleuchtungskram PositionEntity Light, 0, 5, -2 LightRange Light, 3 LightColor Light, 255, 255, 255 Local Mesh = CreateCube() ;Das Mesh, das interpoliert werden soll - einfach die verschiedenen Blitz - Primitiven ausprobieren ;Local Mesh = CreateSphere( 2 ) ;Local Mesh = CreateCone( 4 ) ;Local Mesh = CreateCylinder() PositionEntity Mesh, -2.5, 0, 0 SetNormals Mesh, 1 ;Normalen neu berechnen; Blitz setzt die Normalen in einer für die Interpolation ungünstigen Weise Local Spline = InterpolateMesh( Mesh, 15 ) ;Das Mesh mit LOD 15 PositionEntity Spline, 2.5, 0, 0 Local Timer = CreateTimer( 60 ) While Not KeyHit( 1 ) Cls Wireframe False EntityColor Mesh, 255, 255, 255 EntityColor Spline, 255, 255, 255 ScaleEntity Mesh, 1, 1, 1 ScaleEntity Spline, 1, 1, 1 CameraClsMode Cam, True, True RenderWorld If MouseDown( 1 ) Then ;Mit linker Maustaste Wireframe - Overlay Wireframe True EntityColor Mesh, 0, 0, 0 EntityColor Spline, 0, 0, 0 ScaleEntity Mesh, 1.005, 1.005, 1.005 ScaleEntity Spline, 1.005, 1.005, 1.005 CameraClsMode Cam, False, False RenderWorld EndIf TurnEntity Mesh, 0.5, 1, 1.5 TurnEntity Spline, 0.5, 1, 1.5 Flip 0 WaitTimer Timer Wend End Function InterpolateMesh( Mesh, LOD = 5 ) Local NewMesh = CreateMesh() Local Brush = GetEntityBrush( Mesh ) For SurfIndex = 1 To CountSurfaces( Mesh ) Local Surf = GetSurface( Mesh, SurfIndex ) Local NewSurf = CreateSurface( NewMesh ) Local TriCount = CountTriangles( Surf ) PaintSurface NewSurf, GetSurfaceBrush( Surf ) For TriIndex = 0 To TriCount - 1 Local P102#[ 2 ], P201#[ 2 ], P012#[ 2 ], P111#[ 2 ], P210#[ 2 ], P021#[ 2 ], P120#[ 2 ], P003#[ 2 ], P030#[ 2 ], P300#[ 2 ] ;Koordinaten Local N200#[ 2 ], N020#[ 2 ], N002#[ 2 ], N110#[ 2 ], N011#[ 2 ], N101#[ 2 ] ;Vertexnormalen Local T100#[ 1 ], T010#[ 1 ], T001#[ 1 ] ;Texturkoordinaten Local V1 = TriangleVertex( Surf, TriIndex, 0 ) Local V2 = TriangleVertex( Surf, TriIndex, 1 ) Local V3 = TriangleVertex( Surf, TriIndex, 2 ) P003[ 0 ] = VertexX( Surf, V1 ) ;Die wichtigsten Werte zwischenspeichern P003[ 1 ] = VertexY( Surf, V1 ) P003[ 2 ] = VertexZ( Surf, V1 ) P300[ 0 ] = VertexX( Surf, V2 ) P300[ 1 ] = VertexY( Surf, V2 ) P300[ 2 ] = VertexZ( Surf, V2 ) P030[ 0 ] = VertexX( Surf, V3 ) P030[ 1 ] = VertexY( Surf, V3 ) P030[ 2 ] = VertexZ( Surf, V3 ) N002[ 0 ] = VertexNX( Surf, V1 ) N002[ 1 ] = VertexNY( Surf, V1 ) N002[ 2 ] = VertexNZ( Surf, V1 ) N200[ 0 ] = VertexNX( Surf, V2 ) N200[ 1 ] = VertexNY( Surf, V2 ) N200[ 2 ] = VertexNZ( Surf, V2 ) N020[ 0 ] = VertexNX( Surf, V3 ) N020[ 1 ] = VertexNY( Surf, V3 ) N020[ 2 ] = VertexNZ( Surf, V3 ) T001[ 0 ] = VertexU( Surf, V1 ) T001[ 1 ] = VertexV( Surf, V1 ) T010[ 0 ] = VertexU( Surf, V2 ) T010[ 1 ] = VertexV( Surf, V2 ) T100[ 0 ] = VertexU( Surf, V3 ) T100[ 1 ] = VertexV( Surf, V3 ) InterpolateControlPoint( P003, P300, N002, P102 ) ;Die Kontrollpunkte interpolieren InterpolateControlPoint( P300, P003, N200, P201 ) InterpolateControlPoint( P003, P030, N002, P012 ) InterpolateControlPoint( P030, P003, N020, P021 ) InterpolateControlPoint( P300, P030, N200, P210 ) InterpolateControlPoint( P030, P300, N020, P120 ) ;Den letzten Kontrollpunkt müssen wir anders berechnen P111[ 0 ] = ( P102[ 0 ] + P201[ 0 ] + P012[ 0 ] + P210 [ 0 ] + P021[ 0 ] + P120[ 0 ] )/4. - ( P003[ 0 ] + P030[ 0 ] + P300[ 0 ] )/6. P111[ 1 ] = ( P102[ 1 ] + P201[ 1 ] + P012[ 1 ] + P210 [ 1 ] + P021[ 1 ] + P120[ 1 ] )/4. - ( P003[ 1 ] + P030[ 1 ] + P300[ 1 ] )/6. P111[ 2 ] = ( P102[ 2 ] + P201[ 2 ] + P012[ 2 ] + P210 [ 2 ] + P021[ 2 ] + P120[ 2 ] )/4. - ( P003[ 2 ] + P030[ 2 ] + P300[ 2 ] )/6. InterpolateNormal( N002, N020, P003, P030, N011 ) ;Normalen der Kontrollpunkte interpolieren InterpolateNormal( N200, N020, P300, P030, N110 ) InterpolateNormal( N200, N002, P300, P003, N101 ) Dim Vertices( LOD, LOD ) ;Vertexarray für schnellen Zugriff For A = 0 To LOD ;Vertices je nach LOD - Grad erstellen For B = 0 To LOD If A + B <= LOD Then Local U# = A/Float( LOD ) ;Index in barycentrische Koordinaten umrechnen Local V# = B/Float( LOD ) Local W# = 1 - U# - V# ;Position mithilfe eines kubischen Splines ermitteln ;Die Formel ist leider gigantisch, weswegen ich sie auf mehrere Zeilen verteilt habe Local VX# = U#*U#*U#*P300[ 0 ] + V#*V#*V#*P030[ 0 ] + W#*W#*W#*P003[ 0 ] + 3*U#*U#*V#*P210[ 0 ] VX# = VX# + 3*U#*U#*W#*P201[ 0 ] + 3*U#*V#*V#*P120[ 0 ] + 3*V#*V#*W#*P021[ 0 ] VX# = VX# + 3*V#*W#*W#*P012[ 0 ] + 3*U#*W#*W#*P102[ 0 ] + 6*U#*V#*W#*P111[ 0 ] Local VY# = U#*U#*U#*P300[ 1 ] + V#*V#*V#*P030[ 1 ] + W#*W#*W#*P003[ 1 ] + 3*U#*U#*V#*P210[ 1 ] VY# = VY# + 3*U#*U#*W#*P201[ 1 ] + 3*U#*V#*V#*P120[ 1 ] + 3*V#*V#*W#*P021[ 1 ] VY# = VY# + 3*V#*W#*W#*P012[ 1 ] + 3*U#*W#*W#*P102[ 1 ] + 6*U#*V#*W#*P111[ 1 ] Local VZ# = U#*U#*U#*P300[ 2 ] + V#*V#*V#*P030[ 2 ] + W#*W#*W#*P003[ 2 ] + 3*U#*U#*V#*P210[ 2 ] VZ# = VZ# + 3*U#*U#*W#*P201[ 2 ] + 3*U#*V#*V#*P120[ 2 ] + 3*V#*V#*W#*P021[ 2 ] VZ# = VZ# + 3*V#*W#*W#*P012[ 2 ] + 3*U#*W#*W#*P102[ 2 ] + 6*U#*V#*W#*P111[ 2 ] ;Vertexnormale auf dem quadratischen Spline ermitteln Local NX# = U#*U#*N200[ 0 ] + V#*V#*N020[ 0 ] + W#*W#*N002[ 0 ] + U#*V#*N110[ 0 ] + U#*W#*N101[ 0 ] + V#*W#*N011[ 0 ] Local NY# = U#*U#*N200[ 1 ] + V#*V#*N020[ 1 ] + W#*W#*N002[ 1 ] + U#*V#*N110[ 1 ] + U#*W#*N101[ 1 ] + V#*W#*N011[ 1 ] Local NZ# = U#*U#*N200[ 2 ] + V#*V#*N020[ 2 ] + W#*W#*N002[ 2 ] + U#*V#*N110[ 2 ] + U#*W#*N101[ 2 ] + V#*W#*N011[ 2 ] ;Je nach dem ist die berechnete Normale nicht normalisiert - das holen wir nach TFormNormal NX#, NY#, NZ#, 0, 0 ;Schlussendlich Texturkoordinaten linear interpolieren Local TU# = U#*T010[ 0 ] + V#*T100[ 0 ] + W#*T001[ 0 ] Local TV# = U#*T010[ 1 ] + V#*T100[ 1 ] + W#*T001[ 1 ] Vertices( A, B ) = AddVertex( NewSurf, VX#, VY#, VZ#, TU#, TV# ) ;Vertex hinzufügen VertexNormal NewSurf, Vertices( A, B ), TFormedX(), TFormedY(), TFormedZ() ;Normale setzen EndIf Next Next For A = 0 To LOD - 1 ;Dreiecke erstellen For B = 0 To LOD - 1 If A + B < LOD Then AddTriangle NewSurf, Vertices( A, B ), Vertices( A + 1, B ), Vertices( A, B + 1 ) If A + B < LOD - 1 Then AddTriangle NewSurf, Vertices( A + 1, B + 1 ), Vertices( A, B + 1 ), Vertices( A + 1, B ) EndIf Next Next Next Next PaintEntity NewMesh, Brush Return NewMesh End Function Function InterpolateControlPoint( P1#[ 2 ], P2#[ 2 ], N#[ 2 ], Result#[ 2 ] ) Result[ 0 ] = ( 2*P1[ 0 ] + P2[ 0 ] )/3. ;Den Punkt auf der Strecke P1-P2 positionieren und auf die Normalenebene durch P1 projizieren Result[ 1 ] = ( 2*P1[ 1 ] + P2[ 1 ] )/3. Result[ 2 ] = ( 2*P1[ 2 ] + P2[ 2 ] )/3. Local D# = -( P1[ 0 ]*N[ 0 ] + P1[ 1 ]*N[ 1 ] + P1[ 2 ]*N[ 2 ] ) Local W# = N[ 0 ]*Result[ 0 ] + N[ 1 ]*Result[ 1 ] + N[ 2 ]*Result[ 2 ] + D# Result[ 0 ] = Result[ 0 ] - W#*N[ 0 ] Result[ 1 ] = Result[ 1 ] - W#*N[ 1 ] Result[ 2 ] = Result[ 2 ] - W#*N[ 2 ] End Function Function InterpolateNormal( N1#[ 2 ], N2#[ 2 ], P1#[ 2 ], P2#[ 2 ], Result#[ 2 ] ) Local DX# = P2[ 0 ] - P1[ 0 ] ;Durchschnittsnormale errechnen und an der Mittelnormalebene zu P1-P2 spiegeln Local DY# = P2[ 1 ] - P1[ 1 ] Local DZ# = P2[ 2 ] - P1[ 2 ] Local Nominator# = DX#*( N1[ 0 ] + N2[ 0 ] ) + DY#*( N1[ 1 ] + N2[ 1 ] ) + DZ#*( N1[ 2 ] + N2[ 2 ] ) Local Denominator# = DX#*DX# + DY#*DY# + DZ#*DZ# Local Fraction# = 2*Nominator#/Denominator# Result[ 0 ] = N1[ 0 ] + N2[ 0 ] - Fraction#*DX# Result[ 1 ] = N1[ 1 ] + N2[ 1 ] - Fraction#*DY# Result[ 2 ] = N1[ 2 ] + N2[ 2 ] - Fraction#*DZ# End Function Function SetNormals( Entity, Scale# = 1 ) For SurfIndex = 1 To CountSurfaces( Entity ) Local Surf = GetSurface( Entity, SurfIndex ) For i = 0 To CountVertices( Surf ) - 1 TFormNormal VertexX( Surf, i ), VertexY( Surf, i ), VertexZ( Surf, i ), 0, 0 VertexNormal Surf, i, TFormedX()*Scale#, TFormedY()*Scale#, TFormedZ()*Scale# Next Next End Function Mit gedrückter linker Maustaste kann man die Wireframe - Ansicht einblenden. Screenshot mit Textur (links das Ursprungsmesh, rechts das interpolierte): ![]() |
||
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun |
- Zuletzt bearbeitet von Noobody am Mi, Mai 27, 2009 19:35, insgesamt einmal bearbeitet
![]() |
ChriseBetreff: Re: Normalen - Interpolation für 3D Modelle |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hui, nice!
Vorallem bei Sphere(8) war ich überrascht, wie "rund" das ganze lief ![]() |
||
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet. |
![]() |
ozzi789 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Super wie immer ![]() Als attackierend gemeldete Website! -Gamasutra ?? mfg ozzi |
||
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5 |
![]() |
Noobody |
![]() Antworten mit Zitat ![]() |
---|---|---|
ozzi789 hat Folgendes geschrieben: Als attackierend gemeldete Website! -Gamasutra
Ja, die Meldung kam bei mir auch eben. Eigentlich schade, die Seite war vorgestern noch in Ordnung ![]() Naja, ich nehm den Link vorerst mal raus, bis die das wieder beheben (scheinbar hat jemand Schadcode eingeschleust). |
||
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun |
Kruemelator |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Sehr interessant!
Wenn ich LOD >= 74 habe dann gibt es bei mir einen Fehler. Das Mesh wird nicht richtig angezeigt, es fehlen Polygone. |
||
![]() |
FireballFlame |
![]() Antworten mit Zitat ![]() |
---|---|---|
74 ist ja auch ein bisschen arg übertrieben | ||
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit |
![]() |
Lord_Vader |
![]() Antworten mit Zitat ![]() |
---|---|---|
Sehr nett. Vorallem für die einstellungen ![]() |
||
![]() |
Noobody |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kruemelator hat Folgendes geschrieben: Wenn ich LOD >= 74 habe dann gibt es bei mir einen Fehler. Das Mesh wird nicht richtig angezeigt, es fehlen Polygone.
Logisch, ab LOD > 73 sprengst du die magische Grenze von 65536 erlaubten Triangles in DirectX 7. Man könnte das natürlich umgehen, indem man eine neue Surface erstellt, sobald man an die Grenze kommt; allerdings halte ich das wenig sinnvoll - bereits ab LOD 15 ist keine sichtbare Verfeinerung mehr festzustellen, und mehr als 65536 Polygone pro Mesh ist sowieso der Tod der anständigen Performance ![]() |
||
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun |
Kruemelator |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Ein MAV erreiche ich aber erst bei LOD = 104. Wenn ich trisrendered anzeigen lasse dann habe ich bei LOD 103 den Wert 127320.
Aber der Sinn fehlt, da hast du recht ![]() |
||
![]() |
Noobody |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kruemelator hat Folgendes geschrieben: Ein MAV erreiche ich aber erst bei LOD = 104. Wenn ich trisrendered anzeigen lasse dann habe ich bei LOD 103 den Wert 127320.
Der MAV ist von Situation zu Situation unterschiedlich, aber TrisRendered sagt ja schon ziemlich viel aus (127320 ist weit über den erlaubten 65536, daher Anzeigefehler). Alternativ kannst du dir die Polygonzahl mal per CountTriangles ![]() ![]() |
||
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group