|
@@ -15,6 +15,63 @@ import {
|
|
|
Vector3,
|
|
|
} from 'three';
|
|
|
|
|
|
+function sortOpaque( a, b ) {
|
|
|
+
|
|
|
+ return a.z - b.z;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+function sortTransparent( a, b ) {
|
|
|
+
|
|
|
+ return b.z - a.z;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+class MultiDrawRenderList {
|
|
|
+
|
|
|
+ constructor() {
|
|
|
+
|
|
|
+ this.index = 0;
|
|
|
+ this.pool = [];
|
|
|
+ this.list = [];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ push( drawRange, z ) {
|
|
|
+
|
|
|
+ const pool = this.pool;
|
|
|
+ const list = this.list;
|
|
|
+ if ( this.index >= pool.length ) {
|
|
|
+
|
|
|
+ pool.push( {
|
|
|
+
|
|
|
+ start: - 1,
|
|
|
+ count: - 1,
|
|
|
+ z: - 1,
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const item = pool[ this.index ];
|
|
|
+ list.push( item );
|
|
|
+ this.index ++;
|
|
|
+
|
|
|
+ item.start = drawRange.start;
|
|
|
+ item.count = drawRange.count;
|
|
|
+ item.z = z;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ reset() {
|
|
|
+
|
|
|
+ this.list.length = 0;
|
|
|
+ this.index = 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
const ID_ATTR_NAME = 'batchId';
|
|
|
const _matrix = new Matrix4();
|
|
|
const _identityMatrix = new Matrix4();
|
|
@@ -23,6 +80,7 @@ const _frustum = new Frustum();
|
|
|
const _box = new Box3();
|
|
|
const _sphere = new Sphere();
|
|
|
const _vector = new Vector3();
|
|
|
+const _renderList = new MultiDrawRenderList();
|
|
|
const _mesh = new Mesh();
|
|
|
const _batchIntersects = [];
|
|
|
|
|
@@ -72,6 +130,7 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
this.isBatchedMesh = true;
|
|
|
this.perObjectFrustumCulled = true;
|
|
|
+ this.sortObjects = true;
|
|
|
this.boundingBox = null;
|
|
|
this.boundingSphere = null;
|
|
|
|
|
@@ -799,6 +858,7 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
this.geometry = source.geometry.clone();
|
|
|
this.perObjectFrustumCulled = source.perObjectFrustumCulled;
|
|
|
+ this.sortObjects = source.sortObjects;
|
|
|
this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
|
|
|
this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
|
|
|
|
|
@@ -869,30 +929,87 @@ class BatchedMesh extends Mesh {
|
|
|
}
|
|
|
|
|
|
let count = 0;
|
|
|
- for ( let i = 0, l = visible.length; i < l; i ++ ) {
|
|
|
|
|
|
- if ( visible[ i ] ) {
|
|
|
+ if ( this.sortObjects ) {
|
|
|
|
|
|
- // determine whether the batched geometry is within the frustum
|
|
|
- let culled = false;
|
|
|
- if ( perObjectFrustumCulled ) {
|
|
|
+ // get the camera position
|
|
|
+ _vector.setFromMatrixPosition( camera.matrixWorld );
|
|
|
|
|
|
- // get the bounds in camera space
|
|
|
- this.getMatrixAt( i, _matrix );
|
|
|
+ for ( let i = 0, l = visible.length; i < l; i ++ ) {
|
|
|
|
|
|
- // get the bounds
|
|
|
- this.getBoundingBoxAt( i, _box ).applyMatrix4( _matrix );
|
|
|
+ if ( visible[ i ] ) {
|
|
|
+
|
|
|
+ this.getMatrixAt( i, _matrix );
|
|
|
this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
|
- culled = ! _frustum.intersectsBox( _box ) || ! _frustum.intersectsSphere( _sphere );
|
|
|
+
|
|
|
+ // determine whether the batched geometry is within the frustum
|
|
|
+ let culled = false;
|
|
|
+ if ( perObjectFrustumCulled ) {
|
|
|
+
|
|
|
+ // get the bounds in camera space
|
|
|
+ this.getMatrixAt( i, _matrix );
|
|
|
+
|
|
|
+ // get the bounds
|
|
|
+ this.getBoundingBoxAt( i, _box ).applyMatrix4( _matrix );
|
|
|
+ culled = ! _frustum.intersectsBox( _box ) || ! _frustum.intersectsSphere( _sphere );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( ! culled ) {
|
|
|
+
|
|
|
+ // get the distance from camera used for sorting
|
|
|
+ const z = _vector.distanceToSquared( _sphere.center );
|
|
|
+ _renderList.push( drawRanges[ i ], z );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( ! culled ) {
|
|
|
+ }
|
|
|
+
|
|
|
+ // Sort the draw ranges and prep for rendering
|
|
|
+ const list = _renderList.list;
|
|
|
+ list.sort( material.transparent ? sortTransparent : sortOpaque );
|
|
|
+
|
|
|
+ for ( let i = 0, l = list.length; i < l; i ++ ) {
|
|
|
+
|
|
|
+ const item = list[ i ];
|
|
|
+ multiDrawStarts[ count ] = item.start * bytesPerElement;
|
|
|
+ multiDrawCounts[ count ] = item.count;
|
|
|
+ count ++;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _renderList.reset();
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ for ( let i = 0, l = visible.length; i < l; i ++ ) {
|
|
|
+
|
|
|
+ if ( visible[ i ] ) {
|
|
|
+
|
|
|
+ // determine whether the batched geometry is within the frustum
|
|
|
+ let culled = false;
|
|
|
+ if ( perObjectFrustumCulled ) {
|
|
|
+
|
|
|
+ // get the bounds in camera space
|
|
|
+ this.getMatrixAt( i, _matrix );
|
|
|
+
|
|
|
+ // get the bounds
|
|
|
+ this.getBoundingBoxAt( i, _box ).applyMatrix4( _matrix );
|
|
|
+ this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
|
+ culled = ! _frustum.intersectsBox( _box ) || ! _frustum.intersectsSphere( _sphere );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( ! culled ) {
|
|
|
+
|
|
|
+ const range = drawRanges[ i ];
|
|
|
+ multiDrawStarts[ count ] = range.start * bytesPerElement;
|
|
|
+ multiDrawCounts[ count ] = range.count;
|
|
|
+ count ++;
|
|
|
|
|
|
- const range = drawRanges[ i ];
|
|
|
- multiDrawStarts[ count ] = range.start * bytesPerElement;
|
|
|
- multiDrawCounts[ count ] = range.count;
|
|
|
- count ++;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|