过去几周我一直在学习OpenGL,而且我在实现Phong着色器方面遇到了一些麻烦。尽管我使用smooth
限定符,但似乎在顶点之间没有插值。我在这里错过了什么吗?为了给予信用到期的信用,顶点和片段着色器的代码严重受到OpenGL SuperBible第五版的影响。我强烈推荐这本书!
顶点着色器:
#version 330
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix; // mvp = ModelViewProjection
uniform mat4 mvMatrix; // mv = ModelView
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
void main(void) {
vVaryingNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vVaryingLightDir = normalize(vLightPosition - vPosition3);
gl_Position = mvpMatrix * vVertex;
}
Fragment Shader:
#version 330
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
void main(void) {
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
vFragColor = diff * diffuseColor;
vFragColor += ambientColor;
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir),normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
float fSpec = pow(spec, 32.0);
vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
}
}
来自维基百科的这个(公共领域)图像显示我正在获得什么样的图像以及我的目标 - 我正在获得“平面”图像,但我想要“Phong”图像。
非常感谢任何帮助。谢谢!
编辑:如果它有所作为,我正在使用PyOpenGL 3.0.1和Python 2.6。
EDIT2:
事实证明问题出在我的几何学上;科斯是对的。对于那些遇到Blender模型问题的人来说,Kos指出做Edit->Faces->Set Smooth
就可以了。我发现Wings 3D“开箱即用”。
答案 0 :(得分:64)
作为这个答案的补充,这里有一个简单的几何着色器,可以让你可视化你的法线。根据您的属性位置以及发送矩阵的方式,根据需要修改附带的顶点着色器。
但首先,我们的朋友斯坦福兔子的巨型兔子头像是结果的一个例子!
主要警告:请注意我使用modelview矩阵而不是正确的普通矩阵来转换法线。如果您的模型视图包含非均匀缩放,则无法正常工作。此外,你的法线长度不正确,但如果你只是想检查他们的方向那么重要。
顶点着色器:
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 normal;
layout(location = 2) in mat4 mv;
out Data
{
vec4 position;
vec4 normal;
vec4 color;
mat4 mvp;
} vdata;
uniform mat4 projection;
void main()
{
vdata.mvp = projection * mv;
vdata.position = position;
vdata.normal = normal;
}
几何着色器:
#version 330
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;
in Data
{
vec4 position;
vec4 normal;
vec4 color;
mat4 mvp;
} vdata[3];
out Data
{
vec4 color;
} gdata;
void main()
{
const vec4 green = vec4(0.0f, 1.0f, 0.0f, 1.0f);
const vec4 blue = vec4(0.0f, 0.0f, 1.0f, 1.0f);
for (int i = 0; i < 3; i++)
{
gl_Position = vdata[i].mvp * vdata[i].position;
gdata.color = green;
EmitVertex();
gl_Position = vdata[i].mvp * (vdata[i].position + vdata[i].normal);
gdata.color = blue;
EmitVertex();
EndPrimitive();
}
}
片段着色器:
#version 330
in Data
{
vec4 color;
} gdata;
out vec4 outputColor;
void main()
{
outputColor = gdata.color;
}
答案 1 :(得分:48)
嗯......您正在将法线插值为varying
变量,因此片段着色器应该接收正确的每像素法线。
您在左侧图像上得到结果这一事实的唯一解释(我能想到)是给定面上的每个片段最终都会获得相同的正常。您可以使用片段着色器确认它,如:
void main() {
vFragColor = normalize(vVaryingNormal);
}
如果是这样的话,问题仍然存在:为什么?顶点着色器看起来没问题。
那么你的几何可能有问题吗?您发送到着色器的数据是什么?你确定你已经正确计算了每顶点法线,而不仅仅是每面法线吗?
橙色线是对角线面的法线,红色线是水平面的法线。
如果您的数据看起来像上面的图像,那么即使使用正确的着色器,您也会得到平面着色。确保在下图像上具有正确的每顶点法线。 (对于球体来说,它们的计算非常简单。)