WebGL定向照明-照亮立方体(照明无法正常工作)

WebGL Directional Lighting - Lighting a cube (lighting not working properly)

本文关键字:照明 工作 常工作 立方体 WebGL      更新时间:2023-09-26

我已经重写了几次这个代码,但照明出现了同样的问题。。。我将这个代码与几个月前写的做同样事情(点亮立方体)的代码进行比较,看起来我没有遗漏任何东西。

立方体的正面和背面还可以,但左右两侧的动作很奇怪,顶部和底部。。。看起来法线有问题,但它们还可以。。。检查并重写了几次,只是为了确定。

示例:http://gamedevelopment.t15.org/WebGL/WebGL%20Examples/Example%207%20-%20环境%20和%20定向%20光/

着色器:

<script id="vShader" type="x-shader/x-vertex">
        attribute vec3 aVertexPosition;
        attribute vec2 aTextureCoord;
        attribute vec3 aVertexNormal;
        uniform mat4 uPMatrix;
        uniform mat4 uMVMatrix;
        uniform mat3 uNMatrix;
        uniform vec3 uAmbientLightColor;
        uniform vec3 uDirectionalLightColor;
        uniform vec3 uLightDirection;
        uniform bool uUseLighting;
        varying vec2 vTextureCoord;
        varying vec3 vLightWeighting;
        void main(void){
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
            vTextureCoord = aTextureCoord;
            if(!uUseLighting){
                vLightWeighting = vec3(1.0, 1.0, 1.0);
            }else{
                vec3 transformedNormal = aVertexNormal * uNMatrix;
                float directionalLightWeighting = max(dot(uLightDirection, transformedNormal), 0.0);
                vLightWeighting = uAmbientLightColor + uDirectionalLightColor * directionalLightWeighting;
            }
        }
    </script>
    <script id="fShader" type="x-shader/x-fragment">
        precision mediump float;
        varying vec2 vTextureCoord;
        varying vec3 vLightWeighting;
        uniform sampler2D uSampler;
        void main(void){
            vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
            gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
        }
    </script>

代码:

