ThreeJS WebGLRenderList 画家排序 非透/半透

1,118 阅读1分钟
  • WebGLRenderList类
  • 主要是储存透明(transparent),不透明的物体(opaque),然后进行排序(renderItemsIndex)
  • 当然一个mesh的两个materialindex会被拆成两个,来进行判断
function init() {
    renderItemsIndex = 0;
    opaque.length = 0;
    transparent.length = 0;
}
  • 判断透明与否,通过transparent
  • 然后push到不同的数组里(transparent/opaque)
function push( object, geometry, material, groupOrder, z, group ) {
        const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
        ( material.transparent === true ? transparent : opaque ).push( renderItem );
}
  • renderItems有renderItem,renderItem储存object, geometry, material, groupOrder, z, group属性
function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
        let renderItem = renderItems[ renderItemsIndex ];
        const materialProperties = properties.get( material );
        if ( renderItem === undefined ) {
                renderItem = {
                        id: object.id,
                        object: object,
                        geometry: geometry,
                        material: material,
                        program: materialProperties.program || defaultProgram,
                        groupOrder: groupOrder,
                        renderOrder: object.renderOrder,
                        z: z,
                        group: group
                };
                renderItems[ renderItemsIndex ] = renderItem;
        } else {
                renderItem.id = object.id;
                renderItem.object = object;
                renderItem.geometry = geometry;
                renderItem.material = material;
                renderItem.program = materialProperties.program || defaultProgram;
                renderItem.groupOrder = groupOrder;
                renderItem.renderOrder = object.renderOrder;
                renderItem.z = z;
                renderItem.group = group;
        }
        renderItemsIndex ++;
        return renderItem;
}
  • 非透明使用 从近到远
  • 透明的使用 从远到近
  • 透明材质不考虑 program 和 materialid
function sort( customOpaqueSort, customTransparentSort ) {
        if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
        if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
}
function painterSortStable( a, b ) {
	if ( a.groupOrder !== b.groupOrder ) {
            return a.groupOrder - b.groupOrder;
	} else if ( a.renderOrder !== b.renderOrder ) {
            return a.renderOrder - b.renderOrder;
	} else if ( a.program !== b.program ) {
            return a.program.id - b.program.id;
	} else if ( a.material.id !== b.material.id ) {
            return a.material.id - b.material.id; //materialid进行排序 多层材质的时候要注意
	} else if ( a.z !== b.z ) {
            return a.z - b.z;  //大的在后面
	} else {
            return a.id - b.id;
	}
}
function reversePainterSortStable( a, b ) {
	if ( a.groupOrder !== b.groupOrder ) {
            return a.groupOrder - b.groupOrder;
	} else if ( a.renderOrder !== b.renderOrder ) { 
            return a.renderOrder - b.renderOrder;
	} else if ( a.z !== b.z ) {
            return b.z - a.z;
	} else {
            return a.id - b.id;
	}
}
  • 原文
function WebGLRenderList( properties ) {
	const renderItems = [];
	let renderItemsIndex = 0;
	const opaque = [];
	const transparent = [];
	const defaultProgram = { id: - 1 };
	function init() {
		renderItemsIndex = 0;
		opaque.length = 0;
		transparent.length = 0;
	}
	function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
		let renderItem = renderItems[ renderItemsIndex ];
		const materialProperties = properties.get( material );
		if ( renderItem === undefined ) {
			renderItem = {
				id: object.id,
				object: object,
				geometry: geometry,
				material: material,
				program: materialProperties.program || defaultProgram,
				groupOrder: groupOrder,
				renderOrder: object.renderOrder,
				z: z,
				group: group
			};
			renderItems[ renderItemsIndex ] = renderItem;
		} else {
			renderItem.id = object.id;
			renderItem.object = object;
			renderItem.geometry = geometry;
			renderItem.material = material;
			renderItem.program = materialProperties.program || defaultProgram;
			renderItem.groupOrder = groupOrder;
			renderItem.renderOrder = object.renderOrder;
			renderItem.z = z;
			renderItem.group = group;
		}
		renderItemsIndex ++;
		return renderItem;
	}
	function push( object, geometry, material, groupOrder, z, group ) {
		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
		( material.transparent === true ? transparent : opaque ).push( renderItem );
	}
	function unshift( object, geometry, material, groupOrder, z, group ) {
		const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
		( material.transparent === true ? transparent : opaque ).unshift( renderItem );
	}
	function sort( customOpaqueSort, customTransparentSort ) {
		if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
		if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
	}
	function finish() {
		// Clear references from inactive renderItems in the list
		for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
			const renderItem = renderItems[ i ];
			if ( renderItem.id === null ) break;
			renderItem.id = null;
			renderItem.object = null;
			renderItem.geometry = null;
			renderItem.material = null;
			renderItem.program = null;
			renderItem.group = null;
		}
	}
	return {
		opaque: opaque,
		transparent: transparent,
		init: init,
		push: push,
		unshift: unshift,
		finish: finish,
		sort: sort
	};
}
function WebGLRenderLists( properties ) {
	let lists = new WeakMap();
	function get( scene, renderCallDepth ) {
		let list;
		if ( lists.has( scene ) === false ) {
			list = new WebGLRenderList( properties );
			lists.set( scene, [ list ] );
		} else {
			if ( renderCallDepth >= lists.get( scene ).length ) {
				list = new WebGLRenderList( properties );
				lists.get( scene ).push( list );
			} else {
				list = lists.get( scene )[ renderCallDepth ];
			}
		}
		return list;
	}
	function dispose() {
		lists = new WeakMap();
	}
	return {
		get: get,
		dispose: dispose
	};
}