【问题标题】:Why does my OpenGL Phong shader behave like a flat shader?为什么我的 OpenGL Phong 着色器表现得像平面着色器?
【发布时间】:2011-06-09 20:38:31
【问题描述】:

过去几周我一直在学习 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;
}

片段着色器:

#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);
 }

}

这张来自 Wikipedia 的(公共领域)图像准确地显示了我得到的图像类型以及我的目标——我得到的是“平面”图像,但我想要的是“Phong”图像。

任何帮助将不胜感激。谢谢!

编辑:如果有什么不同,我使用的是 PyOpenGL 3.0.1 和 Python 2.6。

编辑2:

解决方案

原来问题出在我的几何体上;科斯是正确的。对于其他遇到 Blender 模型问题的人,Kos 指出,Edit->Faces->Set Smooth 可以解决问题。我发现 Wings 3D “开箱即用”。

【问题讨论】:

  • 同样的解决方案对我有用。非常感谢。

标签: opengl glsl shader pyopengl


【解决方案1】:

作为对这个答案的补充,这里有一个简单的几何着色器,可以让您可视化您的法线。根据您的属性位置和发送矩阵的方式,根据需要修改随附的顶点着色器。

但首先,我们的朋友斯坦福兔的巨型兔头图片作为结果示例!

主要警告: 请注意,我使用模型视图矩阵而不是正确的法线矩阵来转换法线。如果您的模型视图包含非均匀缩放,这将无法正常工作。此外,法线的长度不会正确,但如果您只是想检查它们的方向,这并不重要。

顶点着色器:

#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;
}

【讨论】:

    【解决方案2】:

    嗯...您将法线插入为varying 变量,因此片段着色器应该接收正确的每像素法线。

    唯一的解释(我能想到的)你得到的结果如左图所示是给定脸上的每个片段最终都会收到相同的法线。您可以使用片段着色器进行确认,例如:

    void main() {
       vFragColor = normalize(vVaryingNormal);
    }
    

    如果是这样,问题仍然存在:为什么?顶点着色器看起来不错。

    那么也许您的几何形状有问题?您发送到着色器的数据是什么?您确定您正确计算了每个顶点的法线,而不仅仅是每个面的法线吗?

    橙色线是对角面的法线,红色线是水平面的法线。

    如果您的数据看起来像上图,那么即使使用正确的着色器,您也会得到平坦的着色。确保您具有正确的每个顶点法线,如下图所示。 (对于一个球体,它们真的很容易计算。)

    【讨论】:

    • 只想指出@Kos 对“球体的计算非常简单”的含义:在原点的单位半径球体的情况下,法线与顶点位置相同。
    • 我试过你的代码 sn-p 并且没有颜色插值,所以我猜这意味着它是几何的问题。我使用的球体实际上是从 Blender 导出为 Wavefront OBJ 文件格式。法线在 Blender 中显示是正确的,但我能做些什么来确保它们正常显示吗?
    • 嗯...这很奇怪。导出前你在 Blender 中做了Edit-&gt;Faces-&gt;Set Smooth 吗?
    • 效果很好!我还发现 Wings 3D 似乎可以导出正常运行的法线,而无需指定任何平滑。
    • 嗯,有时你想要一个结果,有时你想要另一个 - 知道在哪里可以控制它是件好事。但我不知道为什么它会在 Blender 中显示平滑之前你会设置这个?
    猜你喜欢
    • 2014-04-20
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    相关资源
    最近更新 更多