super-three 0.158.0 → 0.160.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.cjs +1719 -379
- package/build/three.js +1719 -379
- package/build/three.min.js +1 -1
- package/build/three.module.js +1718 -380
- package/build/three.module.min.js +1 -1
- package/examples/jsm/Addons.js +2 -1
- package/examples/jsm/controls/OrbitControls.js +50 -40
- package/examples/jsm/csm/CSMShader.js +52 -47
- package/examples/jsm/exporters/GLTFExporter.js +79 -1
- package/examples/jsm/exporters/USDZExporter.js +27 -19
- package/examples/jsm/helpers/TextureHelper.js +237 -0
- package/examples/jsm/interactive/HTMLMesh.js +9 -2
- package/examples/jsm/lines/LineMaterial.js +16 -33
- package/examples/jsm/loaders/ColladaLoader.js +0 -6
- package/examples/jsm/loaders/DRACOLoader.js +4 -3
- package/examples/jsm/loaders/FBXLoader.js +294 -124
- package/examples/jsm/loaders/GLTFLoader.js +71 -3
- package/examples/jsm/loaders/MaterialXLoader.js +73 -54
- package/examples/jsm/loaders/NRRDLoader.js +0 -13
- package/examples/jsm/loaders/SVGLoader.js +4 -4
- package/examples/jsm/loaders/USDZLoader.js +3 -17
- package/examples/jsm/math/Octree.js +15 -4
- package/examples/jsm/misc/Timer.js +119 -0
- package/examples/jsm/misc/TubePainter.js +3 -6
- package/examples/jsm/modifiers/CurveModifier.js +20 -2
- package/examples/jsm/nodes/Nodes.js +11 -7
- package/examples/jsm/nodes/accessors/CameraNode.js +18 -2
- package/examples/jsm/nodes/accessors/CubeTextureNode.js +5 -73
- package/examples/jsm/nodes/accessors/MaterialReferenceNode.js +11 -2
- package/examples/jsm/nodes/accessors/ModelNode.js +1 -1
- package/examples/jsm/nodes/accessors/ModelViewProjectionNode.js +12 -3
- package/examples/jsm/nodes/accessors/MorphNode.js +191 -16
- package/examples/jsm/nodes/accessors/ReferenceNode.js +25 -1
- package/examples/jsm/nodes/accessors/TextureNode.js +122 -36
- package/examples/jsm/nodes/code/CodeNode.js +3 -3
- package/examples/jsm/nodes/core/AttributeNode.js +7 -1
- package/examples/jsm/nodes/core/CacheNode.js +4 -1
- package/examples/jsm/nodes/core/ConstNode.js +1 -1
- package/examples/jsm/nodes/core/Node.js +6 -3
- package/examples/jsm/nodes/core/NodeBuilder.js +84 -27
- package/examples/jsm/nodes/core/NodeFrame.js +10 -8
- package/examples/jsm/nodes/core/NodeUniform.js +12 -0
- package/examples/jsm/nodes/core/NodeUtils.js +3 -7
- package/examples/jsm/nodes/core/OutputStructNode.js +3 -3
- package/examples/jsm/nodes/core/PropertyNode.js +17 -2
- package/examples/jsm/nodes/core/StructTypeNode.js +4 -4
- package/examples/jsm/nodes/core/UniformGroup.js +13 -0
- package/examples/jsm/nodes/core/UniformGroupNode.js +36 -0
- package/examples/jsm/nodes/core/UniformNode.js +17 -0
- package/examples/jsm/nodes/core/VarNode.js +2 -0
- package/examples/jsm/nodes/core/VaryingNode.js +1 -7
- package/examples/jsm/nodes/display/BumpMapNode.js +1 -1
- package/examples/jsm/nodes/display/ColorAdjustmentNode.js +6 -10
- package/examples/jsm/nodes/display/GaussianBlurNode.js +170 -0
- package/examples/jsm/nodes/display/PassNode.js +182 -0
- package/examples/jsm/nodes/display/ViewportDepthNode.js +31 -3
- package/examples/jsm/nodes/display/ViewportDepthTextureNode.js +2 -2
- package/examples/jsm/nodes/display/ViewportNode.js +5 -8
- package/examples/jsm/nodes/functions/PhysicalLightingModel.js +1 -1
- package/examples/jsm/nodes/lighting/AnalyticLightNode.js +52 -17
- package/examples/jsm/nodes/lighting/EnvironmentNode.js +8 -12
- package/examples/jsm/nodes/lighting/LightsNode.js +34 -32
- package/examples/jsm/nodes/materials/InstancedPointsNodeMaterial.js +1 -1
- package/examples/jsm/nodes/materials/Line2NodeMaterial.js +12 -12
- package/examples/jsm/nodes/materials/MeshBasicNodeMaterial.js +1 -0
- package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +1 -1
- package/examples/jsm/nodes/materials/NodeMaterial.js +66 -41
- package/examples/jsm/nodes/materials/PointsNodeMaterial.js +0 -10
- package/examples/jsm/nodes/materials/SpriteNodeMaterial.js +0 -7
- package/examples/jsm/nodes/materialx/MaterialXNodes.js +10 -10
- package/examples/jsm/nodes/materialx/lib/mx_hsv.js +128 -54
- package/examples/jsm/nodes/materialx/lib/mx_noise.js +1430 -618
- package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +24 -14
- package/examples/jsm/nodes/math/MathNode.js +2 -0
- package/examples/jsm/nodes/math/OperatorNode.js +19 -6
- package/examples/jsm/nodes/shadernode/ShaderNode.js +32 -3
- package/examples/jsm/nodes/utils/FunctionOverloadingNode.js +95 -0
- package/examples/jsm/nodes/utils/RemapNode.js +2 -2
- package/examples/jsm/nodes/utils/SplitNode.js +8 -2
- package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +3 -3
- package/examples/jsm/objects/QuadMesh.js +60 -0
- package/examples/jsm/postprocessing/GTAOPass.js +572 -0
- package/examples/jsm/postprocessing/OutputPass.js +2 -0
- package/examples/jsm/renderers/common/Animation.js +10 -21
- package/examples/jsm/renderers/common/Backend.js +19 -3
- package/examples/jsm/renderers/common/Background.js +20 -22
- package/examples/jsm/renderers/common/Bindings.js +30 -21
- package/examples/jsm/renderers/common/ChainMap.js +3 -3
- package/examples/jsm/renderers/common/Color4.js +37 -0
- package/examples/jsm/renderers/common/Geometries.js +4 -4
- package/examples/jsm/renderers/common/Info.js +12 -2
- package/examples/jsm/renderers/common/Pipelines.js +3 -51
- package/examples/jsm/renderers/common/PostProcessing.js +25 -0
- package/examples/jsm/renderers/common/RenderContext.js +1 -1
- package/examples/jsm/renderers/common/RenderContexts.js +1 -1
- package/examples/jsm/renderers/common/RenderObject.js +13 -1
- package/examples/jsm/renderers/common/RenderObjects.js +4 -2
- package/examples/jsm/renderers/common/Renderer.js +137 -37
- package/examples/jsm/renderers/common/StorageTexture.js +1 -0
- package/examples/jsm/renderers/common/Textures.js +4 -1
- package/examples/jsm/renderers/common/nodes/NodeBuilderState.js +10 -2
- package/examples/jsm/renderers/common/nodes/NodeUniformsGroup.js +44 -0
- package/examples/jsm/renderers/common/nodes/Nodes.js +74 -7
- package/examples/jsm/renderers/webgl/WebGLBackend.js +91 -33
- package/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +100 -31
- package/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js +57 -5
- package/examples/jsm/renderers/webgl/utils/WebGLCapabilities.js +36 -0
- package/examples/jsm/renderers/webgl/utils/WebGLExtensions.js +11 -1
- package/examples/jsm/renderers/webgl/utils/WebGLTextureUtils.js +71 -2
- package/examples/jsm/renderers/webgl/utils/WebGLUtils.js +42 -0
- package/examples/jsm/renderers/webgl-legacy/nodes/SlotNode.js +1 -1
- package/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodeBuilder.js +33 -3
- package/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodes.js +4 -14
- package/examples/jsm/renderers/webgpu/WebGPUBackend.js +186 -137
- package/examples/jsm/renderers/webgpu/WebGPURenderer.js +1 -1
- package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +209 -90
- package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +15 -10
- package/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +11 -3
- package/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js +2 -3
- package/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +88 -6
- package/examples/jsm/shaders/FXAAShader.js +133 -133
- package/examples/jsm/shaders/GTAOShader.js +424 -0
- package/examples/jsm/shaders/OutputShader.js +4 -0
- package/examples/jsm/shaders/PoissonDenoiseShader.js +226 -0
- package/examples/jsm/shaders/SAOShader.js +2 -3
- package/examples/jsm/shaders/SSAOShader.js +2 -3
- package/examples/jsm/transpiler/AST.js +40 -1
- package/examples/jsm/transpiler/GLSLDecoder.js +50 -8
- package/examples/jsm/transpiler/ShaderToyDecoder.js +4 -4
- package/examples/jsm/transpiler/TSLEncoder.js +124 -20
- package/examples/jsm/utils/SortUtils.js +158 -0
- package/examples/jsm/utils/TextureUtils.js +33 -21
- package/examples/jsm/webxr/ARButton.js +14 -0
- package/examples/jsm/webxr/VRButton.js +23 -8
- package/examples/jsm/webxr/XRButton.js +25 -11
- package/package.json +5 -6
- package/src/Three.js +1 -0
- package/src/constants.js +2 -1
- package/src/core/BufferAttribute.js +21 -2
- package/src/core/InterleavedBuffer.js +21 -1
- package/src/core/Object3D.js +60 -12
- package/src/core/UniformsGroup.js +7 -1
- package/src/extras/curves/LineCurve3.js +4 -0
- package/src/loaders/AudioLoader.js +1 -1
- package/src/loaders/BufferGeometryLoader.js +0 -7
- package/src/loaders/ImageBitmapLoader.js +25 -1
- package/src/loaders/ObjectLoader.js +49 -0
- package/src/materials/ShaderMaterial.js +2 -1
- package/src/math/ColorManagement.js +0 -16
- package/src/math/Quaternion.js +5 -4
- package/src/math/Sphere.js +2 -0
- package/src/math/Triangle.js +17 -5
- package/src/objects/BatchedMesh.js +1020 -0
- package/src/objects/Skeleton.js +1 -3
- package/src/renderers/WebGL3DRenderTarget.js +2 -2
- package/src/renderers/WebGLArrayRenderTarget.js +2 -2
- package/src/renderers/WebGLRenderer.js +23 -18
- package/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js +19 -0
- package/src/renderers/shaders/ShaderChunk/batching_vertex.glsl.js +5 -0
- package/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +0 -5
- package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +31 -4
- package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +9 -4
- package/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js +6 -0
- package/src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl.js +9 -17
- package/src/renderers/shaders/ShaderChunk/tonemapping_pars_fragment.glsl.js +84 -0
- package/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js +6 -0
- package/src/renderers/shaders/ShaderChunk.js +4 -0
- package/src/renderers/shaders/ShaderLib/depth.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshbasic.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js +3 -0
- package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/shadow.glsl.js +3 -0
- package/src/renderers/webgl/WebGLAttributes.js +39 -5
- package/src/renderers/webgl/WebGLBufferRenderer.js +31 -0
- package/src/renderers/webgl/WebGLCubeMaps.js +1 -1
- package/src/renderers/webgl/WebGLExtensions.js +1 -0
- package/src/renderers/webgl/WebGLIndexedBufferRenderer.js +31 -0
- package/src/renderers/webgl/WebGLLights.js +11 -2
- package/src/renderers/webgl/WebGLProgram.js +20 -1
- package/src/renderers/webgl/WebGLPrograms.js +5 -0
- package/src/renderers/webgl/WebGLShadowMap.js +35 -0
- package/src/renderers/webgl/WebGLTextures.js +7 -11
- package/src/renderers/webgl/WebGLUniforms.js +11 -1
- package/src/renderers/webgl/WebGLUniformsGroups.js +72 -93
- package/src/renderers/webxr/WebXRManager.js +16 -0
- package/examples/jsm/objects/BatchedMesh.js +0 -586
|
@@ -0,0 +1,1020 @@
|
|
|
1
|
+
import { BufferAttribute } from '../core/BufferAttribute.js';
|
|
2
|
+
import { BufferGeometry } from '../core/BufferGeometry.js';
|
|
3
|
+
import { DataTexture } from '../textures/DataTexture.js';
|
|
4
|
+
import { FloatType } from '../constants.js';
|
|
5
|
+
import { Matrix4 } from '../math/Matrix4.js';
|
|
6
|
+
import { Mesh } from './Mesh.js';
|
|
7
|
+
import { RGBAFormat } from '../constants.js';
|
|
8
|
+
import { Box3 } from '../math/Box3.js';
|
|
9
|
+
import { Sphere } from '../math/Sphere.js';
|
|
10
|
+
import { Frustum } from '../math/Frustum.js';
|
|
11
|
+
import { WebGLCoordinateSystem } from '../constants.js';
|
|
12
|
+
import { WebGPUCoordinateSystem } from '../constants.js';
|
|
13
|
+
import { Vector3 } from '../math/Vector3.js';
|
|
14
|
+
|
|
15
|
+
function sortOpaque( a, b ) {
|
|
16
|
+
|
|
17
|
+
return a.z - b.z;
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function sortTransparent( a, b ) {
|
|
22
|
+
|
|
23
|
+
return b.z - a.z;
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class MultiDrawRenderList {
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
|
|
31
|
+
this.index = 0;
|
|
32
|
+
this.pool = [];
|
|
33
|
+
this.list = [];
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
push( drawRange, z ) {
|
|
38
|
+
|
|
39
|
+
const pool = this.pool;
|
|
40
|
+
const list = this.list;
|
|
41
|
+
if ( this.index >= pool.length ) {
|
|
42
|
+
|
|
43
|
+
pool.push( {
|
|
44
|
+
|
|
45
|
+
start: - 1,
|
|
46
|
+
count: - 1,
|
|
47
|
+
z: - 1,
|
|
48
|
+
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const item = pool[ this.index ];
|
|
54
|
+
list.push( item );
|
|
55
|
+
this.index ++;
|
|
56
|
+
|
|
57
|
+
item.start = drawRange.start;
|
|
58
|
+
item.count = drawRange.count;
|
|
59
|
+
item.z = z;
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
reset() {
|
|
64
|
+
|
|
65
|
+
this.list.length = 0;
|
|
66
|
+
this.index = 0;
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const ID_ATTR_NAME = 'batchId';
|
|
73
|
+
const _matrix = /*@__PURE__*/ new Matrix4();
|
|
74
|
+
const _invMatrixWorld = /*@__PURE__*/ new Matrix4();
|
|
75
|
+
const _identityMatrix = /*@__PURE__*/ new Matrix4();
|
|
76
|
+
const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
|
|
77
|
+
const _frustum = /*@__PURE__*/ new Frustum();
|
|
78
|
+
const _box = /*@__PURE__*/ new Box3();
|
|
79
|
+
const _sphere = /*@__PURE__*/ new Sphere();
|
|
80
|
+
const _vector = /*@__PURE__*/ new Vector3();
|
|
81
|
+
const _renderList = /*@__PURE__*/ new MultiDrawRenderList();
|
|
82
|
+
const _mesh = /*@__PURE__*/ new Mesh();
|
|
83
|
+
const _batchIntersects = [];
|
|
84
|
+
|
|
85
|
+
// @TODO: SkinnedMesh support?
|
|
86
|
+
// @TODO: geometry.groups support?
|
|
87
|
+
// @TODO: geometry.drawRange support?
|
|
88
|
+
// @TODO: geometry.morphAttributes support?
|
|
89
|
+
// @TODO: Support uniform parameter per geometry
|
|
90
|
+
// @TODO: Add an "optimize" function to pack geometry and remove data gaps
|
|
91
|
+
|
|
92
|
+
// copies data from attribute "src" into "target" starting at "targetOffset"
|
|
93
|
+
function copyAttributeData( src, target, targetOffset = 0 ) {
|
|
94
|
+
|
|
95
|
+
const itemSize = target.itemSize;
|
|
96
|
+
if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {
|
|
97
|
+
|
|
98
|
+
// use the component getters and setters if the array data cannot
|
|
99
|
+
// be copied directly
|
|
100
|
+
const vertexCount = src.count;
|
|
101
|
+
for ( let i = 0; i < vertexCount; i ++ ) {
|
|
102
|
+
|
|
103
|
+
for ( let c = 0; c < itemSize; c ++ ) {
|
|
104
|
+
|
|
105
|
+
target.setComponent( i + targetOffset, c, src.getComponent( i, c ) );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
} else {
|
|
112
|
+
|
|
113
|
+
// faster copy approach using typed array set function
|
|
114
|
+
target.array.set( src.array, targetOffset * itemSize );
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
target.needsUpdate = true;
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class BatchedMesh extends Mesh {
|
|
123
|
+
|
|
124
|
+
get maxGeometryCount() {
|
|
125
|
+
|
|
126
|
+
return this._maxGeometryCount;
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {
|
|
131
|
+
|
|
132
|
+
super( new BufferGeometry(), material );
|
|
133
|
+
|
|
134
|
+
this.isBatchedMesh = true;
|
|
135
|
+
this.perObjectFrustumCulled = true;
|
|
136
|
+
this.sortObjects = true;
|
|
137
|
+
this.boundingBox = null;
|
|
138
|
+
this.boundingSphere = null;
|
|
139
|
+
this.customSort = null;
|
|
140
|
+
|
|
141
|
+
this._drawRanges = [];
|
|
142
|
+
this._reservedRanges = [];
|
|
143
|
+
|
|
144
|
+
this._visibility = [];
|
|
145
|
+
this._active = [];
|
|
146
|
+
this._bounds = [];
|
|
147
|
+
|
|
148
|
+
this._maxGeometryCount = maxGeometryCount;
|
|
149
|
+
this._maxVertexCount = maxVertexCount;
|
|
150
|
+
this._maxIndexCount = maxIndexCount;
|
|
151
|
+
|
|
152
|
+
this._geometryInitialized = false;
|
|
153
|
+
this._geometryCount = 0;
|
|
154
|
+
this._multiDrawCounts = new Int32Array( maxGeometryCount );
|
|
155
|
+
this._multiDrawStarts = new Int32Array( maxGeometryCount );
|
|
156
|
+
this._multiDrawCount = 0;
|
|
157
|
+
this._visibilityChanged = true;
|
|
158
|
+
|
|
159
|
+
// Local matrix per geometry by using data texture
|
|
160
|
+
this._matricesTexture = null;
|
|
161
|
+
|
|
162
|
+
this._initMatricesTexture();
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
_initMatricesTexture() {
|
|
167
|
+
|
|
168
|
+
// layout (1 matrix = 4 pixels)
|
|
169
|
+
// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
|
|
170
|
+
// with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8)
|
|
171
|
+
// 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16)
|
|
172
|
+
// 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32)
|
|
173
|
+
// 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)
|
|
174
|
+
|
|
175
|
+
let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
|
|
176
|
+
size = Math.ceil( size / 4 ) * 4;
|
|
177
|
+
size = Math.max( size, 4 );
|
|
178
|
+
|
|
179
|
+
const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
|
|
180
|
+
const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );
|
|
181
|
+
|
|
182
|
+
this._matricesTexture = matricesTexture;
|
|
183
|
+
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
_initializeGeometry( reference ) {
|
|
187
|
+
|
|
188
|
+
const geometry = this.geometry;
|
|
189
|
+
const maxVertexCount = this._maxVertexCount;
|
|
190
|
+
const maxGeometryCount = this._maxGeometryCount;
|
|
191
|
+
const maxIndexCount = this._maxIndexCount;
|
|
192
|
+
if ( this._geometryInitialized === false ) {
|
|
193
|
+
|
|
194
|
+
for ( const attributeName in reference.attributes ) {
|
|
195
|
+
|
|
196
|
+
const srcAttribute = reference.getAttribute( attributeName );
|
|
197
|
+
const { array, itemSize, normalized } = srcAttribute;
|
|
198
|
+
|
|
199
|
+
const dstArray = new array.constructor( maxVertexCount * itemSize );
|
|
200
|
+
const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized );
|
|
201
|
+
dstAttribute.setUsage( srcAttribute.usage );
|
|
202
|
+
|
|
203
|
+
geometry.setAttribute( attributeName, dstAttribute );
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if ( reference.getIndex() !== null ) {
|
|
208
|
+
|
|
209
|
+
const indexArray = maxVertexCount > 65536
|
|
210
|
+
? new Uint32Array( maxIndexCount )
|
|
211
|
+
: new Uint16Array( maxIndexCount );
|
|
212
|
+
|
|
213
|
+
geometry.setIndex( new BufferAttribute( indexArray, 1 ) );
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const idArray = maxGeometryCount > 65536
|
|
218
|
+
? new Uint32Array( maxVertexCount )
|
|
219
|
+
: new Uint16Array( maxVertexCount );
|
|
220
|
+
geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );
|
|
221
|
+
|
|
222
|
+
this._geometryInitialized = true;
|
|
223
|
+
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Make sure the geometry is compatible with the existing combined geometry atributes
|
|
229
|
+
_validateGeometry( geometry ) {
|
|
230
|
+
|
|
231
|
+
// check that the geometry doesn't have a version of our reserved id attribute
|
|
232
|
+
if ( geometry.getAttribute( ID_ATTR_NAME ) ) {
|
|
233
|
+
|
|
234
|
+
throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` );
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// check to ensure the geometries are using consistent attributes and indices
|
|
239
|
+
const batchGeometry = this.geometry;
|
|
240
|
+
if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {
|
|
241
|
+
|
|
242
|
+
throw new Error( 'BatchedMesh: All geometries must consistently have "index".' );
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
for ( const attributeName in batchGeometry.attributes ) {
|
|
247
|
+
|
|
248
|
+
if ( attributeName === ID_ATTR_NAME ) {
|
|
249
|
+
|
|
250
|
+
continue;
|
|
251
|
+
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if ( ! geometry.hasAttribute( attributeName ) ) {
|
|
255
|
+
|
|
256
|
+
throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );
|
|
257
|
+
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const srcAttribute = geometry.getAttribute( attributeName );
|
|
261
|
+
const dstAttribute = batchGeometry.getAttribute( attributeName );
|
|
262
|
+
if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {
|
|
263
|
+
|
|
264
|
+
throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
setCustomSort( func ) {
|
|
273
|
+
|
|
274
|
+
this.customSort = func;
|
|
275
|
+
return this;
|
|
276
|
+
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
computeBoundingBox() {
|
|
280
|
+
|
|
281
|
+
if ( this.boundingBox === null ) {
|
|
282
|
+
|
|
283
|
+
this.boundingBox = new Box3();
|
|
284
|
+
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const geometryCount = this._geometryCount;
|
|
288
|
+
const boundingBox = this.boundingBox;
|
|
289
|
+
const active = this._active;
|
|
290
|
+
|
|
291
|
+
boundingBox.makeEmpty();
|
|
292
|
+
for ( let i = 0; i < geometryCount; i ++ ) {
|
|
293
|
+
|
|
294
|
+
if ( active[ i ] === false ) continue;
|
|
295
|
+
|
|
296
|
+
this.getMatrixAt( i, _matrix );
|
|
297
|
+
this.getBoundingBoxAt( i, _box ).applyMatrix4( _matrix );
|
|
298
|
+
boundingBox.union( _box );
|
|
299
|
+
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
computeBoundingSphere() {
|
|
305
|
+
|
|
306
|
+
if ( this.boundingSphere === null ) {
|
|
307
|
+
|
|
308
|
+
this.boundingSphere = new Sphere();
|
|
309
|
+
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const geometryCount = this._geometryCount;
|
|
313
|
+
const boundingSphere = this.boundingSphere;
|
|
314
|
+
const active = this._active;
|
|
315
|
+
|
|
316
|
+
boundingSphere.makeEmpty();
|
|
317
|
+
for ( let i = 0; i < geometryCount; i ++ ) {
|
|
318
|
+
|
|
319
|
+
if ( active[ i ] === false ) continue;
|
|
320
|
+
|
|
321
|
+
this.getMatrixAt( i, _matrix );
|
|
322
|
+
this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
323
|
+
boundingSphere.union( _sphere );
|
|
324
|
+
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {
|
|
330
|
+
|
|
331
|
+
this._initializeGeometry( geometry );
|
|
332
|
+
|
|
333
|
+
this._validateGeometry( geometry );
|
|
334
|
+
|
|
335
|
+
// ensure we're not over geometry
|
|
336
|
+
if ( this._geometryCount >= this._maxGeometryCount ) {
|
|
337
|
+
|
|
338
|
+
throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// get the necessary range fo the geometry
|
|
343
|
+
const reservedRange = {
|
|
344
|
+
vertexStart: - 1,
|
|
345
|
+
vertexCount: - 1,
|
|
346
|
+
indexStart: - 1,
|
|
347
|
+
indexCount: - 1,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
let lastRange = null;
|
|
351
|
+
const reservedRanges = this._reservedRanges;
|
|
352
|
+
const drawRanges = this._drawRanges;
|
|
353
|
+
const bounds = this._bounds;
|
|
354
|
+
if ( this._geometryCount !== 0 ) {
|
|
355
|
+
|
|
356
|
+
lastRange = reservedRanges[ reservedRanges.length - 1 ];
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if ( vertexCount === - 1 ) {
|
|
361
|
+
|
|
362
|
+
reservedRange.vertexCount = geometry.getAttribute( 'position' ).count;
|
|
363
|
+
|
|
364
|
+
} else {
|
|
365
|
+
|
|
366
|
+
reservedRange.vertexCount = vertexCount;
|
|
367
|
+
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if ( lastRange === null ) {
|
|
371
|
+
|
|
372
|
+
reservedRange.vertexStart = 0;
|
|
373
|
+
|
|
374
|
+
} else {
|
|
375
|
+
|
|
376
|
+
reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;
|
|
377
|
+
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const index = geometry.getIndex();
|
|
381
|
+
const hasIndex = index !== null;
|
|
382
|
+
if ( hasIndex ) {
|
|
383
|
+
|
|
384
|
+
if ( indexCount === - 1 ) {
|
|
385
|
+
|
|
386
|
+
reservedRange.indexCount = index.count;
|
|
387
|
+
|
|
388
|
+
} else {
|
|
389
|
+
|
|
390
|
+
reservedRange.indexCount = indexCount;
|
|
391
|
+
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if ( lastRange === null ) {
|
|
395
|
+
|
|
396
|
+
reservedRange.indexStart = 0;
|
|
397
|
+
|
|
398
|
+
} else {
|
|
399
|
+
|
|
400
|
+
reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;
|
|
401
|
+
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (
|
|
407
|
+
reservedRange.indexStart !== - 1 &&
|
|
408
|
+
reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||
|
|
409
|
+
reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount
|
|
410
|
+
) {
|
|
411
|
+
|
|
412
|
+
throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const visibility = this._visibility;
|
|
417
|
+
const active = this._active;
|
|
418
|
+
const matricesTexture = this._matricesTexture;
|
|
419
|
+
const matricesArray = this._matricesTexture.image.data;
|
|
420
|
+
|
|
421
|
+
// push new visibility states
|
|
422
|
+
visibility.push( true );
|
|
423
|
+
active.push( true );
|
|
424
|
+
|
|
425
|
+
// update id
|
|
426
|
+
const geometryId = this._geometryCount;
|
|
427
|
+
this._geometryCount ++;
|
|
428
|
+
|
|
429
|
+
// initialize matrix information
|
|
430
|
+
_identityMatrix.toArray( matricesArray, geometryId * 16 );
|
|
431
|
+
matricesTexture.needsUpdate = true;
|
|
432
|
+
|
|
433
|
+
// add the reserved range and draw range objects
|
|
434
|
+
reservedRanges.push( reservedRange );
|
|
435
|
+
drawRanges.push( {
|
|
436
|
+
start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,
|
|
437
|
+
count: - 1
|
|
438
|
+
} );
|
|
439
|
+
bounds.push( {
|
|
440
|
+
boxInitialized: false,
|
|
441
|
+
box: new Box3(),
|
|
442
|
+
|
|
443
|
+
sphereInitialized: false,
|
|
444
|
+
sphere: new Sphere()
|
|
445
|
+
} );
|
|
446
|
+
|
|
447
|
+
// set the id for the geometry
|
|
448
|
+
const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME );
|
|
449
|
+
for ( let i = 0; i < reservedRange.vertexCount; i ++ ) {
|
|
450
|
+
|
|
451
|
+
idAttribute.setX( reservedRange.vertexStart + i, geometryId );
|
|
452
|
+
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
idAttribute.needsUpdate = true;
|
|
456
|
+
|
|
457
|
+
// update the geometry
|
|
458
|
+
this.setGeometryAt( geometryId, geometry );
|
|
459
|
+
|
|
460
|
+
return geometryId;
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
setGeometryAt( id, geometry ) {
|
|
465
|
+
|
|
466
|
+
if ( id >= this._geometryCount ) {
|
|
467
|
+
|
|
468
|
+
throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
|
|
469
|
+
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
this._validateGeometry( geometry );
|
|
473
|
+
|
|
474
|
+
const batchGeometry = this.geometry;
|
|
475
|
+
const hasIndex = batchGeometry.getIndex() !== null;
|
|
476
|
+
const dstIndex = batchGeometry.getIndex();
|
|
477
|
+
const srcIndex = geometry.getIndex();
|
|
478
|
+
const reservedRange = this._reservedRanges[ id ];
|
|
479
|
+
if (
|
|
480
|
+
hasIndex &&
|
|
481
|
+
srcIndex.count > reservedRange.indexCount ||
|
|
482
|
+
geometry.attributes.position.count > reservedRange.vertexCount
|
|
483
|
+
) {
|
|
484
|
+
|
|
485
|
+
throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );
|
|
486
|
+
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// copy geometry over
|
|
490
|
+
const vertexStart = reservedRange.vertexStart;
|
|
491
|
+
const vertexCount = reservedRange.vertexCount;
|
|
492
|
+
for ( const attributeName in batchGeometry.attributes ) {
|
|
493
|
+
|
|
494
|
+
if ( attributeName === ID_ATTR_NAME ) {
|
|
495
|
+
|
|
496
|
+
continue;
|
|
497
|
+
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// copy attribute data
|
|
501
|
+
const srcAttribute = geometry.getAttribute( attributeName );
|
|
502
|
+
const dstAttribute = batchGeometry.getAttribute( attributeName );
|
|
503
|
+
copyAttributeData( srcAttribute, dstAttribute, vertexStart );
|
|
504
|
+
|
|
505
|
+
// fill the rest in with zeroes
|
|
506
|
+
const itemSize = srcAttribute.itemSize;
|
|
507
|
+
for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {
|
|
508
|
+
|
|
509
|
+
const index = vertexStart + i;
|
|
510
|
+
for ( let c = 0; c < itemSize; c ++ ) {
|
|
511
|
+
|
|
512
|
+
dstAttribute.setComponent( index, c, 0 );
|
|
513
|
+
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
dstAttribute.needsUpdate = true;
|
|
519
|
+
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// copy index
|
|
523
|
+
if ( hasIndex ) {
|
|
524
|
+
|
|
525
|
+
const indexStart = reservedRange.indexStart;
|
|
526
|
+
|
|
527
|
+
// copy index data over
|
|
528
|
+
for ( let i = 0; i < srcIndex.count; i ++ ) {
|
|
529
|
+
|
|
530
|
+
dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );
|
|
531
|
+
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// fill the rest in with zeroes
|
|
535
|
+
for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {
|
|
536
|
+
|
|
537
|
+
dstIndex.setX( indexStart + i, vertexStart );
|
|
538
|
+
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
dstIndex.needsUpdate = true;
|
|
542
|
+
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// store the bounding boxes
|
|
546
|
+
const bound = this._bounds[ id ];
|
|
547
|
+
if ( geometry.boundingBox !== null ) {
|
|
548
|
+
|
|
549
|
+
bound.box.copy( geometry.boundingBox );
|
|
550
|
+
bound.boxInitialized = true;
|
|
551
|
+
|
|
552
|
+
} else {
|
|
553
|
+
|
|
554
|
+
bound.boxInitialized = false;
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if ( geometry.boundingSphere !== null ) {
|
|
559
|
+
|
|
560
|
+
bound.sphere.copy( geometry.boundingSphere );
|
|
561
|
+
bound.sphereInitialized = true;
|
|
562
|
+
|
|
563
|
+
} else {
|
|
564
|
+
|
|
565
|
+
bound.sphereInitialized = false;
|
|
566
|
+
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// set drawRange count
|
|
570
|
+
const drawRange = this._drawRanges[ id ];
|
|
571
|
+
const posAttr = geometry.getAttribute( 'position' );
|
|
572
|
+
drawRange.count = hasIndex ? srcIndex.count : posAttr.count;
|
|
573
|
+
this._visibilityChanged = true;
|
|
574
|
+
|
|
575
|
+
return id;
|
|
576
|
+
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
deleteGeometry( geometryId ) {
|
|
580
|
+
|
|
581
|
+
// Note: User needs to call optimize() afterward to pack the data.
|
|
582
|
+
|
|
583
|
+
const active = this._active;
|
|
584
|
+
if ( geometryId >= active.length || active[ geometryId ] === false ) {
|
|
585
|
+
|
|
586
|
+
return this;
|
|
587
|
+
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
active[ geometryId ] = false;
|
|
591
|
+
this._visibilityChanged = true;
|
|
592
|
+
|
|
593
|
+
return this;
|
|
594
|
+
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// get bounding box and compute it if it doesn't exist
|
|
598
|
+
getBoundingBoxAt( id, target ) {
|
|
599
|
+
|
|
600
|
+
const active = this._active;
|
|
601
|
+
if ( active[ id ] === false ) {
|
|
602
|
+
|
|
603
|
+
return this;
|
|
604
|
+
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// compute bounding box
|
|
608
|
+
const bound = this._bounds[ id ];
|
|
609
|
+
const box = bound.box;
|
|
610
|
+
const geometry = this.geometry;
|
|
611
|
+
if ( bound.boxInitialized === false ) {
|
|
612
|
+
|
|
613
|
+
box.makeEmpty();
|
|
614
|
+
|
|
615
|
+
const index = geometry.index;
|
|
616
|
+
const position = geometry.attributes.position;
|
|
617
|
+
const drawRange = this._drawRanges[ id ];
|
|
618
|
+
for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
|
|
619
|
+
|
|
620
|
+
let iv = i;
|
|
621
|
+
if ( index ) {
|
|
622
|
+
|
|
623
|
+
iv = index.getX( iv );
|
|
624
|
+
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
box.expandByPoint( _vector.fromBufferAttribute( position, iv ) );
|
|
628
|
+
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
bound.boxInitialized = true;
|
|
632
|
+
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
target.copy( box );
|
|
636
|
+
return target;
|
|
637
|
+
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// get bounding sphere and compute it if it doesn't exist
|
|
641
|
+
getBoundingSphereAt( id, target ) {
|
|
642
|
+
|
|
643
|
+
const active = this._active;
|
|
644
|
+
if ( active[ id ] === false ) {
|
|
645
|
+
|
|
646
|
+
return this;
|
|
647
|
+
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// compute bounding sphere
|
|
651
|
+
const bound = this._bounds[ id ];
|
|
652
|
+
const sphere = bound.sphere;
|
|
653
|
+
const geometry = this.geometry;
|
|
654
|
+
if ( bound.sphereInitialized === false ) {
|
|
655
|
+
|
|
656
|
+
sphere.makeEmpty();
|
|
657
|
+
|
|
658
|
+
this.getBoundingBoxAt( id, _box );
|
|
659
|
+
_box.getCenter( sphere.center );
|
|
660
|
+
|
|
661
|
+
const index = geometry.index;
|
|
662
|
+
const position = geometry.attributes.position;
|
|
663
|
+
const drawRange = this._drawRanges[ id ];
|
|
664
|
+
|
|
665
|
+
let maxRadiusSq = 0;
|
|
666
|
+
for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
|
|
667
|
+
|
|
668
|
+
let iv = i;
|
|
669
|
+
if ( index ) {
|
|
670
|
+
|
|
671
|
+
iv = index.getX( iv );
|
|
672
|
+
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
_vector.fromBufferAttribute( position, iv );
|
|
676
|
+
maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector ) );
|
|
677
|
+
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
sphere.radius = Math.sqrt( maxRadiusSq );
|
|
681
|
+
bound.sphereInitialized = true;
|
|
682
|
+
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
target.copy( sphere );
|
|
686
|
+
return target;
|
|
687
|
+
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
setMatrixAt( geometryId, matrix ) {
|
|
691
|
+
|
|
692
|
+
// @TODO: Map geometryId to index of the arrays because
|
|
693
|
+
// optimize() can make geometryId mismatch the index
|
|
694
|
+
|
|
695
|
+
const active = this._active;
|
|
696
|
+
const matricesTexture = this._matricesTexture;
|
|
697
|
+
const matricesArray = this._matricesTexture.image.data;
|
|
698
|
+
const geometryCount = this._geometryCount;
|
|
699
|
+
if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
700
|
+
|
|
701
|
+
return this;
|
|
702
|
+
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
matrix.toArray( matricesArray, geometryId * 16 );
|
|
706
|
+
matricesTexture.needsUpdate = true;
|
|
707
|
+
|
|
708
|
+
return this;
|
|
709
|
+
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
getMatrixAt( geometryId, matrix ) {
|
|
713
|
+
|
|
714
|
+
const active = this._active;
|
|
715
|
+
const matricesArray = this._matricesTexture.image.data;
|
|
716
|
+
const geometryCount = this._geometryCount;
|
|
717
|
+
if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
718
|
+
|
|
719
|
+
return null;
|
|
720
|
+
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
return matrix.fromArray( matricesArray, geometryId * 16 );
|
|
724
|
+
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
setVisibleAt( geometryId, value ) {
|
|
728
|
+
|
|
729
|
+
const visibility = this._visibility;
|
|
730
|
+
const active = this._active;
|
|
731
|
+
const geometryCount = this._geometryCount;
|
|
732
|
+
|
|
733
|
+
// if the geometry is out of range, not active, or visibility state
|
|
734
|
+
// does not change then return early
|
|
735
|
+
if (
|
|
736
|
+
geometryId >= geometryCount ||
|
|
737
|
+
active[ geometryId ] === false ||
|
|
738
|
+
visibility[ geometryId ] === value
|
|
739
|
+
) {
|
|
740
|
+
|
|
741
|
+
return this;
|
|
742
|
+
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
visibility[ geometryId ] = value;
|
|
746
|
+
this._visibilityChanged = true;
|
|
747
|
+
|
|
748
|
+
return this;
|
|
749
|
+
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
getVisibleAt( geometryId ) {
|
|
753
|
+
|
|
754
|
+
const visibility = this._visibility;
|
|
755
|
+
const active = this._active;
|
|
756
|
+
const geometryCount = this._geometryCount;
|
|
757
|
+
|
|
758
|
+
// return early if the geometry is out of range or not active
|
|
759
|
+
if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
760
|
+
|
|
761
|
+
return false;
|
|
762
|
+
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return visibility[ geometryId ];
|
|
766
|
+
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
raycast( raycaster, intersects ) {
|
|
770
|
+
|
|
771
|
+
const visibility = this._visibility;
|
|
772
|
+
const active = this._active;
|
|
773
|
+
const drawRanges = this._drawRanges;
|
|
774
|
+
const geometryCount = this._geometryCount;
|
|
775
|
+
const matrixWorld = this.matrixWorld;
|
|
776
|
+
const batchGeometry = this.geometry;
|
|
777
|
+
|
|
778
|
+
// iterate over each geometry
|
|
779
|
+
_mesh.material = this.material;
|
|
780
|
+
_mesh.geometry.index = batchGeometry.index;
|
|
781
|
+
_mesh.geometry.attributes = batchGeometry.attributes;
|
|
782
|
+
if ( _mesh.geometry.boundingBox === null ) {
|
|
783
|
+
|
|
784
|
+
_mesh.geometry.boundingBox = new Box3();
|
|
785
|
+
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if ( _mesh.geometry.boundingSphere === null ) {
|
|
789
|
+
|
|
790
|
+
_mesh.geometry.boundingSphere = new Sphere();
|
|
791
|
+
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
for ( let i = 0; i < geometryCount; i ++ ) {
|
|
795
|
+
|
|
796
|
+
if ( ! visibility[ i ] || ! active[ i ] ) {
|
|
797
|
+
|
|
798
|
+
continue;
|
|
799
|
+
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const drawRange = drawRanges[ i ];
|
|
803
|
+
_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );
|
|
804
|
+
|
|
805
|
+
// ge the intersects
|
|
806
|
+
this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );
|
|
807
|
+
this.getBoundingBoxAt( i, _mesh.geometry.boundingBox );
|
|
808
|
+
this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere );
|
|
809
|
+
_mesh.raycast( raycaster, _batchIntersects );
|
|
810
|
+
|
|
811
|
+
// add batch id to the intersects
|
|
812
|
+
for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {
|
|
813
|
+
|
|
814
|
+
const intersect = _batchIntersects[ j ];
|
|
815
|
+
intersect.object = this;
|
|
816
|
+
intersect.batchId = i;
|
|
817
|
+
intersects.push( intersect );
|
|
818
|
+
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
_batchIntersects.length = 0;
|
|
822
|
+
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
_mesh.material = null;
|
|
826
|
+
_mesh.geometry.index = null;
|
|
827
|
+
_mesh.geometry.attributes = {};
|
|
828
|
+
_mesh.geometry.setDrawRange( 0, Infinity );
|
|
829
|
+
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
copy( source ) {
|
|
833
|
+
|
|
834
|
+
super.copy( source );
|
|
835
|
+
|
|
836
|
+
this.geometry = source.geometry.clone();
|
|
837
|
+
this.perObjectFrustumCulled = source.perObjectFrustumCulled;
|
|
838
|
+
this.sortObjects = source.sortObjects;
|
|
839
|
+
this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
|
|
840
|
+
this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
|
|
841
|
+
|
|
842
|
+
this._drawRanges = source._drawRanges.map( range => ( { ...range } ) );
|
|
843
|
+
this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );
|
|
844
|
+
|
|
845
|
+
this._visibility = source._visibility.slice();
|
|
846
|
+
this._active = source._active.slice();
|
|
847
|
+
this._bounds = source._bounds.map( bound => ( {
|
|
848
|
+
boxInitialized: bound.boxInitialized,
|
|
849
|
+
box: bound.box.clone(),
|
|
850
|
+
|
|
851
|
+
sphereInitialized: bound.sphereInitialized,
|
|
852
|
+
sphere: bound.sphere.clone()
|
|
853
|
+
} ) );
|
|
854
|
+
|
|
855
|
+
this._maxGeometryCount = source._maxGeometryCount;
|
|
856
|
+
this._maxVertexCount = source._maxVertexCount;
|
|
857
|
+
this._maxIndexCount = source._maxIndexCount;
|
|
858
|
+
|
|
859
|
+
this._geometryInitialized = source._geometryInitialized;
|
|
860
|
+
this._geometryCount = source._geometryCount;
|
|
861
|
+
this._multiDrawCounts = source._multiDrawCounts.slice();
|
|
862
|
+
this._multiDrawStarts = source._multiDrawStarts.slice();
|
|
863
|
+
|
|
864
|
+
this._matricesTexture = source._matricesTexture.clone();
|
|
865
|
+
this._matricesTexture.image.data = this._matricesTexture.image.slice();
|
|
866
|
+
|
|
867
|
+
return this;
|
|
868
|
+
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
dispose() {
|
|
872
|
+
|
|
873
|
+
// Assuming the geometry is not shared with other meshes
|
|
874
|
+
this.geometry.dispose();
|
|
875
|
+
|
|
876
|
+
this._matricesTexture.dispose();
|
|
877
|
+
this._matricesTexture = null;
|
|
878
|
+
return this;
|
|
879
|
+
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {
|
|
883
|
+
|
|
884
|
+
// if visibility has not changed and frustum culling and object sorting is not required
|
|
885
|
+
// then skip iterating over all items
|
|
886
|
+
if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {
|
|
887
|
+
|
|
888
|
+
return;
|
|
889
|
+
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// the indexed version of the multi draw function requires specifying the start
|
|
893
|
+
// offset in bytes.
|
|
894
|
+
const index = geometry.getIndex();
|
|
895
|
+
const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;
|
|
896
|
+
|
|
897
|
+
const visibility = this._visibility;
|
|
898
|
+
const multiDrawStarts = this._multiDrawStarts;
|
|
899
|
+
const multiDrawCounts = this._multiDrawCounts;
|
|
900
|
+
const drawRanges = this._drawRanges;
|
|
901
|
+
const perObjectFrustumCulled = this.perObjectFrustumCulled;
|
|
902
|
+
|
|
903
|
+
// prepare the frustum in the local frame
|
|
904
|
+
if ( perObjectFrustumCulled ) {
|
|
905
|
+
|
|
906
|
+
_projScreenMatrix
|
|
907
|
+
.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )
|
|
908
|
+
.multiply( this.matrixWorld );
|
|
909
|
+
_frustum.setFromProjectionMatrix(
|
|
910
|
+
_projScreenMatrix,
|
|
911
|
+
renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
let count = 0;
|
|
917
|
+
if ( this.sortObjects ) {
|
|
918
|
+
|
|
919
|
+
// get the camera position in the local frame
|
|
920
|
+
_invMatrixWorld.copy( this.matrixWorld ).invert();
|
|
921
|
+
_vector.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );
|
|
922
|
+
|
|
923
|
+
for ( let i = 0, l = visibility.length; i < l; i ++ ) {
|
|
924
|
+
|
|
925
|
+
if ( visibility[ i ] ) {
|
|
926
|
+
|
|
927
|
+
// get the bounds in world space
|
|
928
|
+
this.getMatrixAt( i, _matrix );
|
|
929
|
+
this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
930
|
+
|
|
931
|
+
// determine whether the batched geometry is within the frustum
|
|
932
|
+
let culled = false;
|
|
933
|
+
if ( perObjectFrustumCulled ) {
|
|
934
|
+
|
|
935
|
+
culled = ! _frustum.intersectsSphere( _sphere );
|
|
936
|
+
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if ( ! culled ) {
|
|
940
|
+
|
|
941
|
+
// get the distance from camera used for sorting
|
|
942
|
+
const z = _vector.distanceTo( _sphere.center );
|
|
943
|
+
_renderList.push( drawRanges[ i ], z );
|
|
944
|
+
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Sort the draw ranges and prep for rendering
|
|
952
|
+
const list = _renderList.list;
|
|
953
|
+
const customSort = this.customSort;
|
|
954
|
+
if ( customSort === null ) {
|
|
955
|
+
|
|
956
|
+
list.sort( material.transparent ? sortTransparent : sortOpaque );
|
|
957
|
+
|
|
958
|
+
} else {
|
|
959
|
+
|
|
960
|
+
customSort.call( this, list, camera );
|
|
961
|
+
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
for ( let i = 0, l = list.length; i < l; i ++ ) {
|
|
965
|
+
|
|
966
|
+
const item = list[ i ];
|
|
967
|
+
multiDrawStarts[ count ] = item.start * bytesPerElement;
|
|
968
|
+
multiDrawCounts[ count ] = item.count;
|
|
969
|
+
count ++;
|
|
970
|
+
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
_renderList.reset();
|
|
974
|
+
|
|
975
|
+
} else {
|
|
976
|
+
|
|
977
|
+
for ( let i = 0, l = visibility.length; i < l; i ++ ) {
|
|
978
|
+
|
|
979
|
+
if ( visibility[ i ] ) {
|
|
980
|
+
|
|
981
|
+
// determine whether the batched geometry is within the frustum
|
|
982
|
+
let culled = false;
|
|
983
|
+
if ( perObjectFrustumCulled ) {
|
|
984
|
+
|
|
985
|
+
// get the bounds in world space
|
|
986
|
+
this.getMatrixAt( i, _matrix );
|
|
987
|
+
this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
988
|
+
culled = ! _frustum.intersectsSphere( _sphere );
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
if ( ! culled ) {
|
|
993
|
+
|
|
994
|
+
const range = drawRanges[ i ];
|
|
995
|
+
multiDrawStarts[ count ] = range.start * bytesPerElement;
|
|
996
|
+
multiDrawCounts[ count ] = range.count;
|
|
997
|
+
count ++;
|
|
998
|
+
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
this._multiDrawCount = count;
|
|
1008
|
+
this._visibilityChanged = false;
|
|
1009
|
+
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {
|
|
1013
|
+
|
|
1014
|
+
this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );
|
|
1015
|
+
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
export { BatchedMesh };
|