Как сэмплировать уровень mip в glsl с использованием textureLod? - PullRequest
0 голосов
/ 09 июня 2018

Как мне выполнить выборку уровня mip в glsl с помощью textureLod ()?

Из того, что я знаю, 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 .Однако, когда я вручную устанавливаю базовый уровень mip с помощью параметра текстуры GL_TEXTURE_BASE_LEVEL , он работает.

В общем, почему он не будет выбирать правильный уровень mip в glsl с использованием textureLod?Это несколько устарело в версии 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
}

А вот изображение каждого уровня mipmapгенерируется с помощью плагина dds от NVIDIA:

enter image description here

1 Ответ

0 голосов
/ 13 июня 2018

Поскольку вы производите выборку для каждой вершины, похоже, это именно то, что и ожидалось.

Вы говорите, что параметр уровня mip не имеет никакого влияния, но из того, что я вижу, разница должна быть заметна только тогда, когда плотность пикселей падает ниже плотности вершин и значения начинают усредняться.Однако этого может никогда не произойти, если вы не сохраните весь mipchain, так как самое низкое разрешение может все еще иметь достаточное определение (я не могу точно сказать по снимку экрана, и я могу только догадываться о тесселяции модели).

Поскольку вы генерируете mipchain вручную, вы можете легко протестировать разные плоские цвета для каждого уровня и посмотреть, действительно ли они выбраны правильно (и на самом деле, если вы не уверены насчет импортера, возможно, стоит попробоватьсначала в пиксельном шейдере).

...