У меня есть текстура, которую я хочу использовать в качестве непрямого сияющего света.
Существует проблема: когда я сэмплирую наименьший MIP-текст этой текстуры, результат выглядит следующим образом:
но на самом деле должно выглядеть так:
Я использую вычислительный шейдер для генерации данных о сиянии, но для случая отладки вы можете использовать обычную кубическую карту с MIP-картами, сгенерированными аппаратно (glGenerateTextureMipmap
) или загрузить ее из файла. Результат будет тот же – жесткий перевод лица.
Вершинный шейдер:
#version 460 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
//per instance
layout(location = 2) in vec4 a_modelToWorld0;
layout(location = 3) in vec4 a_modelToWorld1;
layout(location = 4) in vec4 a_modelToWorld2;
layout(location = 5) in vec4 a_modelToWorld3;
layout(location = 0) out vec3 v_worldPosition;
layout(location = 1) out vec3 v_worldNormal;
layout(std140, binding = 0) uniform PerFrame
{
mat4 cameraModel;
mat4 viewProjection;
} u_frame;
void main()
{
mat4 model = mat4(a_modelToWorld0, a_modelToWorld1, a_modelToWorld2, a_modelToWorld3);
vec4 worldPosition = model * vec4(a_position, 1.0f);
v_worldPosition = worldPosition.xyz;
v_worldNormal = mat3(model) * a_normal;
gl_Position = u_frame.viewProjection * worldPosition;
}
пиксельный шейдер:
#version 460 core
layout(location = 0) out vec4 f_color;
layout(location = 0) in vec3 v_worldPosition;
layout(location = 1) in vec3 v_worldNormal;
layout(std140, binding = 0) uniform PerFrame
{
mat4 cameraModel;
mat4 viewProjection;
} u_frame;
layout(binding = 1) uniform samplerCube u_indirectRadiance;
void main()
{
vec3 normal = normalize(v_worldNormal);
vec3 viewDirection = normalize(u_frame.cameraModel[3].xyz - v_worldPosition);
vec3 reflectionDir = reflect(-viewDirection, normal);
vec3 color = textureLod(u_indirectRadiance, reflectionDir, 10.0f).rgb;
f_color = vec4(color, 1.0f);
}
Я провел некоторую отладку и проверил normal
, viewDirection
, reflectionDir
, и эти векторы выглядят правильно:
Я сравнил эти значения с моим приложением DX11, которое дает мне правильный непрямой свет, и все выглядит одинаково.
Что касается самой проблемы, то она не в данных кубической карты, потому что я это проверял. Он имеет правильные значения.
Проблема со способом выборки.
код, создающий кубическую карту сияния и сэмплер
GLuint sampler;
glCreateSamplers(1, &sampler);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
GLuint texture;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &texture);
glTextureStorage2D(texture, 11, GL_RGBA32F, 1024, 1024);
//here you can load a texture from a file
//eg. dds
/*
DirectX::TexMetadata meta;
DirectX::ScratchImage image;
//assuming that radianceCubemap.dds is 1024x1024, cubemap and has mipmaps generated correctly
DirectX::LoadFromDDSFile("assets/radianceCubemap.dds", DirectX::DDS_FLAGS_NONE, &meta, image);
GLuint target = GL_TEXTURE_CUBE_MAP;
GLuint format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; //assuming format is DXGI_FORMAT_BC1_UNORM, but this is just an example
for (std::size_t level = 0; level < meta.mipLevels; ++level) {
for (std::size_t face = 0; face < meta.arraySize; ++face) {
const DirectX::Image* img = image.GetImage(level, face, 0);
if (img) {
glCompressedTextureSubImage3D(texture, level, 0, 0, face, img->width, img->height, 1, format, img->slicePitch, img->pixels);
}
}
}
*/
/*
or you can do whatever, it does not matter, just make sure it's a 1024x1024 cubemap with 11 mips
*/
моя кубическая карта:
как видите, все правильно
Что не так с моим кодом? Как я могу это исправить?
На последнем уровне MIP-карты каждая сторона текстуры имеет размер 1x1. Насколько я знаю, фильтрация по сторонам текстуры кубической карты по умолчанию отключена. Таким образом, даже если вы используете линейную фильтрацию, у вас есть только 1 тексель, поэтому вы не сможете получить градиент. Если вы позвоните glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS)
, вы включите фильтрацию по сторонам.
ДА! Большое спасибо <3 Я не знал об этой опции.