Opengl为啥这个着色器不起作用?

Posted

技术标签:

【中文标题】Opengl为啥这个着色器不起作用?【英文标题】:Opengl why doesn't this Shader Work?Opengl为什么这个着色器不起作用? 【发布时间】:2017-08-16 19:26:12 【问题描述】:

我试图创建一个类来绘制一个正方形,这个类将被实例化一次,每次我想绘制一个正方形时,我都会... Square::draw(float posx, float posy ,float大小,浮动大小)。 我这样做的方式是在着色器上安装一个 unifor vec4,我将在其中传输 pos 和 size。 在 vbo 上:GLint _vertID[4] = 0,1,2,3 一个标识,这样我就可以知道着色器正在处理哪个顶点,这样我就可以放置正确的位置

问题是它没有画正方形,而是随机画一些三角形。(有问题)。 我想知道是我的逻辑错了,还是实现错了。

代码如下:

void Square::initVertex()
    GLint _vertID[4] = 0,1,2,3;
    GLfloat _uvs[8] = 0,0,1,0,1,1,0,1;
    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(2, vbo);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[0]);
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(GLint), _vertID, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 1, GL_INT, false, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[1]);
    glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _uvs, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(1);

和顶点着色器: posSh 是 vec4,每次我想画一个正方形时我都会在其中传递位置,而 vertID 是让我知道正在处理哪个 vert 的 vbo

#version 150
in int vertID;
in vec2 uvs;
in vec4 posSh;
out vec2 ex_uvs;

void main(void)
    vec2 pos;

    if(vertID == 0)
        pos = vec2(posSh.x, posSh.y);
    else if(vertID == 1)
        pos = vec2(posSh.x + posSh.z, posSh.y);
    else if(vertID == 2)
        pos = vec2(posSh.x + posSh.z, posSh.y + posSh.w);
    else if(vertID == 3)
        pos = vec2(posSh.x, posSh.y + posSh.w);
    

    gl_Position = vec4(pos.x, pos.y, 1,1);
    ex_uvs = uvs;

【问题讨论】:

看看你的渲染方法会很有帮助,但从外观上看你永远不会绑定顶点数据。 您知道glDrawElements 函数可以像在着色器中那样执行索引绘制吗?此外,您的代码没有错误处理,您应该在每个其他 gl 调用之后调用 glGetError 并检查返回的值。 #version 150 支持输出变量吗? 整数属性不能用glVertexAttribPointer设置。看看this question 或this answer。但是,对于您的用例来说,这有点实际意义,因为 gl_VertexID 确实存在。 【参考方案1】:

我宁愿删除这些 _vertID 索引。 在我看来,您似乎正试图通过使用单个 vec4 来渲染 4 个顶点而不是 4x vec2(或 vec3,如果需要)来节省内存。 vertIDuvsposSh 都是属性,这意味着它们必须具有相同的元素数。例如:

position: 1[x, y, z], 2[x, y, z], 3[x, y, z]
uvCoords: 1[x, y]   , 2[x, y]   , 3[x, y]

如果我是对的,posSh 的情况并非如此。 这是我在您的设置和着色器代码中看到的:

vertID: 1[n]          , 2[n]      , 3[n]    , 4[n]
uvs:    1[x, y]       , 2[x, y]   , 3[x, y] , 4[x, y]
posSh:  1[x, y, z, w] , ???       , ???     , ???

所以,如果是这种情况,我们现在就解决这个问题。

vbo[0]GL_ARRAY_BUFFER 更改为 GL_ELEMENT_ARRAY_BUFFER。元素数组缓冲区包含您绑定的数组缓冲区的每个元素的索引(查看上面的代码部分,数字是您可以指定的索引)。 (请记住,vbo[0] 将保持绑定,直到绑定另一个 GL_ELEMENT_ARRAY_BUFFER) 从 GL_ELEMENT_ARRAY_BUFFER 中删除 glVertexAttribPointer 和 glEnableVertexAttribArray,因为它只需要绑定并且已经绑定。 在您的vbo[] 数组中创建第三个 vbo,它将包含您的四边形的所有位置。这将替换posSh。您必须像 _uvs 的数组缓冲区一样设置它(这将是一个 vec2 位置) 在第三个 vbo 上使用 glVertexAttribPointer 和 glEnableVertexAttribArray。

你就是这样做的。 试试这个代码(我还没有测试过):

void Square::initVertex()
    GLint _vertID[4] = 0,1,2,3;
    GLfloat _uvs[8] = 0,0,1,0,1,1,0,1;
    GLfloat _pos[8] = 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f ;
    glGenVertexArrays(1, vao); 
    glBindVertexArray(vao[0]);

    glGenBuffers(3, vbo); // the first index is an Element Array Buffer!

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo[0]);
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLint), _vertID, GL_STATIC_DRAW);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[1]);
    glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _pos, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer( GL_ARRAY_BUFFER, vbo[2]);
    glBufferData( GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), _pos, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(1);

着色器代码:

#version 150
in vec2 uvs;
in vec2 pos;
out vec2 ex_uvs;

void main(void)
    gl_Position = vec4(pos.x, pos.y, 1,1);
    ex_uvs = uvs;

你的绘图代码:

 glDrawElements(
     GL_QUADS,      // mode
     4,    // count
     GL_UNSIGNED_INT,   // type
     (void*)0           // element array buffer offset
 );

希望对你有所帮助。试试代码,不知道有没有错别字,我用notepad++写的。

这里是如何正确渲染 VBO 的高级教程:Tutorial 9 : VBO Indexing

【讨论】:

以上是关于Opengl为啥这个着色器不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

Phong 着色器不起作用

Flutter:为啥这个流构建器不起作用?

为啥这个 CSS 选择器不起作用:a:hover ~ span?

为啥 AVPlayer 边界时间观察器不起作用?

着色器在 2d OpenGL 中不起作用

为啥我的直系后代选择器不起作用?