为什么这个Phong着色器有效?

时间:2014-03-14 17:33:51

标签: opengl glsl shader

我最近在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));
}

所以我做的方法是计算光矢量和相机矢量之间的半矢量,然后用法线点。这一切都很好。但是,我做了两件很奇怪的事情。

  1. 通常,一切都在眼睛坐标中完成。但是,我从顶点着色器传递到片段着色器的位置在本地坐标中。

  2. 这是困扰我的部分。在vec3 h = normalize(lightDirCameraCoords - vertexPosLocalCoords);行上我用相对于局部坐标中的顶点位置减去相机坐标中的光矢量。这似乎完全错了。

  3. 简而言之,我理解这段代码应该做什么,以及phong着色的半矢量方法是如何工作的。

    但为什么这段代码有用呢?

    编辑:我们提供的入门代码是开源的,因此如果您愿意,可以download the completed project直接查看。该项目适用于Windows上的VS 2012(您需要设置GLEW,GLM和freeGLUT),并且应该在GCC上工作而不需要更改代码(可能是对makefile库路径的更改或两次)。

    请注意,在源文件中," light_pos"被称为" gem_pos",因为我们的光源是你用WSADXC移动的小宝石。按M键以获得多个灯光的Phong。

1 个答案:

答案 0 :(得分:8)

这种作用的原因是偶然的,但看看为什么它仍然有效是很有趣的。

Phong着色是一种

中的三种技巧

使用phong着色,我们有三个术语:高光漫反射环境;这三个术语代表了phong着色中使用的三种技术。

这些术语都不严格要求矢量空间;只要你是一致的,你就可以在世界,地方或相机空间中进行phong着色。眼睛空间通常用于照明,因为它更容易使用,转换也很简单。

但如果你在原点怎么办?现在你乘以零;很容易看出原点上的任何向量空间之间没有区别。巧合的是,在起源时,你所处的向量空间并不重要;它会工作。

vec3 h = normalize(lightDirCameraCoords - vertexPosLocalCoords);

请注意,它基本上减去了0;这是本地使用的唯一时间,并且它在一个地方使用它可以造成最小的伤害。由于物体位于原点,因此它的所有顶点也应该在原点处或非常接近原点。在原点,近似是精确的;所有向量空间汇合。非常接近原点,它非常接近精确;即使我们使用了精确的实数,它也只是一个非常小的分歧,但我们并没有使用精确的实数,我们使用浮点数,使问题复杂化。

基本上,你很幸运;如果对象不在原点,这将无法工作。尝试移动它,看看!

此外,您还没有使用Phong shading;您正在使用Blinn-Phong shading(这是用半矢量替换reflect()的名称,仅供参考)。