返回

ThreeJS renderBufferDirect 源码解析

前端

ThreeJS renderBufferDirect 源码解析

ThreeJS renderBufferDirect 源码位于 ThreeJS 库的 /src/renderers/webgl/WebGLRenderer.js 文件中。该函数用于直接渲染一个缓冲区。

renderBufferDirect: function ( camera, scene, geometry, material, object ) {

    var uniforms, program;

    // Set shader uniforms
    program = setProgram( camera, scene, material, object );

    // If the program is not set, don't render anything
    if ( program === null ) {

        return;

    }

    // TODO: Move this to WebGLRenderer

    var updateBuffers = false;
    var wireframeBit = material.wireframe ? 1 : 0;
    var fogMaterial = material.fog ? 1 : 0;
    var geometryProgram = geometry.program;
    var materialProgram = material.program;

    var index = geometryProgram.id;
    var dataStart = geometryProgram.seq;
    var indexCount = geometryProgram.indexed ? geometry.index.count : geometry.attributes.position.count;

    //

    if ( geometryProgram.needBuffers || geometryProgram.program !== materialProgram ) {

        geometryProgram.needBuffers = false;
        updateBuffers = true;

    }

    if ( materialProgram !== geometryProgram.program ) {

        setProgram( camera, scene, material, object );

    }

    //

    if ( object.morphTargetInfluences !== undefined ) {

        var activeInfluences = [];
        var morphTargetInfluences = object.morphTargetInfluences;

        for ( var i = 0, il = morphTargetInfluences.length; i < il; i ++ ) {

            activeInfluences.push( [ morphTargetInfluences[ i ], i ] );

        }

        activeInfluences.sort( updateMorphs );

        if ( activeInfluences.length > 8 ) {

            activeInfluences.length = 8;

        }

        for ( var i = 0, il = activeInfluences.length; i < il; i ++ ) {

            morphTargetInfluences[ activeInfluences[ i ][ 1 ] ] = activeInfluences[ i ][ 0 ];

        }

    }

    //

    if ( updateBuffers ) {

        setupVertexAttributes( geometry, material, program );

        if ( geometry.type === BufferGeometry ) {

            bindBuffer( gl.ARRAY_BUFFER, geometry.attributes.position.buffer );

        } else if ( geometry.type === InstancedBufferGeometry ) {

            bindBuffer( gl.ARRAY_BUFFER, geometry.attributes.position.data.buffer );
            bindBuffer( gl.ARRAY_BUFFER, geometry.attributes.instanceMatrix.data.buffer );

        }

    }

    //

    if ( object.disableLocalTransform ) {

        setUniformsLightsDirty( program, true );

    } else {

        setUniformsMatricesDirty( program, object, camera );

    }

    // Set the uniforms to use

    uniforms = material.uniforms;

    if ( uniforms.opacity !== undefined ) {

        gl.uniform1f( uniforms.opacity, material.opacity );

    }

    if ( uniforms.diffuse !== undefined ) {

        gl.uniform3fv( uniforms.diffuse, material.color.toArray() );

    }

    if ( uniforms.emissive !== undefined ) {

        gl.uniform3fv( uniforms.emissive, material.emissive.toArray() );

    }

    if ( uniforms.specular !== undefined ) {

        gl.uniform3fv( uniforms.specular, material.specular.toArray() );

    }

    if ( uniforms.shininess !== undefined ) {

        gl.uniform1f( uniforms.shininess, material.shininess );

    }

    //

    if ( uniforms.map !== undefined ) {

        gl.uniform1i( uniforms.map, 0 );
        setTexture2D( program, uniforms.map, texture, 0 );

    }

    if ( uniforms.alphaMap !== undefined ) {

        gl.uniform1i( uniforms.alphaMap, 1 );
        setTexture2D( program, uniforms.alphaMap, texture, 1 );

    }

    if ( uniforms.lightMap !== undefined ) {

        gl.uniform1i( uniforms.lightMap, 2 );
        setTexture2D( program, uniforms.lightMap, texture, 2 );

    }

    if ( uniforms.shadowMap !== undefined ) {

        var shadowMap = material.shadowMap;

        gl.uniform1i( uniforms.shadowMap, 3 );
        gl.uniformMatrix4fv( uniforms.shadowMapSize, false, shadowMap.size );
        gl.uniformMatrix4fv( uniforms.shadowMapMatrix, false, shadowMap.matrix );

    }

    //

    if ( uniforms.bumpMap !== undefined ) {

        gl.uniform1i( uniforms.bumpMap, 4 );
        setTexture2D( program, uniforms.bumpMap, texture, 4 );

    }

    if ( uniforms.normalMap !== undefined ) {

        gl.uniform1i( uniforms.normalMap, 5 );
        setTexture2D( program, uniforms.normalMap, texture, 5 );

    }

    if ( uniforms.specularMap !== undefined ) {

        gl.uniform1i( uniforms.specularMap, 6 );
        setTexture2D( program, uniforms.specularMap, texture, 6 );

    }

    //

    if ( uniforms.envMap !== undefined ) {

        gl.uniform1i( uniforms.envMap, 7 );

        if ( material.envMap.mapping === THREE.CubeReflectionMapping ) {

            gl.uniform1i( uniforms.envMapMode, 3 );
            setTextureCube( program, uniforms.envMap, material.envMap, 7 );

        } else if ( material.envMap.mapping === THREE.CubeRefractionMapping ) {

            gl.uniform1i( uniforms.envMapMode, 2 );
            setTextureCube( program, uniforms.envMap, material.envMap, 7 );

        } else if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) {

            gl.uniform1i( uniforms.envMapMode, 1 );
            setTextureCube( program, uniforms.envMap, material.envMap, 7 );

        } else if ( material.envMap.mapping === THREE.EquirectangularReflectionMapping ) {

            gl.uniform1i( uniforms.envMapMode, 0 );
            setTexture2D( program, uniforms.envMap, texture, 7 );

        }

    }

    //

    if ( uniforms.reflectivity !== undefined ) {

        gl.uniform1f( uniforms.reflectivity, material.reflectivity );

    }

    if ( uniforms.refractionRatio !== undefined ) {

        gl.uniform1f( uniforms.refractionRatio, material.refractionRatio );

    }

    if ( uniforms.wireframe !== undefined ) {

        gl.uniform1i( uniforms.wireframe, wireframeBit );

    }

    if ( uniforms.fog !== undefined ) {

        gl.uniform1i( uniforms.fog, fogMaterial );

    }

    //

    if ( program.isInstancedMesh !== true ) {

        gl.drawArrays( material.wireframe ? gl.LINES : gl.TRIANGLES, dataStart, indexCount );

    } else {

        var instanceStart = geometry.indexStart;
        var instanceCount = geometry.indexCount;

        if ( geometry.type === InstancedBufferGeometry ) {

            instanceCount = Math.min( indexCount, geometry.attributes.instanceMatrix.count );

        }

        gl.drawArraysInstanced( material.wireframe ? gl.LINES : gl.TRIANGLES, 0, instanceCount, instanceStart, instanceCount );

    }

}

ThreeJS renderBufferDirect 源码分析

  1. 设置着色器统一变量

    首先,通过调用 setProgram() 函数设置着色器统一变量。这个函数将设置用于当前渲染的着色器程序,并将统一变量传递给着色器程序。

  2. 设置几何体属性

    如果几何体需要更新缓冲区,则调用 setupVertexAttributes() 函数设置几何体属性。这个函数将绑定几何体的顶点属性缓冲区到相应的着色器属性。

  3. 设置灯光属性

    如果对象的局部变换被禁用,则调用 `setUniforms