OpenGL,为什么此代码不能按我的预期工作?

问题描述:

你好,对于问这样一个具体问题感到抱歉。OpenGL,为什么此代码不能按我的预期工作?

我有以下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

+1

我不认为这应该是问题,但你应该避免混合'变化'/'属性'(_deprecated_)和'in' /'出' –

+0

好吧,我只是试图用“出“在顶点着色器中,并在片段着色器中使用”in“。 没有变化。 –

+1

你想用'vertex_position/viewport_size'完成什么?这不是转换为窗口空间的正确方法。 –

你的主要问题是最有可能是您的BindAttribLocation()通话来得晚:

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

我们没有看到你在哪里以及如何构建着色器程序,但是基于上下文,我怀疑你已经在此时构建了着色器程序。在连接着色器程序之前,您需要调用BindAttribLocation()调用。否则这些位置将不会生效。

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

+0

非常感谢,你解决了一个让我的头痛一整天的问题! –

+0

请注意,即使着色器版本为“150”,某些平台(即OSX)也具有'GL_ARB_explicit_attrib_location'扩展名,以便您可以使用'layout(location = ...) –

需要一个比我在评论更多的空间......


假设GL.Viewport实际上是glViewport的包装,然后

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

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

技术上,glViewport定义标准化设备坐标窗口坐标转化为X和Y,了解OpenGL的空间是很重要的。花点时间吧。

刚才说过,顶点着色器的输出也很奇怪。如果你想与你的polygon¹以“填补你的窗口”,你不需要做怪

vertex_position/viewport_size 

师在你的顶点着色器。

请记住,在剪辑中的顶点着色器输出坐标,在这之后的OpenGL带来规格化设备坐标的通过将X坐标,Y,Z由W.归一化装置在所有三个坐标范围从-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_QUAD也不是GL_POLYGON

+0

'假设GL.Viewport实际上是glViewport的包装器是的,我使用托管代码,但是包装是直接的。 我正在使用这些数字,因为我来自喜欢整数而不是浮动的软件图形界面,而且我实际上只希望该图像只有50px宽。 我会将这些计算委托给GPU,并避免无效的'uniform vec2 viewport_size;'然后。 感谢您的好解释! –