【发布时间】:2014-04-20 03:46:38
【问题描述】:
我最近在 GLSL 中编写了一个 Phong 着色器,作为学校作业的一部分。我从教程开始,然后玩弄代码直到我让它工作。据我所知,它工作得非常好,但我特别写了一行我不明白为什么它确实工作。
顶点着色器:
#version 330
layout (location = 0) in vec3 Position; // Vertex position
layout (location = 1) in vec3 Normal; // Vertex normal
out vec3 Norm;
out vec3 Pos;
out vec3 LightDir;
uniform mat3 NormalMatrix; // ModelView matrix without the translation component, and inverted
uniform mat4 MVP; // ModelViewProjection Matrix
uniform mat4 ModelView; // ModelView matrix
uniform vec3 light_pos; // Position of the light
void main()
{
Norm = normalize(NormalMatrix * Normal);
Pos = Position;
LightDir = NormalMatrix * (light_pos - Position);
gl_Position = MVP * vec4(Position, 1.0);
}
片段着色器:
#version 330
in vec3 Norm;
in vec3 Pos;
in vec3 LightDir;
layout (location = 0) out vec4 FragColor;
uniform mat3 NormalMatrix;
uniform mat4 ModelView;
void main()
{
vec3 normalDirCameraCoords = normalize(Norm);
vec3 vertexPosLocalCoords = normalize(Pos);
vec3 lightDirCameraCoords = normalize(LightDir);
float dist = max(length(LightDir), 1.0);
float intensity = max(dot(normalDirCameraCoords, lightDirCameraCoords), 0.0) / pow(dist, 1.001);
vec3 h = normalize(lightDirCameraCoords - vertexPosLocalCoords);
float intSpec = max(dot(h, normalDirCameraCoords), 0.0);
vec4 spec = vec4(0.9, 0.9, 0.9, 1.0) * (pow(intSpec, 100) / pow(dist, 1.2));
FragColor = max((intensity * vec4(0.7, 0.7, 0.7, 1.0)) + spec, vec4(0.07, 0.07, 0.07, 1.0));
}
所以我正在做的方法是计算光向量和相机向量之间的半向量,然后用法线点它。这都很好。但是,我做了两件奇怪的事情。
通常,一切都在眼睛坐标中完成。但是,我从顶点着色器传递到片段着色器的位置位于局部坐标中。
这是让我感到困惑的部分。在
vec3 h = normalize(lightDirCameraCoords - vertexPosLocalCoords);线上,我将相机坐标中的光矢量与 local 坐标中的顶点位置相减。这似乎完全错误。
简而言之,我明白这段代码应该做什么,以及 phong 着色的半向量方法是如何工作的。
但是为什么这段代码可以工作?
编辑: 我们提供的起始代码是开源的,因此您可以download the completed project 并直接查看。该项目适用于 Windows 上的 VS 2012(您需要设置 GLEW、GLM 和 freeGLUT),并且应该在没有代码更改的情况下在 GCC 上工作(可能对 makefile 库路径进行一两次更改)。
请注意,在源文件中,“light_pos”称为“gem_pos”,因为我们的光源是您使用 WSADXC 移动的小宝石。按 M 获得具有多个灯的 Phong。
【问题讨论】:
-
你确定它正确有效吗?它可能只是巧合地看起来并没有完全损坏:)
-
可能是对象的原点与世界原点对齐
-
melak47:它确实有效,我的作业完成了 100%。它运行良好,无论我将灯光移动到哪里,它都能让我的模型看起来适当闪亮:D
-
Abhishek:既然你提到了,模型确实是世界原点
-
所以你实际上是在每次相机移动时重新计算所有的法线?无论如何,你似乎不太可能得到 right 结果,但如果你的对象很小(与单位半径相比),以原点为中心并且相当凸,你可能会得到一个看起来有光泽的结果,是的(您的局部顶点坐标然后近似于表面法线)。由于减法,您的中途矢量将位于错误的一侧,因此您的高光将位于错误的位置(尽管再次,它仍然看起来很闪亮:))。