var gl;
function initGL(canvas){
    try{
        gl = canvas.getContext("webgl");
        gl.viewportWidth = canvas.width;
        gl.viewportHeight = canvas.height;
    }catch(e){
        console.log("WebGL context was not initialized.");
        return null;
    }
}
function getShader(id, gl){
    var shaderScript = document.getElementById(id);
    if(!shaderScript){
        console.log(id + " - invalid shader id.");
    }
    var shaderString = "";
    var shaderChild = shaderScript.firstChild;
    while(shaderChild){
        if(shaderChild.nodeType == "3")
            shaderString += shaderChild.textContent;
        shaderChild = shaderChild.nextSibling;
    }
    var shader;
    if(shaderScript.type == "x-shader/x-vertex")
        shader = gl.createShader(gl.VERTEX_SHADER);
    else if(shaderScript.type == "x-shader/x-fragment")
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    else{
        console.log(id + " - invalid shader id.");
        return null;
    }
    gl.shaderSource(shader, shaderString);
    gl.compileShader(shader);
    if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
        console.log(id + " error: " + gl.getShaderInfoLog(shader));
        return null;
    }
    return shader;
}
var shaderProgram;
function initShaders(){
    var vShader = getShader("vShader", gl);
    var fShader = getShader("fShader", gl);
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vShader);
    gl.attachShader(shaderProgram, fShader);
    gl.linkProgram(shaderProgram);
    if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)){
        console.log("Shader program was not linked.");
        return null;
    }
    gl.useProgram(shaderProgram);
    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
    shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
    gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
    shaderProgram.lightDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightDirection");
    shaderProgram.directionalLightColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalLightColor");
    shaderProgram.ambientLightColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientLightColor");
    shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");
}
var cubeVertexPositionBuffer, cubeVertexIndexBuffer, cubeVertexTextureCoordBuffer, cubeVertexNormalBuffer;
function initBuffers(){
    // Cube.
    cubeVertexPositionBuffer = gl.createBuffer();
    vertices = [
        // Front face.
        -1.0, 1.0, 1.0,
        1.0, 1.0, 1.0,
        1.0, -1.0, 1.0,
        -1.0, -1.0, 1.0,
        // Back face.
        -1.0, 1.0, -1.0,
        1.0, 1.0, -1.0,
        1.0, -1.0, -1.0,
        -1.0, -1.0, -1.0,
        // Left face.
        -1.0, 1.0, -1.0,
        -1.0, 1.0, 1.0,
        -1.0, -1.0, 1.0,
        -1.0, -1.0, -1.0,
        // Right face.
        1.0, 1.0, -1.0,
        1.0, 1.0, 1.0,
        1.0, -1.0, 1.0,
        1.0, -1.0, -1.0,
        // Top face.
        1.0, 1.0, -1.0,
        -1.0, 1.0, -1.0,
        -1.0, 1.0, 1.0,
        1.0, 1.0, 1.0,
        // Bottom face.
        1.0, -1.0, -1.0,
        -1.0, -1.0, -1.0,
        -1.0, -1.0, 1.0,
        1.0, -1.0, 1.0
    ]
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    cubeVertexPositionBuffer.itemSize = 3;
    cubeVertexPositionBuffer.rotAngle = 0;
    cubeVertexIndexBuffer = gl.createBuffer();
    var indices = [
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23
    ];
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    cubeVertexIndexBuffer.numItems = 36;
    cubeVertexTextureCoordBuffer = gl.createBuffer();
    textureCoords = [
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 1.0
    ];
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
    cubeVertexTextureCoordBuffer.itemSize = 2;
    cubeVertexNormalBuffer = gl.createBuffer();
    var normals = [
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,
        0.0, 0.0, -1.0,
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,
        0.0, -1.0, 0.0,
    ]
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
    cubeVertexNormalBuffer.itemSize = 3;
}
var pMatrix = mat4.create();
var mvMatrixStack = [];
var mvMatrix = mat4.create();
var nMatrix = mat3.create();
function setMatrixUniforms(){
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
    mat3.normalFromMat4(nMatrix, mvMatrix);
    gl.uniformMatrix3fv(shaderProgram.nMatrixUniform, false, nMatrix);
}
function mvPushMatrix(){
    var copy = mat4.create();
    mat4.copy(copy, mvMatrix);
    mvMatrixStack.push(copy);
}
function mvPopMatrix(){
    mvMatrix = mvMatrixStack.pop();
}
function drawScene(){
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
    mat4.identity(mvMatrix);
    // Draw cube.
    mvPushMatrix();
    mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -7.0]);
    mat4.rotate(mvMatrix, mvMatrix, degToRad(cubeVertexPositionBuffer.rotAngle), [0.0, 1.0, 0.0]);
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, cubeVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
    gl.uniform1i(shaderProgram.samplerUniform, 0);
    // Lighting.
    gl.uniform1i(shaderProgram.useLightingUniform, true);
    gl.uniform3f(shaderProgram.ambientLightColorUniform, 0.2, 0.2, 0.2);
    gl.uniform3f(shaderProgram.directionalLightColorUniform, 0.8, 0.8, 0.8);
    var lightingDirection = [0.0, 0.0, -1.0];
    var adjustedLD = vec3.create();
    vec3.normalize(adjustedLD, lightingDirection);
    vec3.scale(adjustedLD, adjustedLD, -1);
    gl.uniform3fv(shaderProgram.lightDirectionUniform, adjustedLD);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
    mvPopMatrix();
}
var lastTime = 0;
function animate(){
    var timeNow = new Date().getTime();
    if(lastTime != 0){
        var elapsed = timeNow - lastTime;
        if(cubeVertexPositionBuffer.rotAngle > 360) cubeVertexPositionBuffer.rotAngle = 0;
        cubeVertexPositionBuffer.rotAngle += 45 * elapsed / 1000;
    }
    lastTime = timeNow;
}
function tick(){
    animate();
    drawScene();
    requestAnimFrame(tick);
}
function degToRad(degrees){
    return degrees * Math.PI / 180;
}
var cubeTexture;
function initTextures(){
    cubeTexture = gl.createTexture();
    cubeTexture.image = new Image();
    cubeTexture.image.onload = function(){
        handleLoadedTexture(cubeTexture);
    }
    cubeTexture.image.src = "textures/cube.png";
}
function handleLoadedTexture(texture){
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.bindTexture(gl.TEXTURE_2D, null);
}
function webGLStart(){
    initGL(document.getElementById("glCanvas"));
    initShaders();
    initBuffers();
    initTextures();
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.DEPTH_TEST);
    tick();
}

照明代码是:在initShaders()中引用,在initBuffers()中创建法线和顶点缓冲区,在drawScene()中设置统一变量,还在setMatrixUniforms()创建normalMatrix。

如果有人花时间看一看,告诉我出了什么问题,我会很感激。

好的。。生气了,再次重写代码,然后用一个工作示例中的一些代码一点一点地替换代码。。。伙计们告诉我!问题出在顶点着色器上,请告诉我之间的区别

vec3 transformedNormal = uNMatrix * aVertexNormal;

vec3 transformedNormal = aVertexNormal * uNMatrix;

第二个创建了bug,但它毫无意义。。。我乘的顺序有什么关系。