英文:
SOIL2 don't load grayscale texture
问题
I'm sorry, but it appears you've requested code translation, and your content is too long for me to process in one go. Please provide specific portions of code or ask concise questions, and I'll be happy to assist with the translation.
英文:
I am new to OpenGL and am learning it at the moment.
Using SOIL2, I'm loading a texture and trying to render it on the screen. I load the texture like this:
GLuint texture;
texture = SOIL_load_OGL_texture(("resources/textures/" + fileName + ".png").c_str(),
SOIL_LOAD_AUTO, //Problem
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);
The problem is that when I try to load a texture with SOIL_LOAD_AUTO or SOIL_LOAD_LA, I get a black square. That being said, if I use SOIL_LOAD_RGBA, the grayscale texture is displayed.
Internet searches turn up nothing, and I'm inclined to believe that I don't understand how the "Greyscale" mode works.
At the moment my code looks like this (Yes, it's a bit wrong, but right now I'm trying to understand how OpenGL buffers, texture loading and shaders work, so I didn't do everything perfectly):
Render:
void Render::runGame() {
logger->info("Running content rendering...");
glfwShowWindow(window);
World world(width, height, &logger);
GLfloat data[] = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, //Top left
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, //Bottom left
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, //Top right
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f //Bottom right
};
GLubyte edata[6] = { 0, 1, 2, 2, 1, 3 };
world.getNormalizedCoord(0, height, 0, data);
world.getNormalizedCoord(0, 0, 8, data);
world.getNormalizedCoord(width, height, 16, data);
world.getNormalizedCoord(width, 0, 24, data);
GLuint VBO;
glGenBuffers(1, &VBO);
GLuint EBO;
glGenBuffers(1, &EBO);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(edata), edata, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) (2 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) (6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(NULL);
Shader shader = Shader("tile", &logger);
shader.create();
Texture texture = Texture("tile", &logger);
texture.create();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT);
if (texture.use() && shader.use()) {
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL);
glBindVertexArray(NULL);
}
shader.free();
texture.free();
glfwSwapBuffers(window);
}
destroy();
}
Texture class:
//Constructor...
Texture::~Texture() noexcept { glDeleteTextures(1, &texture); }
void Texture::create() {
if (hasLogger()) logger->info("Loading «" + fileName + "» texture...");
if (isCreated()) {
if (hasLogger()) logger->warn("Attempt to create texture «" + fileName + "» that is already created");
return;
}
GLuint texture;
texture = SOIL_load_OGL_texture(("resources/textures/" + fileName + ".png").c_str(),
SOIL_LOAD_AUTO, //Problem
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_NTSC_SAFE_RGB);
if (texture == 0) {
if (hasLogger()) logger->fatal("Failed to create texture «" + fileName + "»: " + SOIL_last_result());
return;
}
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, 0);
this->texture = texture;
created = true;
}
GLuint Texture::getTexture() const noexcept { return texture; }
bool Texture::use() const {
if (!isCreated()) {
if (hasLogger()) logger->warn("Texture «" + fileName + "» using before creating");
return false;
}
else {
glBindTexture(GL_TEXTURE_2D, texture);
return true;
}
}
void Texture::free() const noexcept { glBindTexture(GL_TEXTURE_2D, NULL); }
bool Texture::isCreated() const noexcept { return created; }
bool Texture::hasLogger() const noexcept { return logger != nullptr; }
Verticies shader:
#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texCoord;
out vec4 fragColor;
out vec2 fragTexCoord;
void main() {
gl_Position = vec4(position, 0.0f, 1.0f);
fragColor = color;
fragTexCoord = texCoord;
}
Fragment shader:
#version 330 core
in vec4 fragColor;
in vec2 fragTexCoord;
out vec4 color;
uniform sampler2D fragTexture;
void main() {
color = texture(fragTexture, fragTexCoord);
}
And my result with with SOIL_LOAD_AUTO or SOIL_LOAD_LA
The result I want to get, at the moment it's only possible with SOIL_LOAD_RGBA:
I really do not understand what's the matter, what could be the reason for such strange behavior?
P.S. My OpenGL version is 3.3 core profile and forward compatibility
SOLUTION:
I followed the advice from the accepted answer and abandoned SOIL. I used std_image instead, and loaded the texture into OpenGL correctly. My render code hasn't changed, and the texture loading code now looks like this:
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); //flip y for opengl render correctly
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: { //L
format = GL_RED;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); //Texture swizzle parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); //for correct store and render
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); //image with different channels
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
break;
}
case 2: { //LA
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);
for (int i = 0; i < 2 * width * height; i += 2) { //Multiply alpha
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);
for (int i = 0; i < 4 * width * height; i += 4) { //Multiply alpha
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;
}
}
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 + "»");
}
}
I made loading four texture types like Luminous, Luminous/Alpha, RGB, RGBA. For this I had to use GL_TEXTURE_SWIZZLE. In addition, I did not find an analogue of SOIL_FLAG_MULTIPLY_ALPHA, and without it, transparent textures look a little different than I expected. So I added code to handle this detail
答案1
得分: 0
以下是您要翻译的内容:
- SOIL_LOAD_AUTO (
=0
) 保留图像以其发现的任何格式。 - SOIL_LOAD_LA (
=2
) 强制将图像加载为亮度与Alpha。 - SOIL_LOAD_RGBA (
=4
) 强制将图像加载为红绿蓝Alpha。
在函数SOIL_internal_create_OGL_texture中,第1187行,您会看到,如果通道计数为1
或2
,SOIL使用GL_LUMINANCE
和GL_LUMINANCE_ALPHA
符号。
唯一的问题是,GL_LUMINANCE
和GL_LUMINANCE_ALPHA
在当前OpenGL版本(4.6)中是未知的。然而,在Legacy OpenGL和OpenGL ES中,glTexImage2D
将这些符号识别为format
参数。
解决方案:
- 使用Legacy OpenGL或OpenGL ES,
- 将图像文件保存为rgb(a)(这样您可以在使用当前OpenGL时使用
SOIL_LOAD_AUTO
), - 强制使用
SOIL_LOAD_RGB(A)
(适用于所有OpenGL版本),或者 - 放弃SOIL并使用stb_image(SOIL基于它)自己创建纹理(如果您想学习OpenGL,这是更好的方法)。
示例(使用stb_image):
//如果要垂直翻转纹理数据
//stbi_set_flip_vertically_on_load(1);
const char *filename = ""; //图像文件路径
int width; //图像宽度
int height; //图像高度
int num_channels; //图像通道数
//由于我们关心通道数,将最后一个参数设为0
stbi_uc *data = stbi_load(filename, &width, &height, &num_channels, 0);
//根据通道数选择纹理`format`
GLenum format;
switch (num_channels) {
case 1: format = GL_RED; break; //STBI_grey
case 2: format = GL_RG; break; //STBI_grey_alpha
case 3: format = GL_RGB; break; //STBI_rgb
case 4: format = GL_RGBA; break; //STBI_rgb_alpha
//默认:发生了错误
}
//纹理名称
GLuint tex;
//生成纹理名称
glGenTextures(1, &tex);
//将纹理绑定到特定的纹理目标
glBindTexture(GL_TEXTURE_2D, tex);
//创建纹理图像
glTexImage2D(
GL_TEXTURE_2D,
0, //mipmap级别0,
//使用glGenerateMipmap(GL_TEXTURE_2D)进行自动化
format, //内部格式,不必与格式相同,但
//然后您必须考虑转换效果
width,
height,
0, //没有边框
format,
GL_UNSIGNED_BYTE, //stbi_uc -> unsigned char
data
);
//设置纹理参数(min、mag、wrap_s、wrap_t)
//glTexParameteri...
//从目标解绑纹理
glBindTexture(GL_TEXTURE_2D, 0);
//释放图像数据
stbi_image_free(data)
英文:
The format of images that may be loaded (force_channels) (SOIL.h).
- SOIL_LOAD_AUTO (
=0
) leaves the image in whatever format it was found. - SOIL_LOAD_LA (
=2
) forces the image to load as Luminous with Alpha - SOIL_LOAD_RGBA (
=4
) forces the image to load as Red Green Blue Alpha
In the function SOIL_internal_create_OGL_texture, line 1187, you'll see, that SOIL uses the GL_LUMINANCE
and GL_LUMINANCE_ALPHA
symbols if the channel count is 1
or 2
.
The only problem is, that GL_LUMINANCE
and GL_LUMINANCE_ALPHA
are unknown to the current OpenGL version (4.6). In Legacy OpenGL and OpenGL ES on the other hand, glTexImage2D
will recognize those symbols as format
argument.
Solution:
- use Legacy OpenGL or OpenGL ES,
- save the image file as rgb(a) (so you can use
SOIL_LOAD_AUTO
, if you're using current OpenGL), - force
SOIL_LOAD_RGB(A)
(for all OpenGL versions) or - abandon SOIL and use stb_image (which SOIL is based on) and create the texture(s) yourself (which, if you want to learn OpenGL, is the better approach anyway).
Example (using stb_image):
//if you want to flip the texture data vertically
//stbi_set_flip_vertically_on_load(1);
const char *filename = ""; //path of image file
int width; //width of image
int height; //height of image
int num_channels; //number of channels in image
//since we're interested in the channel count, set last param to 0
stbi_uc *data = stbi_load(filename, &width, &height, &num_channels, 0);
//num_channels to texture `format`
GLenum format;
switch (num_channels) {
case 1: format = GL_RED; break; //STBI_grey
case 2: format = GL_RG; break; //STBI_grey_alpha
case 3: format = GL_RGB; break; //STBI_rgb
case 4: format = GL_RGBA; break; //STBI_rgb_alpha
//default: something went wrong
}
//texture name
GLuint tex;
//generate texture name
glGenTextures(1, &tex);
//bind the texture to a specific texture target
glBindTexture(GL_TEXTURE_2D, tex);
//create the texture image
glTexImage2D(
GL_TEXTURE_2D,
0, //mipmap level 0,
//use glGenerateMipmap(GL_TEXTURE_2D) for automation
format, //internal format, does not have to be the same as format, but
//then you have to consider the conversation effects
width,
height,
0, //no border
format,
GL_UNSIGNED_BYTE, //stbi_uc -> unsigned char
data
);
//set texture params (min, mag, wrap_s, wrap_t)
//glTexParameteri...
//unbind texture from target
glBindTexture(GL_TEXTURE_2D, 0);
//free image data
stbi_image_free(data);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论