@plastic-software/three 0.182.0 → 0.183.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/LICENSE +1 -1
- package/build/three.cjs +11520 -10877
- package/build/three.core.js +11732 -11340
- package/build/three.core.min.js +2 -2
- package/build/three.module.js +509 -262
- package/build/three.module.min.js +2 -2
- package/build/three.tsl.js +7 -11
- package/build/three.tsl.min.js +2 -2
- package/build/three.webgpu.js +3072 -2607
- package/build/three.webgpu.min.js +2 -2
- package/build/three.webgpu.nodes.js +3071 -2607
- package/build/three.webgpu.nodes.min.js +2 -2
- package/examples/jsm/Addons.js +0 -3
- package/examples/jsm/animation/CCDIKSolver.js +2 -2
- package/examples/jsm/controls/ArcballControls.js +3 -3
- package/examples/jsm/controls/OrbitControls.js +103 -0
- package/examples/jsm/effects/AnaglyphEffect.js +102 -7
- package/examples/jsm/environments/ColorEnvironment.js +59 -0
- package/examples/jsm/environments/RoomEnvironment.js +1 -0
- package/examples/jsm/exporters/EXRExporter.js +1 -1
- package/examples/jsm/exporters/GLTFExporter.js +131 -4
- package/examples/jsm/exporters/USDZExporter.js +22 -3
- package/examples/jsm/helpers/AnimationPathHelper.js +302 -0
- package/examples/jsm/helpers/ViewHelper.js +67 -8
- package/examples/jsm/inspector/Inspector.js +21 -5
- package/examples/jsm/inspector/tabs/Console.js +39 -5
- package/examples/jsm/inspector/tabs/Parameters.js +16 -0
- package/examples/jsm/inspector/ui/Style.js +25 -1
- package/examples/jsm/libs/meshopt_decoder.module.js +6 -5
- package/examples/jsm/lines/LineMaterial.js +6 -0
- package/examples/jsm/loaders/3MFLoader.js +2 -2
- package/examples/jsm/loaders/AMFLoader.js +2 -2
- package/examples/jsm/loaders/ColladaLoader.js +24 -4026
- package/examples/jsm/loaders/EXRLoader.js +5 -5
- package/examples/jsm/loaders/FBXLoader.js +2 -2
- package/examples/jsm/loaders/GCodeLoader.js +34 -8
- package/examples/jsm/loaders/GLTFLoader.js +122 -171
- package/examples/jsm/loaders/KMZLoader.js +5 -5
- package/examples/jsm/loaders/KTX2Loader.js +5 -5
- package/examples/jsm/loaders/LWOLoader.js +7 -39
- package/examples/jsm/loaders/NRRDLoader.js +2 -2
- package/examples/jsm/loaders/PCDLoader.js +3 -2
- package/examples/jsm/loaders/USDLoader.js +100 -40
- package/examples/jsm/loaders/UltraHDRLoader.js +182 -30
- package/examples/jsm/loaders/VRMLLoader.js +77 -0
- package/examples/jsm/loaders/VTKLoader.js +37 -24
- package/examples/jsm/loaders/collada/ColladaComposer.js +2950 -0
- package/examples/jsm/loaders/collada/ColladaParser.js +1962 -0
- package/examples/jsm/loaders/usd/USDAParser.js +447 -366
- package/examples/jsm/loaders/usd/USDCParser.js +1841 -6
- package/examples/jsm/loaders/usd/USDComposer.js +4041 -0
- package/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +2 -2
- package/examples/jsm/objects/LensflareMesh.js +1 -1
- package/examples/jsm/objects/Sky.js +76 -4
- package/examples/jsm/objects/SkyMesh.js +114 -7
- package/examples/jsm/objects/Water.js +4 -3
- package/examples/jsm/objects/Water2.js +5 -3
- package/examples/jsm/objects/WaterMesh.js +5 -7
- package/examples/jsm/physics/JoltPhysics.js +7 -5
- package/examples/jsm/physics/RapierPhysics.js +6 -4
- package/examples/jsm/postprocessing/EffectComposer.js +7 -5
- package/examples/jsm/postprocessing/RenderTransitionPass.js +1 -1
- package/examples/jsm/renderers/CSS3DRenderer.js +1 -1
- package/examples/jsm/renderers/SVGRenderer.js +2 -2
- package/examples/jsm/shaders/GTAOShader.js +19 -6
- package/examples/jsm/shaders/HalftoneShader.js +12 -1
- package/examples/jsm/shaders/PoissonDenoiseShader.js +6 -2
- package/examples/jsm/shaders/SAOShader.js +17 -4
- package/examples/jsm/shaders/SSAOShader.js +11 -1
- package/examples/jsm/shaders/SSRShader.js +6 -5
- package/examples/jsm/shaders/VignetteShader.js +1 -1
- package/examples/jsm/tsl/display/AfterImageNode.js +1 -1
- package/examples/jsm/tsl/display/AnaglyphPassNode.js +456 -16
- package/examples/jsm/tsl/display/AnamorphicNode.js +1 -1
- package/examples/jsm/tsl/display/BilateralBlurNode.js +364 -0
- package/examples/jsm/tsl/display/BloomNode.js +5 -5
- package/examples/jsm/tsl/display/CRT.js +150 -0
- package/examples/jsm/tsl/display/DenoiseNode.js +1 -1
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +1 -1
- package/examples/jsm/tsl/display/DotScreenNode.js +1 -1
- package/examples/jsm/tsl/display/FXAANode.js +2 -2
- package/examples/jsm/tsl/display/GTAONode.js +2 -2
- package/examples/jsm/tsl/display/GaussianBlurNode.js +11 -2
- package/examples/jsm/tsl/display/GodraysNode.js +624 -0
- package/examples/jsm/tsl/display/LensflareNode.js +1 -1
- package/examples/jsm/tsl/display/Lut3DNode.js +1 -1
- package/examples/jsm/tsl/display/OutlineNode.js +3 -3
- package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +2 -2
- package/examples/jsm/tsl/display/PixelationPassNode.js +5 -5
- package/examples/jsm/tsl/display/RGBShiftNode.js +2 -2
- package/examples/jsm/tsl/display/RetroPassNode.js +263 -0
- package/examples/jsm/tsl/display/SMAANode.js +2 -2
- package/examples/jsm/tsl/display/SSAAPassNode.js +2 -2
- package/examples/jsm/tsl/display/SSGINode.js +2 -2
- package/examples/jsm/tsl/display/SSRNode.js +7 -7
- package/examples/jsm/tsl/display/SSSNode.js +2 -2
- package/examples/jsm/tsl/display/Shape.js +29 -0
- package/examples/jsm/tsl/display/SobelOperatorNode.js +2 -2
- package/examples/jsm/tsl/display/StereoPassNode.js +1 -2
- package/examples/jsm/tsl/display/TRAANode.js +9 -12
- package/examples/jsm/tsl/display/TransitionNode.js +1 -1
- package/examples/jsm/tsl/display/depthAwareBlend.js +80 -0
- package/examples/jsm/tsl/math/Bayer.js +40 -1
- package/examples/jsm/utils/LDrawUtils.js +1 -1
- package/package.json +11 -19
- package/src/Three.Core.js +1 -1
- package/src/Three.TSL.js +5 -9
- package/src/Three.WebGPU.Nodes.js +2 -0
- package/src/Three.WebGPU.js +3 -0
- package/src/Three.js +1 -0
- package/src/animation/AnimationAction.js +1 -1
- package/src/animation/AnimationClip.js +1 -1
- package/src/animation/AnimationMixer.js +6 -0
- package/src/animation/KeyframeTrack.js +46 -7
- package/src/animation/PropertyMixer.js +4 -4
- package/src/audio/Audio.js +1 -1
- package/src/audio/AudioListener.js +5 -3
- package/src/cameras/Camera.js +32 -2
- package/src/cameras/CubeCamera.js +20 -0
- package/src/constants.js +30 -1
- package/src/core/Clock.js +7 -0
- package/src/core/Object3D.js +56 -4
- package/src/core/RenderTarget.js +3 -4
- package/src/extras/PMREMGenerator.js +4 -8
- package/src/geometries/TorusGeometry.js +8 -3
- package/src/helpers/CameraHelper.js +3 -0
- package/src/helpers/DirectionalLightHelper.js +4 -1
- package/src/helpers/HemisphereLightHelper.js +3 -0
- package/src/helpers/PointLightHelper.js +0 -24
- package/src/helpers/SpotLightHelper.js +3 -0
- package/src/lights/LightShadow.js +15 -3
- package/src/lights/webgpu/IESSpotLight.js +2 -1
- package/src/loaders/Cache.js +28 -0
- package/src/loaders/FileLoader.js +1 -1
- package/src/loaders/ImageBitmapLoader.js +8 -3
- package/src/loaders/Loader.js +6 -0
- package/src/loaders/ObjectLoader.js +18 -1
- package/src/materials/MeshLambertMaterial.js +9 -0
- package/src/materials/MeshPhongMaterial.js +9 -0
- package/src/materials/nodes/Line2NodeMaterial.js +5 -5
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +2 -0
- package/src/materials/nodes/NodeMaterial.js +15 -24
- package/src/materials/nodes/manager/NodeMaterialObserver.js +9 -3
- package/src/math/Line3.js +3 -5
- package/src/math/MathUtils.js +10 -10
- package/src/math/Matrix4.js +35 -26
- package/src/math/Quaternion.js +3 -29
- package/src/math/Vector3.js +3 -3
- package/src/math/interpolants/BezierInterpolant.js +108 -0
- package/src/nodes/Nodes.js +87 -68
- package/src/nodes/TSL.js +2 -5
- package/src/nodes/accessors/Arrays.js +1 -1
- package/src/nodes/accessors/Bitangent.js +5 -5
- package/src/nodes/accessors/BufferAttributeNode.js +1 -1
- package/src/nodes/accessors/Camera.js +149 -28
- package/src/nodes/accessors/InstanceNode.js +105 -40
- package/src/nodes/accessors/Normal.js +9 -9
- package/src/nodes/accessors/Position.js +34 -2
- package/src/nodes/accessors/SceneProperties.js +53 -0
- package/src/nodes/accessors/SkinningNode.js +12 -24
- package/src/nodes/accessors/StorageBufferNode.js +0 -19
- package/src/nodes/accessors/StorageTextureNode.js +37 -1
- package/src/nodes/accessors/Tangent.js +3 -3
- package/src/nodes/accessors/Texture3DNode.js +6 -34
- package/src/nodes/accessors/TextureNode.js +58 -22
- package/src/nodes/accessors/UniformArrayNode.js +2 -0
- package/src/nodes/core/MRTNode.js +48 -2
- package/src/nodes/core/Node.js +29 -3
- package/src/nodes/core/NodeBuilder.js +115 -40
- package/src/nodes/core/NodeError.js +28 -0
- package/src/nodes/core/NodeUtils.js +5 -3
- package/src/nodes/core/OutputStructNode.js +12 -10
- package/src/nodes/core/ParameterNode.js +2 -1
- package/src/nodes/core/StackNode.js +9 -8
- package/src/nodes/core/StackTrace.js +139 -0
- package/src/nodes/core/StructNode.js +15 -0
- package/src/nodes/core/SubBuildNode.js +1 -1
- package/src/nodes/core/UniformNode.js +2 -1
- package/src/nodes/core/VarNode.js +1 -1
- package/src/nodes/core/VaryingNode.js +1 -18
- package/src/nodes/display/BlendModes.js +0 -64
- package/src/nodes/display/ColorAdjustment.js +17 -0
- package/src/nodes/display/ColorSpaceNode.js +3 -3
- package/src/nodes/display/NormalMapNode.js +2 -2
- package/src/nodes/display/PassNode.js +21 -2
- package/src/nodes/display/RenderOutputNode.js +3 -3
- package/src/nodes/display/ScreenNode.js +2 -1
- package/src/nodes/display/ToneMappingNode.js +1 -1
- package/src/nodes/display/ToonOutlinePassNode.js +2 -2
- package/src/nodes/display/ViewportDepthNode.js +52 -4
- package/src/nodes/display/ViewportTextureNode.js +21 -4
- package/src/nodes/fog/Fog.js +18 -35
- package/src/nodes/functions/PhysicalLightingModel.js +25 -3
- package/src/nodes/geometry/RangeNode.js +4 -2
- package/src/nodes/gpgpu/ComputeNode.js +5 -4
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +2 -1
- package/src/nodes/lighting/EnvironmentNode.js +28 -3
- package/src/nodes/lighting/PointShadowNode.js +24 -12
- package/src/nodes/lighting/ShadowFilterNode.js +15 -43
- package/src/nodes/lighting/ShadowNode.js +54 -32
- package/src/nodes/math/ConditionalNode.js +2 -2
- package/src/nodes/math/MathNode.js +3 -40
- package/src/nodes/math/OperatorNode.js +2 -1
- package/src/nodes/pmrem/PMREMUtils.js +9 -15
- package/src/nodes/tsl/TSLCore.js +13 -10
- package/src/nodes/utils/DebugNode.js +11 -11
- package/src/nodes/utils/JoinNode.js +2 -2
- package/src/nodes/utils/LoopNode.js +1 -1
- package/src/nodes/utils/MemberNode.js +1 -1
- package/src/nodes/utils/RTTNode.js +1 -1
- package/src/nodes/utils/ReflectorNode.js +2 -3
- package/src/nodes/utils/SpriteSheetUV.js +35 -0
- package/src/nodes/utils/UVUtils.js +4 -2
- package/src/objects/BatchedMesh.js +22 -12
- package/src/objects/InstancedMesh.js +11 -0
- package/src/renderers/WebGLRenderer.js +34 -60
- package/src/renderers/common/Backend.js +21 -0
- package/src/renderers/common/Background.js +7 -4
- package/src/renderers/common/BindGroup.js +1 -9
- package/src/renderers/common/Bindings.js +20 -5
- package/src/renderers/common/BlendMode.js +143 -0
- package/src/renderers/common/BundleGroup.js +1 -1
- package/src/renderers/common/CubeRenderTarget.js +50 -6
- package/src/renderers/common/Geometries.js +17 -3
- package/src/renderers/common/Lighting.js +5 -21
- package/src/renderers/common/Pipelines.js +4 -4
- package/src/renderers/common/PostProcessing.js +8 -206
- package/src/renderers/common/RenderBundles.js +2 -1
- package/src/renderers/common/RenderContext.js +16 -0
- package/src/renderers/common/RenderContexts.js +33 -56
- package/src/renderers/common/RenderLists.js +2 -1
- package/src/renderers/common/RenderObject.js +2 -3
- package/src/renderers/common/RenderObjectPipeline.js +40 -0
- package/src/renderers/common/RenderObjects.js +18 -2
- package/src/renderers/common/RenderPipeline.js +203 -17
- package/src/renderers/common/Renderer.js +207 -40
- package/src/renderers/common/Sampler.js +4 -4
- package/src/renderers/common/StorageBuffer.js +13 -1
- package/src/renderers/common/Textures.js +16 -0
- package/src/renderers/common/TimestampQueryPool.js +5 -3
- package/src/renderers/common/Uniform.js +8 -0
- package/src/renderers/common/UniformsGroup.js +60 -0
- package/src/renderers/common/XRManager.js +2 -2
- package/src/renderers/common/nodes/NodeBuilderState.js +1 -1
- package/src/renderers/common/nodes/{Nodes.js → NodeManager.js} +18 -6
- package/src/renderers/common/nodes/NodeStorageBuffer.js +13 -2
- package/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js +2 -2
- package/src/renderers/shaders/ShaderChunk/color_fragment.glsl.js +1 -5
- package/src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl.js +1 -5
- package/src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js +1 -5
- package/src/renderers/shaders/ShaderChunk/color_vertex.glsl.js +8 -10
- package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +7 -11
- package/src/renderers/shaders/ShaderChunk/lights_fragment_end.glsl.js +6 -0
- package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +6 -2
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +23 -1
- package/src/renderers/shaders/ShaderChunk/packing.glsl.js +20 -4
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +55 -24
- package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +2 -0
- package/src/renderers/shaders/ShaderLib/shadow.glsl.js +1 -0
- package/src/renderers/shaders/ShaderLib.js +4 -2
- package/src/renderers/shaders/UniformsLib.js +0 -3
- package/src/renderers/webgl/WebGLBackground.js +2 -2
- package/src/renderers/webgl/WebGLBindingStates.js +99 -27
- package/src/renderers/webgl/WebGLEnvironments.js +228 -0
- package/src/renderers/webgl/WebGLGeometries.js +10 -7
- package/src/renderers/webgl/WebGLMaterials.js +12 -0
- package/src/renderers/webgl/WebGLObjects.js +3 -1
- package/src/renderers/webgl/WebGLProgram.js +2 -2
- package/src/renderers/webgl/WebGLPrograms.js +10 -4
- package/src/renderers/webgl/WebGLRenderLists.js +15 -0
- package/src/renderers/webgl/WebGLShadowMap.js +5 -4
- package/src/renderers/webgl/WebGLState.js +12 -17
- package/src/renderers/webgl-fallback/WebGLBackend.js +71 -7
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +98 -29
- package/src/renderers/webgl-fallback/utils/WebGLState.js +168 -7
- package/src/renderers/webgpu/WebGPUBackend.js +58 -9
- package/src/renderers/webgpu/WebGPURenderer.js +1 -0
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +257 -45
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +8 -19
- package/src/renderers/webgpu/utils/WebGPUConstants.js +1 -1
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +56 -31
- package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +152 -200
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +25 -25
- package/src/renderers/webgpu/utils/WebGPUUtils.js +10 -6
- package/src/renderers/webxr/WebXRManager.js +2 -2
- package/src/textures/Texture.js +2 -2
- package/src/utils.js +246 -3
- package/examples/jsm/materials/MeshGouraudMaterial.js +0 -433
- package/examples/jsm/materials/MeshPostProcessingMaterial.js +0 -167
- package/examples/jsm/shaders/GodRaysShader.js +0 -333
- package/src/nodes/accessors/SceneNode.js +0 -145
- package/src/nodes/code/ScriptableNode.js +0 -726
- package/src/nodes/code/ScriptableValueNode.js +0 -253
- package/src/nodes/display/PosterizeNode.js +0 -65
- package/src/nodes/utils/SpriteSheetUVNode.js +0 -90
- package/src/renderers/webgl/WebGLCubeMaps.js +0 -99
- package/src/renderers/webgl/WebGLCubeUVMaps.js +0 -134
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Group,
|
|
6
|
-
NoColorSpace,
|
|
7
|
-
Mesh,
|
|
8
|
-
MeshPhysicalMaterial,
|
|
9
|
-
MirroredRepeatWrapping,
|
|
10
|
-
RepeatWrapping,
|
|
11
|
-
SRGBColorSpace,
|
|
12
|
-
TextureLoader,
|
|
13
|
-
Object3D,
|
|
14
|
-
Vector2
|
|
15
|
-
} from 'three';
|
|
1
|
+
// Pre-compiled regex patterns for performance
|
|
2
|
+
const DEF_MATCH_REGEX = /^def\s+(?:(\w+)\s+)?"?([^"]+)"?$/;
|
|
3
|
+
const VARIANT_STRING_REGEX = /^string\s+(\w+)$/;
|
|
4
|
+
const ATTR_MATCH_REGEX = /^(?:uniform\s+)?(\w+(?:\[\])?)\s+(.+)$/;
|
|
16
5
|
|
|
17
6
|
class USDAParser {
|
|
18
7
|
|
|
19
8
|
parseText( text ) {
|
|
20
9
|
|
|
10
|
+
// Preprocess: strip comments and normalize multiline values
|
|
11
|
+
text = this._preprocess( text );
|
|
12
|
+
|
|
21
13
|
const root = {};
|
|
22
14
|
|
|
23
15
|
const lines = text.split( '\n' );
|
|
@@ -27,18 +19,22 @@ class USDAParser {
|
|
|
27
19
|
|
|
28
20
|
const stack = [ root ];
|
|
29
21
|
|
|
30
|
-
// Parse USDA file
|
|
31
|
-
|
|
32
22
|
for ( const line of lines ) {
|
|
33
23
|
|
|
34
|
-
// console.log( line );
|
|
35
|
-
|
|
36
24
|
if ( line.includes( '=' ) ) {
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
// Find the first '=' that's not inside quotes
|
|
27
|
+
const eqIdx = this._findAssignmentOperator( line );
|
|
28
|
+
|
|
29
|
+
if ( eqIdx === - 1 ) {
|
|
30
|
+
|
|
31
|
+
string = line.trim();
|
|
32
|
+
continue;
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const lhs = line.slice( 0, eqIdx ).trim();
|
|
37
|
+
const rhs = line.slice( eqIdx + 1 ).trim();
|
|
42
38
|
|
|
43
39
|
if ( rhs.endsWith( '{' ) ) {
|
|
44
40
|
|
|
@@ -66,6 +62,20 @@ class USDAParser {
|
|
|
66
62
|
|
|
67
63
|
}
|
|
68
64
|
|
|
65
|
+
} else if ( line.includes( ':' ) && ! line.includes( '=' ) ) {
|
|
66
|
+
|
|
67
|
+
// Handle dictionary entries like "0: [(...)...]" for timeSamples
|
|
68
|
+
const colonIdx = line.indexOf( ':' );
|
|
69
|
+
const key = line.slice( 0, colonIdx ).trim();
|
|
70
|
+
const value = line.slice( colonIdx + 1 ).trim();
|
|
71
|
+
|
|
72
|
+
// Only process if key looks like a number (timeSamples frame)
|
|
73
|
+
if ( /^[\d.]+$/.test( key ) ) {
|
|
74
|
+
|
|
75
|
+
target[ key ] = value;
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
} else if ( line.endsWith( '{' ) ) {
|
|
70
80
|
|
|
71
81
|
const group = target[ string ] || {};
|
|
@@ -98,7 +108,7 @@ class USDAParser {
|
|
|
98
108
|
|
|
99
109
|
target = stack[ stack.length - 1 ];
|
|
100
110
|
|
|
101
|
-
} else {
|
|
111
|
+
} else if ( line.trim() ) {
|
|
102
112
|
|
|
103
113
|
string = line.trim();
|
|
104
114
|
|
|
@@ -110,629 +120,700 @@ class USDAParser {
|
|
|
110
120
|
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
|
|
123
|
+
_preprocess( text ) {
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
// Remove block comments /* ... */
|
|
126
|
+
text = this._stripBlockComments( text );
|
|
116
127
|
|
|
117
|
-
//
|
|
128
|
+
// Collapse triple-quoted strings into single lines
|
|
129
|
+
text = this._collapseTripleQuotedStrings( text );
|
|
118
130
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
131
|
+
// Remove line comments # ... (but preserve #usda header)
|
|
132
|
+
// Only remove # comments that aren't at the start of a line or after whitespace
|
|
133
|
+
const lines = text.split( '\n' );
|
|
134
|
+
const processed = [];
|
|
122
135
|
|
|
123
|
-
|
|
136
|
+
let inMultilineValue = false;
|
|
137
|
+
let bracketDepth = 0;
|
|
138
|
+
let parenDepth = 0;
|
|
139
|
+
let accumulated = '';
|
|
124
140
|
|
|
125
|
-
|
|
126
|
-
const parts = reference.split( '@' );
|
|
127
|
-
const path = parts[ 1 ].replace( /^.\//, '' );
|
|
128
|
-
const id = parts[ 2 ].replace( /^<\//, '' ).replace( />$/, '' );
|
|
141
|
+
for ( let i = 0; i < lines.length; i ++ ) {
|
|
129
142
|
|
|
130
|
-
|
|
143
|
+
let line = lines[ i ];
|
|
131
144
|
|
|
132
|
-
|
|
145
|
+
// Strip inline comments (but not inside strings)
|
|
146
|
+
line = this._stripInlineComment( line );
|
|
133
147
|
|
|
134
|
-
|
|
148
|
+
// Track bracket/paren depth for multiline values
|
|
149
|
+
const trimmed = line.trim();
|
|
135
150
|
|
|
136
|
-
|
|
151
|
+
if ( inMultilineValue ) {
|
|
137
152
|
|
|
138
|
-
|
|
153
|
+
// Continue accumulating multiline value
|
|
154
|
+
accumulated += ' ' + trimmed;
|
|
139
155
|
|
|
140
|
-
|
|
156
|
+
// Update depths
|
|
157
|
+
for ( const ch of trimmed ) {
|
|
141
158
|
|
|
142
|
-
|
|
159
|
+
if ( ch === '[' ) bracketDepth ++;
|
|
160
|
+
else if ( ch === ']' ) bracketDepth --;
|
|
161
|
+
else if ( ch === '(' && bracketDepth > 0 ) parenDepth ++;
|
|
162
|
+
else if ( ch === ')' && bracketDepth > 0 ) parenDepth --;
|
|
143
163
|
|
|
144
|
-
|
|
164
|
+
}
|
|
145
165
|
|
|
146
|
-
|
|
166
|
+
// Check if multiline value is complete
|
|
167
|
+
if ( bracketDepth === 0 && parenDepth === 0 ) {
|
|
147
168
|
|
|
148
|
-
|
|
169
|
+
processed.push( accumulated );
|
|
170
|
+
accumulated = '';
|
|
171
|
+
inMultilineValue = false;
|
|
149
172
|
|
|
150
173
|
}
|
|
151
174
|
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
for ( const name in data ) {
|
|
175
|
+
} else {
|
|
155
176
|
|
|
156
|
-
|
|
177
|
+
// Check if this line starts a multiline array value
|
|
178
|
+
// Look for patterns like "attr = [" or "attr = @path@[" without closing ]
|
|
179
|
+
if ( trimmed.includes( '=' ) ) {
|
|
157
180
|
|
|
158
|
-
|
|
181
|
+
const eqIdx = this._findAssignmentOperator( trimmed );
|
|
159
182
|
|
|
160
|
-
|
|
183
|
+
if ( eqIdx !== - 1 ) {
|
|
161
184
|
|
|
162
|
-
|
|
185
|
+
const rhs = trimmed.slice( eqIdx + 1 ).trim();
|
|
163
186
|
|
|
187
|
+
// Count brackets in the value part
|
|
188
|
+
let openBrackets = 0;
|
|
189
|
+
let closeBrackets = 0;
|
|
164
190
|
|
|
165
|
-
|
|
191
|
+
for ( const ch of rhs ) {
|
|
166
192
|
|
|
167
|
-
|
|
193
|
+
if ( ch === '[' ) openBrackets ++;
|
|
194
|
+
else if ( ch === ']' ) closeBrackets ++;
|
|
168
195
|
|
|
169
|
-
|
|
196
|
+
}
|
|
170
197
|
|
|
171
|
-
|
|
198
|
+
if ( openBrackets > closeBrackets ) {
|
|
172
199
|
|
|
173
|
-
|
|
200
|
+
// Multiline array detected
|
|
201
|
+
inMultilineValue = true;
|
|
202
|
+
bracketDepth = openBrackets - closeBrackets;
|
|
203
|
+
parenDepth = 0;
|
|
204
|
+
accumulated = trimmed;
|
|
205
|
+
continue;
|
|
174
206
|
|
|
175
|
-
|
|
207
|
+
}
|
|
176
208
|
|
|
177
|
-
|
|
209
|
+
}
|
|
178
210
|
|
|
179
|
-
|
|
211
|
+
}
|
|
180
212
|
|
|
181
|
-
|
|
182
|
-
let indices = null;
|
|
183
|
-
let counts = null;
|
|
184
|
-
let uvs = null;
|
|
213
|
+
processed.push( trimmed );
|
|
185
214
|
|
|
186
|
-
|
|
215
|
+
}
|
|
187
216
|
|
|
188
|
-
|
|
217
|
+
}
|
|
189
218
|
|
|
190
|
-
|
|
219
|
+
return processed.join( '\n' );
|
|
191
220
|
|
|
192
|
-
|
|
221
|
+
}
|
|
193
222
|
|
|
194
|
-
|
|
223
|
+
_stripBlockComments( text ) {
|
|
195
224
|
|
|
196
|
-
|
|
225
|
+
// Iteratively remove /* ... */ comments without regex backtracking
|
|
226
|
+
let result = '';
|
|
227
|
+
let i = 0;
|
|
197
228
|
|
|
198
|
-
|
|
229
|
+
while ( i < text.length ) {
|
|
199
230
|
|
|
200
|
-
|
|
201
|
-
|
|
231
|
+
// Check for block comment start
|
|
232
|
+
if ( text[ i ] === '/' && i + 1 < text.length && text[ i + 1 ] === '*' ) {
|
|
202
233
|
|
|
203
|
-
|
|
234
|
+
// Find the closing */
|
|
235
|
+
let j = i + 2;
|
|
204
236
|
|
|
205
|
-
|
|
237
|
+
while ( j < text.length ) {
|
|
206
238
|
|
|
207
|
-
|
|
239
|
+
if ( text[ j ] === '*' && j + 1 < text.length && text[ j + 1 ] === '/' ) {
|
|
208
240
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
241
|
+
// Found closing, skip past it
|
|
242
|
+
j += 2;
|
|
243
|
+
break;
|
|
212
244
|
|
|
213
|
-
|
|
245
|
+
}
|
|
214
246
|
|
|
215
|
-
|
|
247
|
+
j ++;
|
|
216
248
|
|
|
217
|
-
|
|
249
|
+
}
|
|
218
250
|
|
|
219
|
-
|
|
251
|
+
// Move past the comment (or to end if unclosed)
|
|
252
|
+
i = j;
|
|
220
253
|
|
|
221
|
-
|
|
254
|
+
} else {
|
|
222
255
|
|
|
223
|
-
|
|
256
|
+
result += text[ i ];
|
|
257
|
+
i ++;
|
|
224
258
|
|
|
225
259
|
}
|
|
226
260
|
|
|
227
|
-
|
|
261
|
+
}
|
|
228
262
|
|
|
229
|
-
|
|
230
|
-
let attribute = new BufferAttribute( new Float32Array( uvs ), 2 );
|
|
263
|
+
return result;
|
|
231
264
|
|
|
232
|
-
|
|
265
|
+
}
|
|
233
266
|
|
|
234
|
-
|
|
267
|
+
_collapseTripleQuotedStrings( text ) {
|
|
235
268
|
|
|
236
|
-
|
|
269
|
+
let result = '';
|
|
270
|
+
let i = 0;
|
|
237
271
|
|
|
238
|
-
|
|
272
|
+
while ( i < text.length ) {
|
|
239
273
|
|
|
240
|
-
|
|
274
|
+
if ( i + 2 < text.length ) {
|
|
241
275
|
|
|
242
|
-
const
|
|
243
|
-
let indices = JSON.parse( data[ 'int[] primvars:st:indices' ] );
|
|
244
|
-
indices = toTriangleIndices( indices, counts );
|
|
245
|
-
geometry.setAttribute( 'uv', toFlatBufferAttribute( attribute, indices ) );
|
|
276
|
+
const triple = text.slice( i, i + 3 );
|
|
246
277
|
|
|
247
|
-
|
|
278
|
+
if ( triple === '\'\'\'' || triple === '"""' ) {
|
|
248
279
|
|
|
249
|
-
|
|
280
|
+
const quoteChar = triple;
|
|
281
|
+
result += quoteChar;
|
|
282
|
+
i += 3;
|
|
250
283
|
|
|
251
|
-
|
|
284
|
+
while ( i < text.length ) {
|
|
252
285
|
|
|
253
|
-
|
|
254
|
-
let attribute = new BufferAttribute( new Float32Array( normals ), 3 );
|
|
286
|
+
if ( i + 2 < text.length && text.slice( i, i + 3 ) === quoteChar ) {
|
|
255
287
|
|
|
256
|
-
|
|
288
|
+
result += quoteChar;
|
|
289
|
+
i += 3;
|
|
290
|
+
break;
|
|
257
291
|
|
|
258
|
-
|
|
292
|
+
} else {
|
|
259
293
|
|
|
260
|
-
|
|
294
|
+
if ( text[ i ] === '\n' ) {
|
|
261
295
|
|
|
262
|
-
|
|
296
|
+
result += '\\n';
|
|
263
297
|
|
|
264
|
-
|
|
298
|
+
} else if ( text[ i ] !== '\r' ) {
|
|
265
299
|
|
|
266
|
-
|
|
300
|
+
result += text[ i ];
|
|
267
301
|
|
|
268
|
-
|
|
269
|
-
indices = toTriangleIndices( indices, counts );
|
|
270
|
-
attribute = toFlatBufferAttribute( attribute, indices );
|
|
302
|
+
}
|
|
271
303
|
|
|
272
|
-
|
|
304
|
+
i ++;
|
|
273
305
|
|
|
274
|
-
|
|
306
|
+
}
|
|
275
307
|
|
|
276
|
-
|
|
308
|
+
}
|
|
277
309
|
|
|
278
|
-
|
|
310
|
+
continue;
|
|
279
311
|
|
|
280
|
-
|
|
312
|
+
}
|
|
281
313
|
|
|
282
314
|
}
|
|
283
315
|
|
|
284
|
-
|
|
316
|
+
result += text[ i ];
|
|
317
|
+
i ++;
|
|
285
318
|
|
|
286
319
|
}
|
|
287
320
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const indices = [];
|
|
291
|
-
|
|
292
|
-
for ( let i = 0; i < counts.length; i ++ ) {
|
|
293
|
-
|
|
294
|
-
const count = counts[ i ];
|
|
321
|
+
return result;
|
|
295
322
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if ( count === 3 ) {
|
|
323
|
+
}
|
|
299
324
|
|
|
300
|
-
|
|
301
|
-
const b = rawIndices[ stride + 1 ];
|
|
302
|
-
const c = rawIndices[ stride + 2 ];
|
|
325
|
+
_stripInlineComment( line ) {
|
|
303
326
|
|
|
304
|
-
|
|
327
|
+
// Don't strip if line starts with #usda
|
|
328
|
+
if ( line.trim().startsWith( '#usda' ) ) return line;
|
|
305
329
|
|
|
306
|
-
|
|
330
|
+
// Find # that's not inside a string
|
|
331
|
+
let inString = false;
|
|
332
|
+
let stringChar = null;
|
|
333
|
+
let escaped = false;
|
|
307
334
|
|
|
308
|
-
|
|
309
|
-
const b = rawIndices[ stride + 1 ];
|
|
310
|
-
const c = rawIndices[ stride + 2 ];
|
|
311
|
-
const d = rawIndices[ stride + 3 ];
|
|
335
|
+
for ( let i = 0; i < line.length; i ++ ) {
|
|
312
336
|
|
|
313
|
-
|
|
314
|
-
indices.push( a, c, d );
|
|
337
|
+
const ch = line[ i ];
|
|
315
338
|
|
|
316
|
-
|
|
339
|
+
if ( escaped ) {
|
|
317
340
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
341
|
+
escaped = false;
|
|
342
|
+
continue;
|
|
321
343
|
|
|
322
344
|
}
|
|
323
345
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
346
|
+
if ( ch === '\\' ) {
|
|
327
347
|
|
|
328
|
-
|
|
348
|
+
escaped = true;
|
|
349
|
+
continue;
|
|
329
350
|
|
|
330
|
-
|
|
331
|
-
const itemSize = attribute.itemSize;
|
|
351
|
+
}
|
|
332
352
|
|
|
333
|
-
|
|
353
|
+
if ( ! inString && ( ch === '"' || ch === '\'' ) ) {
|
|
334
354
|
|
|
335
|
-
|
|
355
|
+
inString = true;
|
|
356
|
+
stringChar = ch;
|
|
336
357
|
|
|
337
|
-
|
|
358
|
+
} else if ( inString && ch === stringChar ) {
|
|
338
359
|
|
|
339
|
-
|
|
360
|
+
inString = false;
|
|
361
|
+
stringChar = null;
|
|
340
362
|
|
|
341
|
-
|
|
363
|
+
} else if ( ! inString && ch === '#' ) {
|
|
342
364
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
365
|
+
// Found comment start outside of string
|
|
366
|
+
return line.slice( 0, i ).trimEnd();
|
|
346
367
|
|
|
347
368
|
}
|
|
348
369
|
|
|
349
|
-
return new BufferAttribute( array2, itemSize );
|
|
350
|
-
|
|
351
370
|
}
|
|
352
371
|
|
|
353
|
-
|
|
372
|
+
return line;
|
|
354
373
|
|
|
355
|
-
|
|
374
|
+
}
|
|
356
375
|
|
|
357
|
-
|
|
376
|
+
_findAssignmentOperator( line ) {
|
|
358
377
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
378
|
+
// Find the first '=' that's not inside quotes
|
|
379
|
+
let inString = false;
|
|
380
|
+
let stringChar = null;
|
|
381
|
+
let escaped = false;
|
|
362
382
|
|
|
363
|
-
|
|
383
|
+
for ( let i = 0; i < line.length; i ++ ) {
|
|
364
384
|
|
|
365
|
-
|
|
385
|
+
const ch = line[ i ];
|
|
366
386
|
|
|
367
|
-
|
|
387
|
+
if ( escaped ) {
|
|
368
388
|
|
|
369
|
-
|
|
389
|
+
escaped = false;
|
|
390
|
+
continue;
|
|
370
391
|
|
|
371
|
-
|
|
392
|
+
}
|
|
372
393
|
|
|
373
|
-
|
|
394
|
+
if ( ch === '\\' ) {
|
|
374
395
|
|
|
375
|
-
|
|
396
|
+
escaped = true;
|
|
397
|
+
continue;
|
|
376
398
|
|
|
377
|
-
|
|
399
|
+
}
|
|
378
400
|
|
|
379
|
-
|
|
401
|
+
if ( ! inString && ( ch === '"' || ch === '\'' ) ) {
|
|
380
402
|
|
|
381
|
-
|
|
403
|
+
inString = true;
|
|
404
|
+
stringChar = ch;
|
|
382
405
|
|
|
383
|
-
|
|
406
|
+
} else if ( inString && ch === stringChar ) {
|
|
384
407
|
|
|
385
|
-
|
|
408
|
+
inString = false;
|
|
409
|
+
stringChar = null;
|
|
386
410
|
|
|
387
|
-
|
|
411
|
+
} else if ( ! inString && ch === '=' ) {
|
|
388
412
|
|
|
389
|
-
|
|
413
|
+
return i;
|
|
390
414
|
|
|
391
415
|
}
|
|
392
416
|
|
|
393
417
|
}
|
|
394
418
|
|
|
395
|
-
|
|
419
|
+
return - 1;
|
|
396
420
|
|
|
397
|
-
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Parse USDA text and return raw spec data in specsByPath format.
|
|
425
|
+
* Used by USDComposer for unified scene composition.
|
|
426
|
+
*/
|
|
427
|
+
parseData( text ) {
|
|
398
428
|
|
|
399
|
-
|
|
429
|
+
const root = this.parseText( text );
|
|
430
|
+
const specsByPath = {};
|
|
400
431
|
|
|
401
|
-
|
|
432
|
+
// Spec types (must match USDCParser/USDComposer)
|
|
433
|
+
const SpecType = {
|
|
434
|
+
Attribute: 1,
|
|
435
|
+
Prim: 6,
|
|
436
|
+
Relationship: 8
|
|
437
|
+
};
|
|
402
438
|
|
|
403
|
-
|
|
439
|
+
// Parse root metadata
|
|
440
|
+
const rootFields = {};
|
|
441
|
+
if ( '#usda 1.0' in root ) {
|
|
404
442
|
|
|
405
|
-
|
|
443
|
+
const header = root[ '#usda 1.0' ];
|
|
406
444
|
|
|
407
|
-
|
|
445
|
+
if ( header.upAxis ) {
|
|
446
|
+
|
|
447
|
+
rootFields.upAxis = header.upAxis.replace( /"/g, '' );
|
|
408
448
|
|
|
409
449
|
}
|
|
410
450
|
|
|
411
|
-
if (
|
|
451
|
+
if ( header.defaultPrim ) {
|
|
412
452
|
|
|
413
|
-
|
|
453
|
+
rootFields.defaultPrim = header.defaultPrim.replace( /"/g, '' );
|
|
414
454
|
|
|
415
455
|
}
|
|
416
456
|
|
|
417
457
|
}
|
|
418
458
|
|
|
419
|
-
|
|
459
|
+
specsByPath[ '/' ] = { specType: SpecType.Prim, fields: rootFields };
|
|
420
460
|
|
|
421
|
-
|
|
461
|
+
// Walk the tree and build specsByPath
|
|
462
|
+
const walkTree = ( data, parentPath ) => {
|
|
422
463
|
|
|
423
|
-
|
|
464
|
+
const primChildren = [];
|
|
424
465
|
|
|
425
|
-
|
|
466
|
+
for ( const key in data ) {
|
|
426
467
|
|
|
427
|
-
|
|
468
|
+
// Skip metadata
|
|
469
|
+
if ( key === '#usda 1.0' ) continue;
|
|
470
|
+
if ( key === 'variants' ) continue;
|
|
428
471
|
|
|
429
|
-
|
|
472
|
+
// Check for primitive definitions
|
|
473
|
+
// Matches both 'def TypeName "name"' and 'def "name"' (no type)
|
|
474
|
+
const defMatch = key.match( DEF_MATCH_REGEX );
|
|
475
|
+
if ( defMatch ) {
|
|
430
476
|
|
|
431
|
-
const
|
|
477
|
+
const typeName = defMatch[ 1 ] || '';
|
|
478
|
+
const name = defMatch[ 2 ];
|
|
479
|
+
const path = parentPath === '/' ? '/' + name : parentPath + '/' + name;
|
|
432
480
|
|
|
433
|
-
|
|
481
|
+
primChildren.push( name );
|
|
434
482
|
|
|
435
|
-
|
|
436
|
-
|
|
483
|
+
const primFields = { typeName };
|
|
484
|
+
const primData = data[ key ];
|
|
437
485
|
|
|
438
|
-
|
|
486
|
+
// Extract attributes and relationships from this prim
|
|
487
|
+
this._extractPrimData( primData, path, primFields, specsByPath, SpecType );
|
|
439
488
|
|
|
440
|
-
|
|
489
|
+
specsByPath[ path ] = { specType: SpecType.Prim, fields: primFields };
|
|
441
490
|
|
|
442
|
-
|
|
491
|
+
// Recurse into children
|
|
492
|
+
walkTree( primData, path );
|
|
443
493
|
|
|
444
|
-
|
|
494
|
+
}
|
|
445
495
|
|
|
446
|
-
|
|
447
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
496
|
+
}
|
|
448
497
|
|
|
449
|
-
|
|
450
|
-
|
|
498
|
+
// Add primChildren to parent spec
|
|
499
|
+
if ( primChildren.length > 0 && specsByPath[ parentPath ] ) {
|
|
451
500
|
|
|
452
|
-
|
|
501
|
+
specsByPath[ parentPath ].fields.primChildren = primChildren;
|
|
453
502
|
|
|
454
|
-
|
|
503
|
+
}
|
|
455
504
|
|
|
456
|
-
|
|
505
|
+
};
|
|
457
506
|
|
|
458
|
-
|
|
507
|
+
walkTree( root, '/' );
|
|
459
508
|
|
|
460
|
-
|
|
461
|
-
material.color.fromArray( JSON.parse( '[' + color + ']' ) );
|
|
509
|
+
return { specsByPath };
|
|
462
510
|
|
|
463
|
-
|
|
511
|
+
}
|
|
464
512
|
|
|
465
|
-
|
|
513
|
+
_extractPrimData( data, path, primFields, specsByPath, SpecType ) {
|
|
466
514
|
|
|
467
|
-
|
|
468
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
515
|
+
if ( ! data || typeof data !== 'object' ) return;
|
|
469
516
|
|
|
470
|
-
|
|
471
|
-
material.emissiveMap.colorSpace = SRGBColorSpace;
|
|
472
|
-
material.emissive.set( 0xffffff );
|
|
517
|
+
for ( const key in data ) {
|
|
473
518
|
|
|
474
|
-
|
|
519
|
+
// Skip nested defs (handled by walkTree)
|
|
520
|
+
if ( key.startsWith( 'def ' ) ) continue;
|
|
475
521
|
|
|
476
|
-
|
|
522
|
+
if ( key === 'prepend references' ) {
|
|
477
523
|
|
|
478
|
-
|
|
524
|
+
primFields.references = [ data[ key ] ];
|
|
525
|
+
continue;
|
|
479
526
|
|
|
480
|
-
|
|
527
|
+
}
|
|
481
528
|
|
|
482
|
-
|
|
483
|
-
material.emissive.fromArray( JSON.parse( '[' + color + ']' ) );
|
|
529
|
+
if ( key === 'payload' ) {
|
|
484
530
|
|
|
485
|
-
|
|
531
|
+
primFields.payload = data[ key ];
|
|
532
|
+
continue;
|
|
486
533
|
|
|
487
|
-
|
|
534
|
+
}
|
|
488
535
|
|
|
489
|
-
|
|
490
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
536
|
+
if ( key === 'variants' ) {
|
|
491
537
|
|
|
492
|
-
|
|
493
|
-
|
|
538
|
+
const variantSelection = {};
|
|
539
|
+
const variants = data[ key ];
|
|
494
540
|
|
|
495
|
-
|
|
541
|
+
for ( const vKey in variants ) {
|
|
496
542
|
|
|
497
|
-
|
|
543
|
+
const match = vKey.match( VARIANT_STRING_REGEX );
|
|
544
|
+
if ( match ) {
|
|
498
545
|
|
|
499
|
-
|
|
546
|
+
const variantSetName = match[ 1 ];
|
|
547
|
+
const variantValue = variants[ vKey ].replace( /"/g, '' );
|
|
548
|
+
variantSelection[ variantSetName ] = variantValue;
|
|
500
549
|
|
|
501
550
|
}
|
|
502
551
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const path = surface[ 'float inputs:roughness.connect' ];
|
|
506
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
507
|
-
|
|
508
|
-
material.roughness = 1.0;
|
|
509
|
-
material.roughnessMap = buildTexture( sampler );
|
|
510
|
-
material.roughnessMap.colorSpace = NoColorSpace;
|
|
511
|
-
|
|
512
|
-
if ( 'def Shader "Transform2d_roughness"' in data ) {
|
|
513
|
-
|
|
514
|
-
setTextureParams( material.roughnessMap, data[ 'def Shader "Transform2d_roughness"' ] );
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
} else if ( 'float inputs:roughness' in surface ) {
|
|
519
|
-
|
|
520
|
-
material.roughness = parseFloat( surface[ 'float inputs:roughness' ] );
|
|
552
|
+
}
|
|
521
553
|
|
|
522
|
-
|
|
554
|
+
if ( Object.keys( variantSelection ).length > 0 ) {
|
|
523
555
|
|
|
524
|
-
|
|
556
|
+
primFields.variantSelection = variantSelection;
|
|
525
557
|
|
|
526
|
-
|
|
527
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
558
|
+
}
|
|
528
559
|
|
|
529
|
-
|
|
530
|
-
material.metalnessMap = buildTexture( sampler );
|
|
531
|
-
material.metalnessMap.colorSpace = NoColorSpace;
|
|
560
|
+
continue;
|
|
532
561
|
|
|
533
|
-
|
|
562
|
+
}
|
|
534
563
|
|
|
535
|
-
|
|
564
|
+
if ( key.startsWith( 'rel ' ) ) {
|
|
536
565
|
|
|
537
|
-
|
|
566
|
+
const relName = key.slice( 4 );
|
|
567
|
+
const relPath = path + '.' + relName;
|
|
568
|
+
const target = data[ key ].replace( /[<>]/g, '' );
|
|
569
|
+
specsByPath[ relPath ] = {
|
|
570
|
+
specType: SpecType.Relationship,
|
|
571
|
+
fields: { targetPaths: [ target ] }
|
|
572
|
+
};
|
|
573
|
+
continue;
|
|
538
574
|
|
|
539
|
-
|
|
575
|
+
}
|
|
540
576
|
|
|
541
|
-
|
|
577
|
+
// Handle xformOpOrder
|
|
578
|
+
if ( key.includes( 'xformOpOrder' ) ) {
|
|
542
579
|
|
|
543
|
-
|
|
580
|
+
const ops = data[ key ]
|
|
581
|
+
.replace( /[\[\]]/g, '' )
|
|
582
|
+
.split( ',' )
|
|
583
|
+
.map( s => s.trim().replace( /"/g, '' ) );
|
|
584
|
+
primFields.xformOpOrder = ops;
|
|
585
|
+
continue;
|
|
544
586
|
|
|
545
|
-
|
|
587
|
+
}
|
|
546
588
|
|
|
547
|
-
|
|
548
|
-
|
|
589
|
+
// Handle typed attributes
|
|
590
|
+
// Format: [qualifier] type attrName (e.g., "uniform token[] joints", "float3 position")
|
|
591
|
+
const attrMatch = key.match( ATTR_MATCH_REGEX );
|
|
592
|
+
if ( attrMatch ) {
|
|
549
593
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
594
|
+
const valueType = attrMatch[ 1 ];
|
|
595
|
+
const attrName = attrMatch[ 2 ];
|
|
596
|
+
const rawValue = data[ key ];
|
|
553
597
|
|
|
554
|
-
|
|
598
|
+
// Handle connection attributes (e.g., "inputs:normal.connect = </path>")
|
|
599
|
+
if ( attrName.endsWith( '.connect' ) ) {
|
|
555
600
|
|
|
556
|
-
|
|
601
|
+
const baseAttrName = attrName.slice( 0, - 8 ); // Remove '.connect'
|
|
602
|
+
const attrPath = path + '.' + baseAttrName;
|
|
557
603
|
|
|
558
|
-
|
|
604
|
+
// Parse connection path - extract from <path> format
|
|
605
|
+
let connPath = String( rawValue ).trim();
|
|
606
|
+
if ( connPath.startsWith( '<' ) ) connPath = connPath.slice( 1 );
|
|
607
|
+
if ( connPath.endsWith( '>' ) ) connPath = connPath.slice( 0, - 1 );
|
|
559
608
|
|
|
560
|
-
|
|
609
|
+
// Get or create the attribute spec
|
|
610
|
+
if ( ! specsByPath[ attrPath ] ) {
|
|
561
611
|
|
|
562
|
-
|
|
612
|
+
specsByPath[ attrPath ] = {
|
|
613
|
+
specType: SpecType.Attribute,
|
|
614
|
+
fields: { typeName: valueType }
|
|
615
|
+
};
|
|
563
616
|
|
|
564
617
|
}
|
|
565
618
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
const path = surface[ 'float inputs:clearcoatRoughness.connect' ];
|
|
569
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
570
|
-
|
|
571
|
-
material.clearcoatRoughness = 1.0;
|
|
572
|
-
material.clearcoatRoughnessMap = buildTexture( sampler );
|
|
573
|
-
material.clearcoatRoughnessMap.colorSpace = NoColorSpace;
|
|
574
|
-
|
|
575
|
-
if ( 'def Shader "Transform2d_clearcoatRoughness"' in data ) {
|
|
619
|
+
specsByPath[ attrPath ].fields.connectionPaths = [ connPath ];
|
|
620
|
+
continue;
|
|
576
621
|
|
|
577
|
-
|
|
622
|
+
}
|
|
578
623
|
|
|
579
|
-
|
|
624
|
+
// Handle timeSamples attributes specially
|
|
625
|
+
if ( attrName.endsWith( '.timeSamples' ) && typeof rawValue === 'object' ) {
|
|
580
626
|
|
|
581
|
-
|
|
627
|
+
const baseAttrName = attrName.slice( 0, - 12 ); // Remove '.timeSamples'
|
|
628
|
+
const attrPath = path + '.' + baseAttrName;
|
|
582
629
|
|
|
583
|
-
|
|
630
|
+
// Parse timeSamples dictionary into times and values arrays
|
|
631
|
+
const times = [];
|
|
632
|
+
const values = [];
|
|
584
633
|
|
|
585
|
-
|
|
634
|
+
for ( const frameKey in rawValue ) {
|
|
586
635
|
|
|
587
|
-
|
|
636
|
+
const frame = parseFloat( frameKey );
|
|
637
|
+
if ( isNaN( frame ) ) continue;
|
|
588
638
|
|
|
589
|
-
|
|
639
|
+
times.push( frame );
|
|
640
|
+
values.push( this._parseAttributeValue( valueType, rawValue[ frameKey ] ) );
|
|
590
641
|
|
|
591
642
|
}
|
|
592
643
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const path = surface[ 'float inputs:occlusion.connect' ];
|
|
596
|
-
const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
|
|
597
|
-
|
|
598
|
-
material.aoMap = buildTexture( sampler );
|
|
599
|
-
material.aoMap.colorSpace = NoColorSpace;
|
|
644
|
+
// Sort by time
|
|
645
|
+
const sorted = times.map( ( t, i ) => ( { t, v: values[ i ] } ) ).sort( ( a, b ) => a.t - b.t );
|
|
600
646
|
|
|
601
|
-
|
|
647
|
+
specsByPath[ attrPath ] = {
|
|
648
|
+
specType: SpecType.Attribute,
|
|
649
|
+
fields: {
|
|
650
|
+
timeSamples: { times: sorted.map( s => s.t ), values: sorted.map( s => s.v ) },
|
|
651
|
+
typeName: valueType
|
|
652
|
+
}
|
|
653
|
+
};
|
|
602
654
|
|
|
603
|
-
|
|
655
|
+
} else {
|
|
604
656
|
|
|
605
|
-
|
|
657
|
+
// Parse value based on type
|
|
658
|
+
const parsedValue = this._parseAttributeValue( valueType, rawValue );
|
|
606
659
|
|
|
607
|
-
|
|
660
|
+
// Store as attribute spec
|
|
661
|
+
const attrPath = path + '.' + attrName;
|
|
662
|
+
specsByPath[ attrPath ] = {
|
|
663
|
+
specType: SpecType.Attribute,
|
|
664
|
+
fields: { default: parsedValue, typeName: valueType }
|
|
665
|
+
};
|
|
608
666
|
|
|
609
667
|
}
|
|
610
668
|
|
|
611
669
|
}
|
|
612
670
|
|
|
613
|
-
return material;
|
|
614
|
-
|
|
615
671
|
}
|
|
616
672
|
|
|
617
|
-
|
|
673
|
+
}
|
|
618
674
|
|
|
619
|
-
|
|
675
|
+
_parseAttributeValue( valueType, rawValue ) {
|
|
620
676
|
|
|
621
|
-
|
|
677
|
+
if ( rawValue === undefined || rawValue === null ) return undefined;
|
|
622
678
|
|
|
623
|
-
|
|
679
|
+
const str = String( rawValue ).trim();
|
|
624
680
|
|
|
625
|
-
|
|
681
|
+
// Array types
|
|
682
|
+
if ( valueType.endsWith( '[]' ) ) {
|
|
626
683
|
|
|
627
|
-
|
|
684
|
+
// Parse JSON-like arrays
|
|
685
|
+
try {
|
|
628
686
|
|
|
629
|
-
|
|
687
|
+
// Handle arrays with parentheses like [(1,2,3), (4,5,6)]
|
|
688
|
+
// Remove trailing comma (valid in USDA but not JSON)
|
|
689
|
+
let cleaned = str.replace( /\(/g, '[' ).replace( /\)/g, ']' );
|
|
690
|
+
if ( cleaned.endsWith( ',' ) ) cleaned = cleaned.slice( 0, - 1 );
|
|
691
|
+
const parsed = JSON.parse( cleaned );
|
|
630
692
|
|
|
631
|
-
|
|
693
|
+
// Flatten nested arrays for types like point3f[]
|
|
694
|
+
if ( Array.isArray( parsed ) && Array.isArray( parsed[ 0 ] ) ) {
|
|
632
695
|
|
|
633
|
-
|
|
696
|
+
return parsed.flat();
|
|
634
697
|
|
|
635
698
|
}
|
|
636
699
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
700
|
+
return parsed;
|
|
640
701
|
|
|
641
|
-
|
|
702
|
+
} catch ( e ) {
|
|
642
703
|
|
|
643
|
-
|
|
704
|
+
// Try simple array parsing
|
|
705
|
+
const cleaned = str.replace( /[\[\]]/g, '' );
|
|
706
|
+
return cleaned.split( ',' ).map( s => {
|
|
644
707
|
|
|
645
|
-
|
|
708
|
+
const trimmed = s.trim();
|
|
709
|
+
const num = parseFloat( trimmed );
|
|
710
|
+
return isNaN( num ) ? trimmed.replace( /"/g, '' ) : num;
|
|
646
711
|
|
|
647
|
-
|
|
712
|
+
} );
|
|
648
713
|
|
|
649
|
-
|
|
714
|
+
}
|
|
650
715
|
|
|
651
|
-
|
|
652
|
-
'"clamp"': ClampToEdgeWrapping,
|
|
653
|
-
'"mirror"': MirroredRepeatWrapping,
|
|
654
|
-
'"repeat"': RepeatWrapping
|
|
655
|
-
};
|
|
716
|
+
}
|
|
656
717
|
|
|
657
|
-
|
|
718
|
+
// Vector types (double3, float3, point3f, etc.)
|
|
719
|
+
if ( valueType.includes( '3' ) || valueType.includes( '2' ) || valueType.includes( '4' ) ) {
|
|
658
720
|
|
|
659
|
-
|
|
721
|
+
// Parse (x, y, z) format
|
|
722
|
+
const cleaned = str.replace( /[()]/g, '' );
|
|
723
|
+
const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
|
|
724
|
+
return values;
|
|
660
725
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
if ( 'token inputs:wrapT' in data ) {
|
|
726
|
+
}
|
|
664
727
|
|
|
665
|
-
|
|
728
|
+
// Quaternion types (quatf, quatd, quath)
|
|
729
|
+
// Text format is (w, x, y, z), convert to (x, y, z, w)
|
|
730
|
+
if ( valueType.startsWith( 'quat' ) ) {
|
|
666
731
|
|
|
667
|
-
|
|
732
|
+
const cleaned = str.replace( /[()]/g, '' );
|
|
733
|
+
const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
|
|
734
|
+
return [ values[ 1 ], values[ 2 ], values[ 3 ], values[ 0 ] ];
|
|
668
735
|
|
|
669
|
-
|
|
736
|
+
}
|
|
670
737
|
|
|
671
|
-
|
|
738
|
+
// Matrix types
|
|
739
|
+
if ( valueType.includes( 'matrix' ) ) {
|
|
672
740
|
|
|
673
|
-
|
|
741
|
+
const cleaned = str.replace( /[()]/g, '' );
|
|
742
|
+
const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
|
|
743
|
+
return values;
|
|
674
744
|
|
|
675
745
|
}
|
|
676
746
|
|
|
677
|
-
|
|
747
|
+
// Scalar numeric types
|
|
748
|
+
if ( valueType === 'float' || valueType === 'double' || valueType === 'int' ) {
|
|
678
749
|
|
|
679
|
-
|
|
680
|
-
const material = buildMaterial( findMeshMaterial( data ) );
|
|
750
|
+
return parseFloat( str );
|
|
681
751
|
|
|
682
|
-
|
|
752
|
+
}
|
|
683
753
|
|
|
684
|
-
|
|
754
|
+
// String/token types
|
|
755
|
+
if ( valueType === 'string' || valueType === 'token' ) {
|
|
685
756
|
|
|
686
|
-
|
|
757
|
+
return this._parseString( str );
|
|
687
758
|
|
|
688
|
-
|
|
689
|
-
mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
|
|
759
|
+
}
|
|
690
760
|
|
|
691
|
-
|
|
761
|
+
// Asset path
|
|
762
|
+
if ( valueType === 'asset' ) {
|
|
692
763
|
|
|
693
|
-
return
|
|
764
|
+
return str.replace( /@/g, '' ).replace( /"/g, '' );
|
|
694
765
|
|
|
695
766
|
}
|
|
696
767
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
for ( const name in data ) {
|
|
768
|
+
// Default: return as string with quotes removed
|
|
769
|
+
return this._parseString( str );
|
|
700
770
|
|
|
701
|
-
|
|
771
|
+
}
|
|
702
772
|
|
|
703
|
-
|
|
773
|
+
_parseString( str ) {
|
|
704
774
|
|
|
705
|
-
|
|
775
|
+
// Remove surrounding quotes
|
|
776
|
+
if ( ( str.startsWith( '"' ) && str.endsWith( '"' ) ) ||
|
|
777
|
+
( str.startsWith( '\'' ) && str.endsWith( '\'' ) ) ) {
|
|
706
778
|
|
|
707
|
-
|
|
779
|
+
str = str.slice( 1, - 1 );
|
|
708
780
|
|
|
709
|
-
|
|
781
|
+
}
|
|
710
782
|
|
|
711
|
-
|
|
783
|
+
// Handle escape sequences
|
|
784
|
+
let result = '';
|
|
785
|
+
let i = 0;
|
|
712
786
|
|
|
713
|
-
|
|
787
|
+
while ( i < str.length ) {
|
|
714
788
|
|
|
715
|
-
|
|
789
|
+
if ( str[ i ] === '\\' && i + 1 < str.length ) {
|
|
716
790
|
|
|
717
|
-
|
|
791
|
+
const next = str[ i + 1 ];
|
|
718
792
|
|
|
719
|
-
|
|
793
|
+
switch ( next ) {
|
|
720
794
|
|
|
721
|
-
|
|
795
|
+
case 'n': result += '\n'; break;
|
|
796
|
+
case 't': result += '\t'; break;
|
|
797
|
+
case 'r': result += '\r'; break;
|
|
798
|
+
case '\\': result += '\\'; break;
|
|
799
|
+
case '"': result += '"'; break;
|
|
800
|
+
case '\'': result += '\''; break;
|
|
801
|
+
default: result += next; break;
|
|
722
802
|
|
|
723
|
-
|
|
803
|
+
}
|
|
724
804
|
|
|
725
|
-
|
|
805
|
+
i += 2;
|
|
726
806
|
|
|
727
|
-
|
|
807
|
+
} else {
|
|
728
808
|
|
|
729
|
-
|
|
809
|
+
result += str[ i ];
|
|
810
|
+
i ++;
|
|
730
811
|
|
|
731
|
-
|
|
812
|
+
}
|
|
732
813
|
|
|
733
814
|
}
|
|
734
815
|
|
|
735
|
-
return
|
|
816
|
+
return result;
|
|
736
817
|
|
|
737
818
|
}
|
|
738
819
|
|