glVertexAttrib4fv 不会传递到位置 0 的着色器输入

glVertexAttrib4fv won't pass to shader input at location 0

我正在尝试同时学习 OpenGL 和 Rust。我正在使用 OpenGL Superbible 第六版,并卡在第 3 章中,该章介绍了函数 glVertexAttrib4fv 来偏移三角形的位置。当我用 C++ 时它工作得很好,但是当我试图将它转换为 Rust 时,三角形消失了。我已尝试将示例尽可能减少为以下代码(货物依赖项为 glutin = "*"gl = "*"):

main.rs

extern crate glutin;
extern crate gl;

use std::io::Read;

fn main() {
    unsafe {
        let win = glutin::Window::new().unwrap();
        win.make_current().unwrap();
        gl::load_with(|s| win.get_proc_address(s));

        let program = build_shader_program();
        gl::UseProgram(program);

        let mut vao = std::mem::uninitialized();
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        let red = [1.0, 0.0, 0.0, 1.0];

        let mut running = true;
        while running {
            for event in win.poll_events() {
                if let glutin::Event::Closed = event {
                    running = false;
                }
            }

            win.swap_buffers().unwrap();
            gl::ClearBufferfv(gl::COLOR, 0, &red[0]);

            let attrib = [0.5, 0.0, 0.0, 0.0];
            panic_if_error("before VertexAttrib4fv");
            gl::VertexAttrib4fv(0, &attrib[0]);
            panic_if_error("after VertexAttrib4fv");

            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }
    }
}

fn panic_if_error(message: &str) {
    unsafe {
        match gl::GetError() {
            gl::NO_ERROR => (),
            _ => panic!("{}", message),
        }
    }
}

fn load_file_as_cstring(path: &str) -> std::ffi::CString {
    let mut contents = Vec::new();
    let mut file = std::fs::File::open(path).unwrap();
    file.read_to_end(&mut contents).unwrap();
    std::ffi::CString::new(contents).unwrap()
}

fn load_and_compile_shader(path: &str, shader_type: u32) -> u32 {
    let contents = load_file_as_cstring(path);
    unsafe {
        let shader_id = gl::CreateShader(shader_type);

        let source_ptr = contents.as_ptr();
        gl::ShaderSource(shader_id, 1, &source_ptr, std::ptr::null());
        gl::CompileShader(shader_id);

        let mut result = std::mem::uninitialized();
        gl::GetShaderiv(shader_id, gl::COMPILE_STATUS, &mut result);
        assert_eq!(result, gl::TRUE as i32);

        shader_id
    }
}

fn build_shader_program() -> u32 {
    let vert = load_and_compile_shader("a.vert", gl::VERTEX_SHADER);
    let frag = load_and_compile_shader("a.frag", gl::FRAGMENT_SHADER);

    unsafe {
        let program_id = gl::CreateProgram();
        gl::AttachShader(program_id, vert);
        gl::AttachShader(program_id, frag);
        gl::LinkProgram(program_id);

        let mut result = std::mem::uninitialized();
        gl::GetProgramiv(program_id, gl::LINK_STATUS, &mut result);
        assert_eq!(result, gl::TRUE as i32);

        program_id
    }
}

a.frag

#version 430 core
out vec4 color;
void main() {
    color = vec4(1.0, 1.0, 1.0, 1.0);
}

a.vert

#version 430 core
layout (location = 0) in vec4 offset;
void main() {
    const vec4 vertices[3] =
        vec4[3](vec4( 0.25, -0.25, 0.5, 1.0),
                vec4(-0.25, -0.25, 0.5, 1.0),
                vec4( 0.25,  0.25, 0.5, 1.0));

    gl_Position = vertices[gl_VertexID];             // LINE 1
    // gl_Position = vertices[gl_VertexID] + offset; // LINE 2
}

此代码原样在红色中间生成一个白色三角形 window。

现在,我的期望是,当我在顶点着色器中注释掉 LINE 1 并取消注释 LINE 2 时,由于这段代码,三角形应该向右移动四分之一屏幕在 "main.rs":

let attrib = [0.5, 0.0, 0.0, 0.0];
panic_if_error("before VertexAttrib4fv");
gl::VertexAttrib4fv(0, &attrib[0]);
panic_if_error("after VertexAttrib4fv");

但是,三角形完全消失了。 gl::VertexAttrib4fv 前后的 panic_if_error 调用确保 gl::GetError returns gl::NO_ERROR.

问题:有人知道为什么会这样吗?

其他注意事项。当我在寻找这个问题的答案时,我遇到了 this question,用户遇到了类似的问题(除了在 C++ 中,我没有遇到问题)。无论如何,那里的评论之一顺便让我尝试将位置从 0 更改为 1,如下所示:

layout (location = 1) in vec4 offset;

用于顶点着色器,这用于调用 gl::VertexAttrib4fv:

gl::VertexAttrib4fv(1, &attrib[0]);

好吧,那行得通,但我不知道为什么,并且仍然想知道在那里使用位置 0 的问题是什么(因为这是书上显示的内容,并且它在 C++ 中运行良好)。

您需要确保您拥有核心配置文件上下文。如果您不指定它,您可能正在创建一个兼容性配置文件上下文。在兼容性配置文件中,顶点属性 0 具有特殊含义。来自 OpenGL 3.2 兼容性配置文件规范:

Setting generic vertex attribute zero specifies a vertex; the four vertex coordinates are taken from the values of attribute zero. A Vertex2, Vertex3, or Vertex4 command is completely equivalent to the corresponding VertexAttrib* command with an index of zero. Setting any other generic vertex attribute updates the current values of the attribute. There are no current values for vertex attribute zero.

换句话说,顶点属性0是兼容性配置文件中固定函数顶点位置的别名。

以上不适用于核心配置文件。顶点属性 0 没有特殊含义,可以像任何其他顶点属性一样使用。

根据您已经找到的内容,您需要使用带参数 Corewith_gl_profile method 来指定在创建 window 时要使用核心配置文件。