opengl - 附加了分割着色器时,glDrawArrays失败

标签 opengl rust glsl shader tesselation

我正在使用OpenGL SuperBible第6版,并了解有关镶嵌分割着色器的信息。我从INVALID_OPERATION收到gl::DrawArrays错误。这是我的代码:

extern crate libc;
extern crate glutin;
extern crate gl;

use std::io::Read;

fn main() {
    unsafe {
        let win = glutin::WindowBuilder::new()
                  .with_gl_profile(glutin::GlProfile::Core)
                  .build_strict()
                  .unwrap();

        win.make_current().unwrap();
        gl::load_with(|s| win.get_proc_address(s));

        gl::DebugMessageCallback(
            std::mem::transmute(gl_debug_message),
            std::ptr::null_mut());

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

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

        gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);

        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]);

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

extern "system"
fn gl_debug_message(_source: u32, _type: u32, _id: u32, _sev: u32,
                    _len: i32, message: *const libc::c_char,
                    _param: *mut libc::c_void)
{
    unsafe {
        let s = cstring_to_string(message);
        panic!("OpenGL Debug message: {}", s);
    }
}

fn build_shader_program() -> u32 {
    let vert = load_and_compile_shader("a.vert", gl::VERTEX_SHADER);
    let tesc = load_and_compile_shader("a.tesc", gl::TESS_CONTROL_SHADER);
    let tese = load_and_compile_shader("a.tese", gl::TESS_EVALUATION_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, tesc);
        gl::AttachShader(program_id, tese);
        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
    }
}

unsafe fn cstring_to_string(mut cs: *const libc::c_char) -> String {
    let mut v : Vec<u8> = Vec::new();
    while *cs != 0 {
        v.push(*cs as u8);
        cs = cs.offset(1);
    }
    String::from_utf8(v).expect("c-string not utf8")
}

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
    }
}

运行此程序会产生一条调试消息:
OpenGL Debug message: glDrawArrays has generated an error (GL_INVALID_OPERATION)

我省略了着色器(顶点着色器,片段着色器,镶嵌控制着色器和镶嵌评估着色器),但是如果需要的话,我可以显示它们。它们是非常基本的,我只是不想弄乱这个问题。实际上,它们是sb6 git存储库中this example program中的对象。它们编译和链接没有错误。

如果删除两个镶嵌分割着色器对gl::AttachShader的调用,则不会出现错误,并且会绘制一个简单的线框三角形。使用镶嵌分割着色器时,应该绘制相同的三角形,只是将其切成较小的三角形。

我看了glDrawArrays on this site的文档,而我的代码似乎没有做任何可能导致INVALID_OPERATION错误的事情,即aafict。

最佳答案

分割着色器不渲染图元,而是渲染补丁。这些图元是在镶嵌期间创建的。参见Tessellation
您必须使用Primitive类型gl::PATCHES而不是gl::TRIANGLES。另外,您必须通过使用gl::PATCH VERTICES设置参数 gl::PatchParameteri来指定单个补丁的大小:gl::DrawArrays(gl::TRIANGLES, 0, 3);

gl::PatchParameteri(gl::PATCH_VERTICES, 3);
gl::DrawArrays(gl::PATCHES, 0, 3);

关于opengl - 附加了分割着色器时,glDrawArrays失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33598306/

相关文章:

opengl - 如何渲染带纹理的四边形以便淡化不同的角?

arrays - 我可以在 WebGL 的 GLSL 中将什么用作数组索引?

c++ - 使用 C++ 在 OpenGL 中加载纹理

rust - 实现所有权的可选消费的最佳实践是什么?

rust - 当我尝试提交表单Rocket Rust时给出错误422

opengl - texelFetch() 中的 samplerBuffer

c++ - 当顶点属性大小不匹配时会发生什么

c++ - OpenGL 中的非随机半球样​​本

OpenGL将光线距离与深度缓冲区进行比较

rust - 从变量创建具有长度的空数组