@plastic-software/three 0.183.4 → 0.184.1
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 +775 -287
- package/build/three.core.js +372 -110
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +428 -181
- package/build/three.module.min.js +1 -1
- package/build/three.tsl.js +7 -1
- package/build/three.tsl.min.js +1 -1
- package/build/three.webgpu.js +2979 -1281
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +2942 -1281
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/Addons.js +11 -0
- package/examples/jsm/animation/CCDIKSolver.js +5 -1
- package/examples/jsm/controls/ArcballControls.js +4 -1
- package/examples/jsm/controls/DragControls.js +2 -2
- package/examples/jsm/controls/FirstPersonControls.js +58 -54
- package/examples/jsm/controls/FlyControls.js +4 -0
- package/examples/jsm/controls/OrbitControls.js +2 -2
- package/examples/jsm/controls/TrackballControls.js +2 -2
- package/examples/jsm/controls/TransformControls.js +34 -2
- package/examples/jsm/csm/CSMShadowNode.js +6 -2
- package/examples/jsm/exporters/GLTFExporter.js +21 -5
- package/examples/jsm/geometries/TextGeometry.js +18 -0
- package/examples/jsm/helpers/LightProbeGridHelper.js +221 -0
- package/examples/jsm/inspector/Extension.js +13 -0
- package/examples/jsm/inspector/Inspector.js +169 -114
- package/examples/jsm/inspector/RendererInspector.js +2 -2
- package/examples/jsm/inspector/extensions/extensions.json +6 -0
- package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js +916 -0
- package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphLoader.js +281 -0
- package/examples/jsm/inspector/tabs/Memory.js +128 -0
- package/examples/jsm/inspector/tabs/Parameters.js +34 -2
- package/examples/jsm/inspector/tabs/Performance.js +2 -2
- package/examples/jsm/inspector/tabs/Settings.js +264 -0
- package/examples/jsm/inspector/tabs/Timeline.js +1611 -0
- package/examples/jsm/inspector/tabs/Viewer.js +105 -3
- package/examples/jsm/inspector/ui/Graph.js +2 -2
- package/examples/jsm/inspector/ui/List.js +1 -1
- package/examples/jsm/inspector/ui/Profiler.js +273 -176
- package/examples/jsm/inspector/ui/Style.js +64 -10
- package/examples/jsm/inspector/ui/Tab.js +39 -7
- package/examples/jsm/inspector/ui/Values.js +39 -2
- package/examples/jsm/inspector/ui/utils.js +13 -0
- package/examples/jsm/interaction/InteractionManager.js +226 -0
- package/examples/jsm/libs/meshopt_decoder.module.js +8 -8
- package/examples/jsm/lighting/DynamicLighting.js +82 -0
- package/examples/jsm/lighting/LightProbeGrid.js +651 -0
- package/examples/jsm/lines/LineMaterial.js +1 -1
- package/examples/jsm/loaders/EXRLoader.js +682 -43
- package/examples/jsm/loaders/FBXLoader.js +233 -33
- package/examples/jsm/loaders/GLTFLoader.js +24 -7
- package/examples/jsm/loaders/HDRLoader.js +1 -1
- package/examples/jsm/loaders/KTX2Loader.js +8 -2
- package/examples/jsm/loaders/LDrawLoader.js +39 -47
- package/examples/jsm/loaders/SVGLoader.js +1 -1
- package/examples/jsm/loaders/VTKLoader.js +5 -1
- package/examples/jsm/loaders/collada/ColladaComposer.js +101 -7
- package/examples/jsm/loaders/collada/ColladaParser.js +19 -4
- package/examples/jsm/loaders/usd/USDAParser.js +6 -0
- package/examples/jsm/loaders/usd/USDCParser.js +26 -0
- package/examples/jsm/loaders/usd/USDComposer.js +656 -103
- package/examples/jsm/misc/GPUComputationRenderer.js +2 -0
- package/examples/jsm/misc/RollerCoaster.js +42 -4
- package/examples/jsm/modifiers/TessellateModifier.js +1 -1
- package/examples/jsm/objects/Reflector.js +73 -25
- package/examples/jsm/objects/Sky.js +14 -2
- package/examples/jsm/objects/SkyMesh.js +23 -6
- package/examples/jsm/renderers/Projector.js +18 -38
- package/examples/jsm/renderers/SVGRenderer.js +6 -25
- package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
- package/examples/jsm/tsl/WebGLNodesHandler.js +605 -0
- package/examples/jsm/tsl/display/AfterImageNode.js +10 -0
- package/examples/jsm/tsl/display/AnamorphicNode.js +11 -0
- package/examples/jsm/tsl/display/BilateralBlurNode.js +10 -0
- package/examples/jsm/tsl/display/ChromaticAberrationNode.js +3 -36
- package/examples/jsm/tsl/display/FSR1Node.js +477 -0
- package/examples/jsm/tsl/display/GTAONode.js +2 -1
- package/examples/jsm/tsl/display/GaussianBlurNode.js +10 -0
- package/examples/jsm/tsl/display/GodraysNode.js +2 -11
- package/examples/jsm/tsl/display/OutlineNode.js +66 -16
- package/examples/jsm/tsl/display/SSGINode.js +0 -4
- package/examples/jsm/tsl/display/SharpenNode.js +283 -0
- package/examples/jsm/tsl/display/TAAUNode.js +835 -0
- package/examples/jsm/tsl/display/TRAANode.js +48 -7
- package/examples/jsm/tsl/lighting/DynamicLightsNode.js +300 -0
- package/examples/jsm/tsl/lighting/data/AmbientLightDataNode.js +61 -0
- package/examples/jsm/tsl/lighting/data/DirectionalLightDataNode.js +111 -0
- package/examples/jsm/tsl/lighting/data/HemisphereLightDataNode.js +99 -0
- package/examples/jsm/tsl/lighting/data/PointLightDataNode.js +134 -0
- package/examples/jsm/tsl/lighting/data/SpotLightDataNode.js +161 -0
- package/examples/jsm/tsl/math/Bayer.js +13 -2
- package/examples/jsm/utils/BufferGeometryUtils.js +2 -3
- package/examples/jsm/utils/ColorUtils.js +76 -0
- package/examples/jsm/utils/SkeletonUtils.js +14 -8
- package/examples/jsm/webxr/XRHandMeshModel.js +36 -10
- package/examples/jsm/webxr/XRHandModelFactory.js +2 -1
- package/package.json +4 -4
- package/src/Three.Core.js +1 -0
- package/src/Three.TSL.js +6 -0
- package/src/Three.WebGPU.Nodes.js +3 -0
- package/src/Three.WebGPU.js +6 -0
- package/src/animation/AnimationAction.js +11 -1
- package/src/audio/AudioContext.js +2 -2
- package/src/constants.js +1 -1
- package/src/core/BufferAttribute.js +13 -1
- package/src/core/Clock.js +1 -1
- package/src/core/Object3D.js +1 -5
- package/src/core/RenderTarget.js +1 -0
- package/src/extras/curves/CatmullRomCurve3.js +3 -2
- package/src/loaders/AudioLoader.js +11 -1
- package/src/loaders/DataTextureLoader.js +6 -4
- package/src/loaders/FileLoader.js +1 -2
- package/src/loaders/ImageBitmapLoader.js +4 -6
- package/src/loaders/MaterialLoader.js +1 -1
- package/src/loaders/ObjectLoader.js +25 -4
- package/src/loaders/nodes/NodeObjectLoader.js +18 -0
- package/src/materials/MeshToonMaterial.js +1 -1
- package/src/materials/nodes/Line2NodeMaterial.js +27 -0
- package/src/materials/nodes/NodeMaterial.js +0 -27
- package/src/materials/nodes/manager/NodeMaterialObserver.js +188 -89
- package/src/math/Line3.js +3 -0
- package/src/math/Matrix2.js +13 -9
- package/src/math/Matrix3.js +13 -9
- package/src/math/Matrix4.js +13 -9
- package/src/math/Plane.js +4 -3
- package/src/math/Triangle.js +1 -1
- package/src/math/Vector2.js +11 -7
- package/src/math/Vector3.js +12 -8
- package/src/math/Vector4.js +13 -9
- package/src/nodes/Nodes.js +0 -1
- package/src/nodes/TSL.js +1 -1
- package/src/nodes/accessors/BufferAttributeNode.js +9 -3
- package/src/nodes/accessors/CubeTextureNode.js +7 -1
- package/src/nodes/accessors/MaterialProperties.js +2 -5
- package/src/nodes/accessors/Object3DNode.js +1 -1
- package/src/nodes/accessors/ReferenceBaseNode.js +2 -2
- package/src/nodes/accessors/ReferenceNode.js +4 -4
- package/src/nodes/accessors/SceneProperties.js +2 -8
- package/src/nodes/accessors/StorageBufferNode.js +10 -4
- package/src/nodes/accessors/StorageTextureNode.js +4 -9
- package/src/nodes/accessors/TextureNode.js +10 -2
- package/src/nodes/accessors/UniformArrayNode.js +2 -2
- package/src/nodes/code/FunctionCallNode.js +1 -1
- package/src/nodes/code/FunctionNode.js +1 -1
- package/src/nodes/core/ArrayNode.js +1 -1
- package/src/nodes/core/AssignNode.js +1 -1
- package/src/nodes/core/AttributeNode.js +1 -1
- package/src/nodes/core/BypassNode.js +1 -1
- package/src/nodes/core/ContextNode.js +1 -1
- package/src/nodes/core/IndexNode.js +2 -1
- package/src/nodes/core/InputNode.js +1 -1
- package/src/nodes/core/InspectorNode.js +1 -1
- package/src/nodes/core/IsolateNode.js +1 -1
- package/src/nodes/core/Node.js +83 -12
- package/src/nodes/core/NodeBuilder.js +117 -16
- package/src/nodes/core/NodeUtils.js +1 -1
- package/src/nodes/core/OutputStructNode.js +1 -1
- package/src/nodes/core/ParameterNode.js +1 -1
- package/src/nodes/core/StackNode.js +1 -1
- package/src/nodes/core/StructNode.js +1 -1
- package/src/nodes/core/StructTypeNode.js +1 -1
- package/src/nodes/core/SubBuildNode.js +1 -1
- package/src/nodes/core/UniformGroupNode.js +36 -6
- package/src/nodes/core/VarNode.js +1 -1
- package/src/nodes/core/VaryingNode.js +1 -1
- package/src/nodes/display/NormalMapNode.js +2 -2
- package/src/nodes/display/PassNode.js +27 -7
- package/src/nodes/display/RenderOutputNode.js +4 -4
- package/src/nodes/display/ScreenNode.js +1 -1
- package/src/nodes/display/ViewportDepthTextureNode.js +11 -15
- package/src/nodes/display/ViewportTextureNode.js +18 -7
- package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +2 -2
- package/src/nodes/geometry/RangeNode.js +1 -1
- package/src/nodes/gpgpu/AtomicFunctionNode.js +1 -1
- package/src/nodes/gpgpu/BarrierNode.js +9 -0
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -1
- package/src/nodes/gpgpu/ComputeNode.js +69 -44
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +1 -1
- package/src/nodes/lighting/LightsNode.js +6 -27
- package/src/nodes/lighting/ShadowNode.js +24 -2
- package/src/nodes/math/BitcastNode.js +1 -1
- package/src/nodes/math/ConditionalNode.js +1 -1
- package/src/nodes/math/MathNode.js +73 -1
- package/src/nodes/math/OperatorNode.js +1 -1
- package/src/nodes/math/PackFloatNode.js +1 -1
- package/src/nodes/math/UnpackFloatNode.js +1 -1
- package/src/nodes/tsl/TSLBase.js +1 -1
- package/src/nodes/tsl/TSLCore.js +21 -3
- package/src/nodes/utils/ArrayElementNode.js +1 -1
- package/src/nodes/utils/ConvertNode.js +1 -1
- package/src/nodes/utils/DebugNode.js +1 -1
- package/src/nodes/utils/EventNode.js +30 -0
- package/src/nodes/utils/FlipNode.js +1 -1
- package/src/nodes/utils/FunctionOverloadingNode.js +1 -1
- package/src/nodes/utils/JoinNode.js +1 -1
- package/src/nodes/utils/MemberNode.js +1 -1
- package/src/nodes/utils/Remap.js +48 -0
- package/src/nodes/utils/RotateNode.js +1 -1
- package/src/nodes/utils/SetNode.js +1 -1
- package/src/nodes/utils/SplitNode.js +1 -1
- package/src/objects/BatchedMesh.js +17 -2
- package/src/objects/InstancedMesh.js +19 -3
- package/src/objects/SkinnedMesh.js +26 -9
- package/src/renderers/WebGLRenderer.js +147 -48
- package/src/renderers/common/Animation.js +3 -3
- package/src/renderers/common/Attributes.js +15 -1
- package/src/renderers/common/Backend.js +0 -8
- package/src/renderers/common/Background.js +2 -2
- package/src/renderers/common/BindGroup.js +1 -8
- package/src/renderers/common/Bindings.js +2 -2
- package/src/renderers/common/ComputePipeline.js +1 -1
- package/src/renderers/common/CubeRenderTarget.js +1 -1
- package/src/renderers/common/Info.js +333 -4
- package/src/renderers/common/InspectorBase.js +6 -1
- package/src/renderers/common/Pipelines.js +36 -3
- package/src/renderers/common/ReadbackBuffer.js +78 -0
- package/src/renderers/common/RenderBundle.js +3 -1
- package/src/renderers/common/RenderBundles.js +5 -2
- package/src/renderers/common/RenderObject.js +2 -2
- package/src/renderers/common/RenderObjects.js +3 -3
- package/src/renderers/common/RenderPipeline.js +35 -6
- package/src/renderers/common/Renderer.js +232 -53
- package/src/renderers/common/Textures.js +72 -3
- package/src/renderers/common/UniformsGroup.js +1 -1
- package/src/renderers/common/XRManager.js +34 -27
- package/src/renderers/common/extras/PMREMGenerator.js +23 -15
- package/src/renderers/common/nodes/NodeBuilderState.js +1 -1
- package/src/renderers/common/nodes/NodeManager.js +230 -99
- package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +0 -1
- package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/lightprobes_pars_fragment.glsl.js +80 -0
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +8 -0
- package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +2 -0
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +1 -3
- package/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js +7 -0
- package/src/renderers/shaders/ShaderChunk/premultiplied_alpha_fragment.glsl.js +0 -1
- package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +12 -2
- package/src/renderers/shaders/ShaderChunk.js +2 -0
- package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +1 -2
- package/src/renderers/shaders/ShaderLib.js +0 -1
- package/src/renderers/shaders/UniformsLib.js +7 -2
- package/src/renderers/shaders/UniformsUtils.js +27 -5
- package/src/renderers/webgl/WebGLAnimation.js +2 -1
- package/src/renderers/webgl/WebGLBackground.js +13 -13
- package/src/renderers/webgl/WebGLBufferRenderer.js +0 -32
- package/src/renderers/webgl/WebGLCapabilities.js +6 -0
- package/src/renderers/webgl/WebGLIndexedBufferRenderer.js +0 -32
- package/src/renderers/webgl/WebGLMaterials.js +12 -13
- package/src/renderers/webgl/WebGLOutput.js +4 -1
- package/src/renderers/webgl/WebGLProgram.js +4 -0
- package/src/renderers/webgl/WebGLPrograms.js +21 -4
- package/src/renderers/webgl/WebGLRenderStates.js +13 -2
- package/src/renderers/webgl/WebGLState.js +43 -0
- package/src/renderers/webgl/WebGLTextures.js +129 -26
- package/src/renderers/webgl/WebGLUniformsGroups.js +19 -0
- package/src/renderers/webgl-fallback/WebGLBackend.js +106 -65
- package/src/renderers/webgl-fallback/WebGLBufferRenderer.js +0 -41
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +29 -51
- package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +53 -19
- package/src/renderers/webgl-fallback/utils/WebGLCapabilities.js +25 -0
- package/src/renderers/webgl-fallback/utils/WebGLState.js +42 -1
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +63 -50
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +1 -1
- package/src/renderers/webgpu/WebGPUBackend.js +160 -146
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +55 -33
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +103 -17
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +1 -1
- package/src/renderers/webgpu/utils/WebGPUCapabilities.js +48 -0
- package/src/renderers/webgpu/utils/WebGPUConstants.js +8 -0
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +91 -17
- package/src/renderers/webgpu/utils/WebGPUUtils.js +18 -2
- package/src/renderers/webxr/WebXRController.js +12 -0
- package/src/textures/HTMLTexture.js +74 -0
- package/src/textures/Source.js +1 -1
- package/src/textures/Texture.js +13 -2
- package/src/utils.js +23 -1
- package/src/nodes/utils/RemapNode.js +0 -125
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AnimationClip,
|
|
3
|
+
BoxGeometry,
|
|
3
4
|
BufferAttribute,
|
|
4
5
|
BufferGeometry,
|
|
6
|
+
CapsuleGeometry,
|
|
5
7
|
ClampToEdgeWrapping,
|
|
8
|
+
Color,
|
|
9
|
+
ConeGeometry,
|
|
10
|
+
CylinderGeometry,
|
|
11
|
+
DirectionalLight,
|
|
6
12
|
Euler,
|
|
7
13
|
Group,
|
|
8
14
|
Matrix4,
|
|
@@ -11,13 +17,19 @@ import {
|
|
|
11
17
|
MirroredRepeatWrapping,
|
|
12
18
|
NoColorSpace,
|
|
13
19
|
Object3D,
|
|
20
|
+
OrthographicCamera,
|
|
21
|
+
PerspectiveCamera,
|
|
22
|
+
PointLight,
|
|
14
23
|
Quaternion,
|
|
15
24
|
QuaternionKeyframeTrack,
|
|
25
|
+
RectAreaLight,
|
|
16
26
|
RepeatWrapping,
|
|
17
27
|
ShapeUtils,
|
|
18
28
|
SkinnedMesh,
|
|
19
29
|
Skeleton,
|
|
20
30
|
Bone,
|
|
31
|
+
SphereGeometry,
|
|
32
|
+
SpotLight,
|
|
21
33
|
SRGBColorSpace,
|
|
22
34
|
Texture,
|
|
23
35
|
Vector2,
|
|
@@ -44,6 +56,19 @@ const SpecType = {
|
|
|
44
56
|
VariantSet: 11
|
|
45
57
|
};
|
|
46
58
|
|
|
59
|
+
// UsdGeomCamera fallback values (OpenUSD schema)
|
|
60
|
+
const USD_CAMERA_DEFAULTS = {
|
|
61
|
+
projection: 'perspective',
|
|
62
|
+
clippingRange: [ 1, 1000000 ],
|
|
63
|
+
horizontalAperture: 20.955,
|
|
64
|
+
verticalAperture: 15.2908,
|
|
65
|
+
horizontalApertureOffset: 0,
|
|
66
|
+
verticalApertureOffset: 0,
|
|
67
|
+
focalLength: 50,
|
|
68
|
+
focusDistance: 0,
|
|
69
|
+
fStop: 0
|
|
70
|
+
};
|
|
71
|
+
|
|
47
72
|
/**
|
|
48
73
|
* USDComposer handles scene composition from parsed USD data.
|
|
49
74
|
* This includes reference resolution, variant selection, transform handling,
|
|
@@ -92,9 +117,29 @@ class USDComposer {
|
|
|
92
117
|
// Bind skeletons to skinned meshes
|
|
93
118
|
this._bindSkeletons();
|
|
94
119
|
|
|
120
|
+
// Expose skeleton on the root group so that AnimationMixer's
|
|
121
|
+
// PropertyBinding.findNode resolves bone names before scene objects.
|
|
122
|
+
// Without this, Xform prims that share a name with a skeleton joint
|
|
123
|
+
// would be animated instead of the bone.
|
|
124
|
+
const skeletonPaths = Object.keys( this.skeletons );
|
|
125
|
+
if ( skeletonPaths.length === 1 ) {
|
|
126
|
+
|
|
127
|
+
group.skeleton = this.skeletons[ skeletonPaths[ 0 ] ].skeleton;
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
95
131
|
// Build animations
|
|
96
132
|
group.animations = this._buildAnimations();
|
|
97
133
|
|
|
134
|
+
// Handle metersPerUnit scaling
|
|
135
|
+
const metersPerUnit = rootFields.metersPerUnit;
|
|
136
|
+
|
|
137
|
+
if ( metersPerUnit !== undefined && metersPerUnit !== 1 ) {
|
|
138
|
+
|
|
139
|
+
group.scale.setScalar( metersPerUnit );
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
98
143
|
// Handle Z-up to Y-up conversion
|
|
99
144
|
if ( rootSpec && rootSpec.fields && rootSpec.fields.upAxis === 'Z' ) {
|
|
100
145
|
|
|
@@ -423,18 +468,37 @@ class USDComposer {
|
|
|
423
468
|
|
|
424
469
|
}
|
|
425
470
|
|
|
426
|
-
// Build shader index (shaders are children of materials)
|
|
471
|
+
// Build shader index (shaders are children or descendants of materials)
|
|
427
472
|
if ( typeName === 'Shader' && lastSlash > 0 ) {
|
|
428
473
|
|
|
429
|
-
|
|
474
|
+
// Walk up ancestors to find the nearest Material prim.
|
|
475
|
+
// Shaders may be direct children of a Material, or nested
|
|
476
|
+
// inside a NodeGraph (common with MaterialX materials).
|
|
430
477
|
|
|
431
|
-
|
|
478
|
+
let ancestorPath = path.slice( 0, lastSlash );
|
|
432
479
|
|
|
433
|
-
|
|
480
|
+
while ( ancestorPath.length > 0 ) {
|
|
434
481
|
|
|
435
|
-
|
|
482
|
+
const ancestorSpec = this.specsByPath[ ancestorPath ];
|
|
483
|
+
|
|
484
|
+
if ( ancestorSpec && ancestorSpec.specType === SpecType.Prim && ancestorSpec.fields.typeName === 'Material' ) {
|
|
485
|
+
|
|
486
|
+
if ( ! this.shadersByMaterialPath.has( ancestorPath ) ) {
|
|
487
|
+
|
|
488
|
+
this.shadersByMaterialPath.set( ancestorPath, [] );
|
|
436
489
|
|
|
437
|
-
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
this.shadersByMaterialPath.get( ancestorPath ).push( path );
|
|
493
|
+
break;
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const slash = ancestorPath.lastIndexOf( '/' );
|
|
498
|
+
if ( slash <= 0 ) break;
|
|
499
|
+
ancestorPath = ancestorPath.slice( 0, slash );
|
|
500
|
+
|
|
501
|
+
}
|
|
438
502
|
|
|
439
503
|
}
|
|
440
504
|
|
|
@@ -561,56 +625,71 @@ class USDComposer {
|
|
|
561
625
|
const typeName = spec.fields.typeName;
|
|
562
626
|
|
|
563
627
|
// Check for references/payloads
|
|
564
|
-
const
|
|
565
|
-
if (
|
|
628
|
+
const refValues = this._getReferences( spec );
|
|
629
|
+
if ( refValues.length > 0 ) {
|
|
566
630
|
|
|
567
631
|
// Get local variant selections from this prim
|
|
568
632
|
const localVariants = this._getLocalVariantSelections( spec.fields );
|
|
569
633
|
|
|
570
|
-
// Resolve
|
|
571
|
-
const
|
|
572
|
-
|
|
634
|
+
// Resolve all references
|
|
635
|
+
const resolvedGroups = [];
|
|
636
|
+
for ( const refValue of refValues ) {
|
|
637
|
+
|
|
638
|
+
const referencedGroup = this._resolveReference( refValue, localVariants );
|
|
639
|
+
if ( referencedGroup ) resolvedGroups.push( referencedGroup );
|
|
640
|
+
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if ( resolvedGroups.length > 0 ) {
|
|
573
644
|
|
|
574
645
|
const attrs = this._getAttributes( path );
|
|
575
646
|
|
|
576
|
-
//
|
|
647
|
+
// Single reference with single mesh: use optimized path
|
|
577
648
|
// This handles the USDZExporter pattern: Xform references geometry file
|
|
578
|
-
|
|
649
|
+
if ( resolvedGroups.length === 1 ) {
|
|
579
650
|
|
|
580
|
-
|
|
651
|
+
const singleMesh = this._findSingleMesh( resolvedGroups[ 0 ] );
|
|
581
652
|
|
|
582
|
-
|
|
583
|
-
singleMesh.name = name;
|
|
584
|
-
this.applyTransform( singleMesh, spec.fields, attrs );
|
|
653
|
+
if ( singleMesh && ( typeName === 'Xform' || ! typeName ) ) {
|
|
585
654
|
|
|
586
|
-
|
|
587
|
-
|
|
655
|
+
// Merge the mesh into this prim
|
|
656
|
+
singleMesh.name = name;
|
|
657
|
+
this.applyTransform( singleMesh, spec.fields, attrs );
|
|
588
658
|
|
|
589
|
-
|
|
659
|
+
// Apply material binding from the referencing prim if present
|
|
660
|
+
this._applyMaterialBinding( singleMesh, path );
|
|
590
661
|
|
|
591
|
-
|
|
592
|
-
this._buildHierarchy( singleMesh, path );
|
|
662
|
+
parent.add( singleMesh );
|
|
593
663
|
|
|
594
|
-
|
|
664
|
+
// Still build local children (overrides)
|
|
665
|
+
this._buildHierarchy( singleMesh, path );
|
|
666
|
+
|
|
667
|
+
continue;
|
|
595
668
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Create a container for the referenced content
|
|
674
|
+
const obj = new Object3D();
|
|
675
|
+
obj.name = name;
|
|
676
|
+
this.applyTransform( obj, spec.fields, attrs );
|
|
677
|
+
|
|
678
|
+
// Add all children from all resolved references
|
|
679
|
+
for ( const referencedGroup of resolvedGroups ) {
|
|
600
680
|
|
|
601
|
-
// Add all children from the referenced group
|
|
602
681
|
while ( referencedGroup.children.length > 0 ) {
|
|
603
682
|
|
|
604
683
|
obj.add( referencedGroup.children[ 0 ] );
|
|
605
684
|
|
|
606
685
|
}
|
|
607
686
|
|
|
608
|
-
|
|
687
|
+
}
|
|
609
688
|
|
|
610
|
-
|
|
611
|
-
this._buildHierarchy( obj, path );
|
|
689
|
+
parent.add( obj );
|
|
612
690
|
|
|
613
|
-
|
|
691
|
+
// Still build local children (overrides)
|
|
692
|
+
this._buildHierarchy( obj, path );
|
|
614
693
|
|
|
615
694
|
continue;
|
|
616
695
|
|
|
@@ -653,12 +732,41 @@ class USDComposer {
|
|
|
653
732
|
if ( obj ) {
|
|
654
733
|
|
|
655
734
|
parent.add( obj );
|
|
735
|
+
this._buildHierarchy( obj, path );
|
|
736
|
+
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
} else if ( typeName === 'Camera' ) {
|
|
740
|
+
|
|
741
|
+
const obj = this._buildCamera( path );
|
|
742
|
+
obj.name = name;
|
|
743
|
+
const attrs = this._getAttributes( path );
|
|
744
|
+
this.applyTransform( obj, spec.fields, attrs );
|
|
745
|
+
parent.add( obj );
|
|
746
|
+
this._buildHierarchy( obj, path );
|
|
747
|
+
|
|
748
|
+
} else if ( typeName === 'DistantLight' || typeName === 'SphereLight' || typeName === 'RectLight' || typeName === 'DiskLight' ) {
|
|
749
|
+
|
|
750
|
+
const obj = this._buildLight( path, typeName );
|
|
751
|
+
obj.name = name;
|
|
752
|
+
const attrs = this._getAttributes( path );
|
|
753
|
+
this.applyTransform( obj, spec.fields, attrs );
|
|
754
|
+
parent.add( obj );
|
|
755
|
+
this._buildHierarchy( obj, path );
|
|
756
|
+
|
|
757
|
+
} else if ( typeName === 'Cube' || typeName === 'Sphere' || typeName === 'Cylinder' || typeName === 'Cone' || typeName === 'Capsule' ) {
|
|
758
|
+
|
|
759
|
+
const obj = this._buildGeomPrimitive( path, spec, typeName );
|
|
760
|
+
if ( obj ) {
|
|
761
|
+
|
|
762
|
+
parent.add( obj );
|
|
763
|
+
this._buildHierarchy( obj, path );
|
|
656
764
|
|
|
657
765
|
}
|
|
658
766
|
|
|
659
|
-
} else if ( typeName === 'Material' || typeName === 'Shader' ) {
|
|
767
|
+
} else if ( typeName === 'Material' || typeName === 'Shader' || typeName === 'GeomSubset' ) {
|
|
660
768
|
|
|
661
|
-
// Skip materials/shaders, they're referenced by meshes
|
|
769
|
+
// Skip materials/shaders/subsets, they're referenced by meshes
|
|
662
770
|
|
|
663
771
|
} else {
|
|
664
772
|
|
|
@@ -930,27 +1038,44 @@ class USDComposer {
|
|
|
930
1038
|
}
|
|
931
1039
|
|
|
932
1040
|
/**
|
|
933
|
-
* Get reference
|
|
1041
|
+
* Get all reference values from a prim spec.
|
|
1042
|
+
* @returns {string[]} Array of reference strings like "@path@" or "@path@<prim>"
|
|
934
1043
|
*/
|
|
935
|
-
|
|
1044
|
+
_getReferences( spec ) {
|
|
1045
|
+
|
|
1046
|
+
const results = [];
|
|
936
1047
|
|
|
937
1048
|
if ( spec.fields.references && spec.fields.references.length > 0 ) {
|
|
938
1049
|
|
|
939
1050
|
const ref = spec.fields.references[ 0 ];
|
|
940
|
-
|
|
941
|
-
if ( ref
|
|
1051
|
+
|
|
1052
|
+
if ( typeof ref === 'string' ) {
|
|
1053
|
+
|
|
1054
|
+
// Extract all @...@ references (handles both single and array values)
|
|
1055
|
+
const matches = ref.matchAll( /@([^@]+)@(?:<([^>]+)>)?/g );
|
|
1056
|
+
for ( const match of matches ) {
|
|
1057
|
+
|
|
1058
|
+
results.push( match[ 0 ] );
|
|
1059
|
+
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
} else if ( ref.assetPath ) {
|
|
1063
|
+
|
|
1064
|
+
results.push( '@' + ref.assetPath + '@' );
|
|
1065
|
+
|
|
1066
|
+
}
|
|
942
1067
|
|
|
943
1068
|
}
|
|
944
1069
|
|
|
945
|
-
if ( spec.fields.payload ) {
|
|
1070
|
+
if ( results.length === 0 && spec.fields.payload ) {
|
|
946
1071
|
|
|
947
1072
|
const payload = spec.fields.payload;
|
|
948
|
-
if ( typeof payload === 'string' )
|
|
949
|
-
if ( payload.assetPath )
|
|
1073
|
+
if ( typeof payload === 'string' ) results.push( payload );
|
|
1074
|
+
else if ( payload.assetPath ) results.push( '@' + payload.assetPath + '@' );
|
|
950
1075
|
|
|
951
1076
|
}
|
|
952
1077
|
|
|
953
|
-
return
|
|
1078
|
+
return results;
|
|
954
1079
|
|
|
955
1080
|
}
|
|
956
1081
|
|
|
@@ -1048,6 +1173,86 @@ class USDComposer {
|
|
|
1048
1173
|
|
|
1049
1174
|
}
|
|
1050
1175
|
|
|
1176
|
+
/**
|
|
1177
|
+
* Build a mesh from a USD geometric primitive (Cube, Sphere, Cylinder, Cone, Capsule).
|
|
1178
|
+
*/
|
|
1179
|
+
_buildGeomPrimitive( path, spec, typeName ) {
|
|
1180
|
+
|
|
1181
|
+
const attrs = this._getAttributes( path );
|
|
1182
|
+
const name = path.split( '/' ).pop();
|
|
1183
|
+
|
|
1184
|
+
let geometry;
|
|
1185
|
+
|
|
1186
|
+
switch ( typeName ) {
|
|
1187
|
+
|
|
1188
|
+
case 'Cube': {
|
|
1189
|
+
|
|
1190
|
+
const size = attrs[ 'size' ] || 2;
|
|
1191
|
+
geometry = new BoxGeometry( size, size, size );
|
|
1192
|
+
break;
|
|
1193
|
+
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
case 'Sphere': {
|
|
1197
|
+
|
|
1198
|
+
const radius = attrs[ 'radius' ] || 1;
|
|
1199
|
+
geometry = new SphereGeometry( radius, 32, 16 );
|
|
1200
|
+
break;
|
|
1201
|
+
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
case 'Cylinder': {
|
|
1205
|
+
|
|
1206
|
+
const height = attrs[ 'height' ] || 2;
|
|
1207
|
+
const radius = attrs[ 'radius' ] || 1;
|
|
1208
|
+
geometry = new CylinderGeometry( radius, radius, height, 32 );
|
|
1209
|
+
break;
|
|
1210
|
+
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
case 'Cone': {
|
|
1214
|
+
|
|
1215
|
+
const height = attrs[ 'height' ] || 2;
|
|
1216
|
+
const radius = attrs[ 'radius' ] || 1;
|
|
1217
|
+
geometry = new ConeGeometry( radius, height, 32 );
|
|
1218
|
+
break;
|
|
1219
|
+
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
case 'Capsule': {
|
|
1223
|
+
|
|
1224
|
+
const height = attrs[ 'height' ] || 1;
|
|
1225
|
+
const radius = attrs[ 'radius' ] || 0.5;
|
|
1226
|
+
geometry = new CapsuleGeometry( radius, height, 16, 32 );
|
|
1227
|
+
break;
|
|
1228
|
+
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// USD defaults axis to "Z", Three.js uses Y
|
|
1234
|
+
const axis = attrs[ 'axis' ] || 'Z';
|
|
1235
|
+
|
|
1236
|
+
if ( axis === 'X' ) {
|
|
1237
|
+
|
|
1238
|
+
geometry.rotateZ( - Math.PI / 2 );
|
|
1239
|
+
|
|
1240
|
+
} else if ( axis === 'Z' ) {
|
|
1241
|
+
|
|
1242
|
+
geometry.rotateX( Math.PI / 2 );
|
|
1243
|
+
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
const material = this._buildMaterial( path, spec.fields );
|
|
1247
|
+
const mesh = new Mesh( geometry, material );
|
|
1248
|
+
mesh.name = name;
|
|
1249
|
+
|
|
1250
|
+
this.applyTransform( mesh, spec.fields, attrs );
|
|
1251
|
+
|
|
1252
|
+
return mesh;
|
|
1253
|
+
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1051
1256
|
/**
|
|
1052
1257
|
* Build a mesh from a Mesh spec.
|
|
1053
1258
|
*/
|
|
@@ -1112,13 +1317,13 @@ class USDComposer {
|
|
|
1112
1317
|
}
|
|
1113
1318
|
|
|
1114
1319
|
const displayOpacity = attrs[ 'primvars:displayOpacity' ];
|
|
1115
|
-
if ( displayOpacity && displayOpacity.length
|
|
1320
|
+
if ( displayOpacity && displayOpacity.length === 1 && geomSubsets.length === 0 ) {
|
|
1116
1321
|
|
|
1117
1322
|
const opacity = displayOpacity[ 0 ];
|
|
1118
1323
|
|
|
1119
1324
|
const applyDisplayOpacity = ( mat ) => {
|
|
1120
1325
|
|
|
1121
|
-
if ( opacity < 1 ) {
|
|
1326
|
+
if ( opacity < 1 && mat.opacity === 1 && mat.transparent === false ) {
|
|
1122
1327
|
|
|
1123
1328
|
mat.opacity = opacity;
|
|
1124
1329
|
mat.transparent = true;
|
|
@@ -1190,6 +1395,215 @@ class USDComposer {
|
|
|
1190
1395
|
|
|
1191
1396
|
}
|
|
1192
1397
|
|
|
1398
|
+
/**
|
|
1399
|
+
* Build a camera from a Camera spec.
|
|
1400
|
+
*/
|
|
1401
|
+
_buildCamera( path ) {
|
|
1402
|
+
|
|
1403
|
+
const attrs = this._getAttributes( path );
|
|
1404
|
+
const projectionToken = attrs[ 'projection' ];
|
|
1405
|
+
const projection = typeof projectionToken === 'string'
|
|
1406
|
+
? projectionToken.toLowerCase()
|
|
1407
|
+
: USD_CAMERA_DEFAULTS.projection;
|
|
1408
|
+
const clippingRange = attrs[ 'clippingRange' ] || USD_CAMERA_DEFAULTS.clippingRange;
|
|
1409
|
+
const near = Math.max(
|
|
1410
|
+
Number.EPSILON,
|
|
1411
|
+
this._parseNumber( clippingRange[ 0 ], USD_CAMERA_DEFAULTS.clippingRange[ 0 ] )
|
|
1412
|
+
);
|
|
1413
|
+
const far = Math.max(
|
|
1414
|
+
near + Number.EPSILON,
|
|
1415
|
+
this._parseNumber( clippingRange[ 1 ], USD_CAMERA_DEFAULTS.clippingRange[ 1 ] )
|
|
1416
|
+
);
|
|
1417
|
+
const horizontalAperture = this._parseNumber(
|
|
1418
|
+
attrs[ 'horizontalAperture' ],
|
|
1419
|
+
USD_CAMERA_DEFAULTS.horizontalAperture
|
|
1420
|
+
);
|
|
1421
|
+
const verticalAperture = this._parseNumber(
|
|
1422
|
+
attrs[ 'verticalAperture' ],
|
|
1423
|
+
USD_CAMERA_DEFAULTS.verticalAperture
|
|
1424
|
+
);
|
|
1425
|
+
const horizontalApertureOffset = this._parseNumber(
|
|
1426
|
+
attrs[ 'horizontalApertureOffset' ],
|
|
1427
|
+
USD_CAMERA_DEFAULTS.horizontalApertureOffset
|
|
1428
|
+
);
|
|
1429
|
+
const verticalApertureOffset = this._parseNumber(
|
|
1430
|
+
attrs[ 'verticalApertureOffset' ],
|
|
1431
|
+
USD_CAMERA_DEFAULTS.verticalApertureOffset
|
|
1432
|
+
);
|
|
1433
|
+
const focalLength = this._parseNumber( attrs[ 'focalLength' ], USD_CAMERA_DEFAULTS.focalLength );
|
|
1434
|
+
const focusDistance = this._parseNumber( attrs[ 'focusDistance' ], USD_CAMERA_DEFAULTS.focusDistance );
|
|
1435
|
+
const fStop = this._parseNumber( attrs[ 'fStop' ], USD_CAMERA_DEFAULTS.fStop );
|
|
1436
|
+
|
|
1437
|
+
let camera;
|
|
1438
|
+
|
|
1439
|
+
if ( projection === 'orthographic' ) {
|
|
1440
|
+
|
|
1441
|
+
// USD orthographic apertures are in tenths of a world unit.
|
|
1442
|
+
const width = horizontalAperture / 10;
|
|
1443
|
+
const height = verticalAperture / 10;
|
|
1444
|
+
const offsetX = horizontalApertureOffset / 10;
|
|
1445
|
+
const offsetY = verticalApertureOffset / 10;
|
|
1446
|
+
|
|
1447
|
+
camera = new OrthographicCamera(
|
|
1448
|
+
offsetX - width * 0.5,
|
|
1449
|
+
offsetX + width * 0.5,
|
|
1450
|
+
offsetY + height * 0.5,
|
|
1451
|
+
offsetY - height * 0.5,
|
|
1452
|
+
near,
|
|
1453
|
+
far
|
|
1454
|
+
);
|
|
1455
|
+
|
|
1456
|
+
} else {
|
|
1457
|
+
|
|
1458
|
+
const safeVerticalAperture = Math.max( Number.EPSILON, verticalAperture );
|
|
1459
|
+
const safeFocalLength = Math.max( Number.EPSILON, focalLength );
|
|
1460
|
+
const aspect = horizontalAperture / safeVerticalAperture;
|
|
1461
|
+
const fov = 2 * Math.atan( safeVerticalAperture / ( 2 * safeFocalLength ) ) * 180 / Math.PI;
|
|
1462
|
+
|
|
1463
|
+
camera = new PerspectiveCamera( fov, aspect, near, far );
|
|
1464
|
+
camera.filmGauge = Math.max( horizontalAperture, verticalAperture );
|
|
1465
|
+
camera.filmOffset = horizontalApertureOffset;
|
|
1466
|
+
camera.focus = focusDistance;
|
|
1467
|
+
camera.setFocalLength( safeFocalLength );
|
|
1468
|
+
|
|
1469
|
+
if ( verticalApertureOffset !== 0 ) {
|
|
1470
|
+
|
|
1471
|
+
// Three.js supports only horizontal film offset directly.
|
|
1472
|
+
camera.userData.verticalApertureOffset = verticalApertureOffset;
|
|
1473
|
+
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
camera.userData.fStop = fStop;
|
|
1479
|
+
camera.userData.usdProjection = projection;
|
|
1480
|
+
return camera;
|
|
1481
|
+
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* Build a light from a UsdLux light spec.
|
|
1486
|
+
*/
|
|
1487
|
+
_buildLight( path, typeName ) {
|
|
1488
|
+
|
|
1489
|
+
const attrs = this._getAttributes( path );
|
|
1490
|
+
|
|
1491
|
+
const intensity = this._parseNumber( attrs[ 'inputs:intensity' ], 1 );
|
|
1492
|
+
const baseColor = attrs[ 'inputs:color' ] || [ 1, 1, 1 ];
|
|
1493
|
+
const enableColorTemperature = attrs[ 'inputs:enableColorTemperature' ] === true;
|
|
1494
|
+
const colorTemperature = this._parseNumber( attrs[ 'inputs:colorTemperature' ], 6500 );
|
|
1495
|
+
|
|
1496
|
+
const color = new Color( baseColor[ 0 ], baseColor[ 1 ], baseColor[ 2 ] );
|
|
1497
|
+
|
|
1498
|
+
if ( enableColorTemperature ) {
|
|
1499
|
+
|
|
1500
|
+
const temp = this._colorTemperature( colorTemperature );
|
|
1501
|
+
color.multiply( temp );
|
|
1502
|
+
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
let light;
|
|
1506
|
+
|
|
1507
|
+
switch ( typeName ) {
|
|
1508
|
+
|
|
1509
|
+
case 'DistantLight':
|
|
1510
|
+
light = new DirectionalLight( color, intensity );
|
|
1511
|
+
break;
|
|
1512
|
+
|
|
1513
|
+
case 'SphereLight': {
|
|
1514
|
+
|
|
1515
|
+
const coneAngle = this._parseNumber( attrs[ 'shaping:cone:angle' ], 0 );
|
|
1516
|
+
|
|
1517
|
+
if ( coneAngle > 0 ) {
|
|
1518
|
+
|
|
1519
|
+
const angle = coneAngle * Math.PI / 180;
|
|
1520
|
+
const softness = this._parseNumber( attrs[ 'shaping:cone:softness' ], 0 );
|
|
1521
|
+
light = new SpotLight( color, intensity, 0, angle, softness );
|
|
1522
|
+
|
|
1523
|
+
} else {
|
|
1524
|
+
|
|
1525
|
+
light = new PointLight( color, intensity );
|
|
1526
|
+
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
break;
|
|
1530
|
+
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
case 'RectLight': {
|
|
1534
|
+
|
|
1535
|
+
const width = this._parseNumber( attrs[ 'inputs:width' ], 1 );
|
|
1536
|
+
const height = this._parseNumber( attrs[ 'inputs:height' ], 1 );
|
|
1537
|
+
light = new RectAreaLight( color, intensity, width, height );
|
|
1538
|
+
break;
|
|
1539
|
+
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
case 'DiskLight': {
|
|
1543
|
+
|
|
1544
|
+
const radius = this._parseNumber( attrs[ 'inputs:radius' ], 0.5 );
|
|
1545
|
+
const side = radius * 2;
|
|
1546
|
+
light = new RectAreaLight( color, intensity, side, side );
|
|
1547
|
+
break;
|
|
1548
|
+
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
return light;
|
|
1554
|
+
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Convert a color temperature in Kelvin to an RGB Color.
|
|
1559
|
+
* Based on Tanner Helland's algorithm.
|
|
1560
|
+
*/
|
|
1561
|
+
_colorTemperature( kelvin ) {
|
|
1562
|
+
|
|
1563
|
+
const temp = kelvin / 100;
|
|
1564
|
+
let r, g, b;
|
|
1565
|
+
|
|
1566
|
+
if ( temp <= 66 ) {
|
|
1567
|
+
|
|
1568
|
+
r = 1;
|
|
1569
|
+
g = 0.39008157876901960784 * Math.log( temp ) - 0.63184144378862745098;
|
|
1570
|
+
|
|
1571
|
+
} else {
|
|
1572
|
+
|
|
1573
|
+
r = 1.29293618606274509804 * Math.pow( temp - 60, - 0.1332047592 );
|
|
1574
|
+
g = 1.12989086089529411765 * Math.pow( temp - 60, - 0.0755148492 );
|
|
1575
|
+
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
if ( temp >= 66 ) {
|
|
1579
|
+
|
|
1580
|
+
b = 1;
|
|
1581
|
+
|
|
1582
|
+
} else if ( temp <= 19 ) {
|
|
1583
|
+
|
|
1584
|
+
b = 0;
|
|
1585
|
+
|
|
1586
|
+
} else {
|
|
1587
|
+
|
|
1588
|
+
b = 0.54320678911019607843 * Math.log( temp - 10 ) - 1.19625408914;
|
|
1589
|
+
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
return new Color(
|
|
1593
|
+
Math.min( Math.max( r, 0 ), 1 ),
|
|
1594
|
+
Math.min( Math.max( g, 0 ), 1 ),
|
|
1595
|
+
Math.min( Math.max( b, 0 ), 1 )
|
|
1596
|
+
);
|
|
1597
|
+
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
_parseNumber( value, fallback ) {
|
|
1601
|
+
|
|
1602
|
+
const n = Number( value );
|
|
1603
|
+
return Number.isFinite( n ) ? n : fallback;
|
|
1604
|
+
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1193
1607
|
_getGeomSubsets( meshPath ) {
|
|
1194
1608
|
|
|
1195
1609
|
const subsets = [];
|
|
@@ -1203,7 +1617,7 @@ class USDComposer {
|
|
|
1203
1617
|
if ( ! indices || indices.length === 0 ) continue;
|
|
1204
1618
|
|
|
1205
1619
|
// Get material binding - check direct path and variant paths
|
|
1206
|
-
|
|
1620
|
+
const materialPath = this._getMaterialBindingTarget( p );
|
|
1207
1621
|
|
|
1208
1622
|
subsets.push( {
|
|
1209
1623
|
name: p.split( '/' ).pop(),
|
|
@@ -1333,7 +1747,12 @@ class USDComposer {
|
|
|
1333
1747
|
|
|
1334
1748
|
} else {
|
|
1335
1749
|
|
|
1336
|
-
|
|
1750
|
+
// Compute vertex normals from the original indexed topology where
|
|
1751
|
+
// vertices are shared, then expand them like positions.
|
|
1752
|
+
const vertexNormals = this._computeVertexNormals( points, indices );
|
|
1753
|
+
geometry.setAttribute( 'normal', new BufferAttribute( new Float32Array(
|
|
1754
|
+
this._expandAttribute( vertexNormals, indices, 3 )
|
|
1755
|
+
), 3 ) );
|
|
1337
1756
|
|
|
1338
1757
|
}
|
|
1339
1758
|
|
|
@@ -1427,25 +1846,7 @@ class USDComposer {
|
|
|
1427
1846
|
const skinIndices = new Uint16Array( numVertices * 4 );
|
|
1428
1847
|
const skinWeights = new Float32Array( numVertices * 4 );
|
|
1429
1848
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
for ( let j = 0; j < 4; j ++ ) {
|
|
1433
|
-
|
|
1434
|
-
if ( j < elementSize ) {
|
|
1435
|
-
|
|
1436
|
-
skinIndices[ i * 4 + j ] = skinIndexData[ i * elementSize + j ] || 0;
|
|
1437
|
-
skinWeights[ i * 4 + j ] = skinWeightData[ i * elementSize + j ] || 0;
|
|
1438
|
-
|
|
1439
|
-
} else {
|
|
1440
|
-
|
|
1441
|
-
skinIndices[ i * 4 + j ] = 0;
|
|
1442
|
-
skinWeights[ i * 4 + j ] = 0;
|
|
1443
|
-
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1849
|
+
this._selectTopWeights( skinIndexData, skinWeightData, elementSize, numVertices, skinIndices, skinWeights );
|
|
1449
1850
|
|
|
1450
1851
|
geometry.setAttribute( 'skinIndex', new BufferAttribute( skinIndices, 4 ) );
|
|
1451
1852
|
geometry.setAttribute( 'skinWeight', new BufferAttribute( skinWeights, 4 ) );
|
|
@@ -1597,10 +1998,17 @@ class USDComposer {
|
|
|
1597
1998
|
|
|
1598
1999
|
// Triangulate original data using consistent pattern
|
|
1599
2000
|
const { indices: origIndices, pattern: triPattern } = this._triangulateIndicesWithPattern( faceVertexIndices, faceVertexCounts, points, holeMap );
|
|
1600
|
-
const origUvIndices = uvIndices ? this._applyTriangulationPattern( uvIndices, triPattern ) : null;
|
|
1601
|
-
const origUv2Indices = uv2Indices ? this._applyTriangulationPattern( uv2Indices, triPattern ) : null;
|
|
1602
|
-
|
|
1603
2001
|
const numFaceVertices = faceVertexCounts.reduce( ( a, b ) => a + b, 0 );
|
|
2002
|
+
const faceVaryingIdentity = ( uvs && ! uvIndices && uvs.length / 2 === numFaceVertices ) ||
|
|
2003
|
+
( uvs2 && ! uv2Indices && uvs2.length / 2 === numFaceVertices )
|
|
2004
|
+
? this._applyTriangulationPattern( Array.from( { length: numFaceVertices }, ( _, i ) => i ), triPattern )
|
|
2005
|
+
: null;
|
|
2006
|
+
const origUvIndices = uvIndices
|
|
2007
|
+
? this._applyTriangulationPattern( uvIndices, triPattern )
|
|
2008
|
+
: ( uvs && uvs.length / 2 === numFaceVertices ? faceVaryingIdentity : null );
|
|
2009
|
+
const origUv2Indices = uv2Indices
|
|
2010
|
+
? this._applyTriangulationPattern( uv2Indices, triPattern )
|
|
2011
|
+
: ( uvs2 && uvs2.length / 2 === numFaceVertices ? faceVaryingIdentity : null );
|
|
1604
2012
|
const hasIndexedNormals = normals && normalIndicesRaw && normalIndicesRaw.length > 0;
|
|
1605
2013
|
const hasFaceVaryingNormals = normals && normals.length / 3 === numFaceVertices;
|
|
1606
2014
|
const origNormalIndices = hasIndexedNormals
|
|
@@ -1609,14 +2017,20 @@ class USDComposer {
|
|
|
1609
2017
|
? this._applyTriangulationPattern( Array.from( { length: numFaceVertices }, ( _, i ) => i ), triPattern )
|
|
1610
2018
|
: null );
|
|
1611
2019
|
|
|
2020
|
+
// When no normals are provided, compute vertex normals from
|
|
2021
|
+
// the indexed topology so that shared vertices produce averaged normals.
|
|
2022
|
+
const vertexNormals = ( ! normals && origIndices.length > 0 )
|
|
2023
|
+
? this._computeVertexNormals( points, origIndices )
|
|
2024
|
+
: null;
|
|
2025
|
+
|
|
1612
2026
|
// Build reordered vertex data
|
|
1613
2027
|
const vertexCount = triangleCount * 3;
|
|
1614
2028
|
const positions = new Float32Array( vertexCount * 3 );
|
|
1615
2029
|
const uvData = uvs ? new Float32Array( vertexCount * 2 ) : null;
|
|
1616
2030
|
const uv1Data = uvs2 ? new Float32Array( vertexCount * 2 ) : null;
|
|
1617
|
-
const normalData = normals ? new Float32Array( vertexCount * 3 ) : null;
|
|
1618
|
-
const
|
|
1619
|
-
const
|
|
2031
|
+
const normalData = ( normals || vertexNormals ) ? new Float32Array( vertexCount * 3 ) : null;
|
|
2032
|
+
const skinSrcIndices = jointIndices ? new Uint16Array( vertexCount * elementSize ) : null;
|
|
2033
|
+
const skinSrcWeights = jointWeights ? new Float32Array( vertexCount * elementSize ) : null;
|
|
1620
2034
|
|
|
1621
2035
|
for ( let i = 0; i < sortedTriangles.length; i ++ ) {
|
|
1622
2036
|
|
|
@@ -1666,40 +2080,37 @@ class USDComposer {
|
|
|
1666
2080
|
|
|
1667
2081
|
}
|
|
1668
2082
|
|
|
1669
|
-
if ( normalData
|
|
2083
|
+
if ( normalData ) {
|
|
1670
2084
|
|
|
1671
|
-
if ( origNormalIndices ) {
|
|
2085
|
+
if ( normals && origNormalIndices ) {
|
|
1672
2086
|
|
|
1673
2087
|
const normalIdx = origNormalIndices[ origIdx ];
|
|
1674
2088
|
normalData[ newIdx * 3 ] = normals[ normalIdx * 3 ];
|
|
1675
2089
|
normalData[ newIdx * 3 + 1 ] = normals[ normalIdx * 3 + 1 ];
|
|
1676
2090
|
normalData[ newIdx * 3 + 2 ] = normals[ normalIdx * 3 + 2 ];
|
|
1677
2091
|
|
|
1678
|
-
} else if ( normals.length === points.length ) {
|
|
2092
|
+
} else if ( normals && normals.length === points.length ) {
|
|
1679
2093
|
|
|
1680
2094
|
normalData[ newIdx * 3 ] = normals[ pointIdx * 3 ];
|
|
1681
2095
|
normalData[ newIdx * 3 + 1 ] = normals[ pointIdx * 3 + 1 ];
|
|
1682
2096
|
normalData[ newIdx * 3 + 2 ] = normals[ pointIdx * 3 + 2 ];
|
|
1683
2097
|
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
if ( skinIndexData && skinWeightData && jointIndices && jointWeights ) {
|
|
2098
|
+
} else if ( vertexNormals ) {
|
|
1689
2099
|
|
|
1690
|
-
|
|
2100
|
+
normalData[ newIdx * 3 ] = vertexNormals[ pointIdx * 3 ];
|
|
2101
|
+
normalData[ newIdx * 3 + 1 ] = vertexNormals[ pointIdx * 3 + 1 ];
|
|
2102
|
+
normalData[ newIdx * 3 + 2 ] = vertexNormals[ pointIdx * 3 + 2 ];
|
|
1691
2103
|
|
|
1692
|
-
|
|
2104
|
+
}
|
|
1693
2105
|
|
|
1694
|
-
|
|
1695
|
-
skinWeightData[ newIdx * 4 + j ] = jointWeights[ pointIdx * elementSize + j ] || 0;
|
|
2106
|
+
}
|
|
1696
2107
|
|
|
1697
|
-
|
|
2108
|
+
if ( skinSrcIndices && skinSrcWeights && jointIndices && jointWeights ) {
|
|
1698
2109
|
|
|
1699
|
-
|
|
1700
|
-
skinWeightData[ newIdx * 4 + j ] = 0;
|
|
2110
|
+
for ( let j = 0; j < elementSize; j ++ ) {
|
|
1701
2111
|
|
|
1702
|
-
|
|
2112
|
+
skinSrcIndices[ newIdx * elementSize + j ] = jointIndices[ pointIdx * elementSize + j ] || 0;
|
|
2113
|
+
skinSrcWeights[ newIdx * elementSize + j ] = jointWeights[ pointIdx * elementSize + j ] || 0;
|
|
1703
2114
|
|
|
1704
2115
|
}
|
|
1705
2116
|
|
|
@@ -1723,29 +2134,117 @@ class USDComposer {
|
|
|
1723
2134
|
|
|
1724
2135
|
}
|
|
1725
2136
|
|
|
1726
|
-
|
|
2137
|
+
geometry.setAttribute( 'normal', new BufferAttribute( normalData, 3 ) );
|
|
1727
2138
|
|
|
1728
|
-
|
|
2139
|
+
if ( skinSrcIndices && skinSrcWeights ) {
|
|
1729
2140
|
|
|
1730
|
-
|
|
2141
|
+
const skinIndexData = new Uint16Array( vertexCount * 4 );
|
|
2142
|
+
const skinWeightData = new Float32Array( vertexCount * 4 );
|
|
1731
2143
|
|
|
1732
|
-
|
|
2144
|
+
this._selectTopWeights( skinSrcIndices, skinSrcWeights, elementSize, vertexCount, skinIndexData, skinWeightData );
|
|
2145
|
+
|
|
2146
|
+
geometry.setAttribute( 'skinIndex', new BufferAttribute( skinIndexData, 4 ) );
|
|
2147
|
+
geometry.setAttribute( 'skinWeight', new BufferAttribute( skinWeightData, 4 ) );
|
|
1733
2148
|
|
|
1734
2149
|
}
|
|
1735
2150
|
|
|
1736
|
-
|
|
2151
|
+
return geometry;
|
|
1737
2152
|
|
|
1738
|
-
|
|
2153
|
+
}
|
|
1739
2154
|
|
|
1740
|
-
|
|
2155
|
+
_selectTopWeights( srcIndices, srcWeights, elementSize, numVertices, dstIndices, dstWeights ) {
|
|
1741
2156
|
|
|
1742
|
-
if (
|
|
2157
|
+
if ( elementSize <= 4 ) {
|
|
1743
2158
|
|
|
1744
|
-
|
|
2159
|
+
for ( let i = 0; i < numVertices; i ++ ) {
|
|
2160
|
+
|
|
2161
|
+
for ( let j = 0; j < 4; j ++ ) {
|
|
2162
|
+
|
|
2163
|
+
if ( j < elementSize ) {
|
|
2164
|
+
|
|
2165
|
+
dstIndices[ i * 4 + j ] = srcIndices[ i * elementSize + j ] || 0;
|
|
2166
|
+
dstWeights[ i * 4 + j ] = srcWeights[ i * elementSize + j ] || 0;
|
|
2167
|
+
|
|
2168
|
+
} else {
|
|
2169
|
+
|
|
2170
|
+
dstIndices[ i * 4 + j ] = 0;
|
|
2171
|
+
dstWeights[ i * 4 + j ] = 0;
|
|
2172
|
+
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
return;
|
|
1745
2180
|
|
|
1746
2181
|
}
|
|
1747
2182
|
|
|
1748
|
-
|
|
2183
|
+
// When elementSize > 4, find the 4 largest weights per vertex
|
|
2184
|
+
// using a partial selection sort (4 iterations of O(elementSize)).
|
|
2185
|
+
const order = new Uint32Array( elementSize );
|
|
2186
|
+
|
|
2187
|
+
for ( let i = 0; i < numVertices; i ++ ) {
|
|
2188
|
+
|
|
2189
|
+
const base = i * elementSize;
|
|
2190
|
+
|
|
2191
|
+
for ( let j = 0; j < elementSize; j ++ ) order[ j ] = j;
|
|
2192
|
+
|
|
2193
|
+
for ( let k = 0; k < 4; k ++ ) {
|
|
2194
|
+
|
|
2195
|
+
let maxIdx = k;
|
|
2196
|
+
let maxW = srcWeights[ base + order[ k ] ] || 0;
|
|
2197
|
+
|
|
2198
|
+
for ( let j = k + 1; j < elementSize; j ++ ) {
|
|
2199
|
+
|
|
2200
|
+
const w = srcWeights[ base + order[ j ] ] || 0;
|
|
2201
|
+
|
|
2202
|
+
if ( w > maxW ) {
|
|
2203
|
+
|
|
2204
|
+
maxW = w;
|
|
2205
|
+
maxIdx = j;
|
|
2206
|
+
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
if ( maxIdx !== k ) {
|
|
2212
|
+
|
|
2213
|
+
const tmp = order[ k ];
|
|
2214
|
+
order[ k ] = order[ maxIdx ];
|
|
2215
|
+
order[ maxIdx ] = tmp;
|
|
2216
|
+
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
let total = 0;
|
|
2222
|
+
|
|
2223
|
+
for ( let j = 0; j < 4; j ++ ) {
|
|
2224
|
+
|
|
2225
|
+
total += srcWeights[ base + order[ j ] ] || 0;
|
|
2226
|
+
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
for ( let j = 0; j < 4; j ++ ) {
|
|
2230
|
+
|
|
2231
|
+
const s = order[ j ];
|
|
2232
|
+
|
|
2233
|
+
if ( total > 0 ) {
|
|
2234
|
+
|
|
2235
|
+
dstIndices[ i * 4 + j ] = srcIndices[ base + s ] || 0;
|
|
2236
|
+
dstWeights[ i * 4 + j ] = ( srcWeights[ base + s ] || 0 ) / total;
|
|
2237
|
+
|
|
2238
|
+
} else {
|
|
2239
|
+
|
|
2240
|
+
dstIndices[ i * 4 + j ] = 0;
|
|
2241
|
+
dstWeights[ i * 4 + j ] = 0;
|
|
2242
|
+
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
}
|
|
1749
2248
|
|
|
1750
2249
|
}
|
|
1751
2250
|
|
|
@@ -2234,13 +2733,64 @@ class USDComposer {
|
|
|
2234
2733
|
|
|
2235
2734
|
}
|
|
2236
2735
|
|
|
2736
|
+
/**
|
|
2737
|
+
* Compute per-vertex normals from indexed triangle data.
|
|
2738
|
+
* Accumulates area-weighted face normals at each shared vertex and normalizes.
|
|
2739
|
+
*/
|
|
2740
|
+
_computeVertexNormals( points, indices ) {
|
|
2741
|
+
|
|
2742
|
+
const numVertices = points.length / 3;
|
|
2743
|
+
const normals = new Float32Array( numVertices * 3 );
|
|
2744
|
+
|
|
2745
|
+
for ( let i = 0; i < indices.length; i += 3 ) {
|
|
2746
|
+
|
|
2747
|
+
const a = indices[ i ];
|
|
2748
|
+
const b = indices[ i + 1 ];
|
|
2749
|
+
const c = indices[ i + 2 ];
|
|
2750
|
+
|
|
2751
|
+
const ax = points[ a * 3 ], ay = points[ a * 3 + 1 ], az = points[ a * 3 + 2 ];
|
|
2752
|
+
const bx = points[ b * 3 ], by = points[ b * 3 + 1 ], bz = points[ b * 3 + 2 ];
|
|
2753
|
+
const cx = points[ c * 3 ], cy = points[ c * 3 + 1 ], cz = points[ c * 3 + 2 ];
|
|
2754
|
+
|
|
2755
|
+
const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
|
|
2756
|
+
const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
|
|
2757
|
+
|
|
2758
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
2759
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
2760
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
2761
|
+
|
|
2762
|
+
normals[ a * 3 ] += nx; normals[ a * 3 + 1 ] += ny; normals[ a * 3 + 2 ] += nz;
|
|
2763
|
+
normals[ b * 3 ] += nx; normals[ b * 3 + 1 ] += ny; normals[ b * 3 + 2 ] += nz;
|
|
2764
|
+
normals[ c * 3 ] += nx; normals[ c * 3 + 1 ] += ny; normals[ c * 3 + 2 ] += nz;
|
|
2765
|
+
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
for ( let i = 0; i < numVertices; i ++ ) {
|
|
2769
|
+
|
|
2770
|
+
const x = normals[ i * 3 ], y = normals[ i * 3 + 1 ], z = normals[ i * 3 + 2 ];
|
|
2771
|
+
const len = Math.sqrt( x * x + y * y + z * z );
|
|
2772
|
+
|
|
2773
|
+
if ( len > 0 ) {
|
|
2774
|
+
|
|
2775
|
+
normals[ i * 3 ] /= len;
|
|
2776
|
+
normals[ i * 3 + 1 ] /= len;
|
|
2777
|
+
normals[ i * 3 + 2 ] /= len;
|
|
2778
|
+
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
return normals;
|
|
2784
|
+
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2237
2787
|
/**
|
|
2238
2788
|
* Get the material path for a mesh, checking various binding sources.
|
|
2239
2789
|
*/
|
|
2240
2790
|
_getMaterialPath( meshPath, fields ) {
|
|
2241
2791
|
|
|
2242
2792
|
let materialPath = null;
|
|
2243
|
-
|
|
2793
|
+
const materialBinding = fields[ 'material:binding' ];
|
|
2244
2794
|
|
|
2245
2795
|
if ( materialBinding ) {
|
|
2246
2796
|
|
|
@@ -2264,7 +2814,7 @@ class USDComposer {
|
|
|
2264
2814
|
const material = new MeshPhysicalMaterial();
|
|
2265
2815
|
|
|
2266
2816
|
let materialPath = null;
|
|
2267
|
-
|
|
2817
|
+
const materialBinding = fields[ 'material:binding' ];
|
|
2268
2818
|
|
|
2269
2819
|
if ( materialBinding ) {
|
|
2270
2820
|
|
|
@@ -2432,7 +2982,7 @@ class USDComposer {
|
|
|
2432
2982
|
const shaderAttrs = this._getAttributes( path );
|
|
2433
2983
|
const infoId = shaderAttrs[ 'info:id' ] || spec.fields[ 'info:id' ];
|
|
2434
2984
|
|
|
2435
|
-
if ( infoId === 'UsdPreviewSurface' ) {
|
|
2985
|
+
if ( infoId === 'UsdPreviewSurface' || infoId === 'ND_UsdPreviewSurface_surfaceshader' ) {
|
|
2436
2986
|
|
|
2437
2987
|
this._applyPreviewSurface( material, path );
|
|
2438
2988
|
|
|
@@ -3335,6 +3885,7 @@ class USDComposer {
|
|
|
3335
3885
|
}
|
|
3336
3886
|
|
|
3337
3887
|
};
|
|
3888
|
+
|
|
3338
3889
|
image.src = url;
|
|
3339
3890
|
|
|
3340
3891
|
return texture;
|
|
@@ -3429,13 +3980,15 @@ class USDComposer {
|
|
|
3429
3980
|
|
|
3430
3981
|
}
|
|
3431
3982
|
|
|
3432
|
-
// Apply rest transforms
|
|
3983
|
+
// Apply rest transforms as bone local transforms.
|
|
3984
|
+
// Rest transforms are the skeleton's default local-space pose and match
|
|
3985
|
+
// the reference frame used by SkelAnimation data. Bind transforms are
|
|
3986
|
+
// world-space matrices used only for computing inverse bind matrices.
|
|
3433
3987
|
if ( restTransforms && restTransforms.length >= joints.length * 16 ) {
|
|
3434
3988
|
|
|
3435
3989
|
for ( let i = 0; i < joints.length; i ++ ) {
|
|
3436
3990
|
|
|
3437
3991
|
const matrix = new Matrix4();
|
|
3438
|
-
// USD matrices are row-major, Three.js is column-major - need to transpose
|
|
3439
3992
|
const m = restTransforms.slice( i * 16, ( i + 1 ) * 16 );
|
|
3440
3993
|
matrix.set(
|
|
3441
3994
|
m[ 0 ], m[ 4 ], m[ 8 ], m[ 12 ],
|
|
@@ -3562,7 +4115,7 @@ class USDComposer {
|
|
|
3562
4115
|
// Use geomBindTransform if available, otherwise fall back to identity.
|
|
3563
4116
|
// Estimating bind transforms from vertex/joint samples is not robust and can
|
|
3564
4117
|
// produce severe skinning distortion for valid assets.
|
|
3565
|
-
|
|
4118
|
+
const bindMatrix = new Matrix4();
|
|
3566
4119
|
|
|
3567
4120
|
if ( geomBindTransform && geomBindTransform.length === 16 ) {
|
|
3568
4121
|
|