【问题标题】:OpenGL diffuse lighting calculates wrongOpenGL 漫反射光照计算错误
【发布时间】:2015-02-05 12:08:57
【问题描述】:

我有一个涉及旋转立方体和定向(漫射)光源的简单场景,但我似乎没有正确理解照明数学。

我从this教程的obj文件中加载顶点和法线:

我的一些应用代码:

glm::mat4 modelview = ...

glm::mat4 projection = glm::perspective(60.0f, 16.0f/9.0f, 0.1f, 100.0f);

glm::mat4 MVP = projection * modelview;
glm::mat3 NormalMatrix = glm::transpose(glm::inverse(glm::mat3(modelview)));

glUniformMatrix4fv(MVP_location, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix3fv(NormalMatrix_location, 1, GL_FALSE, &NormalMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);

顶点着色器:

#version 430

in vec3 position;
in vec3 in_normal;
uniform mat4 MVP;
uniform mat3 NormalMatrix;

out vec3 Normal;
out vec4 Color;

void main()
{
    gl_Position = MVP * vec4(position, 1.0);

    Color = vec4(clamp(position, 0.0, 1.0), 1.0); //based on vertex position
    Normal = normalize(NormalMatrix * in_normal);
}

片段着色器:

#version 430

const vec3 Ambient = vec3(0.15, 0.15, 0.15);
const vec3 LightDirection = normalize(vec3(1.0, 0.0, 1.0));
const vec3 LightColor = vec3(1.0, 1.0, 1.0);

const float Shininess = 20.0;
const float Strength = 5.0;

in vec3 Normal;
in vec4 Color;

out vec4 FragColor;

void main()
{
    FragColor = Color;

    float diffuse = max(0.0, dot(Normal, LightDirection));

    vec3 scatteredLight = Ambient + LightColor * diffuse;

    vec3 rgb = min(FragColor.rgb * scatteredLight, vec3(1.0));

    FragColor = vec4(rgb, Color.a);
}

这是我得到的: my fail

知道我做错了什么吗?

【问题讨论】:

  • 您的normal 在视图空间中,而LightDirection 在世界空间中。
  • 我将此添加到我的应用程序代码中:glm::vec3 light_direction = glm::mat3(modelview) * glm::vec3(1.0, 0.0, 1.0); glUniform3fv(glGetUniformLocation(program, "light_direction"), 1, &light_direction[0]);并修改了片段着色器:uniform vec3 light_direction; const vec3 LightDirection = normalize(light_direction);仍然得到不正确的结果。
  • 图片看起来更像是您的几何图形中存在错误的顶点或法线。

标签: c++ opengl lighting


【解决方案1】:

让我详细说明一下 dari 的评论。

您的法线向量与从view*model 矩阵(在您的应用程序中称为modelview)派生的法线矩阵相乘。将顶点与模型矩阵相乘将它们从 local-space 转换为 world-space,并将 world-space 中的顶点与视图矩阵相乘以转换它们视图空间坐标。在您的情况下,您使用模型 视图矩阵转换了法线向量;这意味着您的法线向量在视图空间中(它们的方向,从观察者的角度来看:相机)。

现在,您在世界空间中指定了光的方向向量 LightDirection(它的方向就是您希望它在全球世界中的方向,对吧?无需使用模型矩阵以任何方式对其进行转换)。

在计算漫反射/镜面反射照明时,您希望您的方向/位置矢量都位于同一个坐标空间中,否则您在不同空间之间进行计算会产生奇怪的结果。由于您的 LightDirectionworld-space 中,而您的 Normalview-space 中,您会得到奇怪的结果。

因此,您需要做的是解决您的问题:

  • LightDirection 与视图矩阵相乘,将其转换为视图空间(不是modelview,因为它包含模型视图矩阵)。李>
  • 仅从模型矩阵(不是 modelview)计算您的法线矩阵,因此您的法线向量将像 LightDirection 目前一样在 世界空间 中结束。

重要的是两个向量都在同一个空间中(可以是世界或视图,无论你喜欢什么)。

请注意,这适用于当您想在物体静止时给人一种相机在移动的印象(允许您移动到物体的无光照侧);请参阅下面的 Reto Koradi 的评论。

【讨论】:

  • 我不认为这是唯一有意义的事情。这真的取决于你想要什么。有时您想变换对象,并保持光源静止。这给人的印象是物体在四处移动,而相机是静止的(与光源一起)。其他时候,您想给人一种相机在四处移动而物体静止的印象。在这种情况下,您希望使用对象变换光源。 OP 实现的是第一个场景,并且完全有效。
  • 我不确定我是否遵循第一种情况,您说的是无论相机的方向/运动如何,光源都保持在相同的世界空间坐标/方向(如发光的球体例如,光总是在屏幕的右上角)?
  • 没有图片有点难以解释。想象一下相机和光源是静止的,并且物体响应用户输入而四处移动。这是一种非常常见的使用模式。事实上,它通常更有用,因为您总能获得良好、一致的照明。如果您让相机四处移动,但将灯光留在原处,那么当您移动到物体与灯光相反的一侧时,物体就会变暗。
  • 啊,我明白你的意思了,谢谢 :) 我会更新答案以反映这一点
  • 我不得不提一下,问题在于从对象文件中加载法线(之后我得到了预期的结果:对象旋转,相机和光源保持静止),尽管您的解释确实有帮助我明白发生了什么。在此之前,我并没有真正理解为模型和视图转换使用单独的矩阵的意义,所以我将它们混合到一个矩阵中,但现在我知道了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 2017-09-04
  • 1970-01-01
相关资源
最近更新 更多