OpenGL draws a black triangle instead of coloured vertices

50 views Asked by At

I try to implement a trivial graphical engine for my app based on OpenGL (glutin + glow). Below is my draw_object() function:

fn draw_object(&mut self, object: &Object) {
    unsafe {
        let mesh_ref = object.mesh();
        let material_ref = object.material();
        let mesh = mesh_ref.borrow();
        let material = material_ref.borrow();
        let gl_mesh = mesh.as_ref().as_any().downcast_ref::<GlMesh>().unwrap();
        let gl_material = material.as_ref().as_any().downcast_ref::<GlMaterial>().unwrap();
        self.gl.use_program(Some(gl_material.program));
        self.gl.bind_buffer(glow::ARRAY_BUFFER, gl_mesh.vbo);
        match &gl_material.attrs {
            MaterialAttributes::VertexColors => {
                if gl_mesh.has_colors() {
                    self.gl.bind_vertex_array(gl_mesh.color_vao);
                }
            },
            MaterialAttributes::Color(c) =>  {
                let color_location = self.gl.get_uniform_location(gl_material.program, "solidColor");
                self.gl.uniform_4_f32(color_location.as_ref(), c.r, c.g, c.b, c.a);
            },
            MaterialAttributes::Texture(t) => {
                if gl_mesh.has_uvs {
                    let t = t.as_ref().as_ref().as_any().downcast_ref::<GlTexture>().unwrap();
                    self.gl.bind_texture(glow::TEXTURE_2D,Some(t.texture));
                    self.gl.bind_vertex_array(gl_mesh.uv_vao);
                }
            },
        }
        self.gl.bind_vertex_array(gl_mesh.mesh_vao);
        self.gl.draw_arrays(glow::TRIANGLES, 0, gl_mesh.vertex_count().try_into().unwrap());
    }
}

Into this function I pass three objects:

fn main() {
    let app = App::builder()
        .title(String::from(APP_NAME))
        .build();
    let event_loop = GlEventLoop::new();
    let window = GlWindow::new(&event_loop, app.title.to_owned(), 800, 600).unwrap();
    let renderer = GlRenderer::new(&window).unwrap();

    let mut id_gen = IdGen::new();
    let fabric = GlFabric::new(&renderer);

    let solid_attrs = MaterialAttributes::Color(ColorF::rgb(1.0, 0.4, 0.0));
    let solid_material = create_material(app.assets(), &fabric, id_gen.next(), "SolidColor".to_owned(), solid_attrs);

    let texture: Rc<Box<dyn Texture>> = Rc::new(Box::new(fabric.load_asset(id_gen.next(), app.assets(), "textures/wood.jpg").unwrap()));
    let texture_attrs = MaterialAttributes::Texture(texture.clone());
    let texture_material = create_material(app.assets(), &fabric, id_gen.next(), "Texture".to_owned(), texture_attrs);

    let colorful_attrs = MaterialAttributes::VertexColors;
    let colorful_material = create_material(app.assets(), &fabric, id_gen.next(), "ColoredVertex".to_owned(), colorful_attrs);

    let vertices = [
            Vertex3::new(-0.7, -0.7, 0.0),
            Vertex3::new(0.7, -0.7, 0.0),
            Vertex3::new(0.7, 0.7, 0.0),

            Vertex3::new(-0.7, -0.7, 0.0),
            Vertex3::new(0.7, 0.7, 0.0),
            Vertex3::new(-0.7, 0.7, 0.0),
        ];
    let mut box_object = create_object(&fabric, &mut id_gen, "Box".to_owned(), &vertices, None, None, solid_material.clone());

    let vertices = [
            Vertex3::new(-0.5, -0.5, 0.0),
            Vertex3::new(0.5, 0.5, 0.0),
            Vertex3::new(-0.5, 0.5, 0.0),
        ];
    let uvs = [
            Vertex2::new(0.0, 0.0),
            Vertex2::new(1.0, 1.0),
            Vertex2::new(0.0, 1.0),
        ];
    let mut top_left = create_object(&fabric, &mut id_gen, "TopLeft".to_owned(), &vertices, None, Some(&uvs), texture_material.clone()); 

    let vertices = [
            Vertex3::new(-0.5, -0.5, 0.0),
            Vertex3::new(0.5, -0.5, 0.0),
            Vertex3::new(0.5, 0.5, 0.0),
        ];
    let colors = [
            ColorF::rgb(1.0, 0.0, 0.0),
            ColorF::rgb(0.0, 1.0, 0.0),
            ColorF::rgb(0.0, 0.0, 1.0),
        ];
    let mut bottom_right = create_object(&fabric, &mut id_gen, "BottomRight".to_owned(), &vertices, Some(&colors), None, colorful_material.clone()); 

    let background_color = ColorF::rgb(1.0, 1.0, 1.0);

    event_loop.run(move |event| {
        match event {
            Event::START => {
                box_object.on_init();
                top_left.on_init();
                bottom_right.on_init();
            },
            Event::UDPATE => {
                let mut frame = renderer.draw();
                frame.clear_color(&background_color);
                frame.draw_object(&box_object);
                frame.draw_object(&top_left);
                frame.draw_object(&bottom_right);
                frame.finish();
                window.raw_window.request_redraw();
                renderer.swap_buffers();
            },
            Event::EXIT => {
                bottom_right.on_delete();
                top_left.on_delete();
                box_object.on_delete();
            },
        }
    });
}
  1. The first object is a box (two triangles) with solid color.

  2. The second one is a textured triangle (it fails too but I will resolve problems one by one).

  3. Finally, the third one is a coloured vertex triangle. However, when I launch my app, it outputs a black triangle:

    Screenshot

