如何在 OpenGL 中正确转换漫反射照明的法线?
How to properly transform normals for diffuse lighting in OpenGL?
为了获得正确的漫射照明,我阅读了几篇文章并尝试尽可能地应用它们。
然而,即使法向量的变换看起来接近正确,光照仍然会在物体上略微滑动(对于固定光源来说不应该是这种情况)。
注 1:我根据点积添加了波段以使问题更加明显。
注2:这不是索伦之眼。
图中有两个问题很明显:
- 法线受投影矩阵影响:当视口水平时,法线显示椭圆形阴影(如图所示)。当视口是垂直的(高度>宽度)时,椭圆是垂直的。
- 当相机围绕 object.This 旋转时,阴影在表面上的移动在正常光照下不太明显,但在从光源投射图案时会变得明显。
代码和尝试:
不幸的是,一个最小的工作示例很快就会变得非常大,所以我只会 post 相关代码。如果这还不够,我和我会尝试在某个地方发布代码。
在绘图函数中,我有以下矩阵创建:
glm::mat4 projection = glm::perspective(45.0f, (float)m_width/(float)m_height, 0.1f, 200.0f);
glm::mat4 view = glm::translate(glm::mat4(1), glm::vec3(0.0f, 0.0f, -2.5f))*rotationMatrix; // make the camera 2.5f away, and rotationMatrix is driven by the mouse.
glm::mat4 model = glm::mat4(1); //The sphere at the center.
glm::mat4 mvp = projection * view * model;
glm::mat4 normalVp = projection * glm::transpose(glm::inverse(view * model));
在顶点着色器中,mvp用于变换位置和法线:
#version 420 core
uniform mat4 mvp;
uniform mat4 normalMvp;
in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_Texture;
out Vertex
{
vec4 pos;
vec4 normal;
vec2 texture;
} v;
void main(void)
{
v.pos = mvp * vec4(in_Position, 1.0);
gl_Position = v.pos;
v.normal = normalMvp * vec4(in_Normal, 0.0);
v.texture = in_Texture;
}
然后在片段着色器中应用漫反射着色:
#version 420 core
in Vertex
{
vec4 pos;
vec4 normal;
vec2 texture;
} v;
uniform sampler2D uSampler1;
out vec4 out_Color;
uniform mat4 mvp;
uniform mat4 normalMvp;
uniform vec3 lightsPos;
uniform float lightsIntensity;
void main()
{
vec3 color = texture2D(uSampler1, v.texture);
vec3 lightPos = (mvp * vec4(lightsPos, 1.0)).xyz;
vec3 lightDirection = normalize( lightPos - v.pos.xyz );
float dot = clamp(dot(lightDirection, normalize(v.normal.xyz)), 0.0, 1.0);
vec3 ambient = 0.3 * color;
vec3 diffuse = dot * lightsIntensity * color;
// Here I have my debug code to add the projected bands on the image.
// kind of if(dot>=0.5 && dot<0.75) diffuse +=0.2;...
vec3 totalLight = ambient + diffuse;
out_Color = vec4(totalLight, 1.0);
}
问题:
如何正确变换法线以获得漫反射着色?
相关文章:
- How to calculate the normal matrix?
- GLSL normals with non-standard projection matrix
- OpenGL Diffuse Lighting Shader Bug?
- http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
- http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
大多数情况下,所有消息来源都同意将投影矩阵乘以模型视图矩阵的逆矩阵的转置就足够了。这就是我认为我正在做的,但结果显然不正确。
不应在剪辑space(包括投影矩阵)中执行光照计算。让投影远离所有变量,包括光照位置等,你应该很好。
这是为什么?好吧,照明是一种物理现象,本质上取决于角度和距离。因此,要计算它,你应该选择一个保留这些东西的space。世界 space 或相机 space 是角度和距离保持 space 的两个示例(与物理 space 相比)。您当然可以不同地定义它们,但在大多数情况下它们是。剪辑 space 两者都不保留,因此您在此 space 中计算的角度和距离不是确定物理照明所需的物理角度和距离。
为了获得正确的漫射照明,我阅读了几篇文章并尝试尽可能地应用它们。
然而,即使法向量的变换看起来接近正确,光照仍然会在物体上略微滑动(对于固定光源来说不应该是这种情况)。
注 1:我根据点积添加了波段以使问题更加明显。
注2:这不是索伦之眼。
图中有两个问题很明显:
- 法线受投影矩阵影响:当视口水平时,法线显示椭圆形阴影(如图所示)。当视口是垂直的(高度>宽度)时,椭圆是垂直的。
- 当相机围绕 object.This 旋转时,阴影在表面上的移动在正常光照下不太明显,但在从光源投射图案时会变得明显。
代码和尝试:
不幸的是,一个最小的工作示例很快就会变得非常大,所以我只会 post 相关代码。如果这还不够,我和我会尝试在某个地方发布代码。
在绘图函数中,我有以下矩阵创建:
glm::mat4 projection = glm::perspective(45.0f, (float)m_width/(float)m_height, 0.1f, 200.0f);
glm::mat4 view = glm::translate(glm::mat4(1), glm::vec3(0.0f, 0.0f, -2.5f))*rotationMatrix; // make the camera 2.5f away, and rotationMatrix is driven by the mouse.
glm::mat4 model = glm::mat4(1); //The sphere at the center.
glm::mat4 mvp = projection * view * model;
glm::mat4 normalVp = projection * glm::transpose(glm::inverse(view * model));
在顶点着色器中,mvp用于变换位置和法线:
#version 420 core
uniform mat4 mvp;
uniform mat4 normalMvp;
in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_Texture;
out Vertex
{
vec4 pos;
vec4 normal;
vec2 texture;
} v;
void main(void)
{
v.pos = mvp * vec4(in_Position, 1.0);
gl_Position = v.pos;
v.normal = normalMvp * vec4(in_Normal, 0.0);
v.texture = in_Texture;
}
然后在片段着色器中应用漫反射着色:
#version 420 core
in Vertex
{
vec4 pos;
vec4 normal;
vec2 texture;
} v;
uniform sampler2D uSampler1;
out vec4 out_Color;
uniform mat4 mvp;
uniform mat4 normalMvp;
uniform vec3 lightsPos;
uniform float lightsIntensity;
void main()
{
vec3 color = texture2D(uSampler1, v.texture);
vec3 lightPos = (mvp * vec4(lightsPos, 1.0)).xyz;
vec3 lightDirection = normalize( lightPos - v.pos.xyz );
float dot = clamp(dot(lightDirection, normalize(v.normal.xyz)), 0.0, 1.0);
vec3 ambient = 0.3 * color;
vec3 diffuse = dot * lightsIntensity * color;
// Here I have my debug code to add the projected bands on the image.
// kind of if(dot>=0.5 && dot<0.75) diffuse +=0.2;...
vec3 totalLight = ambient + diffuse;
out_Color = vec4(totalLight, 1.0);
}
问题:
如何正确变换法线以获得漫反射着色?
相关文章:
- How to calculate the normal matrix?
- GLSL normals with non-standard projection matrix
- OpenGL Diffuse Lighting Shader Bug?
- http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
- http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
大多数情况下,所有消息来源都同意将投影矩阵乘以模型视图矩阵的逆矩阵的转置就足够了。这就是我认为我正在做的,但结果显然不正确。
不应在剪辑space(包括投影矩阵)中执行光照计算。让投影远离所有变量,包括光照位置等,你应该很好。
这是为什么?好吧,照明是一种物理现象,本质上取决于角度和距离。因此,要计算它,你应该选择一个保留这些东西的space。世界 space 或相机 space 是角度和距离保持 space 的两个示例(与物理 space 相比)。您当然可以不同地定义它们,但在大多数情况下它们是。剪辑 space 两者都不保留,因此您在此 space 中计算的角度和距离不是确定物理照明所需的物理角度和距离。