美文网首页
2022-10-14 聚光灯

2022-10-14 聚光灯

作者: MrSwilder | 来源:发表于2022-10-13 15:22 被阅读0次

一、原理

image.png

1.在点光源的基础上,当ϕ>θ时,渲染光照效果
2.需要多传入一个spotDir和cos(θ)值;
3.cos(ϕ)为LightDir与SpotDir的单位向量点积;
4.ϕ>θ,即cos(ϕ)<cos(θ)

二、效果

spotLight.gif

三、实现


    //顶点着色器
    var VS = /*glsl*/ `
      attribute vec4 a_Position;
      attribute vec4 a_Color;
      attribute vec2 a_Uv;
      attribute vec4 a_Normal;

      uniform mat4 u_MvpMatrix;
      uniform mat4 u_ModelMatrix; 
      uniform mat4 u_NormalMatrix;
      varying vec4 v_Color;
      varying vec2 v_Uv;
      varying vec3 v_Normal;
      varying vec3 v_Position;
      void main(){
       
         gl_Position = u_MvpMatrix * a_Position;
         v_Color = a_Color;
         v_Uv=a_Uv;
         v_Normal= normalize(vec3(u_NormalMatrix*a_Normal));
            // v_Normal=a_Normal;
         v_Position=(u_ModelMatrix*a_Position).rgb;

      }`;

    //片元着色器
    var FS = /*glsl*/ `
      #ifdef GL_ES
      precision mediump float;
      #endif
     
      uniform sampler2D u_Texture;
       uniform vec3 u_AmbitionColor;

      uniform vec3 u_LightPosition;
      uniform vec3 u_LightColor;
      uniform float u_CutOff;
      uniform float u_OutCutOff;
      uniform vec3 u_SpotDir;
      varying vec2 v_Uv;
      varying vec3 v_Normal;
      varying vec3 v_Position;
       varying vec4 v_Color;
      void main(){
        vec4 baseColor= texture2D(u_Texture,v_Uv);
        // vec4 baseColor=vec4(1.0);
        vec3 normal=normalize(v_Normal);
        //计算光照方向
        vec3 lightDirection=normalize(u_LightPosition-vec3(v_Position));
        //计算光线与spotDir之间的夹角
        float theta=max(dot(normalize(-lightDirection),normalize(u_SpotDir)),0.0);
        //如果夹角小于切光角,则绘制,即余弦值大 theta>cos(u_CutOff)
        vec3 diffuseColor;
        if(theta>u_CutOff){
            float dotL=max(0.0,dot(lightDirection,normal));
            diffuseColor=u_LightColor*dotL;
        }else if(theta>u_OutCutOff&&theta<u_CutOff){
             float dotL=max(0.0,dot(lightDirection,normal));
             //渐变
             float value=(theta-u_OutCutOff)/(u_CutOff-u_OutCutOff);
            diffuseColor=u_LightColor*dotL*smoothstep(0.0,1.0,value);
        }
                


         gl_FragColor =vec4((diffuseColor+u_AmbitionColor)*baseColor.rgb,baseColor.a);
         
      }`;


    //声明js需要的相关变量
    var canvas = document.getElementById("canvas");
    var gl = getWebGLContext(canvas);

    async function main() {
        if (!gl) {
            console.log("你的浏览器不支持WebGL");
            return;
        }

        const program = createProgram(gl, VS, FS);
        if (!program) {
            console.warn("创建程序失败!");
            return;
        }

        gl.program = program;
        gl.useProgram(program);

        //获取内置变量的信息
        getVariableLocation();

        var n = createCube(gl);
        if (n < 0) {
            console.log("无法创建缓冲区");
            return;
        }
        //设置底色
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        //初始化纹理
        await initTexture(gl, "./image/texture1.jpg", 0);



        const ambitionColor = gl.getUniformLocation(gl.program, "u_AmbitionColor");

        gl.uniform3fv(ambitionColor, [0.2, 0.2, 0.2]);

        //设置点光源
        const lightPosition = gl.getUniformLocation(gl.program, "u_LightPosition");

        gl.uniform3fv(lightPosition, [-4, 4, 4]);


        const lightColor = gl.getUniformLocation(gl.program, "u_LightColor");
        gl.uniform3fv(lightColor, [148 / 255, 216 / 255, 146 / 255]);

        var spotDir_x = 1
        var spotDir_y = -1
        var spotDir_z = -1

        const spotDir = gl.getUniformLocation(gl.program, "u_SpotDir");
        gl.uniform3fv(spotDir, [spotDir_x, spotDir_y, spotDir_z]);

        const cutOff = gl.getUniformLocation(program, "u_CutOff");
        const angle = 5
        gl.uniform1f(cutOff, Math.cos(angle * Math.PI / 180));

        const outCutOff = gl.getUniformLocation(program, "u_OutCutOff");
        const outAngle = 8
        gl.uniform1f(outCutOff, Math.cos(outAngle * Math.PI / 180));


        //开启隐藏面清除
        gl.enable(gl.DEPTH_TEST);
        // gl.enable(gl.CULL_FACE)


        document.addEventListener("keydown", (e) => {
            if (e.key === "ArrowUp") {
                spotDir_y += 0.01
            } else if (e.key === "ArrowDown") {
                spotDir_y -= 0.01
            } else if (e.key === "ArrowLeft") {
                spotDir_x -= 0.01
            } else if (e.key === "ArrowRight") {
                spotDir_x += 0.01
            }
            gl.uniform3fv(spotDir, [spotDir_x, spotDir_y, spotDir_z]);
        });

        //根据时间绘制
        var tick = function () {
            //变换角度
            currentAngle = animate(currentAngle)
            // gl.enable(gl.BLEND)
            // gl.blendFunc(gl.SRC_ALPHA, gl.DST_ALPHA)
            //绘制三角形
            draw(gl, 36, currentAngle);
            //重复请求
            requestAnimationFrame(tick)
        }
        tick()


    }




    var g_last = Date.now()
    var currentAngle = 0
    function animate(currentAngle) {

        //获取当前时间
        var currentTime = Date.now()
        timeD = currentTime - g_last
        g_last = currentTime

        //计算旋转的角度
        currentAngle = currentAngle + (timeD * 30) / 1000
        return currentAngle %= 360
    }

    function draw(gl, n, currentAngle) {
        const program = gl.program;
        //设置视角矩阵的相关信息(视点,视线,上方向)
        var viewMatrix = new Matrix4();
        viewMatrix.setLookAt(-7, 7, 7, 0, 0, 0, 0, 1, 0);

        //设置模型矩阵的相关信息
        var modelMatrix = new Matrix4();
        modelMatrix.setRotate(currentAngle, 0, 1, 0);

        gl.uniformMatrix4fv(program.modelMatrix, false, modelMatrix.elements);
        viewMatrix.multiply(modelMatrix)





        //设置透视投影矩阵
        var projMatrix = new Matrix4();
        projMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);


        projMatrix.multiply(viewMatrix)

        //将试图矩阵传给u_ViewMatrix变量
        // gl.uniformMatrix4fv(program.mvpMatrix, false, projMatrix.elements);
        gl.uniformMatrix4fv(program.mvpMatrix, false, projMatrix.elements);

        var normalMatrix = new Matrix4()
        normalMatrix.setInverseOf(modelMatrix)
        normalMatrix.transpose()
        gl.uniformMatrix4fv(program.normalMatrix, false, normalMatrix.elements);


        //清空颜色和深度缓冲区
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        //绘制图形
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    }

相关文章

网友评论

      本文标题:2022-10-14 聚光灯

      本文链接:https://www.haomeiwen.com/subject/zrkczrtx.html