意外的纹理坐标插值 - 处理 + GLSL
Unexpected Texture Coordinate Interpolation - Processing + GLSL
在过去的几天里,我偶然发现了一个特别棘手的错误。我已将我的代码缩减为一组非常简单直接的示例。
这是我用来调用着色器的处理代码:
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();
}
这是我的顶点着色器:
attribute vec2 vertex;
attribute vec2 texCoord;
varying vec2 vertTexCoord;
void main() {
gl_Position = vec4(vertex, 0, 1);
vertTexCoord = texCoord;
}
当我调用这个片段着色器时:
uniform sampler2D image;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = texture2D(image, vertTexCoord);
}
我明白了:
这是预期的结果。但是,当我使用以下片段着色器将纹理坐标渲染到红色和绿色通道时:
uniform sampler2D image;
uniform float size;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = vec4(vertTexCoord, 0, 1);
}
我明白了:
如您所见,大部分屏幕都是黑色的,这表明在这些片段处,纹理坐标为 [0, 0]。但事实并非如此,因为当传递到 texture2D 函数时,它们会正确映射到图像中的相应位置。为了验证在这两种情况下使用的纹理坐标值完全相同,我将它们与以下着色器结合使用。
uniform sampler2D image;
uniform float size;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = texture2D(image, vertTexCoord) + vec4(vertTexCoord, 0, 0);
}
这产生了:
如果纹理坐标在屏幕上平滑变化,这正是您所期望的。所以我尝试了一个全黑的图像,希望在没有脸的情况下更清楚地看到这种变化。当我这样做时,我又得到了带有两个三角形的图像。玩了一会儿之后,我发现如果我有一个全黑的图像,除了左上角的像素透明,我得到这个:
这最终是我期望平滑变化的图像 coordinates.This 完全难倒了我。为什么纹理查找工作正常但渲染实际坐标给我的大部分都是垃圾?
编辑:
我找到了一个已发布的解决方案,但仍然不确定为什么该错误首先存在。我遇到了一个有趣的测试用例,它可能会提供更多关于为什么会发生这种情况的信息。
片段着色器:
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = vec4(vertTexCoord, 0, 0.5);
}
结果:
我找到了两种不同的解决方案。两者都涉及处理代码的更改。我不知道这些更改如何或为何使其起作用。
解决方案一:
传递屏幕 space 坐标而不是剪辑 space 坐标,并使用处理生成的变换矩阵将其转换为顶点着色器中的剪辑 space。
处理代码:
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();
}
顶点着色器:
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;
}
结果:
注意穿过屏幕中心的线。这是因为我们没有在处理代码中调用 noStroke()。不过,纹理坐标已正确插值。
方案二:
如果我们只是在设置中调用 noStroke() ,我们可以毫无问题地传递剪辑 space 坐标,并且一切都按预期进行。无需更改着色器。
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();
}
结果:
很容易修复。这一变化如何影响纹理坐标 interpolated/not 在片段着色器中插值的方式超出了我的范围。
对于任何可能更熟悉处理如何包装 OpenGL 并且可能了解为什么存在这些错误的人,我很想知道。
在过去的几天里,我偶然发现了一个特别棘手的错误。我已将我的代码缩减为一组非常简单直接的示例。
这是我用来调用着色器的处理代码:
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();
}
这是我的顶点着色器:
attribute vec2 vertex;
attribute vec2 texCoord;
varying vec2 vertTexCoord;
void main() {
gl_Position = vec4(vertex, 0, 1);
vertTexCoord = texCoord;
}
当我调用这个片段着色器时:
uniform sampler2D image;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = texture2D(image, vertTexCoord);
}
我明白了:
这是预期的结果。但是,当我使用以下片段着色器将纹理坐标渲染到红色和绿色通道时:
uniform sampler2D image;
uniform float size;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = vec4(vertTexCoord, 0, 1);
}
我明白了:
如您所见,大部分屏幕都是黑色的,这表明在这些片段处,纹理坐标为 [0, 0]。但事实并非如此,因为当传递到 texture2D 函数时,它们会正确映射到图像中的相应位置。为了验证在这两种情况下使用的纹理坐标值完全相同,我将它们与以下着色器结合使用。
uniform sampler2D image;
uniform float size;
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = texture2D(image, vertTexCoord) + vec4(vertTexCoord, 0, 0);
}
这产生了:
如果纹理坐标在屏幕上平滑变化,这正是您所期望的。所以我尝试了一个全黑的图像,希望在没有脸的情况下更清楚地看到这种变化。当我这样做时,我又得到了带有两个三角形的图像。玩了一会儿之后,我发现如果我有一个全黑的图像,除了左上角的像素透明,我得到这个:
这最终是我期望平滑变化的图像 coordinates.This 完全难倒了我。为什么纹理查找工作正常但渲染实际坐标给我的大部分都是垃圾?
编辑:
我找到了一个已发布的解决方案,但仍然不确定为什么该错误首先存在。我遇到了一个有趣的测试用例,它可能会提供更多关于为什么会发生这种情况的信息。
片段着色器:
varying vec2 vertTexCoord;
void main(void) {
gl_FragColor = vec4(vertTexCoord, 0, 0.5);
}
结果:
我找到了两种不同的解决方案。两者都涉及处理代码的更改。我不知道这些更改如何或为何使其起作用。
解决方案一:
传递屏幕 space 坐标而不是剪辑 space 坐标,并使用处理生成的变换矩阵将其转换为顶点着色器中的剪辑 space。
处理代码:
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();
}
顶点着色器:
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;
}
结果:
注意穿过屏幕中心的线。这是因为我们没有在处理代码中调用 noStroke()。不过,纹理坐标已正确插值。
方案二:
如果我们只是在设置中调用 noStroke() ,我们可以毫无问题地传递剪辑 space 坐标,并且一切都按预期进行。无需更改着色器。
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();
}
结果:
很容易修复。这一变化如何影响纹理坐标 interpolated/not 在片段着色器中插值的方式超出了我的范围。
对于任何可能更熟悉处理如何包装 OpenGL 并且可能了解为什么存在这些错误的人,我很想知道。