3 Stimmen

GLSL: Wie greife ich auf nahegelegene Vertex-Farben zu? (bilineare Interpolation ohne Uniforms)

Ich versuche, lineare Farbinterpolation auf einem Quad zu erstellen. Ich habe mit Hilfe meiner vorherigen Frage hier Erfolg gehabt, aber die Leistung ist schlecht, weil ich repeat glBegin() und glEnd() und 4 mal glUniform() vor glBegin() wiederholen muss.

Die Frage ist: Ist es irgendwie möglich, lineare Farbinterpolation auf einem Quad wie folgt anzuwenden:

glBegin(GL_QUADS); 
    glColor4f(...); glVertexAttrib2f(uv, 0, 0); glTexCoord2f(...); glVertex3f(...); 
    glColor4f(...); glVertexAttrib2f(uv, 1, 0); glTexCoord2f(...); glVertex3f(...); 
    glColor4f(...); glVertexAttrib2f(uv, 1, 1); glTexCoord2f(...); glVertex3f(...); 
    glColor4f(...); glVertexAttrib2f(uv, 0, 1); glTexCoord2f(...); glVertex3f(...); 
... // hier können beliebig viele Quads sein, ohne glBegin()/glEnd() zu wiederholen
glEnd(); 

Um dies zu erreichen, denke ich, dass ich irgendwie auf die benachbarten Eckfarben zugreifen sollte, aber wie? Oder gibt es andere Lösungen dafür?

Ich brauche das, um auf diese Weise zu funktionieren, damit ich leicht zwischen verschiedenen Interpolations-Shadern wechseln kann.

Jede andere Lösung, die mit einem glBegin()-Befehl funktioniert, ist ebenfalls gut, aber das Senden aller Eckfarben pro Vertex ist nicht akzeptabel, es sei denn, das ist hier die einzige Lösung?

Bearbeiten: Der Beispielcode verwendet nur den Sofortmodus zur Klarheit. Selbst mit Vertex-Arrays/-Puffern wäre das Problem dasselbe: Ich müsste die Rendering-Aufrufe in 4 Vertex-Chunks aufteilen, was den gesamten Geschwindigkeitsabfall verursacht!

3voto

Nick Gebbie Punkte 520

Lange Rede, kurzer Sinn: Dies ist mit einem Vertex-Shader nicht möglich.

Der Interpolator (oder Rasterisierer) ist eine der Komponenten des Grafik-Pipelines, die nicht programmierbar ist. Angesichts der Arbeitsweise der Grafik-Pipeline haben weder ein Vertex-Shader noch ein Fragment-Shader Zugriff auf etwas anderes als ihren Vertex (bzw. Fragment), aus Gründen von Geschwindigkeit, Einfachheit und Parallelität.

Die Umgehungslösung besteht darin, eine Texturensuche zu verwenden, was bereits in früheren Antworten erwähnt wurde.

In neueren Versionen von OpenGL (3.0 und höher, glaube ich) gibt es nun das Konzept eines Geometry-Shaders. Geometry-Shaders sind komplizierter zu implementieren als die relativ einfachen Vertex- und Fragment-Shaders, erhalten jedoch topologische Informationen. Das heißt, sie werden auf einem Primitiv (Dreieck, Linie, Quad usw.) ausgeführt, anstelle eines einzelnen Punktes. Mit diesen Informationen könnten sie zusätzliche Geometrie erstellen, um Ihre alternative Farbinterpolationsmethode zu lösen.

Allerdings ist das viel komplizierter als nötig. Ich würde bei einer 4-Texel-Texturkarte bleiben und Ihre Logik bei der Fragmenten-Suche implementieren.

2voto

Unter der Haube wird OpenGL (und die gesamte Hardware, die es steuert) alles als Dreiecke bearbeiten, sodass, wenn Sie wählen, Farben über Eckpunktinterpolation zu mischen, es sich um eine Dreiecksinterpolation handeln wird, weil die Hardware auf keine andere Weise funktioniert.

Wenn Sie eine "quad" Interpolation wünschen, sollten Sie Ihre Farben in eine Textur legen, denn in der Hardware ist eine Textur immer "quad"-förmig.

0voto

timday Punkte 24269

Lineare Interpolation mit pro Vertex angegebenen Farben kann effizient mit glColorPointer eingerichtet werden. Ebenso sollten Sie glTexCoordPointer / glVertexAttribPointer / glVertexPointer verwenden, um all diese einzelnen pro-Vertex-Aufrufe durch einen einzelnen Aufruf zu ersetzen, der auf die Daten in einem Array verweist. Rendern Sie dann alle Ihre Quadrate mit einem einzigen (oder höchstens einer Handvoll) glDrawArrays- oder glDrawElements-Aufruf. Sie werden eine enorme Verbesserung sehen, selbst ohne VBOs (die nur den Speicherort der Arrays ändern).

Sie erwähnen, dass Sie die Shader (zwischen ShaderA und ShaderB beispielsweise) quadweise ändern möchten. Sie sollten entweder:

  • Die Dinge so anordnen, dass Sie alle ShaderA-Quadrate zusammenstellen und alle ShaderB-Quadrate zusammenstellen und alle zusammen mit einem einzigen Aufruf rendern. Das Ändern des Shaders ist in der Regel ziemlich teuer, daher sollten Sie die Anzahl der Änderungen minimieren.

oder

  • Implementieren Sie alle unterschiedlichen Shader-Logiken, die Sie in einem einzigen "vereinheitlichten" Shader möchten, jedoch ausgewählt durch ein weiteres Vertex-Attribut, das zwischen den verschiedenen Codepfaden auswählt. Ob dies annähernd so effizient ist wie der Stapelungsansatz (der bevorzugt wird), hängt davon ab, ob jede "Kachel" von SIMD-Shadern tendiert, einen Mix aus Pfaden oder nur einen auszuführen.

0voto

Bahbar Punkte 17300

Wenn Sie wirklich denken, dass die Anzahl der Zeichnungen Ihren Leistungsabfall verursacht, können Sie versuchen, Instanzierung zu verwenden (Verwenden von glDrawArrayInstanced+glVertexAttribDivisor), verfügbar in GL 3.1 Core.

Alternativ könnte es Punktsprites geben, abhängig von Ihrem Anwendungsmodell (hauptsächlich maximale Größe Ihrer Quadrate und ob sie immer senkrecht zur Ansicht sind). Das ist seit GL 2.0 Core verfügbar.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X