【问题标题】:Converting normals to global coordinate system将法线转换为全局坐标系
【发布时间】:2014-01-19 12:41:25
【问题描述】:

更新: 是的,我解决了。有人告诉我在 ModelView 矩阵处于活动状态时使用 gluLookAt()。现在我将它与投影矩阵一起使用,矩阵计算可以正常工作。

我正在 GLSL 上编写简单的光照着色器。

代码:http://pastebin.com/vdzyGVBS

/// VERTEX
//uniform mat4 gl_ProjectionMatrixTranspose;
//uniform mat4 gl_ModelViewProjectionMatrixTranspose;

//uniform mat4 gl_ModelViewMatrixTranspose;
uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix;
uniform mat3 gl_NormalMatrix;

varying vec3 norm;
varying vec4 color;


void main()
{
    //norm = normalize(gl_Normal) * mat3(gl_ModelViewMatrix); // It should work, but result is very weird

    //norm = normalize(gl_Normal) * transpose(mat3(gl_ModelViewMatrix)); // I don't know why, but it transforms normals to camera/eye coordinates

    norm = normalize(gl_Normal); // Light level is constant, event when model is rotating

    color = gl_Color;
    gl_Position = ftransform();
}

/// FRAGMENT 
const float dirlight_factor = 1.0;
const float amblight_factor = 0.2;
const float ambshad_factor = 0.1;

varying vec3 norm;
varying vec4 color;

void main()
{
    float shade;
    float nz = normalize(norm).z;
    if (nz > 0)
    {
        shade = amblight_factor + (nz * (dirlight_factor-amblight_factor));
    }
    else
    {
        shade = ambshad_factor + ((nz + 1) * (amblight_factor-ambshad_factor));
    }
    gl_FragColor = vec4(color.rgb * shade, color.a);
}

一切正常,但是当我尝试使用 ModelView 矩阵多边形旋转模型时,不会改变它们的光照水平。似乎法线不受 ModelView 矩阵变换的影响。我尝试了许多矩阵变换,但都没有奏效。 那么,我如何将法线转换为全局坐标系? 那么,我如何将光线方向和法线转换为相同的坐标系(世界空间或眼睛/相机空间)?

更新:

你的相机是想要世界空间定向光还是定向“头灯”?

.

我刚刚意识到(我只关注法线变换部分),您不会将任何类型的灯光参数传递给着色器。难怪您看不到适当的照明。

我没有传递任何灯光参数,因为我不需要更改它们。 我尝试制作始终从 +Z 下降到 -Z 的世界空间定向光。

【问题讨论】:

  • 你的相机是想要世界空间定向光还是定向“头灯”?

标签: opengl matrix glsl normals


【解决方案1】:

它将法线转换为眼睛坐标,因为您将它们乘以模型视图矩阵。模型矩阵将坐标转换为世界空间,然后视图矩阵将坐标转换为眼睛空间。如果要将法线转换为世界空间,则必须分别传递两个矩阵,然后必须在着色器中将它们相乘。

【讨论】:

    【解决方案2】:

    切线空间(法线是局部切线空间基础的一部分)不会被常规模型视图矩阵变换。相反,它们必须通过模型视图矩阵的转置逆进行转换。

    在您编写的代码中

    // It should work, but result is very weird
    //norm = normalize(gl_Normal) * mat3(gl_ModelViewMatrix);
    

    不,它应该也不会起作用,因为法线不会转换为与位置相同的规则。运算顺序也很重要,颠倒乘法的顺序只会转置结果,但它错过了反相部分;但是有一种预感告诉我,您并没有故意在乘法的左侧写法向量来转置整个事物。

    如前所述,法线是局部空间坐标系基础的一部分。你已经有那个制服 gl_NormalMatrix 在那里,它很可能包含这个。

    所以你的代码应该是这样的

    norm = normalize(gl_NormalMatrix * gl_Normal);
    

    更新

    我刚刚意识到(我只关注法线变换部分),您不会将任何类型的灯光参数传递给着色器。难怪您看不到适当的照明。

    【讨论】:

    • 我在一个绕 Y 轴旋转的球体上测试它。如果法线被正确传输,光线会落在 -Z 方向。如果我使用norm = normalize(gl_Normal) * mat3(gl_ModelViewMatrix);,lightsourse 会以奇怪的“8”状轨迹围绕该球体飞行。如果我使用norm = normalize(gl_NormalMatrix * gl_Normal);,光线会朝视线方向下降并稍微摆动。
    • @user2752075:如果您在每个顶点基础而不是每个片段基础上进行照明计算,可能会导致“摆动”效果。灯光方向关闭表明您错误地转换了灯光位置。通常,您应该在视图空间中进行所有照明计算。但为此,您必须确保应用正确的转换。这让我意识到,您根本不会将灯光位置传递到着色器中。
    • @user2752075:如果您只使用法线向 Z 轴的投影,这基本上就是您的着色器所做的,那么“光”将从 +Z 方向落入。跨度>
    • 是的,这正是我希望这个着色器工作的方式。好的,现在我将尝试在眼睛/相机空间内进行计算。使用以下方法转换法线:vec3 norm = normalize(gl_NormalMatrix * gl_Normal);(“摆动”是 gluSphere() 中的正常计算错误,如果我尝试绘制低多边形球体,则会出现这种错误)。但我仍然不知道如何将光的方向 (vec3(0, 0, -1.0)) 从世界空间转换到眼睛/相机空间。
    • @user2752075:摆动不是错误,它是逐顶点光照计算的产物。是的,它对于低三角形计数很明显。但可以通过在每个片段基础上在片段着色器中进行光照计算(也称为基于像素的光照)来完全避免这种情况,这是解决问题的标准方法,因为自从有了着色器之后。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 2012-09-06
    相关资源
    最近更新 更多