You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL纹理加载异常:颜色错误、纹理偏移问题求助

OpenGL纹理加载异常:颜色错误与纹理偏移问题

使用OpenGL结合SDL2加载图像时,多张图片均出现颜色显示错误、纹理偏移的情况。参照LearnOpenGL教程实现,甚至直接复制示例代码仍未解决问题。怀疑问题与OpenGL状态机有关,或是自身实现存在疏漏。目前已将图像加载逻辑封装到TextureManager类中,不确定是否是该类的实现导致异常。

显示输出:存在明显的颜色失真与纹理位置偏移现象


主函数代码

#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);
}

Window初始化类代码

#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();
}
}

内容的提问来源于stack exchange,提问作者Kaimetsu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 19:52:00