And I can't get why... Here is my coloured vertex shaders:

Vertex shader:

#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;

out vec4 ourColor;

void main() {
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor;
}

Fragment shader:

#version 330 core

out vec4 FragColor;  
in vec4 ourColor;

void main() {
    FragColor = ourColor;
}

And Mesh implementation:

#[derive(Debug)]
pub struct GlMesh {
    gl: Rc<Context>,
    pub id: Id,
    pub name: String,
    pub draw_mode: u32,
    pub visible: bool,
    pub has_colors: bool,
    pub has_uvs: bool,
    pub data: Vec<f32>,
    pub vbo: Option<NativeBuffer>,
    pub mesh_vao: Option<NativeVertexArray>,
    pub color_vao: Option<NativeVertexArray>,
    pub uv_vao: Option<NativeVertexArray>,
}

impl GlMesh {

    pub fn new(gl: Rc<Context>, id: Id, name: String, vertices: &[Vertex3], colors: Option<&[ColorF]>, uvs: Option<&[Vertex2]>) -> Result<Self, GlMeshError> {
        let draw_mode = glow::STATIC_DRAW;
        let data = Self::create_data(vertices, colors, uvs)?;

        Ok(Self {
            gl,
            id,
            name,
            draw_mode,
            visible: true,
            has_colors: colors.is_some(),
            has_uvs: uvs.is_some(),
            data,
            vbo: None,
            mesh_vao: None,
            color_vao: None, 
            uv_vao: None,
        })
    }

    fn create_data(vertices: &[Vertex3], colors: Option<&[ColorF]>, uvs: Option<&[Vertex2]>) -> Result<Vec<f32>, GlMeshError> {
        let colors_len: usize;
        if colors.is_some() {
            colors_len = colors.unwrap().len();
            if vertices.len() != colors_len {
                return Err(GlMeshError::InvalidData("The number of colors and vertices must be same".to_owned()));
            }
        } else {
            colors_len = 0;
        }

        let uvs_len: usize;
        if uvs.is_some() {
            uvs_len = uvs.unwrap().len();
            if vertices.len() != uvs.unwrap().len() {
                return Err(GlMeshError::InvalidData("The number of UV vertices and mesh vertices must be same".to_owned()));
            }
        } else {
            uvs_len = 0;
        }

        let data_len = 3 * vertices.len() + 4 * colors_len + 2 * uvs_len;
        let mut data = Vec::with_capacity(data_len);
        for (i, v) in vertices.iter().enumerate() {
            data.extend(v.data);
            if colors.is_some() {
                let color = colors.unwrap().get(i).unwrap();
                data.push(color.r);
                data.push(color.g);
                data.push(color.b);
                data.push(color.a);
            }
            if uvs.is_some() {
                let uv_vertex = uvs.unwrap().get(i).unwrap();
                data.extend(uv_vertex.data);
            }
        }
        Ok(data)
    }

