SOIL2无法加载灰度纹理。

huangapple go评论71阅读模式
英文:

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

Texture:
SOIL2无法加载灰度纹理。

And my result with with SOIL_LOAD_AUTO or SOIL_LOAD_LA
SOIL2无法加载灰度纹理。

The result I want to get, at the moment it's only possible with SOIL_LOAD_RGBA:
SOIL2无法加载灰度纹理。

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行,您会看到,如果通道计数为12,SOIL使用GL_LUMINANCEGL_LUMINANCE_ALPHA符号。

唯一的问题是,GL_LUMINANCEGL_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);

huangapple
  • 本文由 发表于 2023年6月6日 07:05:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410503.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定