Nachdem vor kurzem eine neue Bumpmapping Methode auf OpenGL.org präsentiert (oder besser gesagt wieder entdeckt) wurde, wollte ich mal ausprobieren, wie das sogenannte "Parallax Mapping" mit fxPascal umgesetzt werden kann.
Erst war die Enttäuschung groß - fxPascal "verschluckte" Variablen, auf der Sourcefourge Seite gab es aber glücklicherweise eine neue Version (von heute!), bei der dieser Fehler nicht mehr auftrat.
Der Code für das Parallax Mapping sieht dann folgendermaßen aus (ich komme mir zwar wie ein Behinderter vor, wenn ich Shader programmiere und eine Stunde oder mehr für ein paar Codezeilen brauche, weil es ziemliches Neuland ist - mit fxPascal geht es aber relativ problemlos)
das Vertexprogramm:
Code: {$optimize-} program VertexProgram1; uses arb_vertex_program, arb_position_invariant; // input: // texture #0 = color map // texture #1 = normal map // texture #2 = offset map // vertex.attrib[6] = tangent // output: // texcoord[0] offset in texture map // texcoord[1] tangent space light0 vector // texcoord[2] tangent space eye vector // remarks // binormal is computed on the fly // light is taken from light source 0 // viewer position is taken from modelview.invtrans var binormal, eyevec, light0pos, light0vec: vec4; begin // compute binormal binormal := cross(vertex.attrib[6], vertex.normal); // vector pointing to light 0 with state do light0pos := MatrixMult4(matrix.modelview.inverse, light[0].position); light0vec := vertex.position - light0pos; // transform light0 vector into tangent space with vertex do result.texcoord[1] := MatrixMult3(Matrix(attrib[6], binormal, normal), light0vec); result.texcoord[1].w := 1.0; // vector pointing to eye eyevec := vertex.position - state.matrix.modelview.invtrans.row[3]; // transform eye vector into tangent space with vertex do result.texcoord[2] := MatrixMult3(Matrix(attrib[6], binormal, normal), eyevec); result.texcoord[2].w := 1.0; result.color:=vertex.color; result.texcoord[0]:=vertex.texcoord[0]; end;
und das Fragmentprogramm:
Code: {$optimize-} program FragmentProgram1; uses arb_fragment_program; // input: // texture #0 = color map // texture #1 = normal map // texture #2 = offset map // texcoord[0] offset in texture map // texcoord[1] tangent space light0 vector // texcoord[2] tangent space eye vector var eyevects, rgb, normal, height, bump, total, light0tsvec, newtexcoord: vec4; begin // normalize tangent space eye vector eyevects := normalize(fragment.texcoord[2]); // calculate offset and new texture coordinate height := texture2d(2, fragment.texcoord[0]); newtexcoord := (height * 0.04 - 0.02) * eyevects + fragment.texcoord[0]; // get texture data rgb := texture2d(0, newtexcoord); normal := normalize(texture2d(1, newtexcoord) * 2.0 - 1.0); // normalize light0 vector light0tsvec := normalize(fragment.texcoord[1]); // normal dot lightdir bump := dot3(normal, light0tsvec); // compute total effect total := sat(bump * state.light[0].diffuse + state.lightmodel.ambient); // and multiply by regular texture map color result.color := sat(rgb * total); end;
Leider muss ich die Codeoptimierung ausschalten, damit das Programm korrekt generiert wird (es gibt keinen Absturz, der Assembler Source scheint aber falsch zu rechnen). Das "Leider" ist hier ehrlich gemeint, denn an sich ist es eine wahre Freude, fxPascal dabei zuzusehen, Optimierungen in den Assemblercode einzubauen, auf die ich selbst gar nicht gekommen wäre. Normalerweise funktioniert es ja auch, bei komplexeren Shadern mit vielen Variablen, scheint da irgend etwas durcheinander zu kommen. Bei abgeschalteter Optimierung kompilieren die Shader aber korrekt, was auch keine geringe Leistung ist.
Es gibt natürlich auch einen Screenshot - Carad berechnet die Tangenten fürs TBN Mapping in ein Vertexattribut, wenn man genau hinsieht, erkennt man, dass 9 Shader benötigt werden, um Parallax Mapping zu implementieren:
1) RenderSettings: Einschalten der Vertex- und Fragmentprogramme
2) TextureSettings: Aktivierung TexUnit #0, 2D-Texturen
3) Textur: Decal-Map
4) TextureSettings: Aktivierung TexUnit #1, 2D-Texturen
5) Textur: Normal-Map
6) TextureSettings: Aktivierung TexUnit #3, 2D-Texturen
7) Textur: Height-Map
8) Vertex Programm
9) Fragment Programm
Das alles klappt auch einwandfrei, die Komponenten werden alle richtig berechnet, darauf bin ich auch recht stolz, zeigt es doch dass BaseGraph und Carad recht allgemeingültig sind, da auch "neue" Algorithmen interaktiv implementiert werden können, ohne dass sie fest verdrahtet im Programm vorliegen müssen.
Leider kann Carad noch keine Vertexattribute als DelphiSource abspeichern, sobald ich diese Funktion eingebaut habe stelle ich das fertige Demo mit Source online.
Dateianhänge: |
Dateikommentar: ScreenShot aus der Carad IDE, beachtenswert die 9 Shader fürs Parallax Bumpmapping, sowie die neuen TSynEdit Fenster für fxPascal Source (viel schöner als der TRichText Hack).

ParMap.jpg [ 46.74 KiB | 3810-mal betrachtet ]
|
|