opengl 执行glDrawElements时需要具有glVertexAttribDivisor

jjjwad0x  于 2023-01-25  发布在  其他
关注(0)|答案(1)|浏览(180)

我在我的小项目,这里是一些代码:

四元组定义:

#Geometry definitions   XYZ             UV
quad_vertices = [-0.5, -0.5, 0.0,   0.0, 0.0,
                  0.5, -0.5, 0.0,   1.0, 0.0,
                  0.5,  0.5, 0.0,   1.0, 1.0,
                 -0.5,  0.5, 0.0,   0.0, 1.0]

quad_indices = [0, 1, 2, 2, 3, 0]

quad_vertices = np.array(quad_vertices, dtype=np.float32)
quad_indices = np.array(quad_indices, dtype=np.uint32)

着色器定义:

vertex_src2 = """
# version 330 core

layout(location = 0) in vec3 a_position;
layout(location = 1) in vec2 a_texture_uv;
layout(location = 2) in vec4 a_color;
layout(location = 3) in vec3 translation;
layout(location = 4) in vec3 scale;
layout(location = 5) in vec2 a_tex_index;
layout(location = 6) in vec4 a_effect_params; //currently not used

uniform mat4 projection;
uniform mat4 view;

out vec4 v_color;
out vec2 v_texture;
out float z_texture0;
out float z_texture1;
out vec4 effect_params;

mat4 BuildTranslation(vec3 delta)
{
    return mat4(1.0, 0.0, 0.0, 0.0,
                0.0, 1.0, 0.0, 0.0,
                0.0, 0.0, 1.0, 0.0,
                delta, 1.0);
}

mat4 BuildRotation(vec3 delta){
    return mat4(cos(radians(delta[2])), -sin(radians(delta[2])),  0.0, 0.0,
                sin(radians(delta[2])),  cos(radians(delta[2])),  0.0, 0.0,
                0.0,         0.0,         1.0, 0.0,
                0.0,         0.0,         0.0, 1.0);
}

mat4 BuildScale(vec3 delta){
    return mat4(delta[0], 0.0, 0.0, 0.0,
                0.0, delta[1], 0.0, 0.0,
                0.0, 0.0, delta[2], 0.0,
                0.0, 0.0, 0.0, 1.0);
}

void main()
{
    mat4 model = BuildTranslation(translation) * BuildScale(scale);
    gl_Position = projection * view * model * vec4(a_position, 1.0f);
    v_texture = a_texture_uv;
    v_color = a_color;
    z_texture0 = a_tex_index.x;
    z_texture1 = a_tex_index.y;
    effect_params = vec4(0);
}
"""

#Fragment shader definition
fragment_src2 = """
# version 330 core

in vec4 v_color;
in vec2 v_texture;
in float z_texture0;
in float z_texture1;
in vec4 effect_params;

out vec4 out_color;

uniform int switcher;
uniform sampler2DArray s_texture;

void main()
{
    if (switcher == 0){
        float effectNo = effect_params[3];
        vec4 texel = texture(s_texture, vec3(v_texture, z_texture0));
       
        texel.a = texel.a * v_color.a;
        if (texel.a < 0.05){
            discard;
        }
        out_color = texel;
    }
}
"""

以下是绑定:

def bind_buffer_data(self):
        glBindVertexArray(self.VAO)
        glBindBuffer(GL_ARRAY_BUFFER, self.VBO[0])
        glBufferData(GL_ARRAY_BUFFER, quad_vertices.nbytes, quad_vertices, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.EBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, quad_indices.nbytes, quad_indices, GL_STATIC_DRAW)

        for i in range(6):
            glEnableVertexAttribArray(i)
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(0))
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(12))
        glBindBuffer(GL_ARRAY_BUFFER, self.VBO[1]) // This is bound for later loading of buffer data during draw_object()

最终装订和绘图:

def draw_object(self, depth, alpha=1.0, switcher=0):
        self.color[3] = alpha
        buffer_data = np.array(
            [self.color[0], self.color[1], self.color[2], self.color[3], 
             self.pos_x, self.pos_y, depth, 
             self.scale[0], self.scale[1], self.scale[2], 
             0, 0], 
             dtype=np.float32)

        glBindVertexArray(self.VAO)
        glBindTexture(GL_TEXTURE_2D_ARRAY, self.get_current_texture())

        glBufferData(GL_ARRAY_BUFFER, buffer_data.nbytes, buffer_data, GL_DYNAMIC_DRAW)
        
        glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 48, ctypes.c_void_p(0))
        glVertexAttribDivisor(2, 1) #Cannot delete that?
        
        glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 48, ctypes.c_void_p(16))
        glVertexAttribDivisor(3, 1) #Cannot delete that?
        
        glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 48, ctypes.c_void_p(28))
        glVertexAttribDivisor(4, 1) #Cannot delete that?
        
        glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, 48, ctypes.c_void_p(40))
        glVertexAttribDivisor(5, 1) #Cannot delete that?

        glUniform1i(shader.switcher_loc2, switcher)
        glDrawElements(GL_TRIANGLES, len(quad_indices), GL_UNSIGNED_INT, None)

我很困惑,因为上面的代码工作正常,一切都渲染正常。然而,一旦我删除glVertexAttribDivisor行,它没有渲染任何东西。你知道为什么会这样吗?
请注意,我使用的是glDrawElements,而不是glDrawElementsInstanced。我以为glDrawElements甚至不查看glVertexAttribDivisor,因为我绘制的是单个图元。这是否与我将2个不同的VBO绑定到GL_ARRAY_BUFFER目标有关?但是......只有当适当的VBO绑定到 VAO 以及glBufferData时,我才调用glVertexAttribPointer函数。所以我不明白请你帮我弄明白。

atmip9wb

atmip9wb1#

所以我的误解是我以为glDrawElements会为我绘制一个给定图元的单个示例(在我的例子中是四边形),使用的属性与从buffer为每个单独的顶点提供的属性相同。
如果没有glVertexAttribDivisor,只有4个顶点中的第一个会得到正确的属性,其余的顶点会得到0,0,0,0,0 ....所以如果我在这种情况下将缓冲区大小增加一倍,它们中的一半会得到数据,有些会呈现垃圾。
我从中得到的教训是,**如果没有指定vertexAttribDivisor,属性将作为每个顶点的步幅从缓冲区读取,**而不是每个整个示例。

相关问题