OpenGL,为什么这段代码不能像我预期的那样工作?

时间:2014-06-15 10:51:19

标签: opengl glsl shader

您好,很抱歉提出这样一个具体问题。

我有以下GLSL顶点着色器:

#version 140

uniform vec2 viewport_size;

in vec2 vertex_position;

in vec2 in_texture_uv;
varying vec2 texture_uv;


void main(void)
{
    texture_uv = in_texture_uv;

    gl_Position = vec4(vertex_position / viewport_size, 0, 1);
}

和相应的片段着色器:

#version 140

uniform sampler2D texture_image;

out vec4 out_frag_color;

varying vec2 texture_uv;


void main(void)
{
    out_frag_color = texture(texture_image, texture_uv);
}
产生此输出的

(注意左下角的小蓝点): output_actual

奇怪的是,如果我更换

texture_uv = in_texture_uv;

texture_uv = vertex_position;

输出变为:output_vertpos(注意底部和左侧的边框)。

最后,如果我写:

texture_uv = vertex_position;
texture_uv = in_texture_uv;

输出正确:output_correct,这对我没有任何意义......

有人可以解释为什么会发生这种情况吗?谢谢你的时间!


相关代码段:

float[] positionVboData = new float[] {
    // X       Y     U       V
     0.0f,   0.0f,   0f,     0f,
    50.0f,   0.0f,   1f,     0f,
    50.0f,  25.0f,   1f,    .5f,
     0.0f,  50.0f,   0f,     1f,
};

// vertices
GL.GenBuffers(1, out verticesHandle);
GL.BindBuffer(BufferTarget.ArrayBuffer, verticesHandle);
GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);

// vertices: vertex_position
GL.EnableVertexAttribArray(0);
GL.BindAttribLocation(program, 0, "vertex_position");
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(float)*4, 0);

// vertices: texture_uv
GL.EnableVertexAttribArray(1);
GL.BindAttribLocation(program, 1, "in_texture_uv");
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, sizeof(float)*4, sizeof(float) * 2);

质地:

sample_texture

2 个答案:

答案 0 :(得分:3)

需要比我在评论中所拥有的空间更多的空间......


假设GL.Viewport实际上是glViewport的包装器,那么<​​/ p>

GL.Viewport(-Width, -Height, Width*2, Height*2)

没有意义,因为它会将3/4的视口带到窗口外面。 只需通过(0, 0, width, height)在整个窗口上绘画,0,0位于左下角。如果要将GL输出限制为窗口的子集,请相应地调整参数。

从技术上讲,glViewport为X和Y定义规范化设备坐标窗口坐标转换。了解OpenGL中的空间非常重要。花一些时间。

据说,顶点着色器输出也很奇怪。如果你想用你的多边形¹“填充你的窗口”,你不需要做那个奇怪的

vertex_position / viewport_size
在你的顶点着色器中进行

划分。

请记住,顶点着色器在剪辑坐标中输出,然后通过将X,Y,Z除以W,OpenGL将坐标置于标准化设备坐标中。标准化设备坐标在所有三个维度中,范围从-1到1。只有落在这个2x2x2立方体内的点才会被栅格化。

还记得我对glViewport所说的内容吗?

那么,诀窍是什么?只输出W = 1的坐标,以便它们已经有效地已经在NDC中。因此,如果您希望四边形跨越GL绘制的窗口的整个区域,只需构建类似

的内容
float coords[] = { -1, -1,
                    1, -1,
                    1,  1,
                   -1,  1 };

或者,根据您的原始代码,如果您想要一个梯形,请使用类似

的内容
float coords[] = { -1, -1,
                    1, -1,
                    1,  0,
                   -1,  1 };

然后将它们传递给顶点着色器:

in vec2 position;

void main() {
    gl_Position = vec4(position, 0, 1);
}

结果:

result


¹请将其设为GL_TRIANGLE_FAN,而不是GL_QUADGL_POLYGON

答案 1 :(得分:2)

您的主要问题很可能是您的BindAttribLocation()来电太晚了:

GL.BindAttribLocation(program, 0, "vertex_position");
...
GL.BindAttribLocation(program, 1, "in_texture_uv");

我们不知道您在何处以及如何构建着色器程序,但根据上下文我怀疑您已经构建了着色器程序。您需要在链接着色器程序之前进行BindAttribLocation()调用 。否则这些位置将不会生效。

如果您可以将着色器版本增加到330,则还可以使用layout (location=...)指令在着色器代码本身中指定顶点着色器输入的位置。