    fn rebuild_buffers(&mut self) -> Result<(), GlMeshError> {
        let vbo = Self::create_vbo(&self.gl)?;
        Self::set_buffer_data(&self.gl, vbo, &self.data, self.draw_mode);
        self.vbo = Some(vbo);

        let mut stride = 12;
        if self.has_colors {
            stride += 16;
        }
        if self.has_uvs {
            stride += 8;
        }
        let mut offset = 0;

        self.mesh_vao = Some(Self::create_vao(&self.gl, 0, 3, false, stride, offset)?);
        offset += 12;

        if self.has_colors {
            self.color_vao = Some(Self::create_vao(&self.gl, 1, 4, false, stride, offset)?);
            offset += 16;
        }
        if self.has_uvs {
            self.uv_vao = Some(Self::create_vao(&self.gl, 2, 2, false, stride, offset)?);
        }
        Ok(())
    }

    fn create_vbo(gl: &Context) -> Result<NativeBuffer, GlMeshError> {
        unsafe {
            match gl.create_buffer() {
                Ok(vbo) => Ok(vbo),
                Err(msg) => Err(GlMeshError::InternalGlError(msg)),
            }
        }
    }

    fn set_buffer_data(gl: &Context, vbo: NativeBuffer, data: &Vec<f32>, draw_mode: u32) {
        unsafe {
            let data_u8: &[u8] = core::slice::from_raw_parts(
                data.as_ptr() as *const u8,
                data.len() * core::mem::size_of::<f32>(),
            );
            gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
            gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, data_u8, draw_mode);
        }
    }

    fn delete_vbo(gl: &Context, vbo: NativeBuffer) {
        unsafe {
            gl.delete_buffer(vbo);
        }
    }

    fn create_vao(gl: &Context, index: u32, size: i32, normalized: bool, stride: i32, offset: i32) -> Result<NativeVertexArray, GlMeshError> {
        unsafe { 
            match gl.create_vertex_array() {
                Ok(vao) => {
                    gl.bind_vertex_array(Some(vao));
                    gl.vertex_attrib_pointer_f32(index, size, glow::FLOAT, normalized, stride, offset);
                    gl.enable_vertex_attrib_array(index);
                    Ok(vao)
                },
                Err(msg) => Err(GlMeshError::InternalGlError(msg)),
            }
        }
    }

    fn delete_vao(gl: &Context, vao: NativeVertexArray) {
        unsafe {
            gl.delete_vertex_array(vao);
        }
    }
}

impl LifeCycle for GlMesh {

    fn on_init(&mut self) {
        self.rebuild_buffers().unwrap();
    }

    fn on_delete(&mut self) {
        if self.vbo.is_some() {
            Self::delete_vbo(&self.gl, self.vbo.unwrap());
        }
        if self.mesh_vao.is_some() {
            Self::delete_vao(&self.gl, self.mesh_vao.unwrap());
        }
        if self.color_vao.is_some() {
            Self::delete_vao(&self.gl, self.color_vao.unwrap());
        }
        if self.uv_vao.is_some() {
            Self::delete_vao(&self.gl, self.uv_vao.unwrap());
        }
    }
}

I've checked VBO and VAOs in debugger (although my debugger can't work with Rust well) and I didn't notice any errors.

Where can the problem be?

0

There are 0 answers