webgl进阶操作学习

24 阅读3分钟

光照

首先的作用就是让立方体有棱角

光照分为:

点光源(灯泡,火焰等)定义一个点光源需要光源的位置,光线方向以及颜色,照射点的位置不同,光的方向也不同

平行光(太阳光)只需要光照方向和光照颜色

环境光:光源发出后,经过其他物体的反射,照到物体表面上的光线。环境光强度差距非常小,没有必要精确计算光线强度,只需要定义光照颜色

环境反射:环境反射是针对环境光而言的,环境反射中,环境光照射物体各方面均匀,强度相等,反射的方向就是入射光的反方向,最终物体的颜色只跟入射光颜色和基底色有关 环境光颜色 = 入射光颜色 * 基底色

漫反射:漫反射中反射光的颜色取决于入射光的颜色,表面基底色,还有入射光与物体表面的法向量的入射角 漫反射颜色 = 入射光颜色 * 基底色 * cos deg 光线方向和法线方向的点积 = cos deg

    const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    //法向量,需要计算
    attribute vec4 aNormal;
    varying vec4 vColor;
    uniform mat4 mat;
    void main(){
        //定义点光源的颜色
        vec3 uPointLightColor = vec3(1.0,1.0,0.0);
        //定义点光源的位置
        vec3 uPointLightPosition = vec3(-5.0,6.0,10.0);
        //环境光
        vec3 uAmbientLightColor = vec3(0.2,0.2,0.2);
        //物体表面颜色
        vec4 aColor = vec4(1.0,0.0,0.0,1.0);
        //顶点的世界坐标
        vec4 vertexPosition = mat * aPosition;
        //点光源的方向(点光源的位置和世界坐标的差值取得)
        vec3 lightDirection = normalize(uPointLightPosition-vec3(vertexPosition));
        //环境反射
        vec3 ambient = uAmbientLightColor * vec3(aColor);
        //计算入射角 光线方向和法线方向的点积
        float dotDeg = dot(lightDirection,vec3(aNormal));
        //漫反射光的颜色
        vec3 diffuseColor = uPointLightColor * vec3(aColor) * dotDeg;

        gl_Position =vertexPosition;
        //环境反射和漫反射相加就是看到的物体表面的颜色
        vColor = vec4(ambient + diffuseColor,aColor.a);

    }
    ` //顶点着色器
        //创建法向量数据,数据需要和顶点数据保持一致(4份)
    const normal = new Float32Array([
    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,//下
    ])
    const normalBuffer = gl.createBuffer()

    gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer)

    gl.bufferData(gl.ARRAY_BUFFER, normal, gl.STATIC_DRAW)

    gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);

    gl.enableVertexAttribArray(aNormal)

...
      
    gl.enable(gl.DEPTH_TEST)

添加光源的代码,没有效果。开启gl.DEPTH_TEST后可以正常显示

雾化

表示距离越远看的越模糊,雾化实现 通过某点和视点的距离,距离越远,雾化程度越高,这种雾化叫线性雾化,某一点的雾化程度叫做雾化因子

image.png

雾化因子计算: 雾化因子 = (终点 - 当前点)/(终点 - 起点)

物体颜色计算: 颜色 = 物体颜色 * 雾化因子 + 雾化颜色 * (1 - 雾化因子)


    const start = 0
    const end = 200
    const FogColor = new Float32Array([0.0,0.0,0.0])
    const FogDist = new Float32Array([start,end])
    const uFogColor = gl.getUniformLocation(program, 'uFogColor')
    const uFogDist = gl.getUniformLocation(program, 'uFogDist')

    
    const matrix = getViewMatrix(3, 3, 5, 0.0, 0.0, 0.0, 0.0, 0.6, 0.0)
    
    const perspective = getPerspective(30, ctx.width / ctx.height, 100, 1)
    
    gl.uniformMatrix4fv(mat, false,mixMatrix(perspective, matrix));
    
    gl.uniform3fv(uFogColor,FogColor)
    function draw(){
        FogDist[1] -=1
        if(FogDist[1]>start){
            FogDist[1]=end
        }
        // gl.enable(gl.DEPTH_TEST)
        gl.uniform2fv(uFogDist,FogDist)
        gl.drawElements(gl.TRIANGLES, index.length,gl.UNSIGNED_BYTE,0);
        requestAnimationFrame(draw)
    }

    draw()

着色器代码

    const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;
varying float vDist;
    varying vec4 vColor;

    //雾化颜色
    uniform vec3 uFogColor;
    //起点到终点的距离,第一个是起点,第二个是终点
    uniform vec2 uFogDist;

    void main(){
        //计算雾化因子
        float fogFactor = (uFogDist.y-vDist)/(uFogDist.y-uFogDist.x);
        //计算颜色
        //mix 线性混合计算mix(x,y,z) x*(1-z) + y*z
        vec3 color = mix(uFogColor,vec3(vColor),fogFactor);

        gl_FragColor = vec4(color,vColor.a);

    }
    `//片元着色器

没有视频中的效果,不知道为什么

绘制圆点

绘制圆点需要修改片元着色器

计算距离+判断:

    const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;

    void main(){
        //计算距离(当前绘制的点和定义的范围的距离)
        //                   当前绘制的点的位置
        float dis = distance(gl_PointCoord,vec2(0.5,0.5));
        // 大于为白色,没有大于为红色
        if(dis>0.5){
            gl_FragColor = vec4(1.0,1.0,1.0,1.0);
            //或者使用discard
            //大于 0.5直接放弃绘制
            discard;
        }
        else{
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }

    }
    `//片元着色器

绘制半透明物体

直接将rgba中的a改小并不能实现效果,只会让颜色变模糊

    //着色器中需要改变vColor的alpha
    
    gl.enable(gl.BLEND)
    gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_CONSTANT_ALPHA)
    
    //删掉 gl.enable(gl.DEPTH_TEST)