如何使用textureLod在glsl中对mip级别进行采样?
Posted
技术标签:
【中文标题】如何使用textureLod在glsl中对mip级别进行采样?【英文标题】:How to sample a mip level in glsl using textureLod? 【发布时间】:2018-06-09 12:52:34 【问题描述】:如何在 glsl 中使用 textureLod() 对 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 值,结果总是求助于这个:
这似乎是最后一个 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 级别的图像:
【问题讨论】:
textureLod
不被 OpenGL 4 弃用。你也不需要设置 GL_TEXTURE_MAX_LEVEL
和 GL_TEXTURE_BASE_LEVEL
除非你想强制 OpenGL 使用现有 mipmap 的子集。 1000
和 0
的默认值应该没问题。是什么让您相信您的代码始终对 LOD 9 进行采样,而不管您为 textureLod
提供什么值?
请显示您上传或生成每个 mip 地图级别的代码。
抱歉回复晚了!我已经上传了整个 dds 加载器代码 ^ :) 谢谢。
Fibbles - 感谢您对这个主题有所了解。基本上,目标是使用每个 LOD 值作为立方体贴图卷积的粗糙度步骤,因此具有 10 个级别将允许每 0.1 R 1 个。TextureLod 是实时访问 mips 的唯一方法 - 尽管你可以看,由于它的低级三线性质量,结果被视为使用了最后一个级别。谢谢。
(我很想知道将纹理采样器换成插值器的实际好处,你试过分析它吗?:))
【参考方案1】:
由于您对每个顶点进行采样,这似乎正是预期的行为。
您说 mip 级别参数没有影响,但据我所知,只有当像素密度低于顶点密度并且值开始平均时,差异才会明显。但是,如果您不存储整个 mipchain,这可能永远不会发生,因为最低分辨率可能仍然具有足够的定义(我无法从屏幕截图中真正看出,我只能猜测模型的镶嵌)。
由于您是手动生成 mipchain,尽管您可以轻松地为每个级别使用不同的平面颜色进行测试,并查看它们是否确实正确获取(实际上,如果您不确定导入器,它可能是值得的首先在像素着色器中尝试一下)。
【讨论】:
以上是关于如何使用textureLod在glsl中对mip级别进行采样?的主要内容,如果未能解决你的问题,请参考以下文章