如何在 OpenGL 中为 Phong 着色插入法线?
Posted
技术标签:
【中文标题】如何在 OpenGL 中为 Phong 着色插入法线?【英文标题】:How to interpolate normals for Phong shading in OpenGL? 【发布时间】:2016-06-28 08:26:34 【问题描述】:目前,我正在实施良好的旧 Phong 着色。总体而言,它看起来很正确,但出现了一种常态,我无法解释。
如果不仔细看,Stanford Bunny 看起来很正确,我认为。
但在耳朵上,例如有一个奇怪的图案:
在这张图片中,我将法线可视化并提高了饱和度以使问题更加明显。
这是我的顶点着色器:
#version 330 core
layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec3 vNormal;
out vec4 fWorldPosition;
smooth out vec3 fWorldNormalSmooth;
...
void main()
fWorldNormalSmooth = normalize(NormalMatrix*vNormal);
fWorldPosition = WorldMatrix*vPosition;
gl_Position = ProjectionMatrix*ViewMatrix*WorldMatrix*vPosition;
这是我的片段着色器:
#version 330 core
smooth in vec3 fWorldNormalSmooth;
in vec4 fWorldPosition;
out vec4 color;
...
vec4 shadePointLight(Material material, PointLight pointLight, vec3 worldPosition, vec3 worldNormal)
vec3 cameraPosition = wdiv(inverse(ViewMatrix)*vec4(0, 0, 0, 1));
vec3 cameraDirection = normalize(cameraPosition - worldPosition);
vec3 lightDirection = normalize(pointLight.position - worldPosition);
vec3 reflectionDirection = reflect(-lightDirection, worldNormal);
vec4 i_amb = material.ambientReflection*pointLight.ambientColor;
vec4 i_diff = max(0, dot(worldNormal, lightDirection))*material.diffuseReflection*pointLight.diffuseColor;
vec4 i_spec = pow(max(0, dot(reflectionDirection, cameraDirection)), material.shininess)*material.specularReflection*pointLight.specularColor;
float distance = length(pointLight.position - worldPosition);
float d = 1.0 / (pointLight.falloff.constant + pointLight.falloff.linear*distance + pointLight.falloff.quadratic*distance*distance);
return i_amb + d*(i_diff + i_spec);
void main()
...
color = shadePointLight(material, pointLight, wdiv(fWorldPosition), normalize(fWorldNormalSmooth));
谁能解释一下这种行为?
【问题讨论】:
你如何计算你的法线?也许根本原因就在那里。 我正在使用模型中的法线,无需进一步计算。 我在你链接的 obj 中看不到法线。 这很不幸。我链接错了兔子。现在已经更正了。 【参考方案1】:当在两个相同长度的向量之间进行线性插值时,就像在顶点和片段阶段之间发生的那样,结果向量的长度在两者之间会更短。在两个法线之间进行插值的数学上正确的方法是执行spherical linear interpolation (SLERP),但是对于角度的微小变化,您可以简单地在 fragment 着色器中对插值法线向量进行归一化(即因为小角度近似sin(x) ≈ x
用于小x
)。 编辑:对于更大的角度,需要通过适当的 SLERP 插值。
【讨论】:
我相信在这一行的片段着色器中已经完成了规范化:color = shadePointLight(material, pointLight, wdiv(fWorldPosition), normalize(fWorldNormalSmooth));
@Sunreef:啊,确实如此。没看到(剪辑在我屏幕的右边框)。以上是关于如何在 OpenGL 中为 Phong 着色插入法线?的主要内容,如果未能解决你的问题,请参考以下文章