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

旧版OpenGL纹理渲染异常求助:自定义3x3 RGBA纹理无法正确显示

旧版OpenGL纹理渲染异常求助:自定义3x3 RGBA纹理无法正确显示

各位好,我正在迁移一个依赖旧版OpenGL的程序,为了复现下遇到的纹理渲染问题写了这个测试示例(请原谅用了老风格的OpenGL,暂时这样能简化迁移流程)。

我定义了一个3x3的RGBA纹理图案,预期能在窗口中显示对应的彩色四边形,但实际运行后只有左上角的红色纹理像素是对的,其他像素都像是被跳过或者错位了。我一开始怀疑是非2的幂尺寸的问题,但调整后问题依然存在,实在找不到原因,麻烦大家帮忙看看哪里出错了?

测试代码(main.c)

#include <SDL_opengl.h>
#include <stdio.h>

#define INITIAL_SCREEN_WIDTH 640
#define INITIAL_SCREEN_HEIGHT 480
#define PATTERN_WIDTH  3
#define PATTERN_HEIGHT 3

int screenWidth, screenHeight;
const float quadWidth = 300.0f;
const float quadHeight = 300.0f;
float quadX = (INITIAL_SCREEN_WIDTH / 2) - (quadWidth / 2);
float quadY = (INITIAL_SCREEN_HEIGHT / 2) - (quadHeight / 2);
GLuint texture;

#define RED   0xff0000ff
#define GREEN 0xff00ff00
#define BLUE  0xffff0000

static unsigned long pattern[] = {
    RED,   GREEN, BLUE,
    GREEN, BLUE,  RED,
    BLUE,  RED,   GREEN
};

void setupOpenGL(int width, int height) {
    screenWidth = width;
    screenHeight = height;
    glViewport(0, 0, screenWidth, screenHeight);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT, 0, -1, 1);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PATTERN_WIDTH, PATTERN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, pattern);
}

void drawQuad() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    glBegin(GL_QUADS);
    glColor3f(1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0, 0.0); glVertex2f(quadX, quadY);
    glTexCoord2f(1.0, 0.0); glVertex2f(quadX + quadWidth, quadY);
    glTexCoord2f(1.0, 1.0); glVertex2f(quadX + quadWidth, quadY + quadHeight);
    glTexCoord2f(0.0, 1.0); glVertex2f(quadX, quadY + quadHeight);
    glEnd();
    
    SDL_GL_SwapWindow(SDL_GL_GetCurrentWindow());
}

int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return 1;
    }
    
    SDL_Window* window = SDL_CreateWindow("OpenGL Quad Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!window) {
        fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError());
        return 1;
    }
    
    SDL_GLContext glContext = SDL_GL_CreateContext(window);
    if (!glContext) {
        fprintf(stderr, "OpenGL context could not be created! SDL_Error: %s\n", SDL_GetError());
        return 1;
    }
    
    setupOpenGL(INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT);
    
    int quit = 0;
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = 1;
            }
            else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                int newWidth = event.window.data1;
                int newHeight = event.window.data2;
                setupOpenGL(newWidth, newHeight);
            }
        }
        drawQuad();
    }
    
    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

编译用Makefile

CFLAGS = -Wall -Wextra -std=c99
INCLUDES = $(shell pkg-config --cflags sdl2)
LIBS = $(shell pkg-config --libs sdl2) -lGL
OUTPUT = main
SRC = main.c

all: $(OUTPUT)

$(OUTPUT): $(SRC)
	$(CC) $(CFLAGS) $(INCLUDES) -o $(OUTPUT) $(SRC) $(LIBS)

clean:
	rm -f $(OUTPUT)

.PHONY: all clean

问题根源与修复方案

你遇到的核心问题是纹理数据数组的类型不匹配:

在64位Ubuntu系统中,unsigned long是8字节长度,但你的纹理每个像素是4字节的RGBA数据,而glTexImage2D指定了GL_UNSIGNED_BYTE(每个分量1字节,每个像素共4字节),这导致OpenGL读取纹理数据时发生了错位:第一个像素读取了RED的前4字节(正确显示红色),但第二个像素读取的是RED的后4字节(全0,透明黑色),后续像素的读取全部错位,自然显示异常。

修复步骤:

  1. 修正纹理数据数组类型:
    把unsigned long改成uint32_t(需要包含<stdint.h>头文件)或者unsigned int(32位,和你的RGBA宏尺寸匹配):

    #include <stdint.h>
    // ...
    static const uint32_t pattern[] = {
        RED,   GREEN, BLUE,
        GREEN, BLUE,  RED,
        BLUE,  RED,   GREEN
    };
    
  2. 同步glTexImage2D的类型参数:
    因为现在每个元素是32位整数,需要告诉OpenGL正确的数据解析方式,把glTexImage2D的最后两个参数调整为:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PATTERN_WIDTH, PATTERN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pattern);
    

    这里用GL_UNSIGNED_INT_8_8_8_8是为了匹配你定义的AARRGGBB格式宏,确保颜色通道顺序正确。

    如果你想更直观避免字节顺序问题,也可以直接用unsigned char数组定义每个像素的分量:

    static const unsigned char pattern[] = {
        // 第一行:RED, GREEN, BLUE
        0x00, 0x00, 0xFF, 0xFF,
        0x00, 0xFF, 0x00, 0xFF,
        0xFF, 0x00, 0x00, 0xFF,
        // 第二行:GREEN, BLUE, RED
        0x00, 0xFF, 0x00, 0xFF,
        0xFF, 0x00, 0x00, 0xFF,
        0x00, 0x00, 0xFF, 0xFF,
        // 第三行:BLUE, RED, GREEN
        0xFF, 0x00, 0x00, 0xFF,
        0x00, 0x00, 0xFF, 0xFF,
        0x00, 0xFF, 0x00, 0xFF
    };
    

    这种方式下,glTexImage2D保持原来的GL_UNSIGNED_BYTE参数即可,完全不会有类型错位问题。

  3. 额外优化:修正窗口resize时的投影矩阵
    目前你的setupOpenGL中,不管窗口实际尺寸是多少,glOrtho都用固定的初始尺寸,这会导致窗口resize后画面拉伸。建议改成用当前窗口的尺寸:

    glOrtho(0, screenWidth, screenHeight, 0, -1, 1);
    

做完这些修改后,纹理应该就能正确显示你定义的3x3图案了。

备注:内容来源于stack exchange,提问作者denormal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 13:02:59