SOIL2加载灰度纹理异常:SOIL_LOAD_AUTO/LA显示黑块
OpenGL灰度纹理加载异常问题及解决方案
问题现象
作为OpenGL初学者,使用SOIL2加载纹理时遇到以下问题:
- 使用
SOIL_LOAD_AUTO或SOIL_LOAD_LA加载灰度纹理时,画面显示为黑块 - 使用
SOIL_LOAD_RGBA时,纹理可正常显示
环境说明:OpenGL 3.3核心配置文件,启用向前兼容。曾排查灰度模式相关资料但未找到解决思路,附带完整渲染代码、Texture类代码、着色器代码及纹理图、错误/预期显示效果(此处略)。
原SOIL2加载代码
GLuint texture; texture = SOIL_load_OGL_texture(("resources/textures/" + fileName + ".png").c_str(), SOIL_LOAD_AUTO, // 问题出在这里 SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_NTSC_SAFE_RGB); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, NULL);
解决方案:改用stb_image加载
最终放弃SOIL2,改用stb_image加载纹理,通过配置GL_TEXTURE_SWIZZLE参数并手动实现SOIL_FLAG_MULTIPLY_ALPHA的逻辑,解决了灰度纹理显示问题。
新的纹理加载代码
void Texture::create() noexcept { if (hasLogger()) logger->info("Loading «" + fileName + "» texture..."); if (isCreated()) { if (hasLogger()) logger->warn("Attempt to create texture «" + fileName + "» that is already created"); return; } int width, height, nrChannels; stbi_set_flip_vertically_on_load(true); // 翻转Y轴以适配OpenGL坐标系 stbi_uc* data = stbi_load(("resources/textures/" + fileName + ".png").c_str(), &width, &height, &nrChannels, 0); if (data) { GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); GLenum format; switch (nrChannels) { case 1: { // 单通道灰度图 format = GL_RED; // 配置纹理通道重映射,将R通道复制到G、B通道,A通道设为1 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); break; } case 2: { // 灰度+Alpha通道 format = GL_RG; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_GREEN); // 实现SOIL_FLAG_MULTIPLY_ALPHA的逻辑:灰度值乘以Alpha值 for (int i = 0; i < 2 * width * height; i += 2) { data[i] = (data[i] * data[i + 1] + 128) >> 8; } break; } case 3: default: { // RGB三通道 format = GL_RGB; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); break; } case 4: { // RGBA四通道 format = GL_RGBA; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); // 实现SOIL_FLAG_MULTIPLY_ALPHA的逻辑:RGB值乘以Alpha值 for (int i = 0; i < 4 * width * height; i += 4) { data[i + 0] = (data[i + 0] * data[i + 3] + 128) >> 8; data[i + 1] = (data[i + 1] * data[i + 3] + 128) >> 8; data[i + 2] = (data[i + 2] * data[i + 3] + 128) >> 8; } break; } } // 根据纹理格式设置环绕方式,带Alpha的纹理使用边缘钳位 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, format == GL_RGBA || format == GL_RG ? GL_CLAMP_TO_EDGE : GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, format == GL_RGBA || format == GL_RG ? GL_CLAMP_TO_EDGE : GL_REPEAT); 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, width, height, 0, format, GL_UNSIGNED_BYTE, data); glBindTexture(GL_TEXTURE_2D, NULL); stbi_image_free(data); this->texture = texture; created = true; } else { if (hasLogger()) logger->fatal("Failed to create texture «" + fileName + "»"); } }
内容的提问来源于stack exchange,提问作者Unable error
相关产品推荐
相关产品推荐

