JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=ce702977807de850e883ee2dc018dd53Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Curved Surfaces & CO

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
David
Super JLI'ler


Alter: 33
Anmeldedatum: 13.10.2005
Beiträge: 315

Medaillen: Keine

BeitragVerfasst am: 08.11.2005, 21:54    Titel: Curved Surfaces & CO Antworten mit Zitat

Hi!

Ein ganz interessantes Thema der 3D Programmierung sind wohl gekrümmte Oberflächen. Es gibt etliche Methoden diese zu berechnen, in diesem Tutorial nehmen wir die sogenannten Bézier Patches.

Fangen wir also (klein) an. Wink
Wenn man sich einen Linienabschnitt betrachtet der von Punkt P0 zu P1 geht kann man jeden Punkt auf der Linie mit folgender Gleichung darstellen:

Q(t) = (1-t)P0 + (t)P1 => wobei t zwischen 0 und 1 liegt.

Aha, toll... nur wo ist hier die Kurve? Ganz einfach, nehmen wir einen weiteren Punkt hinzu P2 und interpolieren zwischen P0 und P1 sowie zwischen P1 und P2 so erhalten wir zwei weitere Punkte S0 und S1. Jetzt nurnoch zwischen S0 und S1 interpolieren und raus kommt der Punkt Q (abhängig von t) welcher jeden Punkt auf der Kurve repräsentiert.

In einer Gleichung ausgedrückt sieht das folgermaßen aus:

Q(t) = summe( i=0 bis 3, BiPi )

wobei die Basisfunktionen

B0 = ( 1-t )^2
B1 = 2t(1-t)
B3 = t^2

und P0-P2 die Kontrollpunkte sind.

So, zur Oberfläche ist es kein weiter Weg mehr, hier bilden die Kontrollpunkte ein 3x3 großes Gitter:

P0,0 P1,0 P2,0
P0,1 P1,1 P2,1
P0,2 P1,2 P2,2

Nun wegen die Kurven zwischen den Punkten P0,0 P0,1 P0,2 sowie P1,0 P1,1 P1,2 und P2,0 P2,1 und P2,2 berechnet. Danach die Kurve zwischen den daraus resultierenden Punkten und schon hat man seine gekrümmte Oberfläche. Wink

Und nun noch ein bisschen Code:

CPP:
FVector3 Interpolate( FVector3 v[ 3 ], float t )
{
   float b1, b2, b3;
   FVector3 res;

   b1 = ( 1-t )*( 1-t );
   b2 = 2*t*( 1-t );
   b3 = t*t;

   res.x = v[ 0 ].x*b1+v[ 1 ].x*b2+v[ 2 ].x*b3;
   res.y = v[ 0 ].y*b1+v[ 1 ].y*b2+v[ 2 ].y*b3;
   res.z = v[ 0 ].z*b1+v[ 1 ].z*b2+v[ 2 ].z*b3;

   return res;
}

void Subdivide( float tessx, float tessy, FVector3 **pts )
{
   int i, j;
   float t, f, subdivx, subdivy;
   FVector3 p[ 3 ], *q;

   subdivx = 1.0f / (tessy-1);
   subdivy = 1.0f / (tessx-1);

   *pts = new FVector3[ tessy*tessx ];
   q = *pts;

   for ( i = 0, t = .0f; i < tessy; i++, t += subdivx )
   {
      p[ 0 ] = Interpolate( &ctl_pts[ 0*3 ], t );
      p[ 1 ] = Interpolate( &ctl_pts[ 1*3 ], t );
      p[ 2 ] = Interpolate( &ctl_pts[ 2*3 ], t );

      for ( j = 0, f = .0f; j < tessx; j++, f += subdivy )
      {
         *q = Interpolate( p, f );
         q++;
      }
   }
}


ctl_pts ist ein Array welches die Kontrollpunkte enthält. tessx und tessy ist die Anzahl der Segmente in die Subdividiert werden soll.

Jetzt müssen nurnoch die einzelnen Polygone definiert werden:
CPP:
int GenerateIndexes( float tessx, float tessy, int **indexes )
{
   int num_indexes, *p;
   int p0, p1, p2, p3, u, v;

   num_indexes = ( ( tessx-1 ) * ( tessy-1 ) ) * 6;

   *indexes = new int[ num_indexes ];
   p = *indexes;

   for ( v = 0; v < tessx-1; v++ )
   {
      for ( u = 0; u < tessy-1; u++ )
      {
         p0 = u*tessx+v;
         p1 = p0 + 1;
         p2 = p0 + tessx + 1;
         p3 = p0 + tessx;

         *( p++ ) = p0;
         *( p++ ) = p2;
         *( p++ ) = p1;
         *( p++ ) = p0;
         *( p++ ) = p3;
         *( p++ ) = p2;
      }
   }

   return num_indexes;
}


Und losgehts mit dem Rendern des Patches:

CPP:
// ...
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, pts );
glDrawElements( GL_TRIANGLES, num_elements, GL_UNSIGNED_INT, indexes );
glDisableClientState( GL_VERTEX_ARRAY );
// ...


( Zum Schluss nicht vergessen den reservierten Speicher wieder freizugeben Wink)

Und es klappt wirklich:

Screenshot 1
Screenshot 2
Screenshot 3

Verbesserungsvorschläge:

Auf Screenshot 3 ist zu erkennen, das nur in eine Richtung subdividiert wurde. Dies macht Sinn, da der Patch in eine Richtung "Planar" ist, also die Kontrollpunkte jeweils auf einer Höhe liegen.
Wenn man das also vor dem Subdividieren abtestet kann man einiges an Polygonen sparen.

Ich hoffe das ich das Thema "Bezierpatches" einigen von euch etwas näher bringen konnte. Zum Schluss noch ein Link auf ein PDF zum Thema, das ich mal geschrieben habe: Link

grüße
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Jonathan_Klein
Living Legend


Alter: 31
Anmeldedatum: 17.02.2003
Beiträge: 3430
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 08.11.2005, 22:03    Titel: Antworten mit Zitat

Kurze Frage: Was sind die Einsatzgebiete? Landschaften macht mal wohl meistens mit Heighmaps, man könnte das wohl vielleihct für Torbögen oder so machen, aber würde man die nicht eher modellieren? Naja, aber auf jeden fall coole Technik in der Demoscenen kann man das zum Platzsparen bestimmt gut benutezn, oder?
_________________
http://www.C3-Soft.de
http://www.nikodemus.net
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
David
Super JLI'ler


Alter: 33
Anmeldedatum: 13.10.2005
Beiträge: 315

Medaillen: Keine

BeitragVerfasst am: 08.11.2005, 22:54    Titel: Antworten mit Zitat

Hi!

Der eine Vorteil ist halt, das man ziemlich viel Platz sparen kann, ein anderer ist das Unterteilungslevel. So kann man für bessere Rechner eine viel weichere Krümmung erzeugen als für leistungsschwächere. Außerdem können weit entfernte Patches mit weniger Details angezeigt werden.

Aktuell verwenden viele Spiele diese (und ähnliche Techniken). Doom3 beispielsweise nutzt Bézier Patches für Rohre, Torbögen und allerhand andere Objekte.

Und noch ein Paar bilder von Bézier Patches in Quake3 (übrigens mit meiner Implementation erzeugt Wink):
Screenshot 1
Screenshot 2
Screenshot 3

grüße
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum