美文网首页
2022-10-29 雾化

2022-10-29 雾化

作者: MrSwilder | 来源:发表于2022-10-30 20:17 被阅读0次

    一 、原理

    在三维图形学中,术语雾化(fog)用来描述远处的物体看上去较为模糊的现象。在现实中,任何介质中的物体都可能表现出雾化现象,比如水下的物体。

    如何实现雾化:

    实现雾化的方式有很多种,这里使用最简单的一种:线性雾化(linear fog)。在线性雾化中,某一点的雾化程度取决于它与视点之间的距离,距离越远雾化程度越高。线性雾化有起点和终点,起点表示开始雾化之处,终点表示完全雾化之处,两点之间的某一点的雾化程度与该点与视点的距离呈线性关系。注意,比终点更远的点完全雾化了,即完全看不见了。某一点雾化的程度可以被定义为雾化因子(fog factor),并在线性雾化公式中被计算出来。

    <雾化因子> = ( <终点> - <当前点与视点间的距离>) / ( <终点> - <起点> )

    这里

    <起点> 小于等于 <当前点与视点间的距离> 小于等于 <终点>

    如果雾化因子为1.0,表示该点完全没有被雾化,可以很清晰地看到此处的物体。如果其为0.0,就表示该点完全雾化了,此处的物体完全看不见,如图10.8所示。在视线上,起点之前的点的雾化因子为1.0,终点之后的点的雾化因子为0.0 。

    在片元着色器中根据雾化因子计算片元的颜色:

    <片元颜色> = <物体表面颜色> x <雾化因子> + <雾的颜色> x ( 1 - <雾化因子> )

    二、效果

    image.png

    三、代码

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>雾化</title>
        <style>
            body {
                margin: 0;
                text-align: center;
            }
    
            #canvas {
                margin: 0;
            }
        </style>
    </head>
    
    <body onload="main()">
        <canvas id="canvas" height="800" width="1200"></canvas>
    </body>
    <script src="/lib/webgl-utils.js"></script>
    <script src="/lib/webgl-debug.js"></script>
    <script src="/lib/cuon-utils.js"></script>
    <script src="/lib/cuon-matrix.js"></script>
    <script src="/lib/helper.js"></script>
    <script src="/geometry/SphereGeometry.js"></script>
    <script src="/texture/Texture2D.js"></script>
    <script>
        //顶点着色器
        var VSHADER_SOURCE = /*glsl*/`
            attribute vec2 a_Uv;
            attribute vec4 a_Position;
            uniform mat4 u_MvpMatrix; 
            varying vec2 v_Uv;
            varying float v_dist;
            void main(){ 
                vec4 clip_Position=u_MvpMatrix*a_Position;
                gl_Position=clip_Position;
                v_Uv=a_Uv;
                v_dist=gl_Position.w;
            }`;
    
        //片元着色器
        var FSHADER_SOURCE = /*glsl*/`
            #ifdef GL_ES
            precision mediump float;
            #endif
            uniform sampler2D u_Texture;
            
            varying vec2 v_Uv;
            varying float v_dist;
            void main(){
                vec3 fogColor=vec3(1.0,1.0,1.0);
                //定义最大最小值
                float fogDistMax=3.6;
                float fogDistMin=3.0;
                //计算雾化因子
                float factor=clamp((fogDistMax-v_dist)/(fogDistMax-fogDistMin),0.0,1.0);
                vec4 baseColor=texture2D(u_Texture,vec2(v_Uv.x,1.0-v_Uv.y));
               gl_FragColor =vec4( mix(baseColor.rgb,fogColor,1.0-1.0*factor),baseColor.a);
            // gl_FragColor=vec4(baseColor.rgb,v_dist*0.5);
           
            }`;
    
        //声明js需要的相关变量
        var canvas = document.getElementById("canvas");
        var gl = getWebGLContext(canvas);
         //设置视角矩阵的相关信息(视点,视线,上方向)
        var viewMatrix = new Matrix4();
    
    
    
        //设置透视投影矩阵
        var projMatrix = new Matrix4();
        projMatrix.setPerspective(30, canvas.width / canvas.height,0.1, 10);
    
        const rotateViewMatrix=new Matrix4()
    
    
        var currentAngle = [0,0]
        async function main() {
            if (!gl) {
                console.log("你的浏览器不支持WebGL");
                return;
            }
    
            const program=createProgram(gl,VSHADER_SOURCE,FSHADER_SOURCE)
    
            if(!program){
                console.error('创建着色器程序失败')
                return
            }
    
            gl.program=program
            gl.useProgram(program)
    
            getVariableLocation()
    
            //绘制球形
            const sphereGeometry=new SphereGeometry(gl,1,180,90)
            const sphere= sphereGeometry.create()
            //绘制纹理
            const texture=Texture2D.initTexture(gl,'./image/earth.jpg', 0)
            //设置底色
            gl.clearColor(0.0,0.0,0.0, 1.0);
           
            var tick = function () {
                viewMatrix.setLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);
                rotateViewMatrix.setRotate(currentAngle[1],1,0,0)
                rotateViewMatrix.rotate(currentAngle[0],0,1,0)
                viewMatrix.multiply(rotateViewMatrix)
    
                draw(gl, sphere)
                requestAnimationFrame(tick)
            }
            tick()
            
    
            registerMouseEvent()
        }
    
        /**
         * 
         * 注册鼠标事件
         * */
        function registerMouseEvent(){
            //是否按下
            let isDown=false
            let last_X=0,last_Y=0
            canvas.onmousedown=function(e){
                //获取当前鼠标位置
                const x=e.clientX,y=e.clientY
                //获取canvas边界范围
                const bound=e.target.getBoundingClientRect()
    
                if(bound.left<x&&bound.right>x&&bound.top<y&&bound.bottom>y){
    
                    last_X=x
                    last_Y=y
                    isDown=true
                }   
               
            }
    
            canvas.onmousemove=function(e){
                // console.log('鼠标移动',e)
                const x=e.clientX,y=e.clientY
                if(isDown){
                   
                    const offset_X=x-last_X
                    const offset_Y=y-last_Y
                    currentAngle[0]+=offset_X/10
                    currentAngle[1]+=offset_Y/10
            
                 
    
                }
                last_X=x
                last_Y=y
            }
    
    
            canvas.onmouseup=function(e){
                isDown=false
               
            }
        }
    
        function draw(gl, sphere) {
           
    
            //设置模型矩阵的相关信息
            var modelMatrix = new Matrix4();
    
            var mvpMatrix=new Matrix4()
            mvpMatrix.set(projMatrix)
           
            mvpMatrix.multiply(viewMatrix.multiply(modelMatrix));
    
    
            //将试图矩阵传给u_ViewMatrix变量
            gl.uniformMatrix4fv(gl.program.mvpMatrix, false, mvpMatrix.elements);
    
            //开启隐藏面清除
            gl.enable(gl.DEPTH_TEST);
    
            //清空颜色和深度缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
            const length=sphere.length
    
            //绘制图形
            gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0);
    
    
    
        }
    
    
    
    
    
    </script>
    
    </html>
    

    相关文章

      网友评论

          本文标题:2022-10-29 雾化

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