OpenGL渲染图像怪异

kqhtkvqz  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(108)

我遇到了OpenGL加载图像的问题,我已经尝试了几个图像,但颜色显示不正确,纹理显示偏移。
我是以下代码从Learnopengl.com加载图像的帮助下,SDL2,甚至去尽可能复制和粘贴代码后,几天的挫折,我想知道这是否有任何与OpenGL状态机或它纯粹是我缺乏经验。
我试图隔离我的图像加载代码到一个纹理管理器类。我想知道这是否是我的错。
Display Output

#include <iostream>
#include <Window/Window.hpp>
#include <Shaders/Shader.hpp>
#include <Managers/TextureManager.hpp>

int main(int argc, char* argv[]) {
    Kaim::Window window("Game", 1080, 720);

    Kaim::Shader shader("Assets/shaders/basic/vertex.glsl", "Assets/shaders/basic/fragment.glsl");
    Kaim::Manager::TextureManager textureManager;

        float vertices[] = {
        // positions          // colors           // texture coords
        0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
        0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left 
    };
    unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };
    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    textureManager.LoadTexture("box", "Assets/images/Box.png");

    while (window.IsOpen()) {
        GLenum error = glGetError();
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                window.Close();
            }
        }
        window.Update(0.2f, 0.3f, 0.3f, 1.0f);

        shader.use();
        textureManager.Bind("box");
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        window.Render();
    }
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

TextureManager.cpp

#include "TextureManager.hpp"

namespace Kaim { namespace Manager {
TextureManager::TextureManager() {
    INFO("Texture Manager Created");
}
TextureManager::~TextureManager() {
    INFO("Texture Manager Destroyed");
}

void TextureManager::LoadTexture(std::string name, std::string path) {
    for(auto const& [key, val] : textures) {
        if (val.path == path) {
            WARNING("Texture with path %s already exists", path.c_str());
            return;
        }
        if(key == name) {
            WARNING("Texture with name %s already exists", name.c_str());
            return;
        }
    }

    SDL_Surface* surface = IMG_Load(path.c_str());
    if (surface == NULL) {
        ERROR("Failed to load image: %s", IMG_GetError());
        return;
    }
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    // get number of channels in the SDL surface
    GLint nOfColors = surface->format->BytesPerPixel;
    unsigned int format;

    if (nOfColors == 4)     // contains an alpha channel
    {
            if (surface->format->Rmask == 0x000000ff)
                    format = GL_RGBA;
            else
                    format = GL_BGRA;
    } else if (nOfColors == 3)     // no alpha channel
    {
            if (surface->format->Rmask == 0x000000ff)
                    format = GL_RGB;
            else
                    format = GL_BGR;
    } else {
            ERROR("Image is not truecolor");
            return;
    }
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);   // set texture wrapping to GL_REPEAT (default wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    glTexImage2D(GL_TEXTURE_2D, 0, format, surface->w, surface->h, 0, format, GL_UNSIGNED_BYTE, surface->pixels);
    
    glGenerateMipmap(GL_TEXTURE_2D);
    SDL_FreeSurface(surface);

    Texture textureStruct;
    textureStruct.id = texture;
    textureStruct.path = path;
    textures[name] = textureStruct;
}
void TextureManager::Bind(std::string path) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[path].id);
}
void TextureManager::Unbind() {
    glBindTexture(GL_TEXTURE_2D, 0);
}
}}

顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;

void main()
{
    FragColor = texture(texture1, TexCoord);
}

尝试从纹理管理器类显示OpenGL中的图像
编辑:我想我应该添加窗口类,因为这是我初始化一切的地方。

#include "Window.hpp"

namespace Kaim {
Window::Window(std::string title, int width, int height) {
    SDL_Init(SDL_INIT_EVERYTHING);
    IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
    this->width = width;
    this->height = height;
    window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
    if (window == NULL) {
        ERROR("Failed to create window: %s", SDL_GetError());
        open = false;
        return;
    } 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    context = SDL_GL_CreateContext(window);
    if (glewInit() != GLEW_OK) {
        ERROR("OpenGL Could not Initalize");
        open = false;
    }

    glewExperimental = GL_TRUE;

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glViewport(0, 0, width, height);

    open = true;
}
void Window::Update(float r, float g, float b, float a) {
    glClearColor(r, g, b, a);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Window::Render() {
    SDL_GL_SwapWindow(window);
}

SDL_Window* Window::GetWindow() {
    return this->window;
}
bool Window::IsOpen() {
    return this->open;
}
void Window::Close() {
    this->open = false;
}

Window::~Window() {
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(this->window);
    IMG_Quit();
    SDL_Quit();
}
}
hujrc8aj

hujrc8aj1#

假设默认情况下图像的行对齐为4字节。如果加载RGB图像,则必须更改此设置,因为3个颜色通道只需要3个字节,并且图像的3 * 宽度可能无法被4整除。在指定图像之前(在glTexImage2D之前),使用glPixelStore设置GL_UNPACK_ALIGNMENT参数:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

相关问题