2016-04-13 7 views
1

In den letzten Tagen bin ich auf einen besonders kniffligen Fehler gestoßen. Ich habe meinen Code auf ein sehr einfaches und direktes Beispiel reduziert.Unerwartete Textur Koordinateninterpolation - Verarbeitung + GLSL

Dies ist die Verarbeitung Code verwende ich meine Shadern zu nennen:

PGraphics test; 
PShader testShader; 
PImage testImage; 

void setup() { 
    size(400, 400, P2D); 
    testShader = loadShader("test.frag", "vert2D.vert"); 
    testImage = loadImage("test.png"); 
    testShader.set("image", testImage); 
    testShader.set("size", testImage.width); 
    shader(testShader); 
} 

void draw() { 
    background(0, 0, 0); 
    shader(testShader); 
    beginShape(TRIANGLES); 
    vertex(-1, -1, 0, 1); 
    vertex(1, -1, 1, 1); 
    vertex(-1, 1, 0, 0); 
    vertex(1, -1, 1, 1); 
    vertex(-1, 1, 0, 0); 
    vertex(1, 1, 1, 0); 
    endShape(); 
} 

Hier meine Vertex-Shader ist:

attribute vec2 vertex; 
attribute vec2 texCoord; 
varying vec2 vertTexCoord; 
void main() { 
    gl_Position = vec4(vertex, 0, 1); 
    vertTexCoord = texCoord; 
} 

Als ich nenne das Fragment-Shader:

uniform sampler2D image; 
varying vec2 vertTexCoord; 
void main(void) { 
    gl_FragColor = texture2D(image, vertTexCoord); 
} 

Ich bekomme das:

Dies ist das erwartete Ergebnis. Allerdings, wenn ich die Texturkoordinaten zu den roten und grünen Kanälen anstatt mit den folgenden Fragment-Shader machen:

uniform sampler2D image; 
uniform float size; 
varying vec2 vertTexCoord; 
void main(void) { 
    gl_FragColor = vec4(vertTexCoord, 0, 1); 
} 

ich diese:

enter image description here

Wie Sie sehen können, eine Mehrheit der Bildschirm ist schwarz, was anzeigen würde, dass bei diesen Fragmenten die Texturkoordinaten [0, 0] sind. Dies kann jedoch nicht der Fall sein, da sie bei der Übergabe an die texture2D-Funktion korrekt auf die entsprechenden Positionen im Bild abgebildet werden. Um zu überprüfen, dass in beiden Fällen die exakt gleichen Werte für Texturkoordinaten verwendet wurden, habe ich sie mit dem folgenden Shader kombiniert.

uniform sampler2D image; 
uniform float size; 
varying vec2 vertTexCoord; 
void main(void) { 
    gl_FragColor = texture2D(image, vertTexCoord) + vec4(vertTexCoord, 0, 0); 
} 

Dies erzeugt:
enter image description here

das ist genau das, was man erwarten würde, wenn die Texturkoordinaten gleichmäßig über den Bildschirm variieren tun. Also habe ich ein komplett schwarzes Bild ausprobiert, in der Erwartung, diese Variation ohne das Gesicht deutlicher zu sehen. Als ich das tat, bekam ich das Bild mit den zwei Dreiecken wieder. Nach dem Spielen etwas mehr mit ihm um, fand ich, dass, wenn ich ein völlig schwarzes Bild nur mit dem linken oberen Pixel transparent, bekomme ich diese: mit

enter image description here

die schließlich das Bild, das ich erwarte reibungslos variierende Koordinaten. Das hat mich völlig ratlos gemacht. Warum funktioniert die Textur-Suche richtig, aber das Rendern der tatsächlichen Koordinaten gibt mir meistens Müll?

EDIT:
Ich fand eine Lösung, die ich geschrieben habe, bin aber immer noch unsicher, warum der Fehler überhaupt existiert. Ich bin auf einen interessanten Testfall gestoßen, der ein wenig mehr Informationen darüber liefern könnte, warum dies geschieht.

Fragment Shader:

varying vec2 vertTexCoord; 
void main(void) { 
    gl_FragColor = vec4(vertTexCoord, 0, 0.5); 
} 

Ergebnis:
enter image description here

+0

