当前位置: 首页 > 知识库问答 >
问题:

在openGL中使用照明进行正常映射

纪翰
2023-03-14

我正在尝试在片段着色器中实现法线贴图和照明。但我的密码似乎不起作用。我的想法是将ModelMatrix的额外副本传递给片段着色器,以便它可以变换存储在纹理中的法线。但反射光实际上发生在另一侧。

[更新]在得到一些建议后,我在顶点着色器中计算了TBN矩阵,将TBN基变换为世界空间,将光位置和眼位置转换为切线空间。但这一次,这颗行星根本就不发光!只显示环境光。然后我发现这是因为漫反射组件的计算结果为负值,然后被钳制为0。我似乎在着色器中找不到bug。

顶点着色器:

#version 400

in layout(location=0) vec3 vertexPosition;
in layout(location=1) vec2 vertexUV;
in layout(location=2) vec3 vertexNormal;
in layout(location=3) vec3 vertexTangent;
in layout(location=4) vec3 vertexBitangent;

out vec2 UV;
out vec3 vertexPositionWorld;
out vec3 tangentLightPos;
out vec3 tangentViewPos;
out vec3 tangentFragPos;

uniform vec3 lightPositionWorld;
uniform vec3 eyePositionWorld;

uniform mat4 M;
uniform mat4 V;
uniform mat4 P;

void main()
{
gl_Position = P * V * M * vec4(vertexPosition, 1.0f);
vertexPositionWorld = vec3(M * vec4(vertexPosition, 1.0f));
UV = vertexUV;

// note scaling problem here 
mat3 normalMatrix = transpose(inverse(mat3(M)));
// mat3 normalMatrix = inverse(transpose(mat3(M)));
vec3 T = normalize(normalMatrix * vertexTangent);
vec3 B = normalize(normalMatrix * vertexBitangent);
vec3 N = normalize(normalMatrix * vertexNormal);

mat3 TBN = transpose(mat3(T, B, N));
tangentLightPos = TBN * lightPositionWorld;
tangentViewPos = TBN * eyePositionWorld;
tangentFragPos = TBN * vertexPositionWorld;
}

碎片着色器:

#version 400

uniform sampler2D textureSampler_1;
uniform sampler2D textureSampler_2;
uniform vec3 AmbientLightPower;
uniform vec3 DiffuseLightPower;
uniform vec3 SpecularLightPower;
uniform float specularLightPower;

in vec2 UV;
in vec3 vertexPositionWorld;
in vec3 tangentLightPos;
in vec3 tangentViewPos;
in vec3 tangentFragPos;

out vec4 finalColor;

void main()
{
vec3 normal = texture(textureSampler_2, UV).rgb;
normal = normalize(normal * 2.0 - 1.0);

vec3 MaterialAmbientColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialDiffuseColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);
// diffuse light
vec3 lightDirection = normalize(tangentLightPos - tangentFragPos);
float DiffuseBrightness = clamp(dot(lightDirection, normal), 0, 1);

// specular light
vec3 reflectedDirection = normalize(reflect(-lightDirection, normal));
vec3 viewDirection = normalize(tangentViewPos - tangentFragPos);
float SpecularBrightness = clamp(dot(reflectedDirection, viewDirection), 0, 1);

finalColor = vec4(

MaterialAmbientColor  * AmbientLightPower +

MaterialDiffuseColor  * DiffuseLightPower * DiffuseBrightness +

MaterialSpecularColor * SpecularLightPower * pow(SpecularBrightness, specularLightPower), 1.0f);
}

共有1个答案

宦书
2023-03-14

你的方法是采用法线贴图,并通过模型矩阵对其进行转换。这只有在法线贴图是世界空间法线贴图时才有效。世界空间法线贴图很少使用,通常法线贴图是切线空间法线贴图。如果你不确定你有哪种类型的法线贴图,那么你可以检查纹理——如果它看起来大部分是蓝色的,那么你很可能有一个切线空间法线贴图,如果它颜色非常多,那么它可能是世界空间的,我的答案对你来说是错误的。

要使用切线空间法线贴图,您需要做更多的工作。通常,在顶点着色器中,您会得到一些基向量(法线、二正态和切线又名NBT),您可以使用这些向量将法线贴图转换为世界空间,或者将光线位置转换为切线空间(后者通常对于少量灯光更有效,因为您在顶点着色器中做了更多的工作)。

切线空间很难让你的头脑清醒过来,我建议你围绕主题读一读。这篇文章可能是一个不错的开始。

 类似资料:
  • 在我的照明场景中,由于某种原因,环境照明根本不起作用。无论朝哪个方向,整个模型都是相同的亮度。我试图消除衰减,但仍然有相同的结果。除此之外,无论相机位于何处,镜面照明都会一直闪烁。它应该根据球员的位置而发光。以下是环境问题的截图:Imgur。通用域名格式 如您所见,球体背向光线的部分(位于[0.0,4.0,0.0])与面向光线的部分颜色相同。环境因子应该是片段颜色的0.2。 顶点着色器源: 片段着

  • 我正在为体素游戏开发一个3通道延迟照明系统,但是我在像素化照明和环境遮挡方面有问题。 第一阶段将屏幕上每个像素的颜色、位置和法线渲染成单独的纹理。这部分工作正常: 第二个着色器为屏幕上的每个像素计算环境光遮挡值,并将其渲染为纹理。此部分工作不正常,已像素化: 原始遮挡数据: 第三个着色器使用颜色、位置、法线和遮挡纹理将游戏场景渲染到屏幕上。这一阶段的照明也是像素化的: SSAO(第二遍)片段着色器

  • 我有一个由2个网格(平面、立方体)、一个灯和一个相机组成的场景。我想使用GLSL着色器和OpenGL的阴影映射技术在我的场景中显示阴影。 以下是我得到的结果(为了简单起见,我的立方体和平面都是蓝色和蓝色): 这是FBO和深度纹理初始化: 以下是我的顶点着色器的内容: 还有我的片段着色器: 正如你所见,模型上有一些工件,我不知道如何取出它们。但是阴影看起来是正确的,所以我的着色器中输入的变量也应该是

  • 本文档介绍了在 After Effects 中使用 OpenGL 和 GPU 的硬件和软件注意事项。 使用哪款 GPU 才能获得最佳性能? 市面上不断推出各种新的 GPU 芯片组,After Effects 无法一一对其进行验证,也无法判断哪个 GPU 芯片组最适用,然而,您可遵循以下指导原则,找出最适合自己工作流程的 GPU。 个别 GPU 技术的重要程度,低于整体 GPU 性能。After E

  • 本文档介绍了在 After Effects 中使用 OpenGL 和 GPU 的硬件和软件注意事项。 使用哪款 GPU 才能获得最佳性能? 市面上不断推出各种新的 GPU 芯片组,After Effects 无法一一对其进行验证,也无法判断哪个 GPU 芯片组最适用,然而,您可遵循以下指导原则,找出最适合自己工作流程的 GPU。 个别 GPU 技术的重要程度,低于整体 GPU 性能。After E

  • 问题内容: 似乎我的正则表达式已关闭或我在案例陈述中没有正确使用它。我想要的是一个字符串:以一个大写字母开头,然后以两个小写字母开头,后跟至少一个数字。 我已经检查了regex API,并尝试了三种变体(贪婪的,勉强的和所有格的量词),却不知道它们的正确用法。还检查了String方法,但没有找到与我的需求相关的方法。 问题答案: 您不能将正则表达式用作开关盒。(考虑一下:Java如何知道您要匹配字