如何使用textureLod在glsl中对mip级别进行采样?

时间:2018-06-09 12:52:35

标签: c++ opengl glsl shader sampling

如何使用textureLod()在glsl中对mip级别进行采样?

据我所知,mipmap LOD可以通过顶点着色器“显式”访问(虽然不确定它是否在版本420中受支持,因为大多数情况下文档已过时)。其次,您需要通过设置纹理参数来定义mipmap细节级别,例如 GL_TEXTURE_MAX_LEVEL GL_TEXTURE_BASE_LEVEL

在我的代码中,我在调用 glCompressedTexImage2D 后定义了这些纹理参数:

glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri(texture_type, GL_TEXTURE_MAX_LEVEL, 9);
glTexParameteri(texture_type, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap_s);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap_t);

接下来,我将每个纹理样本的每个绑定使用此代码(反照率地图等类型):

glActiveTexture(GL_TEXTURE0 + unit);    // Set active texture type
glBindTexture(GL_TEXTURE_2D, id);   // Bind the texture object

最后,这是我的着色器代码:

顶点:

#version 420 core

out vec3 _texcoord;
out vec4 _albedo_lod;

uniform sampler2D albedo;   // Albedo and specular map

void main()
{
    _texcoord = texcoord;
    _albedo_lod = textureLod(albedo, vec2(_texcoord.st), 2.0);
}

使用附加片段:

#version 420 core

layout(location = 0) out vec4 gAlbedo;  // Albedo texel colour

in vec3 _texcoord;
in vec4 _albedo_lod;

void main()
{
    gAlbedo = _albedo_lod;  // Assign albedo
}

现在出于某种原因,无论我输入了什么LOD值,结果总是采用以下方式:

enter image description here 这似乎是最后一个mip级别(尽管我输入了什么价值)。请记住,我将10个mip级别打包为 .dds 文件。但是,当我通过纹理参数 GL_TEXTURE_BASE_LEVEL 手动设置基本mip级别时,它可以正常工作。

总而言之,为什么不使用textureLod在glsl中采样正确的mip级别?这在版本420中有点弃用吗?

编辑:以下是加载dds文件的代码:

// This function imports a dds file and returns the dds data as a struct
inline GLuint LoadDds(std::vector<std::string> file, size_t &img_width, size_t &img_height, size_t &num_mips, GLvoid* data, GLint wrap_s, GLint wrap_t, GLint min_filter, GLint mag_filter, size_t texture_type, bool anistropic_filtering)
{

    // Create one OpenGL texture
    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(texture_type, textureID);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    for (unsigned int i = 0; i < file.size(); i++)  // For each image...
    {
        FILE *fp;

        unsigned char header[124];
        unsigned int height;
        unsigned int width;
        unsigned int linearSize;
        unsigned int mipMapCount;
        unsigned int fourCC;
        unsigned int components;
        unsigned int format;
        unsigned int bufsize;
        unsigned char* buffer;


        /* try to open the file */
        errno_t err;
        err = fopen_s(&fp, file[i].c_str(), "rb");
        if (fp == NULL)
            return 0;

        /* verify the type of file */
        char filecode[4];
        fread(filecode, 1, 4, fp);
        if (strncmp(filecode, "DDS ", 4) != 0)
        {
            fclose(fp);
            return 0;
        }

        /* get the surface desc */
        fread(&header, 124, 1, fp);

        height = *(unsigned int*)&(header[8]);
        width = *(unsigned int*)&(header[12]);
        linearSize = *(unsigned int*)&(header[16]);
        mipMapCount = *(unsigned int*)&(header[24]);
        fourCC = *(unsigned int*)&(header[80]);
        bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
        buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char));

        fread(buffer, 1, bufsize, fp);

        /* close the file pointer */
        fclose(fp);

        components = (fourCC == FOURCC_DXT1) ? 3 : 4;
        switch (fourCC)
        {
        case FOURCC_DXT1:
            format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            break;
        case FOURCC_DXT3:
            format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            break;
        case FOURCC_DXT5:
            format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            break;
        default:
            free(buffer);
            return 0;
        }

        unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;

        unsigned int offset = 0;
        for (unsigned int level = 0; level < mipMapCount && (width || height); ++level)
        {
            unsigned int size = ((width + 3) / 4) * ((height + 3) / 4) * blockSize;
            glCompressedTexImage2D(texture_type != GL_TEXTURE_CUBE_MAP ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, format, width, height,
                0, size, buffer + offset);

            if ((level < 1) && (i < 1))     // Only assign input variable values from first image
            {
                img_width = width;  // Assign texture width
                img_height = height;    // Assign texture height
                data = buffer;  // Assign buffer data
                num_mips = mipMapCount;     // Assign number of mips
            }

            offset += size;
            width /= 2;
            height /= 2;
        }

        if (anistropic_filtering)   // If anistropic_filtering is true...
        {
            GLfloat f_largest;  // A contianer for storing the amount of texels in view for anistropic filtering
            glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &f_largest);     // Query the amount of texels for calculation
            glTexParameterf(texture_type, GL_TEXTURE_MAX_ANISOTROPY_EXT, f_largest);    // Apply filter to texture
        }

        if (!mipMapCount)
            glGenerateMipmap(texture_type); // Generate mipmap

        free(buffer);   // Free buffers from memory
    }

    // Parameters
    glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, min_filter);
    glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, mag_filter);
    glTexParameteri(texture_type, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexParameteri(texture_type, GL_TEXTURE_MAX_LEVEL, 9);
    glTexParameteri(texture_type, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap_s);
    glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap_t);

    // Set additional cubemap parameters
    if (texture_type == GL_TEXTURE_CUBE_MAP)
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, wrap_s);

    return textureID;   // Return texture id
}

这是使用NVIDIA的dds插件生成的每个mipmap级别的图像:

enter image description here

1 个答案:

答案 0 :(得分:2)

由于您对每个顶点进行采样,这似乎正是预期的行为。

你说mip level参数没有影响,但是从我看到的情况来看,只有当像素密度低于顶点密度并且值开始平均时,差异应该是显而易见的。但是,如果你不存储整个mipchain,这可能永远不会发生,因为最低分辨率可能仍然有足够的定义(我无法从屏幕截图中看出来,我只能猜测模型的细分)。

由于您手动生成了mipchain,尽管您可以轻松地为每个级别测试不同的平面颜色并查看它们是否确实已正确获取(实际上,如果您对进口商不确定,那么它可能是值得的首先在像素着色器中尝试一下。)