Welche Gfx-Karte und Treiber haben Sie (kann ein Fehler auf der Fahrerseite oder "Feature" sein)? was für ist die "Größe"? Meine Wette ist, dass der Fahrer eine Interpolation von Texturkoordinaten optimiert, wenn Sie keinen Zugriff auf die Textur verwenden. Versuchen Sie eine alberne Sache verwenden Sie 'texture2D (image, vertTexCoord)', wenn fug-Koordinaten '0,0' sind, wenn es hilft. – Spektre

+0

Ich habe in früheren Tests gl_FragCoord/size anstelle von texCoords verwendet, um zu sehen, ob das gleiche Verhalten hatte. Ich habe es gelassen, damit ich zwischen diesen Tests zurück und viert wechseln und sie vergleichen kann. Ich habe dein Beispiel und andere Variationen ausprobiert und ich habe immer noch das Bild mit den zwei Dreiecken. Ich habe jedoch eine besonders rätselhafte Lösung gefunden, die ich gepostet habe. Es scheint zu zeigen, dass der Ursprung des Fehlers in den internen APIs von Processing und nicht in GLSL liegt, obwohl ich nicht verstehe, wie sich die Art des Fehlers in der Mitte der Pipeline zu ändern scheint. –

Antwort

0

Ich habe zwei verschiedene Lösungen gefunden. Beide beinhalten Änderungen im Verarbeitungscode.Ich habe keine Ahnung, wie oder warum diese Änderungen funktionieren.

Lösung 1:
Geben Bildschirmraum Setzkoordinaten anstelle von Raumkoordinaten-Clip und die Matrix durch Verarbeitung erzeugten Transformation verwenden, um diese in Clip Raum in dem Vertex-Shader zu konvertieren.
Verarbeitungscode:

PGraphics test; 
PShader testShader; 
PImage testImage; 

void setup() { 
    size(400, 400, P2D); 
    testShader = loadShader("test.frag", "vert2D.vert"); 
    testImage = loadImage("test.png"); 
    testShader.set("image", testImage); 
    testShader.set("size", testImage.width); 
    shader(testShader); 
} 

void draw() { 
    background(0, 0, 0); 
    shader(testShader); 
    beginShape(TRIANGLES); 
    //Pass down screen space coordinates instead. 
    vertex(0, 400, 0, 1); 
    vertex(400, 400, 1, 1); 
    vertex(0, 0, 0, 0); 
    vertex(400, 400, 1, 1); 
    vertex(0, 0, 0, 0); 
    vertex(400, 0, 1, 0); 
    endShape(); 
} 

Vertex Shader:

attribute vec2 vertex; 
attribute vec2 texCoord; 
uniform mat4 transform; 
varying vec2 vertTexCoord; 
void main() { 
    //Multiply transform matrix. 
    gl_Position = transform * vec4(vertex, 0, 1); 
    vertTexCoord = texCoord; 
} 

Ergebnis:
enter image description here
Beachten Sie die Linie durch die Mitte des Bildschirms. Dies liegt daran, dass wir noStroke() im Verarbeitungscode nicht aufgerufen haben. Dennoch werden Texturkoordinaten richtig interpoliert.

Lösung 2:
Wenn wir() im Setup nur noStroke nennen, können wir den Clip Raum passieren Koordinaten ohne Probleme nach unten und alles funktioniert genau wie erwartet. Keine Shader-Änderungen erforderlich.

PGraphics test; 
PShader testShader; 
PImage testImage; 

void setup() { 
    size(400, 400, P2D); 
    //Call noStroke() 
    noStroke(); 
    testShader = loadShader("test.frag", "vert2D.vert"); 
    testImage = loadImage("test.png"); 
    testShader.set("image", testImage); 
    testShader.set("size", testImage.width); 
    shader(testShader); 
} 

void draw() { 
    background(0, 0, 0); 
    shader(testShader); 
    beginShape(TRIANGLES); 
    vertex(-1, -1, 0, 1); 
    vertex(1, -1, 1, 1); 
    vertex(-1, 1, 0, 0); 
    vertex(1, -1, 1, 1); 
    vertex(-1, 1, 0, 0); 
    vertex(1, 1, 1, 0); 
    endShape(); 
} 

Ergebnis:
enter image description here
recht einfache Lösung. Wie sich diese eine Änderung auf die Art und Weise auswirkt, in der die Texturkoordinaten im Fragment-Shader interpoliert/nicht interpoliert werden, liegt außerhalb meiner Grenzen.

Für jeden, der vielleicht etwas vertrauter mit der Verarbeitung von OpenGL ist, die vielleicht einen Einblick hat, warum diese Fehler existieren, würde mich das interessieren.