ThreeJS 多Material源码解析 多层材质 projectObject renderObject

1,049 阅读1分钟
  • 一Materail的初始设置
mesh = new THREE.Mesh( geometry, material );
  • Mesh返回的Material对象是对象
material: MeshBasicMaterial
  • 多Material的初始设置
//mesh.geometry.addGroup(0, +Infinity, 0) //一般不这么写,会触发BUG,射线选中的BUG
//mesh.geometry.addGroup(0, +Infinity, 1)
mesh.geometry.addGroup(0,mesh.geometry.index.count,0);
mesh.geometry.addGroup(0,mesh.geometry.index.count,1)
let boxMesh = new THREE.Mesh(mesh.geometry,  [material1,material2])
  • Mesh返回的material对象是数组
geometry: Model
    groups: Array(2)
        0: {start: 0, count: xxxxx, materialIndex: 0} //最里层
        1: {start: 0, count: xxxxx, materialIndex: 1} //最外层
material: Array(2)
    0: MeshStandardSGMaterial
    1: MeshStandardSGMaterial
  • AddGroup 源码
addGroup: function (start, count, materialIndex) {
        this.groups.push({
                start: start,
                count: count,
                materialIndex: materialIndex !== undefined ? materialIndex : 0
        });
},
  • projectObject
/**
 * @desc 场景内的对象分类并生成渲染对象<br />
 * 分为光照,闪光,透镜,普通等几类
 * @param {THREE.Scene} scene 场景对象
 * @param {THREE.Object3D} object 3D对象
 */
function projectObject( object, camera, groupOrder, sortObjects ) {
        if ( object.visible === false ) return;
        const visible = object.layers.test( camera.layers );
        if ( visible ) {
                if ( object.isGroup ) {
                        groupOrder = object.renderOrder;
                } else if ( object.isLOD ) {
                        if ( object.autoUpdate === true ) object.update( camera );
                } else if ( object.isLight ) {//光照与其他 Object3D 不一样,它是另外单独被放在 currentRenderState 中的。
                        currentRenderState.pushLight( object );
                        if ( object.castShadow ) {
                                currentRenderState.pushShadow( object );
                        }
                } else if ( object.isSprite ) {
                        if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
                                if ( sortObjects ) {
                                        _vector3
                                                .setFromMatrixPosition( object.matrixWorld )
                                                .applyMatrix4( _projScreenMatrix );
                                }
                                const geometry = objects.update( object );
                                const material = object.material;
                                if ( material.visible ) {
                                        currentRenderList.push(
                                                object,
                                                geometry,
                                                material,
                                                groupOrder,
                                                _vector3.z,
                                                null
                                        );
                                }
                        }
                } else if ( object.isImmediateRenderObject ) {
                        if ( sortObjects ) {
                                _vector3
                                        .setFromMatrixPosition( object.matrixWorld )
                                        .applyMatrix4( _projScreenMatrix );
                        }
                        currentRenderList.push(
                                object,
                                null,
                                object.material,
                                groupOrder,
                                _vector3.z,
                                null
                        );
                } else if ( object.isMesh || object.isLine || object.isPoints ) {
                        if ( object.isSkinnedMesh ) {
                                // update skeleton only once in a frame
                                if ( object.skeleton.frame !== info.render.frame ) {
                                        object.skeleton.update();
                                        object.skeleton.frame = info.render.frame;
                                }
                        }
                        if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
                                if ( sortObjects ) {
                                        _vector3
                                                .setFromMatrixPosition( object.matrixWorld )
                                                .applyMatrix4( _projScreenMatrix );
                                }
                                const geometry = objects.update( object );
                                const material = object.material;
                                if ( Array.isArray( material ) ) {
                                        const groups = geometry.groups;
                                        for ( let i = 0, l = groups.length; i < l; i ++ ) {
                                                const group = groups[ i ];
                                                const groupMaterial = material[ group.materialIndex ];
                                                if ( groupMaterial && groupMaterial.visible ) {
                                                        currentRenderList.push(
                                                                object,
                                                                geometry,
                                                                groupMaterial,
                                                                groupOrder,
                                                                _vector3.z,
                                                                group
                                                        );
                                                }
                                        }
                                } else if ( material.visible ) {
                                        currentRenderList.push(
                                                object,
                                                geometry,
                                                material,
                                                groupOrder,
                                                _vector3.z,
                                                null
                                        );
                                }
                        }
                }
        }

        // 遍历子对象,进行构建渲染对象
        const children = object.children;
        for ( let i = 0, l = children.length; i < l; i ++ ) {
                projectObject( children[ i ], camera, groupOrder, sortObjects );
        }
}
  • renderObject
function renderObject( object, camera, shadowCamera, light, type ) {
        if ( object.visible === false ) return;
        const visible = object.layers.test( camera.layers );
        if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
                if (
                        ( object.castShadow ||
                                ( object.receiveShadow && type === VSMShadowMap ) ) &&
                        ( ! object.frustumCulled || _frustum.intersectsObject( object ) )
                ) {
                        object.modelViewMatrix.multiplyMatrices(
                                shadowCamera.matrixWorldInverse,
                                object.matrixWorld
                        );
                        const geometry = _objects.update( object );
                        const material = object.material;
                        if ( Array.isArray( material ) ) {
                                const groups = geometry.groups;
                                for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
                                        const group = groups[ k ];
                                        const groupMaterial = material[ group.materialIndex ];
                                        if ( groupMaterial && groupMaterial.visible ) {
                                                const depthMaterial = getDepthMaterial(
                                                        object,
                                                        geometry,
                                                        groupMaterial,
                                                        light,
                                                        shadowCamera.near,
                                                        shadowCamera.far,
                                                        type
                                                );
                                                _renderer.renderBufferDirect(
                                                        shadowCamera,
                                                        null,
                                                        geometry,
                                                        depthMaterial,
                                                        object,
                                                        group
                                                );
                                        }
                                }
                        } else if ( material.visible ) {
                                const depthMaterial = getDepthMaterial(
                                        object,
                                        geometry,
                                        material,
                                        light,
                                        shadowCamera.near,
                                        shadowCamera.far,
                                        type
                                );
                                _renderer.renderBufferDirect(
                                        shadowCamera,
                                        null,
                                        geometry,
                                        depthMaterial,
                                        object,
                                        null
                                );
                        }
                }
        }
        const children = object.children;
        for ( let i = 0, l = children.length; i < l; i ++ ) {
                renderObject( children[ i ], camera, shadowCamera, light, type );
        }
}