@plastic-software/three 0.181.2 → 0.182.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/README.md +3 -4
- package/build/three.cjs +1192 -522
- package/build/three.core.js +345 -219
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +864 -328
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +15 -3
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +3660 -1545
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +3659 -1544
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/controls/MapControls.js +55 -1
- package/examples/jsm/controls/OrbitControls.js +6 -6
- package/examples/jsm/controls/TrackballControls.js +6 -6
- package/examples/jsm/csm/CSM.js +2 -1
- package/examples/jsm/environments/RoomEnvironment.js +2 -0
- package/examples/jsm/geometries/DecalGeometry.js +1 -1
- package/examples/jsm/helpers/LightProbeHelperGPU.js +1 -1
- package/examples/jsm/helpers/TextureHelperGPU.js +1 -1
- package/examples/jsm/inspector/Inspector.js +53 -9
- package/examples/jsm/inspector/RendererInspector.js +12 -2
- package/examples/jsm/inspector/tabs/Console.js +2 -2
- package/examples/jsm/inspector/tabs/Parameters.js +2 -2
- package/examples/jsm/inspector/tabs/Performance.js +2 -2
- package/examples/jsm/inspector/tabs/Viewer.js +4 -4
- package/examples/jsm/inspector/ui/Profiler.js +1836 -31
- package/examples/jsm/inspector/ui/Style.js +948 -13
- package/examples/jsm/inspector/ui/Tab.js +188 -1
- package/examples/jsm/inspector/ui/Values.js +17 -1
- package/examples/jsm/loaders/3DMLoader.js +5 -4
- package/examples/jsm/loaders/DRACOLoader.js +5 -5
- package/examples/jsm/loaders/FBXLoader.js +0 -2
- package/examples/jsm/loaders/HDRLoader.js +0 -1
- package/examples/jsm/loaders/KTX2Loader.js +16 -0
- package/examples/jsm/loaders/LDrawLoader.js +2 -3
- package/examples/jsm/loaders/PCDLoader.js +1 -0
- package/examples/jsm/loaders/SVGLoader.js +1 -1
- package/examples/jsm/loaders/TDSLoader.js +0 -2
- package/examples/jsm/loaders/TGALoader.js +0 -2
- package/examples/jsm/loaders/UltraHDRLoader.js +110 -137
- package/examples/jsm/loaders/VOXLoader.js +660 -117
- package/examples/jsm/loaders/VRMLLoader.js +2 -2
- package/examples/jsm/loaders/usd/USDCParser.js +1 -1
- package/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +1 -1
- package/examples/jsm/materials/MeshGouraudMaterial.js +0 -1
- package/examples/jsm/materials/WoodNodeMaterial.js +11 -11
- package/examples/jsm/math/Octree.js +131 -1
- package/examples/jsm/misc/Volume.js +0 -1
- package/examples/jsm/misc/VolumeSlice.js +0 -1
- package/examples/jsm/objects/SkyMesh.js +13 -3
- package/examples/jsm/physics/AmmoPhysics.js +12 -7
- package/examples/jsm/physics/JoltPhysics.js +3 -1
- package/examples/jsm/physics/RapierPhysics.js +3 -1
- package/examples/jsm/postprocessing/OutputPass.js +9 -0
- package/examples/jsm/postprocessing/RenderPass.js +10 -0
- package/examples/jsm/postprocessing/UnrealBloomPass.js +48 -18
- package/examples/jsm/renderers/Projector.js +268 -30
- package/examples/jsm/renderers/SVGRenderer.js +191 -58
- package/examples/jsm/shaders/UnpackDepthRGBAShader.js +2 -4
- package/examples/jsm/transpiler/AST.js +44 -0
- package/examples/jsm/transpiler/GLSLDecoder.js +61 -4
- package/examples/jsm/transpiler/ShaderToyDecoder.js +2 -0
- package/examples/jsm/transpiler/TSLEncoder.js +46 -3
- package/examples/jsm/transpiler/TranspilerUtils.js +3 -3
- package/examples/jsm/transpiler/WGSLEncoder.js +27 -0
- package/examples/jsm/tsl/display/AnaglyphPassNode.js +2 -0
- package/examples/jsm/tsl/display/BloomNode.js +11 -1
- package/examples/jsm/tsl/display/GTAONode.js +3 -2
- package/examples/jsm/tsl/display/PixelationPassNode.js +2 -1
- package/examples/jsm/tsl/display/SSGINode.js +7 -19
- package/examples/jsm/tsl/display/SSRNode.js +1 -1
- package/examples/jsm/tsl/display/SSSNode.js +4 -2
- package/examples/jsm/tsl/display/StereoCompositePassNode.js +8 -1
- package/examples/jsm/tsl/display/TRAANode.js +265 -114
- package/examples/jsm/tsl/display/radialBlur.js +68 -0
- package/examples/jsm/utils/ShadowMapViewer.js +24 -10
- package/examples/jsm/utils/ShadowMapViewerGPU.js +1 -1
- package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
- package/package.json +14 -12
- package/src/Three.Core.js +1 -0
- package/src/Three.TSL.js +14 -2
- package/src/animation/AnimationUtils.js +1 -12
- package/src/animation/KeyframeTrack.js +1 -1
- package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
- package/src/animation/tracks/ColorKeyframeTrack.js +1 -1
- package/src/animation/tracks/NumberKeyframeTrack.js +1 -1
- package/src/animation/tracks/QuaternionKeyframeTrack.js +1 -1
- package/src/animation/tracks/StringKeyframeTrack.js +1 -1
- package/src/animation/tracks/VectorKeyframeTrack.js +1 -1
- package/src/constants.js +61 -5
- package/src/core/BufferGeometry.js +14 -2
- package/src/core/Raycaster.js +2 -2
- package/src/extras/PMREMGenerator.js +3 -10
- package/src/extras/TextureUtils.js +5 -1
- package/src/geometries/ExtrudeGeometry.js +2 -2
- package/src/geometries/PolyhedronGeometry.js +1 -1
- package/src/helpers/PointLightHelper.js +1 -1
- package/src/lights/DirectionalLight.js +13 -0
- package/src/lights/HemisphereLight.js +10 -0
- package/src/lights/Light.js +1 -11
- package/src/lights/LightProbe.js +0 -15
- package/src/lights/LightShadow.js +0 -3
- package/src/lights/PointLight.js +15 -0
- package/src/lights/PointLightShadow.js +0 -86
- package/src/lights/SpotLight.js +22 -1
- package/src/loaders/MaterialLoader.js +2 -1
- package/src/loaders/ObjectLoader.js +3 -1
- package/src/loaders/nodes/NodeLoader.js +2 -2
- package/src/materials/Material.js +2 -0
- package/src/materials/ShaderMaterial.js +20 -1
- package/src/materials/nodes/Line2NodeMaterial.js +2 -2
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +3 -2
- package/src/materials/nodes/MeshStandardNodeMaterial.js +5 -4
- package/src/materials/nodes/NodeMaterial.js +59 -3
- package/src/materials/nodes/manager/NodeMaterialObserver.js +1 -1
- package/src/math/Matrix4.js +40 -40
- package/src/math/Sphere.js +1 -1
- package/src/math/Vector3.js +0 -2
- package/src/nodes/TSL.js +4 -1
- package/src/nodes/accessors/BatchNode.js +10 -10
- package/src/nodes/accessors/BufferAttributeNode.js +98 -12
- package/src/nodes/accessors/BufferNode.js +29 -2
- package/src/nodes/accessors/ClippingNode.js +4 -4
- package/src/nodes/accessors/CubeTextureNode.js +20 -1
- package/src/nodes/accessors/InstanceNode.js +69 -29
- package/src/nodes/accessors/MaterialNode.js +9 -1
- package/src/nodes/accessors/MaterialReferenceNode.js +1 -2
- package/src/nodes/accessors/ModelNode.js +1 -1
- package/src/nodes/accessors/Normal.js +2 -2
- package/src/nodes/accessors/ReferenceBaseNode.js +4 -4
- package/src/nodes/accessors/ReferenceNode.js +4 -4
- package/src/nodes/accessors/RendererReferenceNode.js +1 -2
- package/src/nodes/accessors/SkinningNode.js +15 -2
- package/src/nodes/accessors/StorageBufferNode.js +4 -2
- package/src/nodes/accessors/Tangent.js +1 -11
- package/src/nodes/accessors/Texture3DNode.js +26 -1
- package/src/nodes/accessors/UniformArrayNode.js +2 -2
- package/src/nodes/accessors/UserDataNode.js +1 -2
- package/src/nodes/accessors/VertexColorNode.js +1 -2
- package/src/nodes/code/FunctionNode.js +1 -2
- package/src/nodes/core/ArrayNode.js +20 -1
- package/src/nodes/core/AssignNode.js +2 -2
- package/src/nodes/core/AttributeNode.js +2 -2
- package/src/nodes/core/ContextNode.js +103 -4
- package/src/nodes/core/NodeBuilder.js +56 -14
- package/src/nodes/core/NodeFrame.js +12 -4
- package/src/nodes/core/NodeUtils.js +5 -5
- package/src/nodes/core/ParameterNode.js +1 -2
- package/src/nodes/core/PropertyNode.js +19 -3
- package/src/nodes/core/StackNode.js +56 -8
- package/src/nodes/core/StructNode.js +1 -2
- package/src/nodes/core/StructTypeNode.js +11 -17
- package/src/nodes/core/UniformNode.js +19 -4
- package/src/nodes/core/VarNode.js +46 -21
- package/src/nodes/display/NormalMapNode.js +37 -2
- package/src/nodes/display/PassNode.js +77 -7
- package/src/nodes/display/ScreenNode.js +1 -0
- package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +3 -3
- package/src/nodes/functions/BSDF/DFGLUT.js +56 -0
- package/src/nodes/functions/BSDF/EnvironmentBRDF.js +2 -2
- package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +1 -1
- package/src/nodes/functions/PhysicalLightingModel.js +102 -43
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -2
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +1 -1
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +2 -3
- package/src/nodes/lighting/AnalyticLightNode.js +53 -0
- package/src/nodes/lighting/LightsNode.js +2 -2
- package/src/nodes/lighting/PointShadowNode.js +141 -140
- package/src/nodes/lighting/ShadowFilterNode.js +53 -37
- package/src/nodes/lighting/ShadowNode.js +53 -19
- package/src/nodes/math/BitcountNode.js +433 -0
- package/src/nodes/math/PackFloatNode.js +98 -0
- package/src/nodes/math/UnpackFloatNode.js +96 -0
- package/src/nodes/pmrem/PMREMNode.js +1 -1
- package/src/nodes/tsl/TSLCore.js +4 -4
- package/src/nodes/utils/ArrayElementNode.js +13 -0
- package/src/nodes/utils/EventNode.js +1 -2
- package/src/nodes/utils/Packing.js +13 -1
- package/src/nodes/utils/PostProcessingUtils.js +33 -1
- package/src/nodes/utils/ReflectorNode.js +1 -1
- package/src/nodes/utils/SampleNode.js +1 -1
- package/src/nodes/utils/UVUtils.js +26 -0
- package/src/objects/BatchedMesh.js +5 -2
- package/src/objects/Line.js +1 -1
- package/src/objects/Mesh.js +1 -1
- package/src/objects/Points.js +1 -1
- package/src/objects/Skeleton.js +9 -0
- package/src/renderers/WebGLRenderer.js +145 -33
- package/src/renderers/common/Backend.js +8 -0
- package/src/renderers/common/Background.js +19 -9
- package/src/renderers/common/Binding.js +11 -0
- package/src/renderers/common/Bindings.js +7 -7
- package/src/renderers/common/Buffer.js +40 -0
- package/src/renderers/common/ChainMap.js +30 -6
- package/src/renderers/common/Geometries.js +12 -0
- package/src/renderers/common/RenderContexts.js +8 -1
- package/src/renderers/common/RenderObject.js +14 -1
- package/src/renderers/common/Renderer.js +53 -35
- package/src/renderers/common/Textures.js +1 -1
- package/src/renderers/common/UniformsGroup.js +1 -0
- package/src/renderers/common/XRManager.js +1 -0
- package/src/renderers/common/extras/PMREMGenerator.js +2 -8
- package/src/renderers/common/nodes/NodeUniformBuffer.js +52 -0
- package/src/renderers/shaders/DFGLUTData.js +19 -34
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +5 -2
- package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +8 -4
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +90 -51
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +194 -186
- package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk.js +3 -3
- package/src/renderers/shaders/ShaderLib/depth.glsl.js +3 -0
- package/src/renderers/shaders/ShaderLib/{distanceRGBA.glsl.js → distance.glsl.js} +1 -2
- package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +1 -2
- package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -9
- package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/shadow.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/vsm.glsl.js +4 -6
- package/src/renderers/shaders/ShaderLib.js +3 -3
- package/src/renderers/webgl/WebGLCapabilities.js +3 -4
- package/src/renderers/webgl/WebGLLights.js +18 -1
- package/src/renderers/webgl/WebGLOutput.js +267 -0
- package/src/renderers/webgl/WebGLProgram.js +43 -107
- package/src/renderers/webgl/WebGLPrograms.js +35 -45
- package/src/renderers/webgl/WebGLShadowMap.js +188 -25
- package/src/renderers/webgl/WebGLState.js +20 -20
- package/src/renderers/webgl/WebGLTextures.js +89 -28
- package/src/renderers/webgl/WebGLUniforms.js +40 -3
- package/src/renderers/webgl/WebGLUtils.js +6 -2
- package/src/renderers/webgl-fallback/WebGLBackend.js +79 -13
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +59 -7
- package/src/renderers/webgl-fallback/utils/WebGLState.js +18 -3
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +5 -3
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +9 -9
- package/src/renderers/webgl-fallback/utils/WebGLUtils.js +6 -2
- package/src/renderers/webgpu/WebGPUBackend.js +61 -4
- package/src/renderers/webgpu/WebGPURenderer.js +1 -1
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +65 -23
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +4 -17
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +354 -186
- package/src/renderers/webgpu/utils/WebGPUConstants.js +2 -0
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +20 -7
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +40 -17
- package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +7 -7
- package/src/renderers/webgpu/utils/WebGPUUtils.js +7 -5
- package/src/textures/CubeDepthTexture.js +76 -0
- package/src/textures/Source.js +1 -1
- package/src/textures/Texture.js +1 -1
- package/src/utils.js +13 -1
- package/src/nodes/functions/BSDF/DFGApprox.js +0 -71
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
Data3DTexture,
|
|
5
5
|
FileLoader,
|
|
6
6
|
Float32BufferAttribute,
|
|
7
|
+
Group,
|
|
7
8
|
Loader,
|
|
8
9
|
LinearFilter,
|
|
10
|
+
Matrix4,
|
|
9
11
|
Mesh,
|
|
10
12
|
MeshStandardMaterial,
|
|
11
13
|
NearestFilter,
|
|
@@ -13,21 +15,228 @@ import {
|
|
|
13
15
|
SRGBColorSpace
|
|
14
16
|
} from 'three';
|
|
15
17
|
|
|
18
|
+
// Helper function to read a STRING from the data view
|
|
19
|
+
function readString( data, offset ) {
|
|
20
|
+
|
|
21
|
+
const size = data.getUint32( offset, true );
|
|
22
|
+
offset += 4;
|
|
23
|
+
|
|
24
|
+
let str = '';
|
|
25
|
+
for ( let i = 0; i < size; i ++ ) {
|
|
26
|
+
|
|
27
|
+
str += String.fromCharCode( data.getUint8( offset ++ ) );
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { value: str, size: 4 + size };
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Helper function to read a DICT from the data view
|
|
36
|
+
function readDict( data, offset ) {
|
|
37
|
+
|
|
38
|
+
const dict = {};
|
|
39
|
+
const count = data.getUint32( offset, true );
|
|
40
|
+
offset += 4;
|
|
41
|
+
|
|
42
|
+
let totalSize = 4;
|
|
43
|
+
|
|
44
|
+
for ( let i = 0; i < count; i ++ ) {
|
|
45
|
+
|
|
46
|
+
const key = readString( data, offset );
|
|
47
|
+
offset += key.size;
|
|
48
|
+
totalSize += key.size;
|
|
49
|
+
|
|
50
|
+
const value = readString( data, offset );
|
|
51
|
+
offset += value.size;
|
|
52
|
+
totalSize += value.size;
|
|
53
|
+
|
|
54
|
+
dict[ key.value ] = value.value;
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { value: dict, size: totalSize };
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Helper function to decode ROTATION byte into a rotation matrix
|
|
63
|
+
function decodeRotation( byte ) {
|
|
64
|
+
|
|
65
|
+
// The rotation is stored as a row-major 3x3 matrix encoded in a single byte
|
|
66
|
+
// Bits 0-1: index of the non-zero entry in the first row
|
|
67
|
+
// Bits 2-3: index of the non-zero entry in the second row
|
|
68
|
+
// Bit 4: sign of the first row entry (0 = positive, 1 = negative)
|
|
69
|
+
// Bit 5: sign of the second row entry
|
|
70
|
+
// Bit 6: sign of the third row entry
|
|
71
|
+
// The third row index is determined by the remaining column
|
|
72
|
+
|
|
73
|
+
const index1 = byte & 0x3;
|
|
74
|
+
const index2 = ( byte >> 2 ) & 0x3;
|
|
75
|
+
const sign1 = ( byte >> 4 ) & 0x1 ? - 1 : 1;
|
|
76
|
+
const sign2 = ( byte >> 5 ) & 0x1 ? - 1 : 1;
|
|
77
|
+
const sign3 = ( byte >> 6 ) & 0x1 ? - 1 : 1;
|
|
78
|
+
|
|
79
|
+
// Find the third row index (the one not used by row 0 or row 1)
|
|
80
|
+
const index3 = 3 - index1 - index2;
|
|
81
|
+
|
|
82
|
+
// Build the VOX rotation matrix (row-major 3x3)
|
|
83
|
+
// r[row][col] - each row has one non-zero entry
|
|
84
|
+
const r = [
|
|
85
|
+
[ 0, 0, 0 ],
|
|
86
|
+
[ 0, 0, 0 ],
|
|
87
|
+
[ 0, 0, 0 ]
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
r[ 0 ][ index1 ] = sign1;
|
|
91
|
+
r[ 1 ][ index2 ] = sign2;
|
|
92
|
+
r[ 2 ][ index3 ] = sign3;
|
|
93
|
+
|
|
94
|
+
// Convert from VOX coordinate system (Z-up) to Three.js (Y-up)
|
|
95
|
+
// VOX: X-right, Y-forward, Z-up
|
|
96
|
+
// Three.js: X-right, Y-up, Z-backward
|
|
97
|
+
// Transformation: x' = x, y' = z, z' = -y
|
|
98
|
+
//
|
|
99
|
+
// To convert rotation matrix R_vox to R_three:
|
|
100
|
+
// R_three = C * R_vox * C^-1
|
|
101
|
+
// where C converts VOX coords to Three.js coords
|
|
102
|
+
|
|
103
|
+
// Apply coordinate change: swap Y and Z, negate new Z
|
|
104
|
+
// This is equivalent to: C * R * C^-1
|
|
105
|
+
const m = new Matrix4();
|
|
106
|
+
m.set(
|
|
107
|
+
r[ 0 ][ 0 ], r[ 0 ][ 2 ], - r[ 0 ][ 1 ], 0,
|
|
108
|
+
r[ 2 ][ 0 ], r[ 2 ][ 2 ], - r[ 2 ][ 1 ], 0,
|
|
109
|
+
- r[ 1 ][ 0 ], - r[ 1 ][ 2 ], r[ 1 ][ 1 ], 0,
|
|
110
|
+
0, 0, 0, 1
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return m;
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Apply VOX transform to a Three.js object
|
|
118
|
+
function applyTransform( object, node ) {
|
|
119
|
+
|
|
120
|
+
if ( node.attributes._name ) {
|
|
121
|
+
|
|
122
|
+
object.name = node.attributes._name;
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ( node.frames.length > 0 ) {
|
|
127
|
+
|
|
128
|
+
const frame = node.frames[ 0 ];
|
|
129
|
+
|
|
130
|
+
if ( frame.rotation ) {
|
|
131
|
+
|
|
132
|
+
object.applyMatrix4( frame.rotation );
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if ( frame.translation ) {
|
|
137
|
+
|
|
138
|
+
// VOX uses Z-up, Three.js uses Y-up
|
|
139
|
+
object.position.set(
|
|
140
|
+
frame.translation.x,
|
|
141
|
+
frame.translation.z,
|
|
142
|
+
- frame.translation.y
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Recursively build Three.js object graph from VOX nodes
|
|
152
|
+
function buildObject( nodeId, nodes, chunks ) {
|
|
153
|
+
|
|
154
|
+
const node = nodes[ nodeId ];
|
|
155
|
+
|
|
156
|
+
if ( node.type === 'transform' ) {
|
|
157
|
+
|
|
158
|
+
const childNode = nodes[ node.childNodeId ];
|
|
159
|
+
|
|
160
|
+
// Check if this transform has actual transformation data
|
|
161
|
+
const frame = node.frames[ 0 ];
|
|
162
|
+
const hasTransform = frame && ( frame.rotation || frame.translation );
|
|
163
|
+
|
|
164
|
+
// Flatten: if child is a single-model shape, apply transform directly to mesh
|
|
165
|
+
if ( childNode.type === 'shape' && childNode.models.length === 1 ) {
|
|
166
|
+
|
|
167
|
+
const chunk = chunks[ childNode.models[ 0 ].modelId ];
|
|
168
|
+
const mesh = buildMesh( chunk );
|
|
169
|
+
applyTransform( mesh, node );
|
|
170
|
+
return mesh;
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// If no transform, just return the child directly (avoid unnecessary group)
|
|
175
|
+
if ( ! hasTransform ) {
|
|
176
|
+
|
|
177
|
+
const child = buildObject( node.childNodeId, nodes, chunks );
|
|
178
|
+
if ( child && node.attributes._name ) child.name = node.attributes._name;
|
|
179
|
+
return child;
|
|
180
|
+
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Otherwise create a group
|
|
184
|
+
const group = new Group();
|
|
185
|
+
applyTransform( group, node );
|
|
186
|
+
|
|
187
|
+
const child = buildObject( node.childNodeId, nodes, chunks );
|
|
188
|
+
if ( child ) group.add( child );
|
|
189
|
+
|
|
190
|
+
return group;
|
|
191
|
+
|
|
192
|
+
} else if ( node.type === 'group' ) {
|
|
193
|
+
|
|
194
|
+
const group = new Group();
|
|
195
|
+
|
|
196
|
+
for ( const childId of node.childIds ) {
|
|
197
|
+
|
|
198
|
+
const child = buildObject( childId, nodes, chunks );
|
|
199
|
+
if ( child ) group.add( child );
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return group;
|
|
204
|
+
|
|
205
|
+
} else if ( node.type === 'shape' ) {
|
|
206
|
+
|
|
207
|
+
// Shape reached directly (shouldn't happen in well-formed files, but handle it)
|
|
208
|
+
if ( node.models.length === 1 ) {
|
|
209
|
+
|
|
210
|
+
const chunk = chunks[ node.models[ 0 ].modelId ];
|
|
211
|
+
return buildMesh( chunk );
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const group = new Group();
|
|
216
|
+
|
|
217
|
+
for ( const model of node.models ) {
|
|
218
|
+
|
|
219
|
+
const chunk = chunks[ model.modelId ];
|
|
220
|
+
group.add( buildMesh( chunk ) );
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return group;
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return null;
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
|
|
16
232
|
/**
|
|
17
233
|
* A loader for the VOX format.
|
|
18
234
|
*
|
|
19
235
|
* ```js
|
|
20
236
|
* const loader = new VOXLoader();
|
|
21
|
-
* const
|
|
22
|
-
*
|
|
23
|
-
* for ( let i = 0; i < chunks.length; i ++ ) {
|
|
237
|
+
* const result = await loader.loadAsync( 'models/vox/monu10.vox' );
|
|
24
238
|
*
|
|
25
|
-
*
|
|
26
|
-
* const mesh = new VOXMesh( chunk );
|
|
27
|
-
* mesh.scale.setScalar( 0.0015 );
|
|
28
|
-
* scene.add( mesh );
|
|
29
|
-
*
|
|
30
|
-
* }
|
|
239
|
+
* scene.add( result.scene.children[ 0 ] );
|
|
31
240
|
* ```
|
|
32
241
|
* @augments Loader
|
|
33
242
|
* @three_import import { VOXLoader } from 'three/addons/loaders/VOXLoader.js';
|
|
@@ -39,7 +248,7 @@ class VOXLoader extends Loader {
|
|
|
39
248
|
* to the `onLoad()` callback.
|
|
40
249
|
*
|
|
41
250
|
* @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
|
|
42
|
-
* @param {function(
|
|
251
|
+
* @param {function(Object)} onLoad - Executed when the loading process has been finished.
|
|
43
252
|
* @param {onProgressCallback} onProgress - Executed while the loading is in progress.
|
|
44
253
|
* @param {onErrorCallback} onError - Executed when errors occur.
|
|
45
254
|
*/
|
|
@@ -78,10 +287,10 @@ class VOXLoader extends Loader {
|
|
|
78
287
|
}
|
|
79
288
|
|
|
80
289
|
/**
|
|
81
|
-
* Parses the given VOX data and returns the
|
|
290
|
+
* Parses the given VOX data and returns the result object.
|
|
82
291
|
*
|
|
83
292
|
* @param {ArrayBuffer} buffer - The raw VOX data as an array buffer.
|
|
84
|
-
* @return {
|
|
293
|
+
* @return {Object} The parsed VOX data with properties: chunks, scene.
|
|
85
294
|
*/
|
|
86
295
|
parse( buffer ) {
|
|
87
296
|
|
|
@@ -97,7 +306,7 @@ class VOXLoader extends Loader {
|
|
|
97
306
|
|
|
98
307
|
}
|
|
99
308
|
|
|
100
|
-
if ( version !== 150 ) {
|
|
309
|
+
if ( version !== 150 && version !== 200 ) {
|
|
101
310
|
|
|
102
311
|
console.error( 'THREE.VOXLoader: Invalid VOX file. Unsupported version:', version );
|
|
103
312
|
return;
|
|
@@ -144,6 +353,10 @@ class VOXLoader extends Loader {
|
|
|
144
353
|
let chunk;
|
|
145
354
|
const chunks = [];
|
|
146
355
|
|
|
356
|
+
// Extension data
|
|
357
|
+
const nodes = {};
|
|
358
|
+
let palette = DEFAULT_PALETTE;
|
|
359
|
+
|
|
147
360
|
while ( i < data.byteLength ) {
|
|
148
361
|
|
|
149
362
|
let id = '';
|
|
@@ -181,7 +394,7 @@ class VOXLoader extends Loader {
|
|
|
181
394
|
|
|
182
395
|
} else if ( id === 'RGBA' ) {
|
|
183
396
|
|
|
184
|
-
|
|
397
|
+
palette = [ 0 ];
|
|
185
398
|
|
|
186
399
|
for ( let j = 0; j < 256; j ++ ) {
|
|
187
400
|
|
|
@@ -191,186 +404,516 @@ class VOXLoader extends Loader {
|
|
|
191
404
|
|
|
192
405
|
chunk.palette = palette;
|
|
193
406
|
|
|
194
|
-
} else {
|
|
407
|
+
} else if ( id === 'nTRN' ) {
|
|
408
|
+
|
|
409
|
+
// Transform Node
|
|
410
|
+
const nodeId = data.getUint32( i, true ); i += 4;
|
|
411
|
+
const attributes = readDict( data, i );
|
|
412
|
+
i += attributes.size;
|
|
413
|
+
|
|
414
|
+
const childNodeId = data.getUint32( i, true ); i += 4;
|
|
415
|
+
i += 4; // reserved (-1)
|
|
416
|
+
const layerId = data.getInt32( i, true ); i += 4;
|
|
417
|
+
const numFrames = data.getUint32( i, true ); i += 4;
|
|
418
|
+
|
|
419
|
+
const frames = [];
|
|
420
|
+
|
|
421
|
+
for ( let f = 0; f < numFrames; f ++ ) {
|
|
422
|
+
|
|
423
|
+
const frameDict = readDict( data, i );
|
|
424
|
+
i += frameDict.size;
|
|
425
|
+
|
|
426
|
+
const frame = { rotation: null, translation: null };
|
|
427
|
+
|
|
428
|
+
if ( frameDict.value._r !== undefined ) {
|
|
429
|
+
|
|
430
|
+
frame.rotation = decodeRotation( parseInt( frameDict.value._r ) );
|
|
195
431
|
|
|
196
|
-
|
|
432
|
+
}
|
|
197
433
|
|
|
434
|
+
if ( frameDict.value._t !== undefined ) {
|
|
435
|
+
|
|
436
|
+
const parts = frameDict.value._t.split( ' ' ).map( Number );
|
|
437
|
+
frame.translation = { x: parts[ 0 ], y: parts[ 1 ], z: parts[ 2 ] };
|
|
438
|
+
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
frames.push( frame );
|
|
442
|
+
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
nodes[ nodeId ] = {
|
|
446
|
+
type: 'transform',
|
|
447
|
+
id: nodeId,
|
|
448
|
+
attributes: attributes.value,
|
|
449
|
+
childNodeId: childNodeId,
|
|
450
|
+
layerId: layerId,
|
|
451
|
+
frames: frames
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
} else if ( id === 'nGRP' ) {
|
|
455
|
+
|
|
456
|
+
// Group Node
|
|
457
|
+
const nodeId = data.getUint32( i, true ); i += 4;
|
|
458
|
+
const attributes = readDict( data, i );
|
|
459
|
+
i += attributes.size;
|
|
460
|
+
|
|
461
|
+
const numChildren = data.getUint32( i, true ); i += 4;
|
|
462
|
+
const childIds = [];
|
|
463
|
+
|
|
464
|
+
for ( let c = 0; c < numChildren; c ++ ) {
|
|
465
|
+
|
|
466
|
+
childIds.push( data.getUint32( i, true ) ); i += 4;
|
|
467
|
+
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
nodes[ nodeId ] = {
|
|
471
|
+
type: 'group',
|
|
472
|
+
id: nodeId,
|
|
473
|
+
attributes: attributes.value,
|
|
474
|
+
childIds: childIds
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
} else if ( id === 'nSHP' ) {
|
|
478
|
+
|
|
479
|
+
// Shape Node
|
|
480
|
+
const nodeId = data.getUint32( i, true ); i += 4;
|
|
481
|
+
const attributes = readDict( data, i );
|
|
482
|
+
i += attributes.size;
|
|
483
|
+
|
|
484
|
+
const numModels = data.getUint32( i, true ); i += 4;
|
|
485
|
+
const models = [];
|
|
486
|
+
|
|
487
|
+
for ( let m = 0; m < numModels; m ++ ) {
|
|
488
|
+
|
|
489
|
+
const modelId = data.getUint32( i, true ); i += 4;
|
|
490
|
+
const modelAttributes = readDict( data, i );
|
|
491
|
+
i += modelAttributes.size;
|
|
492
|
+
|
|
493
|
+
models.push( {
|
|
494
|
+
modelId: modelId,
|
|
495
|
+
attributes: modelAttributes.value
|
|
496
|
+
} );
|
|
497
|
+
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
nodes[ nodeId ] = {
|
|
501
|
+
type: 'shape',
|
|
502
|
+
id: nodeId,
|
|
503
|
+
attributes: attributes.value,
|
|
504
|
+
models: models
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
} else {
|
|
508
|
+
|
|
509
|
+
// Skip unknown chunks
|
|
198
510
|
i += chunkSize;
|
|
199
511
|
|
|
200
512
|
}
|
|
201
513
|
|
|
202
514
|
}
|
|
203
515
|
|
|
204
|
-
|
|
516
|
+
// Apply palette to all chunks
|
|
517
|
+
for ( let c = 0; c < chunks.length; c ++ ) {
|
|
518
|
+
|
|
519
|
+
chunks[ c ].palette = palette;
|
|
520
|
+
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Build Three.js scene graph from nodes
|
|
524
|
+
let scene = null;
|
|
525
|
+
|
|
526
|
+
if ( Object.keys( nodes ).length > 0 ) {
|
|
527
|
+
|
|
528
|
+
scene = buildObject( 0, nodes, chunks );
|
|
529
|
+
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Build result object
|
|
533
|
+
const result = {
|
|
534
|
+
chunks: chunks,
|
|
535
|
+
scene: scene
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// @deprecated, r182
|
|
539
|
+
// Proxy for backwards compatibility with array-like access
|
|
540
|
+
let warned = false;
|
|
541
|
+
|
|
542
|
+
return new Proxy( result, {
|
|
543
|
+
|
|
544
|
+
get( target, prop ) {
|
|
545
|
+
|
|
546
|
+
// Handle numeric indices
|
|
547
|
+
if ( typeof prop === 'string' && /^\d+$/.test( prop ) ) {
|
|
548
|
+
|
|
549
|
+
if ( ! warned ) {
|
|
550
|
+
|
|
551
|
+
console.warn( 'THREE.VOXLoader: Accessing result as an array is deprecated. Use result.chunks[] instead.' );
|
|
552
|
+
warned = true;
|
|
553
|
+
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return target.chunks[ parseInt( prop ) ];
|
|
557
|
+
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Handle array properties/methods
|
|
561
|
+
if ( prop === 'length' ) {
|
|
562
|
+
|
|
563
|
+
if ( ! warned ) {
|
|
564
|
+
|
|
565
|
+
console.warn( 'THREE.VOXLoader: Accessing result as an array is deprecated. Use result.chunks instead.' );
|
|
566
|
+
warned = true;
|
|
567
|
+
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return target.chunks.length;
|
|
571
|
+
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Handle iteration
|
|
575
|
+
if ( prop === Symbol.iterator ) {
|
|
576
|
+
|
|
577
|
+
if ( ! warned ) {
|
|
578
|
+
|
|
579
|
+
console.warn( 'THREE.VOXLoader: Iterating result as an array is deprecated. Use result.chunks instead.' );
|
|
580
|
+
warned = true;
|
|
581
|
+
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return target.chunks[ Symbol.iterator ].bind( target.chunks );
|
|
585
|
+
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return target[ prop ];
|
|
589
|
+
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
} );
|
|
205
593
|
|
|
206
594
|
}
|
|
207
595
|
|
|
208
596
|
}
|
|
209
597
|
|
|
210
598
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* Instances of this class are created from the loaded chunks of {@link VOXLoader}.
|
|
599
|
+
* Builds a mesh from a VOX chunk.
|
|
214
600
|
*
|
|
215
|
-
* @
|
|
601
|
+
* @param {Object} chunk - A VOX chunk loaded via {@link VOXLoader}.
|
|
602
|
+
* @return {Mesh} The generated mesh.
|
|
216
603
|
*/
|
|
217
|
-
|
|
604
|
+
function buildMesh( chunk ) {
|
|
218
605
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
606
|
+
const data = chunk.data;
|
|
607
|
+
const size = chunk.size;
|
|
608
|
+
const palette = chunk.palette;
|
|
609
|
+
|
|
610
|
+
const sx = size.x;
|
|
611
|
+
const sy = size.y;
|
|
612
|
+
const sz = size.z;
|
|
613
|
+
|
|
614
|
+
// Build volume with color indices
|
|
615
|
+
|
|
616
|
+
const volume = new Uint8Array( sx * sy * sz );
|
|
617
|
+
|
|
618
|
+
for ( let j = 0; j < data.length; j += 4 ) {
|
|
619
|
+
|
|
620
|
+
const x = data[ j + 0 ];
|
|
621
|
+
const y = data[ j + 1 ];
|
|
622
|
+
const z = data[ j + 2 ];
|
|
623
|
+
const c = data[ j + 3 ];
|
|
624
|
+
|
|
625
|
+
volume[ x + y * sx + z * sx * sy ] = c;
|
|
626
|
+
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Greedy meshing
|
|
630
|
+
|
|
631
|
+
const vertices = [];
|
|
632
|
+
const indices = [];
|
|
633
|
+
const colors = [];
|
|
634
|
+
|
|
635
|
+
const _color = new Color();
|
|
636
|
+
let hasColors = false;
|
|
637
|
+
|
|
638
|
+
// Process each of the 6 face directions
|
|
639
|
+
// dims: the 3 axis sizes, d: which axis is normal to the face
|
|
640
|
+
const dims = [ sx, sy, sz ];
|
|
641
|
+
|
|
642
|
+
for ( let d = 0; d < 3; d ++ ) {
|
|
643
|
+
|
|
644
|
+
const u = ( d + 1 ) % 3;
|
|
645
|
+
const v = ( d + 2 ) % 3;
|
|
646
|
+
|
|
647
|
+
const dimsD = dims[ d ];
|
|
648
|
+
const dimsU = dims[ u ];
|
|
649
|
+
const dimsV = dims[ v ];
|
|
650
|
+
|
|
651
|
+
const q = [ 0, 0, 0 ];
|
|
652
|
+
const mask = new Int16Array( dimsU * dimsV );
|
|
653
|
+
|
|
654
|
+
q[ d ] = 1;
|
|
655
|
+
|
|
656
|
+
// Sweep through slices
|
|
657
|
+
for ( let slice = 0; slice <= dimsD; slice ++ ) {
|
|
658
|
+
|
|
659
|
+
// Build mask for this slice
|
|
660
|
+
let n = 0;
|
|
661
|
+
|
|
662
|
+
for ( let vv = 0; vv < dimsV; vv ++ ) {
|
|
663
|
+
|
|
664
|
+
for ( let uu = 0; uu < dimsU; uu ++ ) {
|
|
665
|
+
|
|
666
|
+
const pos = [ 0, 0, 0 ];
|
|
667
|
+
pos[ d ] = slice;
|
|
668
|
+
pos[ u ] = uu;
|
|
669
|
+
pos[ v ] = vv;
|
|
225
670
|
|
|
226
|
-
|
|
227
|
-
const size = chunk.size;
|
|
228
|
-
const palette = chunk.palette;
|
|
671
|
+
const x0 = pos[ 0 ], y0 = pos[ 1 ], z0 = pos[ 2 ];
|
|
229
672
|
|
|
230
|
-
|
|
673
|
+
// Get voxel behind and in front of this face
|
|
674
|
+
const behind = ( slice > 0 ) ? volume[ ( x0 - q[ 0 ] ) + ( y0 - q[ 1 ] ) * sx + ( z0 - q[ 2 ] ) * sx * sy ] : 0;
|
|
675
|
+
const infront = ( slice < dimsD ) ? volume[ x0 + y0 * sx + z0 * sx * sy ] : 0;
|
|
231
676
|
|
|
232
|
-
|
|
233
|
-
|
|
677
|
+
// Face exists if exactly one side is solid
|
|
678
|
+
if ( behind > 0 && infront === 0 ) {
|
|
234
679
|
|
|
235
|
-
|
|
236
|
-
const px = [ 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 ];
|
|
237
|
-
const py = [ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1 ];
|
|
238
|
-
const ny = [ 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0 ];
|
|
239
|
-
const nz = [ 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0 ];
|
|
240
|
-
const pz = [ 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1 ];
|
|
680
|
+
mask[ n ] = behind; // positive face
|
|
241
681
|
|
|
242
|
-
|
|
682
|
+
} else if ( infront > 0 && behind === 0 ) {
|
|
243
683
|
|
|
244
|
-
|
|
684
|
+
mask[ n ] = - infront; // negative face
|
|
245
685
|
|
|
246
|
-
|
|
247
|
-
y -= size.z / 2;
|
|
248
|
-
z += size.y / 2;
|
|
686
|
+
} else {
|
|
249
687
|
|
|
250
|
-
|
|
688
|
+
mask[ n ] = 0;
|
|
251
689
|
|
|
252
|
-
|
|
690
|
+
}
|
|
253
691
|
|
|
254
|
-
|
|
255
|
-
|
|
692
|
+
n ++;
|
|
693
|
+
|
|
694
|
+
}
|
|
256
695
|
|
|
257
696
|
}
|
|
258
697
|
|
|
259
|
-
|
|
698
|
+
// Greedy merge mask into quads
|
|
699
|
+
n = 0;
|
|
260
700
|
|
|
261
|
-
|
|
701
|
+
for ( let vv = 0; vv < dimsV; vv ++ ) {
|
|
262
702
|
|
|
263
|
-
|
|
264
|
-
const offsetz = size.x * size.y;
|
|
703
|
+
for ( let uu = 0; uu < dimsU; ) {
|
|
265
704
|
|
|
266
|
-
|
|
705
|
+
const c = mask[ n ];
|
|
267
706
|
|
|
268
|
-
|
|
707
|
+
if ( c !== 0 ) {
|
|
269
708
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const z = data[ j + 2 ];
|
|
709
|
+
// Find width
|
|
710
|
+
let w = 1;
|
|
273
711
|
|
|
274
|
-
|
|
712
|
+
while ( uu + w < dimsU && mask[ n + w ] === c ) {
|
|
275
713
|
|
|
276
|
-
|
|
714
|
+
w ++;
|
|
277
715
|
|
|
278
|
-
|
|
716
|
+
}
|
|
279
717
|
|
|
280
|
-
|
|
718
|
+
// Find height
|
|
719
|
+
let h = 1;
|
|
720
|
+
let done = false;
|
|
281
721
|
|
|
282
|
-
|
|
722
|
+
while ( vv + h < dimsV && ! done ) {
|
|
283
723
|
|
|
284
|
-
|
|
724
|
+
for ( let k = 0; k < w; k ++ ) {
|
|
285
725
|
|
|
286
|
-
|
|
287
|
-
const y = data[ j + 1 ];
|
|
288
|
-
const z = data[ j + 2 ];
|
|
289
|
-
const c = data[ j + 3 ];
|
|
726
|
+
if ( mask[ n + k + h * dimsU ] !== c ) {
|
|
290
727
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const g = ( hex >> 8 & 0xff ) / 0xff;
|
|
294
|
-
const b = ( hex >> 16 & 0xff ) / 0xff;
|
|
728
|
+
done = true;
|
|
729
|
+
break;
|
|
295
730
|
|
|
296
|
-
|
|
731
|
+
}
|
|
297
732
|
|
|
298
|
-
|
|
733
|
+
}
|
|
299
734
|
|
|
300
|
-
|
|
301
|
-
if ( array[ index - 1 ] === 0 || x === 0 ) add( nx, x, z, - y, r, g, b );
|
|
302
|
-
if ( array[ index + offsety ] === 0 || y === size.y - 1 ) add( ny, x, z, - y, r, g, b );
|
|
303
|
-
if ( array[ index - offsety ] === 0 || y === 0 ) add( py, x, z, - y, r, g, b );
|
|
304
|
-
if ( array[ index + offsetz ] === 0 || z === size.z - 1 ) add( pz, x, z, - y, r, g, b );
|
|
305
|
-
if ( array[ index - offsetz ] === 0 || z === 0 ) add( nz, x, z, - y, r, g, b );
|
|
735
|
+
if ( ! done ) h ++;
|
|
306
736
|
|
|
307
|
-
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// Add quad
|
|
740
|
+
const pos = [ 0, 0, 0 ];
|
|
741
|
+
pos[ d ] = slice;
|
|
742
|
+
pos[ u ] = uu;
|
|
743
|
+
pos[ v ] = vv;
|
|
744
|
+
|
|
745
|
+
const du = [ 0, 0, 0 ];
|
|
746
|
+
const dv = [ 0, 0, 0 ];
|
|
747
|
+
du[ u ] = w;
|
|
748
|
+
dv[ v ] = h;
|
|
749
|
+
|
|
750
|
+
// Get color
|
|
751
|
+
const colorIndex = Math.abs( c );
|
|
752
|
+
const hex = palette[ colorIndex ];
|
|
753
|
+
const r = ( hex >> 0 & 0xff ) / 0xff;
|
|
754
|
+
const g = ( hex >> 8 & 0xff ) / 0xff;
|
|
755
|
+
const b = ( hex >> 16 & 0xff ) / 0xff;
|
|
756
|
+
|
|
757
|
+
if ( r > 0 || g > 0 || b > 0 ) hasColors = true;
|
|
758
|
+
|
|
759
|
+
_color.setRGB( r, g, b, SRGBColorSpace );
|
|
760
|
+
|
|
761
|
+
// Convert VOX coords to Three.js coords (Y-up)
|
|
762
|
+
// VOX: X right, Y forward, Z up -> Three.js: X right, Y up, Z back
|
|
763
|
+
const toThree = ( p ) => [
|
|
764
|
+
p[ 0 ] - sx / 2,
|
|
765
|
+
p[ 2 ] - sz / 2,
|
|
766
|
+
- p[ 1 ] + sy / 2
|
|
767
|
+
];
|
|
768
|
+
|
|
769
|
+
const v0 = toThree( pos );
|
|
770
|
+
const v1 = toThree( [ pos[ 0 ] + du[ 0 ], pos[ 1 ] + du[ 1 ], pos[ 2 ] + du[ 2 ] ] );
|
|
771
|
+
const v2 = toThree( [ pos[ 0 ] + du[ 0 ] + dv[ 0 ], pos[ 1 ] + du[ 1 ] + dv[ 1 ], pos[ 2 ] + du[ 2 ] + dv[ 2 ] ] );
|
|
772
|
+
const v3 = toThree( [ pos[ 0 ] + dv[ 0 ], pos[ 1 ] + dv[ 1 ], pos[ 2 ] + dv[ 2 ] ] );
|
|
773
|
+
|
|
774
|
+
const idx = vertices.length / 3;
|
|
775
|
+
|
|
776
|
+
// Winding order depends on face direction
|
|
777
|
+
if ( c > 0 ) {
|
|
778
|
+
|
|
779
|
+
vertices.push( ...v0, ...v1, ...v2, ...v3 );
|
|
780
|
+
indices.push( idx, idx + 1, idx + 2, idx, idx + 2, idx + 3 );
|
|
781
|
+
|
|
782
|
+
} else {
|
|
308
783
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
geometry.computeVertexNormals();
|
|
784
|
+
vertices.push( ...v0, ...v3, ...v2, ...v1 );
|
|
785
|
+
indices.push( idx, idx + 1, idx + 2, idx, idx + 2, idx + 3 );
|
|
312
786
|
|
|
313
|
-
|
|
787
|
+
}
|
|
314
788
|
|
|
315
|
-
|
|
789
|
+
colors.push(
|
|
790
|
+
_color.r, _color.g, _color.b,
|
|
791
|
+
_color.r, _color.g, _color.b,
|
|
792
|
+
_color.r, _color.g, _color.b,
|
|
793
|
+
_color.r, _color.g, _color.b
|
|
794
|
+
);
|
|
316
795
|
|
|
317
|
-
|
|
318
|
-
|
|
796
|
+
// Clear mask
|
|
797
|
+
for ( let hh = 0; hh < h; hh ++ ) {
|
|
798
|
+
|
|
799
|
+
for ( let ww = 0; ww < w; ww ++ ) {
|
|
800
|
+
|
|
801
|
+
mask[ n + ww + hh * dimsU ] = 0;
|
|
802
|
+
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
uu += w;
|
|
808
|
+
n += w;
|
|
809
|
+
|
|
810
|
+
} else {
|
|
811
|
+
|
|
812
|
+
uu ++;
|
|
813
|
+
n ++;
|
|
814
|
+
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
}
|
|
319
820
|
|
|
320
821
|
}
|
|
321
822
|
|
|
322
|
-
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const geometry = new BufferGeometry();
|
|
826
|
+
geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
|
|
827
|
+
geometry.setIndex( indices );
|
|
828
|
+
geometry.computeVertexNormals();
|
|
829
|
+
|
|
830
|
+
const material = new MeshStandardMaterial();
|
|
831
|
+
|
|
832
|
+
if ( hasColors ) {
|
|
833
|
+
|
|
834
|
+
geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
|
|
835
|
+
material.vertexColors = true;
|
|
323
836
|
|
|
324
837
|
}
|
|
325
838
|
|
|
839
|
+
return new Mesh( geometry, material );
|
|
840
|
+
|
|
326
841
|
}
|
|
327
842
|
|
|
328
843
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
* Instances of this class are created from the loaded chunks of {@link VOXLoader}.
|
|
844
|
+
* Builds a 3D texture from a VOX chunk.
|
|
332
845
|
*
|
|
333
|
-
* @
|
|
846
|
+
* @param {Object} chunk - A VOX chunk loaded via {@link VOXLoader}.
|
|
847
|
+
* @return {Data3DTexture} The generated 3D texture.
|
|
334
848
|
*/
|
|
335
|
-
|
|
849
|
+
function buildData3DTexture( chunk ) {
|
|
850
|
+
|
|
851
|
+
const data = chunk.data;
|
|
852
|
+
const size = chunk.size;
|
|
853
|
+
|
|
854
|
+
const offsety = size.x;
|
|
855
|
+
const offsetz = size.x * size.y;
|
|
856
|
+
|
|
857
|
+
const array = new Uint8Array( size.x * size.y * size.z );
|
|
858
|
+
|
|
859
|
+
for ( let j = 0; j < data.length; j += 4 ) {
|
|
860
|
+
|
|
861
|
+
const x = data[ j + 0 ];
|
|
862
|
+
const y = data[ j + 1 ];
|
|
863
|
+
const z = data[ j + 2 ];
|
|
864
|
+
|
|
865
|
+
const index = x + ( y * offsety ) + ( z * offsetz );
|
|
866
|
+
|
|
867
|
+
array[ index ] = 255;
|
|
868
|
+
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const texture = new Data3DTexture( array, size.x, size.y, size.z );
|
|
872
|
+
|
|
873
|
+
texture.format = RedFormat;
|
|
874
|
+
texture.minFilter = NearestFilter;
|
|
875
|
+
texture.magFilter = LinearFilter;
|
|
876
|
+
texture.unpackAlignment = 1;
|
|
877
|
+
texture.needsUpdate = true;
|
|
878
|
+
|
|
879
|
+
return texture;
|
|
880
|
+
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// @deprecated, r182
|
|
884
|
+
|
|
885
|
+
class VOXMesh extends Mesh {
|
|
336
886
|
|
|
337
|
-
/**
|
|
338
|
-
* Constructs a new VOX 3D texture.
|
|
339
|
-
*
|
|
340
|
-
* @param {Object} chunk - A VOX chunk loaded via {@link VOXLoader}.
|
|
341
|
-
*/
|
|
342
887
|
constructor( chunk ) {
|
|
343
888
|
|
|
344
|
-
|
|
345
|
-
const size = chunk.size;
|
|
889
|
+
console.warn( 'VOXMesh has been deprecated. Use buildMesh() instead.' );
|
|
346
890
|
|
|
347
|
-
const
|
|
348
|
-
const offsetz = size.x * size.y;
|
|
891
|
+
const mesh = buildMesh( chunk );
|
|
349
892
|
|
|
350
|
-
|
|
893
|
+
super( mesh.geometry, mesh.material );
|
|
351
894
|
|
|
352
|
-
|
|
895
|
+
}
|
|
353
896
|
|
|
354
|
-
|
|
355
|
-
const y = data[ j + 1 ];
|
|
356
|
-
const z = data[ j + 2 ];
|
|
897
|
+
}
|
|
357
898
|
|
|
358
|
-
|
|
899
|
+
class VOXData3DTexture extends Data3DTexture {
|
|
359
900
|
|
|
360
|
-
|
|
901
|
+
constructor( chunk ) {
|
|
361
902
|
|
|
362
|
-
|
|
903
|
+
console.warn( 'VOXData3DTexture has been deprecated. Use buildData3DTexture() instead.' );
|
|
904
|
+
|
|
905
|
+
const texture = buildData3DTexture( chunk );
|
|
363
906
|
|
|
364
|
-
super(
|
|
907
|
+
super( texture.image.data, texture.image.width, texture.image.height, texture.image.depth );
|
|
365
908
|
|
|
366
|
-
this.format =
|
|
367
|
-
this.minFilter =
|
|
368
|
-
this.magFilter =
|
|
369
|
-
this.unpackAlignment =
|
|
909
|
+
this.format = texture.format;
|
|
910
|
+
this.minFilter = texture.minFilter;
|
|
911
|
+
this.magFilter = texture.magFilter;
|
|
912
|
+
this.unpackAlignment = texture.unpackAlignment;
|
|
370
913
|
this.needsUpdate = true;
|
|
371
914
|
|
|
372
915
|
}
|
|
373
916
|
|
|
374
917
|
}
|
|
375
918
|
|
|
376
|
-
export { VOXLoader, VOXMesh, VOXData3DTexture };
|
|
919
|
+
export { VOXLoader, buildMesh, buildData3DTexture, VOXMesh, VOXData3DTexture };
|