如何在 opengl 中使用白色作为纹理?

问题描述 投票:0回答:0

有这个简单的代码:

#include <iostream>
#include <array>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <test/main/shader.hpp>
#include <test/main/texture.hpp>

struct QuadVertex {
    glm::vec3 position;
    glm::vec4 color;
    glm::vec2 texture_coordinates;
    float texture_index;
};

struct Data {
    static const int max_quads = 10000;
    static const int max_vertices = max_quads * 4;
    static const int max_indices = max_quads * 6;
    static const int max_texture_slots = 32;

    Shader *shader = nullptr;

    int index_count = 0;
    QuadVertex *quad_vb_ptr = nullptr;

    std::array<const Texture *, max_texture_slots> textures;
    int texture_slot_index = 1.0;
};

static Data data;

void
DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color) {
    float texture_index = 0.0f; // white texture

    data.quad_vb_ptr->position = position;
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {0.0f, 0.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x + size.x, position.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {1.0f, 0.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x + size.x, position.y + size.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {1.0f, 1.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x, position.y + size.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {0.0f, 1.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.index_count += 6;
}

void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color, const Texture *texture) {

    float texture_index = 0.0f;
    for (int i = 1; i < data.textures.size(); i++) {
        if (data.textures[i] && *data.textures[i] == *texture) {
            texture_index = (float) i;
            break;
        }
    }
    if (texture_index == 0.0f) {
        texture_index = (float) data.texture_slot_index;
        data.textures[data.texture_slot_index] = texture;
        data.texture_slot_index++;
    }

    data.quad_vb_ptr->position = position;
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {0.0f, 0.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x + size.x, position.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {1.0f, 0.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x + size.x, position.y + size.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {1.0f, 1.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.quad_vb_ptr->position = {position.x, position.y + size.y, 0.0f};
    data.quad_vb_ptr->color = color;
    data.quad_vb_ptr->texture_coordinates = {0.0f, 1.0f};
    data.quad_vb_ptr->texture_index = texture_index;
    data.quad_vb_ptr++;

    data.index_count += 6;
}

int main() {
    glfwInit();
    GLFWwindow *window = glfwCreateWindow(1280, 720, "test", nullptr, nullptr);
    if (window == nullptr) {
        std::cerr << "failed to create GLFW window\n";
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, [](GLFWwindow *_, int width, int height) {
        glViewport(0, 0, width, height);
    });
    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        std::cerr << "failed to initialize GLAD\n";
    }

    uint32_t quad_va, quad_vb, quad_ib;

    glGenVertexArrays(1, &quad_va);
    glBindVertexArray(quad_va);

    glGenBuffers(1, &quad_vb);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
    glBufferData(GL_ARRAY_BUFFER, data.max_vertices * sizeof(QuadVertex), nullptr, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 10 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 10 * sizeof(float),
                          reinterpret_cast<const void *>(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 10 * sizeof(float),
                          reinterpret_cast<const void *>(7 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 10 * sizeof(float),
                          reinterpret_cast<const void *>(9 * sizeof(float)));
    glEnableVertexAttribArray(3);

    QuadVertex *quad_vb_base = new QuadVertex[data.max_vertices];
    data.quad_vb_ptr = quad_vb_base;

    int *quad_indices = new int[data.max_indices];
    int offset = 0;
    for (int i = 0; i < data.max_indices; i += 6) {
        quad_indices[i + 0] = offset + 0;
        quad_indices[i + 1] = offset + 1;
        quad_indices[i + 2] = offset + 2;
        quad_indices[i + 3] = offset + 2;
        quad_indices[i + 4] = offset + 3;
        quad_indices[i + 5] = offset + 0;
        offset += 4;
    }
    glGenBuffers(1, &quad_ib);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ib);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.max_indices * sizeof(int), quad_indices, GL_STATIC_DRAW);
    delete[] quad_indices;

    Texture white_texture(1, 1);
    uint32_t white_texture_data = 0xffffffff;
    white_texture.SetData(&white_texture_data);
    data.textures[0] = &white_texture;

    Texture texture("assets/textures/checkerboard.png");

    data.shader = new Shader("assets/GLSL/test3.glsl");
    data.shader->Bind();
    data.shader->SetInt("u_texture", 0);

    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.1f, 0.1f, 0.1f, 1);
        glClear(GL_COLOR_BUFFER_BIT);

        data.shader->Bind();

        DrawQuad({-0.5f, 0.0f, 0.0f}, {0.5f, 0.8f}, {0.8f, 0.2f, 0.3f, 1.0f});
        DrawQuad({0.5f, -0.5f, 0.0f}, {0.5f, 0.75f}, {0.2f, 0.3f, 0.8f, 1.0f});
//        DrawQuad({-0.5f, 0.0f, 0.0f}, {0.5f, 0.8f}, glm::vec4(1.0f), &texture); // THIS WORKS, BECAUSE THE TEXTURE IS SET EXPLICITLY (AND THUS NO "WHITE TEXTURE" IS USED)

        for (int i = 0; i < data.texture_slot_index; i++) {
            data.textures[i]->BindToArray(i);
        }

        int size = (uint8_t *) data.quad_vb_ptr - (uint8_t *) quad_vb_base;
        glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
        glBufferSubData(GL_ARRAY_BUFFER, 0, size, quad_vb_base);
        glDrawElements(GL_TRIANGLES, data.index_count, GL_UNSIGNED_INT, nullptr);
        data.quad_vb_ptr = quad_vb_base;
        data.index_count = 0;

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

着色器

#type vertex
#version 330 core

layout(location = 0) in vec3 a_pos;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_texcoord;
layout(location = 3) in float a_texindex;

out vec4 v_color;
out vec2 v_texcoord;
out float v_texindex;

void main()
{
        v_color = a_color;
        v_texcoord = a_texcoord;
        v_texindex = a_texindex;
        gl_Position = vec4(a_pos, 1.0);
}

#type fragment
#version 330 core

in vec4 v_color;
in vec2 v_texcoord;
in float v_texindex;

out vec4 color;

uniform sampler2DArray u_textures;

void main()
{
        color = texture(u_textures, vec3(v_texcoord.xy, v_texindex)) * v_color;
}

未显示的 Shader 类简单地解析包含顶点和片段部分的着色器文件。

DrawQuad(position, size, color, texture)
函数运行正常(即绘制指定纹理)。但它的同胞没有纹理
DrawQuad(position, size, color)
,其中未指定纹理,但选择为白色,因为
texture_index
设置为
0.0f
(其中
white_texture
也绑定为0),绘制黑色矩形(所以不工作)。我不确定原因是否是实际数据是
0xffffffff
,但这应该不是问题。但作为白色纹理(如 rgba 中的白色全为 1),它不应影响实际颜色(在 DrawQuad 中指定为 3 参数)。那么出了什么问题?

为了完整性,这里是纹理类:

#include <test/main/texture.hpp>

#include <iostream>

#include <glad/glad.h>

#define STB_IMAGE_IMPLEMENTATION

#include <stb/stb_image.h>

Texture::Texture(int width, int height) : width_(width), height_(height) {
    glGenTextures(1, &renderer_id_);
    glBindTexture(GL_TEXTURE_2D, renderer_id_);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    InitArray();
}

Texture::Texture(const std::string& filepath) {
    stbi_set_flip_vertically_on_load(1);
    data_ = stbi_load(filepath.c_str(), &width_, &height_, nullptr, 4);
    if (data_ == nullptr) {
        std::cerr << "Failed to load image";
    }

    glGenTextures(1, &renderer_id_);
    glBindTexture(GL_TEXTURE_2D, renderer_id_);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    InitArray();
}

Texture::~Texture() {
    glDeleteTextures(1, &renderer_id_);
}

void Texture::Bind(int slot) const {
    glActiveTexture(GL_TEXTURE0 + slot);
    glBindTexture(GL_TEXTURE_2D, renderer_id_);
}

void Texture::BindToArray(int slot) const {
    if(data_ == nullptr){
        std::cerr << "no texture data loaded";
    }
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slot, width_, height_, 1, GL_RGBA, GL_UNSIGNED_BYTE, data_);
}

void Texture::SetData(void *data) {
    data_ = data;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}

void *Texture::GetData() const {
    return data_;
}

int Texture::GetWidth() const {
    return width_;
}

int Texture::GetHeight() const {
    return height_;
}

void Texture::InitArray() {
    if(array_renderer_id_ == 0){
        glGenTextures(1, &array_renderer_id_);
        glBindTexture(GL_TEXTURE_2D_ARRAY, array_renderer_id_);
        int max_textures;
        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_textures);
        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, width_, height_, max_textures, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
}

bool Texture::operator==(const Texture& rhs) const {
    return renderer_id_ == rhs.renderer_id_;
}

bool Texture::operator!=(const Texture& rhs) const {
    return !(rhs == *this);
}
c++ opengl glsl textures
© www.soinside.com 2019 - 2024. All rights reserved.