OpenGL - как рендерить как нетекстурированные, так и текстурированные квадраты одновременно

Я пытаюсь отобразить следующее изображение в OpenGL:

(не обращайте внимания на белую линию, которая не является частью изображения)

Для рендеринга у меня есть неподвижная текстура текста в формате PNG, показанная ниже:

На данный момент это мой 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/шейдеров для наложения текстового четырехугольника на прямоугольный четырехугольник? Есть ли способ лучше?

Будет ли вариант иметь текстовую текстуру в виде двоичного изображения, где текст = 1 и фон = 0? Затем фрагментный шейдер мог выбирать между двумя цветами (текст или фон).

Yun 24.06.2023 12:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нет ничего плохого в использовании двух или более программ VAO/VBO/shader. Любое реалистичное приложение будет использовать десятки из них. Но также довольно легко визуализировать эти два прямоугольника с помощью одного прохода: вам просто нужно добавить больше треугольников с внешними треугольниками, имеющими текстурные координаты, соответствующие прозрачной части текстуры (0, 0).

Поскольку текст представляет собой текстуру с альфа-каналом, после включения альфа-смешивания для текстовой текстуры не будет ли отображаться только текст, а прямоугольник фона непосредственно за текстом будет прозрачным, а не сплошным цветом, который я хотел?

JS4137 24.06.2023 15:06

@ JS4137 Этот подход подразумевает, что шейдер будет смешивать сплошной цвет фона с текстурой.

user7860670 24.06.2023 15:38

Другие вопросы по теме