代码之家  ›  专栏  ›  技术社区  ›  JS4137

OpenGL-如何同时渲染无纹理的四边形和纹理四边形

  •  1
  • JS4137  · 技术社区  · 3 年前

    我正试图在OpenGL中渲染以下图像:

    Render target image

    (忽略白线,那不是图像的一部分)

    要渲染,我有一个文本的静止纹理作为PNG,如下所示:

    enter image description here

    现在,这是我的 Cargo.toml :

    [package]
    name = "render-clock"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    elara-gfx = { git = "https://github.com/elaraproject/elara-gfx" }
    

    这是我的顶点着色器代码:

    #version 100
    attribute highp vec2 position;
    attribute highp vec2 tex_coord;
    attribute lowp vec4 vertex_color;
    varying highp vec2 TexCoord;
    varying lowp vec4 VertexColor;
    
    void main() {
        VertexColor = vertex_color;
        TexCoord = tex_coord;
        gl_Position = vec4(position.x * 0.66, position.y, 0.0, 1.0);
    }
    

    还有我的碎片着色器:

    #version 100
    varying highp vec2 TexCoord;
    varying lowp vec4 VertexColor;
    uniform sampler2D uTexture;
    
    void main() {
        lowp vec4 col = texture2D(uTexture, TexCoord);
        gl_FragColor = vec4(VertexColor.rgb, col.a);
    }
    

    我的程序代码:

    use elara_gfx::{Buffer, BufferType, Program, Shader, VertexArray, PixelArray, Texture2D};
    use elara_gfx::{GLWindow, HandlerResult, WindowHandler};
    use std::error::Error;
    
    const VERT_SHADER: &str = include_str!("shaders/clock.vert"); // code given above
    const FRAG_SHADER: &str = include_str!("shaders/clock.frag"); // code given above
    const IMG_PATH: &str = "clock_text.png"; // image shown above
    
    struct Handler {
        vao: VertexArray,
        texture: Texture2D
    }
    impl Handler {
        fn new() -> Result<Handler, String> {
            
            let vertices: [f32; 42] = [
                 // positions  // colors        // texture coords
                 0.5,  0.5,    0.13, 0.15, 0.16,   1.0, 1.0, // top right
                 0.5, -0.5,    0.13, 0.15, 0.16,   1.0, 0.0, // bottom right
                -0.5,  0.5,    0.13, 0.15, 0.16,   0.0, 1.0, // top left
                 0.5, -0.5,    0.13, 0.15, 0.16,   1.0, 0.0, // bottom right
                -0.5, -0.5,    0.13, 0.15, 0.16,   0.0, 0.0, // bottom left
                -0.5,  0.5,    0.13, 0.15, 0.16,   0.0, 1.0,  // top left
            ];
    
            let texture = Texture2D::new()?;
            texture.bind();
    
            texture.parameter_2d(gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
            texture.parameter_2d(gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
    
            let mut img = PixelArray::load_png(IMG_PATH).unwrap();
            img.flipv();
            texture.set_image_2d(img);
            texture.generate_mipmap();
    
            let vao = VertexArray::new()?;
            vao.bind();
    
            let vbo = Buffer::new()?;
            vbo.bind(BufferType::Array);
            vbo.data::<f32>(BufferType::Array, &vertices, gl::STATIC_DRAW);
    
            let vertex_shader = Shader::new(&VERT_SHADER, gl::VERTEX_SHADER)?;
            let fragment_shader = Shader::new(&FRAG_SHADER, gl::FRAGMENT_SHADER)?;
            let program = Program::new(&[vertex_shader, fragment_shader])?;
            program.use_program();
    
            let pos_attrib = vao.get_attrib_location(&program, "position");
            let col_attrib = vao.get_attrib_location(&program, "vertex_color");
            let tex_coord_attrib = vao.get_attrib_location(&program, "tex_coord");
    
            vao.enable_vertex_attrib(pos_attrib as u32);
            vao.enable_vertex_attrib(col_attrib as u32);
            vao.enable_vertex_attrib(tex_coord_attrib as u32);
    
            vao.vertex_attrib_pointer::<f32>(pos_attrib as u32, 2, gl::FLOAT, false, 7, 0);
            vao.vertex_attrib_pointer::<f32>(col_attrib as u32, 3, gl::FLOAT, false, 7, 2);
            vao.vertex_attrib_pointer::<f32>(tex_coord_attrib as u32, 2, gl::FLOAT, false, 7, 5);
    
            Ok(Handler {vao, texture})
    
        }
    }
    
    impl WindowHandler for Handler {
        fn on_draw(&mut self) -> HandlerResult<()> {
            unsafe {
                gl::ClearColor(1.0, 1.0, 1.0, 1.0);
                gl::Clear(gl::COLOR_BUFFER_BIT);
                self.texture.bind();
                self.vao.bind();
                gl::DrawArrays(gl::TRIANGLES, 0, 6);
                self.vao.unbind();
                self.texture.unbind();
            }
            Ok(())
        }
    }
    
    fn main() -> Result<(), Box<dyn Error>> {
        let (app, window) = GLWindow::new_with_title("OpenGL clock")?;
        window.get_context()?;
        
        let render_handler = Handler::new()?;
    
        app.run_loop(window, render_handler);
        Ok(())
    }
    
    

    我的缺点是,要渲染我想要的图像,需要渲染两个四边形,其中一个是透明的文本,下面是一个填充了纯色的矩形四边形。文本四边形需要有纹理坐标,但矩形四边形不应该(也不需要)有纹理坐标。然而,试图用一个着色器程序/VAO/VBO同时渲染这两个着色器似乎是OpenGL无法做到的。我必须使用两个VAO/VBO/着色器程序将文本四边形层叠在矩形四边形上吗?有更好的方法吗?

    0 回复  |  直到 3 年前
        1
  •  1
  •   user7860670    3 年前

    使用2个或多个VAO/VBO/着色器程序没有任何问题。任何实际的应用程序都将使用数十个。但是,使用一次渲染这两个矩形也相当容易:您只需要添加更多的三角形,外部三角形的纹理坐标与纹理的透明部分(0,0)相对应。

    enter image description here

    推荐文章