为什么顶点位置取自颜色缓冲区而不是位置缓冲区?

时间:2014-11-17 10:40:20

标签: opengl rust

今天我想我修改了一个如何使用gl-rs(Rust的OpenGL绑定)添加颜色数组并绘制一些点而不是三角形的小例子。琐碎,我以为......

然而,我的COLOUR_DATA似乎以某种方式用于顶点位置。

鉴于

static VERTEX_DATA: [GLfloat, ..6] = [
  0.2, 0.0,
  0.0, 0.2,
  0.0, 0.0];

static COLOUR_DATA: [GLfloat, ..12] = [
  0.0, 0.5, 0.0, 1.0,
  0.5, 0.0, 0.0, 1.0,
  0.0, 0.0, 5.0, 1.0];

很明显,下面的屏幕截图中的点是COLOUR_DATA的前6个值,而不是VERTEX_DATA。问题'当我注释掉与我的颜色缓冲区对象相关的BindBufferBufferData调用时,它会消失。

源代码位于屏幕截图下方,当然删除BindBuffer / BufferData也意味着删除EnableVertexAttribArrayVertexAttribPointer类以进行编译,但它们没有对现有情况的影响)。

为什么会发生这种情况,我该如何避免呢?我只是错过了一些明显的东西吗?或者我在这里处理更深层次的事情(例如gl-rs中的错误)?

output

#![feature(globs)]

extern crate gl;
extern crate glfw;
extern crate native;

use gl::types::*;
use glfw::Context;

use std::mem;
use std::ptr;
use std::str;

// Vertex data
static VERTEX_DATA: [GLfloat, ..6] = [
  0.2,  0.0,
  0.0,  0.2,
  0.0,  0.0];

static COLOUR_DATA: [GLfloat, ..12] = [
  0.0,  0.5, 0.0, 1.0,
  0.5,  0.0, 0.0, 1.0,
  0.0,  0.0, 5.0, 1.0];

// Shader sources
static VS_SRC: &'static str =
"#version 150\n\
in vec2 position;\n\
in vec4 vertexColor;\n\
out vec4 fragmentColor;\n\
void main() {\n\
gl_Position = vec4(position, 0.0, 1.0);\n\
fragmentColor = vertexColor;\n\
}";

static FS_SRC: &'static str =
"#version 150\n\
in vec4 fragmentColor;\n\
out vec4 out_color;\n\
void main() {\n\
out_color = vec4(1.0, 0.0, 0.0, 1.0);\n\
}";
//out_color = fragmentColor;\n\
// the above line removed from shader string for debugging this

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader;
  unsafe {
    shader = gl::CreateShader(ty);

    // Attempt to compile the shader
    src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }
  }
  shader
}


fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
  unsafe {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }
    program
  }
}

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
  native::start(argc, argv, main)
}

fn main() {
  let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  // Choose a GL profile that is compatible with OS X 10.7+
  glfw.window_hint(glfw::ContextVersion(3, 2));
  glfw.window_hint(glfw::OpenglForwardCompat(true));
  glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

  let (window, _) = glfw.create_window(800, 600, "OpenGL", glfw::Windowed)
    .expect("Failed to create GLFW window.");

  // It is essential to make the context current before calling `gl::load_with`.
  window.make_current();

  // Load the OpenGL function pointers
  gl::load_with(|s| window.get_proc_address(s));

  // Create GLSL shaders
  let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
  let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
  let program = link_program(vs, fs);
  let mut vao = 0;
  let mut vbo = 0;

  let mut cbo = 0;

  unsafe {
    // Create Vertex Array Object
    gl::GenVertexArrays(1, &mut vao);
    gl::BindVertexArray(vao);

    // Set up vertex buffer object
    gl::GenBuffers(1, &mut vbo);
    gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
    gl::BufferData(gl::ARRAY_BUFFER,
                   (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, 
                   mem::transmute(&VERTEX_DATA[0]),
                   gl::STATIC_DRAW);

    // Set up colour buffer object
    gl::GenBuffers(1, &mut cbo);
    gl::BindBuffer(gl::ARRAY_BUFFER, cbo);
    gl::BufferData(gl::ARRAY_BUFFER,
                   (COLOUR_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, 
                   mem::transmute(&COLOUR_DATA[0]),
                   gl::STATIC_DRAW);

    gl::UseProgram(program);
    // Bind fragment shader
    "out_color".with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));

    // Configure vertex buffer
    let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
    println!("{}", pos_attr);
    gl::EnableVertexAttribArray(pos_attr as GLuint);
    gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                            gl::FALSE as GLboolean, 0, ptr::null());


    gl::PointSize(10.0);
    // Configure colour buffer
    let col_attr = "vertexColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
    println!("{}", col_attr);
    gl::EnableVertexAttribArray(col_attr as GLuint);
    gl::VertexAttribPointer(col_attr as GLuint, 4, gl::FLOAT,
                            gl::FALSE as GLboolean, 0, ptr::null());
  }

  while !window.should_close() {
    glfw.poll_events();
    unsafe {
      gl::ClearColor(0.3, 0.3, 0.3, 1.0);
      gl::Clear(gl::COLOR_BUFFER_BIT);
      gl::DrawArrays(gl::POINTS, 0, 3);
    }
    window.swap_buffers();
  }
  unsafe {
    gl::DeleteProgram(program);
    gl::DeleteShader(fs);
    gl::DeleteShader(vs);
    gl::DeleteBuffers(1, &cbo);
    gl::DeleteBuffers(1, &vbo);
    gl::DeleteVertexArrays(1, &vao);
  }
}

注意:代码取决于gl-rsglfw-rs。每晚运行Windows 8.1和Rust 0.13 40fb87d40)。 gl-rs在问题跟踪器中似乎没有这样的东西。

1 个答案:

答案 0 :(得分:6)

因为在调用BindBuffer之前需要绑定正确的缓冲区(VertexAttribPointer)。

// Configure vertex buffer
let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
println!("{}", pos_attr);
gl::EnableVertexAttribArray(pos_attr as GLuint);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                        gl::FALSE as GLboolean, 0, ptr::null());


gl::PointSize(10.0);
// Configure colour buffer
let col_attr = "vertexColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
println!("{}", col_attr);
gl::EnableVertexAttribArray(col_attr as GLuint);
gl::BindBuffer(gl::ARRAY_BUFFER, cbo);
gl::VertexAttribPointer(col_attr as GLuint, 4, gl::FLOAT,
                        gl::FALSE as GLboolean, 0, ptr::null());

没有缓冲区绑定,VertexAttribPointer的最后一个参数是指向系统内存的指针。对于顶点缓冲区对象,它将成为当前绑定缓冲区的偏移量。在您的情况下,颜色缓冲区是在初始化期间最后绑定的颜色缓冲区,并且用于两个顶点属性。