opengl - 如何计算法线矩阵?

标签 opengl matrix webgl

我有经典的简单照明示例:

precision mediump float;
varying vec3 lighting;
attribute vec3 vertex;
attribute vec3 normal;
uniform mat4 mvMatrix, pMatrix, nMatrix;
void main() {
    gl_Position = pMatrix * mvMatrix * vec4(vertex,1.0);
    vec3 ambientLight = vec3(0.6,0.6,0.6);
    vec3 lightColour = vec3(0.5,0.5,0.75);
    vec3 lightDir = vec3(0.85,0.8,0.75);
    vec3 transformed = (nMatrix * vec4(normal,1.0)).xyz;
    float directional = max(dot(transformed,lightDir),0.0);
    lighting = ambientLight + (lightColour*directional);
}

precision mediump float;
varying vec3 lighting;
void main() {
    gl_FragColor = vec4(lighting,1.0);
}

此代码来自Mozilla webGL example .

我的法线看起来是正确的(如果我绘制原始法线而不是计算的颜色,我会得到漂亮的彩虹)。然而,我计算出的光对于所有点来说都是相同的颜色。

我认为我的法线矩阵是错误的。我是这样计算的:

pMatrix = createPerspective(60.0,canvas.offsetWidth/canvas.offsetHeight,0.1,4),
mvMatrix = createLookAt([2,2,2],[0,0,0],[0,1,0]),
nMatrix = mat4_inverse(mvMatrix);

作为 webGL,我必须制作自己的小矩阵助手(OpenGL 使用转置矩阵):

function createPerspective(fovy,aspect,near,far) {
        var top = near*Math.tan(fovy*Math.PI/360.0);
        var right = top*aspect, left = -right, bottom = -top;
        var rl = (right-left);
        var tb = (top-bottom);
        var fn = (far-near);
        return [(near*2)/rl,    0,  0,  0,
            0,  (near*2)/tb,    0,  0,
            (right+left)/rl,    (top+bottom)/tb, -(far+near)/fn,    -1,
            0,  0,  -(far*near*2)/fn,   0];
}

function createLookAt(eye,centre,up) {
        if (eye[0] == centre[0] && eye[1] == centre[1] && eye[2] == centre[2])
                return [1, 0, 0, 0,
                    0, 1, 0, 0,
                    0, 0, 1, 0,
                    0, 0, 0, 1];
        var z0,z1,z2,x0,x1,x2,y0,y1,y2,len; 
        //vec3.direction(eye, center, z);
        z0 = eye[0] - centre[0];
        z1 = eye[1] - centre[1];
        z2 = eye[2] - centre[2];
        // normalize (no check needed for 0 because of early return)
        len = 1/Math.sqrt(z0*z0 + z1*z1 + z2*z2);
        z0 *= len;
        z1 *= len;
        z2 *= len;
        //vec3.normalize(vec3.cross(up, z, x));
        x0 = up[1]*z2 - up[2]*z1;
        x1 = up[2]*z0 - up[0]*z2;
        x2 = up[0]*z1 - up[1]*z0;
        len = Math.sqrt(x0*x0 + x1*x1 + x2*x2);
        if(len) len = 1/len; else len = 0;
    x0 *= len;
    x1 *= len;
    x2 *= len;
        //vec3.normalize(vec3.cross(z, x, y));
        y0 = z1*x2 - z2*x1;
        y1 = z2*x0 - z0*x2;
        y2 = z0*x1 - z1*x0;
        len = Math.sqrt(y0*y0 + y1*y1 + y2*y2);
        if(len) len = 1/len; else len = 0;
    y0 *= len;
    y1 *= len;
    y2 *= len;
        return [x0, y0, z0, 0,
            x1, y1, z1, 0,
            x2, y2, z2, 0,
            -(x0*eye[0] + x1*eye[1] + x2*eye[2]), -(y0*eye[0] + y1*eye[1] + y2*eye[2]), -(z0*eye[0] + z1*eye[1] + z2*eye[2]), 1];
}

function mat4_inverse(mat) {
        var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
        var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
        var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
        var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
        var b00 = a00*a11 - a01*a10;
        var b01 = a00*a12 - a02*a10;
        var b02 = a00*a13 - a03*a10;
        var b03 = a01*a12 - a02*a11;
        var b04 = a01*a13 - a03*a11;
        var b05 = a02*a13 - a03*a12;
        var b06 = a20*a31 - a21*a30;
        var b07 = a20*a32 - a22*a30;
        var b08 = a20*a33 - a23*a30;
        var b09 = a21*a32 - a22*a31;
        var b10 = a21*a33 - a23*a31;
        var b11 = a22*a33 - a23*a32;
        var invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
        return [
        (a11*b11 - a12*b10 + a13*b09)*invDet,
        (-a01*b11 + a02*b10 - a03*b09)*invDet,
        (a31*b05 - a32*b04 + a33*b03)*invDet,
        (-a21*b05 + a22*b04 - a23*b03)*invDet,
        (-a10*b11 + a12*b08 - a13*b07)*invDet,
        (a00*b11 - a02*b08 + a03*b07)*invDet,
        (-a30*b05 + a32*b02 - a33*b01)*invDet,
        (a20*b05 - a22*b02 + a23*b01)*invDet,
        (a10*b10 - a11*b08 + a13*b06)*invDet,
        (-a00*b10 + a01*b08 - a03*b06)*invDet,
        (a30*b04 - a31*b02 + a33*b00)*invDet,
        (-a20*b04 + a21*b02 - a23*b00)*invDet,
        (-a10*b09 + a11*b07 - a12*b06)*invDet,
        (a00*b09 - a01*b07 + a02*b06)*invDet,
        (-a30*b03 + a31*b01 - a32*b00)*invDet,
        (a20*b03 - a21*b01 + a22*b00)*invDet];
}

我相信这些矩阵函数是正确的 - 因为我以前没有遇到过它们的问题。

所以我对 gluLookAt 矩阵不正交并且弄乱了法线矩阵有一个挥之不去的内存,但我在 Google 上找不到任何与此相关的内容,也找不到我的基本错误或错误已经做了。

如何计算和应用正确的法线矩阵?

最佳答案

法线矩阵应该是模型 View 矩阵转置的逆矩阵,即

nMatrix = mat4_inverse(mat4_transpose(mvMatrix));

关于opengl - 如何计算法线矩阵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12050620/

相关文章:

R 帮助 : divide values by sum produced through factor

javascript - 如何使用 JavaScript 计算行列式,并将输入作为 LaTeX 输入格式?

javascript - 使用 Webgl 时 Firefox "This operation requires zeroing texture data"警告

javascript - three.js渐进渲染大网格

image - 我怎么知道图像是否为 "Premultiplied Alpha"?

java - jogl 列出所有图形设备

c++ - 如何计算插值三角曲面的主曲率?

python - 寻找一个使用 GLFW 的简单 OpenGL (3.2+) Python 示例

java - 文本文件到字符串矩阵java

javascript - 如何在webgl中获取纹理?没有Canvas.toDataUrl()