@plastic-software/three 0.178.0 → 0.179.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.
Files changed (141) hide show
  1. package/README.md +1 -1
  2. package/build/three.cjs +856 -196
  3. package/build/three.core.js +647 -123
  4. package/build/three.core.min.js +1 -1
  5. package/build/three.module.js +211 -76
  6. package/build/three.module.min.js +1 -1
  7. package/build/three.tsl.js +70 -21
  8. package/build/three.tsl.min.js +1 -1
  9. package/build/three.webgpu.js +1796 -557
  10. package/build/three.webgpu.min.js +1 -1
  11. package/build/three.webgpu.nodes.js +1754 -557
  12. package/build/three.webgpu.nodes.min.js +1 -1
  13. package/examples/jsm/Addons.js +1 -2
  14. package/examples/jsm/capabilities/WebGPU.js +1 -1
  15. package/examples/jsm/csm/CSMShadowNode.js +4 -4
  16. package/examples/jsm/environments/RoomEnvironment.js +8 -3
  17. package/examples/jsm/exporters/USDZExporter.js +676 -299
  18. package/examples/jsm/geometries/RoundedBoxGeometry.js +47 -8
  19. package/examples/jsm/interactive/HTMLMesh.js +5 -3
  20. package/examples/jsm/libs/meshopt_decoder.module.js +75 -58
  21. package/examples/jsm/lights/LightProbeGenerator.js +14 -3
  22. package/examples/jsm/loaders/EXRLoader.js +210 -22
  23. package/examples/jsm/loaders/FBXLoader.js +1 -1
  24. package/examples/jsm/loaders/MaterialXLoader.js +212 -30
  25. package/examples/jsm/loaders/TTFLoader.js +13 -1
  26. package/examples/jsm/loaders/USDLoader.js +219 -0
  27. package/examples/jsm/loaders/USDZLoader.js +4 -892
  28. package/examples/jsm/loaders/usd/USDAParser.js +741 -0
  29. package/examples/jsm/loaders/usd/USDCParser.js +17 -0
  30. package/examples/jsm/objects/LensflareMesh.js +3 -3
  31. package/examples/jsm/objects/SkyMesh.js +2 -2
  32. package/examples/jsm/physics/RapierPhysics.js +14 -5
  33. package/examples/jsm/postprocessing/GTAOPass.js +10 -9
  34. package/examples/jsm/postprocessing/OutlinePass.js +17 -17
  35. package/examples/jsm/postprocessing/SSAOPass.js +10 -9
  36. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +11 -2
  37. package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
  38. package/examples/jsm/tsl/display/BloomNode.js +8 -7
  39. package/examples/jsm/tsl/display/GaussianBlurNode.js +6 -8
  40. package/examples/jsm/tsl/display/{TRAAPassNode.js → TRAANode.js} +181 -172
  41. package/examples/jsm/tsl/lighting/TiledLightsNode.js +1 -1
  42. package/package.json +1 -1
  43. package/src/Three.Core.js +1 -0
  44. package/src/Three.TSL.js +69 -20
  45. package/src/animation/KeyframeTrack.js +1 -1
  46. package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
  47. package/src/animation/tracks/StringKeyframeTrack.js +1 -1
  48. package/src/cameras/Camera.js +14 -0
  49. package/src/cameras/OrthographicCamera.js +1 -1
  50. package/src/cameras/PerspectiveCamera.js +1 -1
  51. package/src/constants.js +1 -1
  52. package/{examples/jsm/misc → src/core}/Timer.js +4 -42
  53. package/src/extras/PMREMGenerator.js +11 -0
  54. package/src/helpers/CameraHelper.js +41 -11
  55. package/src/helpers/SkeletonHelper.js +35 -6
  56. package/src/lights/LightShadow.js +21 -8
  57. package/src/lights/PointLightShadow.js +1 -1
  58. package/src/loaders/FileLoader.js +25 -2
  59. package/src/loaders/ImageBitmapLoader.js +23 -0
  60. package/src/loaders/Loader.js +14 -0
  61. package/src/loaders/LoadingManager.js +23 -0
  62. package/src/materials/MeshBasicMaterial.js +1 -1
  63. package/src/materials/nodes/Line2NodeMaterial.js +0 -8
  64. package/src/materials/nodes/NodeMaterial.js +1 -1
  65. package/src/materials/nodes/PointsNodeMaterial.js +5 -0
  66. package/src/materials/nodes/manager/NodeMaterialObserver.js +87 -2
  67. package/src/math/Frustum.js +19 -8
  68. package/src/math/FrustumArray.js +10 -5
  69. package/src/math/Line3.js +129 -2
  70. package/src/math/Matrix4.js +48 -27
  71. package/src/math/Spherical.js +2 -2
  72. package/src/nodes/Nodes.js +1 -0
  73. package/src/nodes/TSL.js +1 -0
  74. package/src/nodes/accessors/Camera.js +12 -12
  75. package/src/nodes/accessors/Normal.js +11 -11
  76. package/src/nodes/accessors/ReferenceNode.js +18 -3
  77. package/src/nodes/accessors/SceneNode.js +1 -1
  78. package/src/nodes/accessors/StorageTextureNode.js +1 -1
  79. package/src/nodes/accessors/TextureNode.js +12 -0
  80. package/src/nodes/core/ArrayNode.js +12 -0
  81. package/src/nodes/core/AssignNode.js +3 -0
  82. package/src/nodes/core/ContextNode.js +20 -1
  83. package/src/nodes/core/Node.js +14 -2
  84. package/src/nodes/core/NodeBuilder.js +25 -20
  85. package/src/nodes/core/NodeUtils.js +4 -1
  86. package/src/nodes/core/StackNode.js +42 -0
  87. package/src/nodes/core/UniformNode.js +63 -5
  88. package/src/nodes/core/VarNode.js +91 -2
  89. package/src/nodes/display/PassNode.js +148 -2
  90. package/src/nodes/display/ViewportTextureNode.js +67 -7
  91. package/src/nodes/functions/PhysicalLightingModel.js +2 -2
  92. package/src/nodes/gpgpu/AtomicFunctionNode.js +1 -1
  93. package/src/nodes/gpgpu/ComputeNode.js +67 -23
  94. package/src/nodes/gpgpu/WorkgroupInfoNode.js +28 -3
  95. package/src/nodes/lighting/ProjectorLightNode.js +19 -6
  96. package/src/nodes/lighting/ShadowFilterNode.js +1 -1
  97. package/src/nodes/materialx/MaterialXNodes.js +131 -2
  98. package/src/nodes/materialx/lib/mx_noise.js +165 -1
  99. package/src/nodes/math/ConditionalNode.js +1 -1
  100. package/src/nodes/math/MathNode.js +78 -54
  101. package/src/nodes/math/OperatorNode.js +22 -22
  102. package/src/nodes/tsl/TSLCore.js +64 -9
  103. package/src/nodes/utils/DebugNode.js +1 -1
  104. package/src/nodes/utils/EventNode.js +83 -0
  105. package/src/nodes/utils/RTTNode.js +9 -0
  106. package/src/objects/BatchedMesh.js +4 -2
  107. package/src/renderers/WebGLRenderer.js +21 -22
  108. package/src/renderers/common/Bindings.js +19 -18
  109. package/src/renderers/common/Color4.js +2 -2
  110. package/src/renderers/common/PostProcessing.js +60 -5
  111. package/src/renderers/common/Renderer.js +18 -15
  112. package/src/renderers/common/SampledTexture.js +3 -71
  113. package/src/renderers/common/Sampler.js +79 -0
  114. package/src/renderers/common/Storage3DTexture.js +21 -0
  115. package/src/renderers/common/StorageArrayTexture.js +21 -0
  116. package/src/renderers/common/StorageTexture.js +19 -0
  117. package/src/renderers/common/Textures.js +19 -3
  118. package/src/renderers/common/XRManager.js +26 -8
  119. package/src/renderers/common/nodes/NodeSampledTexture.js +0 -12
  120. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +20 -2
  121. package/src/renderers/shaders/ShaderLib/depth.glsl.js +11 -2
  122. package/src/renderers/webgl/WebGLCapabilities.js +2 -2
  123. package/src/renderers/webgl/WebGLMaterials.js +6 -6
  124. package/src/renderers/webgl/WebGLProgram.js +22 -16
  125. package/src/renderers/webgl/WebGLPrograms.js +4 -4
  126. package/src/renderers/webgl/WebGLShadowMap.js +11 -1
  127. package/src/renderers/webgl/WebGLTextures.js +19 -7
  128. package/src/renderers/webgl-fallback/WebGLBackend.js +22 -12
  129. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +2 -2
  130. package/src/renderers/webgpu/WebGPUBackend.js +54 -15
  131. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +53 -73
  132. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +35 -31
  133. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +1 -1
  134. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +11 -64
  135. package/src/renderers/webgpu/utils/WebGPUUtils.js +2 -17
  136. package/src/renderers/webxr/WebXRDepthSensing.js +6 -10
  137. package/src/renderers/webxr/WebXRManager.js +68 -8
  138. package/src/textures/ExternalTexture.js +45 -0
  139. package/src/textures/FramebufferTexture.js +2 -2
  140. package/src/textures/Source.js +11 -1
  141. package/src/textures/VideoTexture.js +30 -2
@@ -19,10 +19,9 @@ class ComputeNode extends Node {
19
19
  * Constructs a new compute node.
20
20
  *
21
21
  * @param {Node} computeNode - TODO
22
- * @param {number} count - TODO.
23
- * @param {Array<number>} [workgroupSize=[64]] - TODO.
22
+ * @param {Array<number>} workgroupSize - TODO.
24
23
  */
25
- constructor( computeNode, count, workgroupSize = [ 64 ] ) {
24
+ constructor( computeNode, workgroupSize ) {
26
25
 
27
26
  super( 'void' );
28
27
 
@@ -42,18 +41,12 @@ class ComputeNode extends Node {
42
41
  */
43
42
  this.computeNode = computeNode;
44
43
 
45
- /**
46
- * TODO
47
- *
48
- * @type {number}
49
- */
50
- this.count = count;
51
44
 
52
45
  /**
53
46
  * TODO
54
47
  *
55
48
  * @type {Array<number>}
56
- * @default [64]
49
+ * @default [ 64 ]
57
50
  */
58
51
  this.workgroupSize = workgroupSize;
59
52
 
@@ -62,7 +55,7 @@ class ComputeNode extends Node {
62
55
  *
63
56
  * @type {number}
64
57
  */
65
- this.dispatchCount = 0;
58
+ this.count = null;
66
59
 
67
60
  /**
68
61
  * TODO
@@ -95,7 +88,19 @@ class ComputeNode extends Node {
95
88
  */
96
89
  this.onInitFunction = null;
97
90
 
98
- this.updateDispatchCount();
91
+ }
92
+
93
+ setCount( count ) {
94
+
95
+ this.count = count;
96
+
97
+ return this;
98
+
99
+ }
100
+
101
+ getCount() {
102
+
103
+ return this.count;
99
104
 
100
105
  }
101
106
 
@@ -114,7 +119,7 @@ class ComputeNode extends Node {
114
119
  * @param {string} name - The name of the uniform.
115
120
  * @return {ComputeNode} A reference to this node.
116
121
  */
117
- label( name ) {
122
+ setName( name ) {
118
123
 
119
124
  this.name = name;
120
125
 
@@ -123,18 +128,17 @@ class ComputeNode extends Node {
123
128
  }
124
129
 
125
130
  /**
126
- * TODO
131
+ * Sets the {@link ComputeNode#name} property.
132
+ *
133
+ * @deprecated
134
+ * @param {string} name - The name of the uniform.
135
+ * @return {ComputeNode} A reference to this node.
127
136
  */
128
- updateDispatchCount() {
129
-
130
- const { count, workgroupSize } = this;
131
-
132
- let size = workgroupSize[ 0 ];
137
+ label( name ) {
133
138
 
134
- for ( let i = 1; i < workgroupSize.length; i ++ )
135
- size *= workgroupSize[ i ];
139
+ console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179
136
140
 
137
- this.dispatchCount = Math.ceil( count / size );
141
+ return this.setName( name );
138
142
 
139
143
  }
140
144
 
@@ -213,6 +217,45 @@ class ComputeNode extends Node {
213
217
 
214
218
  export default ComputeNode;
215
219
 
220
+ /**
221
+ * TSL function for creating a compute kernel node.
222
+ *
223
+ * @tsl
224
+ * @function
225
+ * @param {Node} node - TODO
226
+ * @param {Array<number>} [workgroupSize=[64]] - TODO.
227
+ * @returns {AtomicFunctionNode}
228
+ */
229
+ export const computeKernel = ( node, workgroupSize = [ 64 ] ) => {
230
+
231
+ if ( workgroupSize.length === 0 || workgroupSize.length > 3 ) {
232
+
233
+ console.error( 'THREE.TSL: compute() workgroupSize must have 1, 2, or 3 elements' );
234
+
235
+ }
236
+
237
+ for ( let i = 0; i < workgroupSize.length; i ++ ) {
238
+
239
+ const val = workgroupSize[ i ];
240
+
241
+ if ( typeof val !== 'number' || val <= 0 || ! Number.isInteger( val ) ) {
242
+
243
+ console.error( `THREE.TSL: compute() workgroupSize element at index [ ${ i } ] must be a positive integer` );
244
+
245
+ }
246
+
247
+ }
248
+
249
+ // Implicit fill-up to [ x, y, z ] with 1s, just like WGSL treats @workgroup_size when fewer dimensions are specified
250
+
251
+ while ( workgroupSize.length < 3 ) workgroupSize.push( 1 );
252
+
253
+ //
254
+
255
+ return nodeObject( new ComputeNode( nodeObject( node ), workgroupSize ) );
256
+
257
+ };
258
+
216
259
  /**
217
260
  * TSL function for creating a compute node.
218
261
  *
@@ -223,6 +266,7 @@ export default ComputeNode;
223
266
  * @param {Array<number>} [workgroupSize=[64]] - TODO.
224
267
  * @returns {AtomicFunctionNode}
225
268
  */
226
- export const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) );
269
+ export const compute = ( node, count, workgroupSize ) => computeKernel( node, workgroupSize ).setCount( count );
227
270
 
228
271
  addMethodChaining( 'compute', compute );
272
+ addMethodChaining( 'computeKernel', computeKernel );
@@ -116,15 +116,23 @@ class WorkgroupInfoNode extends Node {
116
116
  */
117
117
  this.scope = scope;
118
118
 
119
+ /**
120
+ * The name of the workgroup scoped buffer.
121
+ *
122
+ * @type {string}
123
+ * @default ''
124
+ */
125
+ this.name = '';
126
+
119
127
  }
120
128
 
121
129
  /**
122
- * Sets the name/label of this node.
130
+ * Sets the name of this node.
123
131
  *
124
132
  * @param {string} name - The name to set.
125
133
  * @return {WorkgroupInfoNode} A reference to this node.
126
134
  */
127
- label( name ) {
135
+ setName( name ) {
128
136
 
129
137
  this.name = name;
130
138
 
@@ -132,6 +140,21 @@ class WorkgroupInfoNode extends Node {
132
140
 
133
141
  }
134
142
 
143
+ /**
144
+ * Sets the name/label of this node.
145
+ *
146
+ * @deprecated
147
+ * @param {string} name - The name to set.
148
+ * @return {WorkgroupInfoNode} A reference to this node.
149
+ */
150
+ label( name ) {
151
+
152
+ console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179
153
+
154
+ return this.setName( name );
155
+
156
+ }
157
+
135
158
  /**
136
159
  * Sets the scope of this node.
137
160
  *
@@ -185,7 +208,9 @@ class WorkgroupInfoNode extends Node {
185
208
 
186
209
  generate( builder ) {
187
210
 
188
- return builder.getScopedArray( this.name || `${this.scope}Array_${this.id}`, this.scope.toLowerCase(), this.bufferType, this.bufferCount );
211
+ const name = ( this.name !== '' ) ? this.name : `${this.scope}Array_${this.id}`;
212
+
213
+ return builder.getScopedArray( name, this.scope.toLowerCase(), this.bufferType, this.bufferCount );
189
214
 
190
215
  }
191
216
 
@@ -1,8 +1,10 @@
1
1
  import SpotLightNode from './SpotLightNode.js';
2
2
 
3
- import { Fn, vec2 } from '../tsl/TSLCore.js';
3
+ import { float, Fn, If, vec2 } from '../tsl/TSLCore.js';
4
4
  import { length, min, max, saturate, acos } from '../math/MathNode.js';
5
5
  import { div, sub } from '../math/OperatorNode.js';
6
+ import { lightShadowMatrix } from '../accessors/Lights.js';
7
+ import { positionWorld } from '../accessors/Position.js';
6
8
 
7
9
  const sdBox = /*@__PURE__*/ Fn( ( [ p, b ] ) => {
8
10
 
@@ -61,13 +63,24 @@ class ProjectorLightNode extends SpotLightNode {
61
63
  */
62
64
  getSpotAttenuation( builder ) {
63
65
 
66
+ const attenuation = float( 0 );
64
67
  const penumbraCos = this.penumbraCosNode;
65
- const spotLightCoord = this.getLightCoord( builder );
66
- const coord = spotLightCoord.xyz.div( spotLightCoord.w );
67
68
 
68
- const boxDist = sdBox( coord.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
69
- const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
70
- const attenuation = saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) );
69
+ // compute the fragment's position in the light's clip space
70
+
71
+ const spotLightCoord = lightShadowMatrix( this.light ).mul( builder.context.positionWorld || positionWorld );
72
+
73
+ // the sign of w determines whether the current fragment is in front or behind the light.
74
+ // to avoid a back-projection, it's important to only compute an attenuation if w is positive
75
+
76
+ If( spotLightCoord.w.greaterThan( 0 ), () => {
77
+
78
+ const projectionUV = spotLightCoord.xyz.div( spotLightCoord.w );
79
+ const boxDist = sdBox( projectionUV.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) );
80
+ const angleFactor = div( - 1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) );
81
+ attenuation.assign( saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) ) );
82
+
83
+ } );
71
84
 
72
85
  return attenuation;
73
86
 
@@ -22,7 +22,7 @@ const shadowMaterialLib = /*@__PURE__*/ new WeakMap();
22
22
  */
23
23
  export const BasicShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, depthLayer } ) => {
24
24
 
25
- let basic = texture( depthTexture, shadowCoord.xy ).label( 't_basic' );
25
+ let basic = texture( depthTexture, shadowCoord.xy ).setName( 't_basic' );
26
26
 
27
27
  if ( depthTexture.isArrayTexture ) {
28
28
 
@@ -2,13 +2,17 @@ import {
2
2
  mx_perlin_noise_float, mx_perlin_noise_vec3,
3
3
  mx_worley_noise_float as worley_noise_float, mx_worley_noise_vec2 as worley_noise_vec2, mx_worley_noise_vec3 as worley_noise_vec3,
4
4
  mx_cell_noise_float as cell_noise_float,
5
+ mx_unifiednoise2d as unifiednoise2d, mx_unifiednoise3d as unifiednoise3d,
5
6
  mx_fractal_noise_float as fractal_noise_float, mx_fractal_noise_vec2 as fractal_noise_vec2, mx_fractal_noise_vec3 as fractal_noise_vec3, mx_fractal_noise_vec4 as fractal_noise_vec4
6
7
  } from './lib/mx_noise.js';
7
8
  import { mx_hsvtorgb, mx_rgbtohsv } from './lib/mx_hsv.js';
8
9
  import { mx_srgb_texture_to_lin_rec709 } from './lib/mx_transform_color.js';
9
- import { mix, smoothstep } from '../math/MathNode.js';
10
+
11
+ import { float, vec2, vec3, vec4, int, add, sub, mul, div, mod, atan, mix, pow, smoothstep } from '../tsl/TSLBase.js';
10
12
  import { uv } from '../accessors/UV.js';
11
- import { float, vec2, vec4, int } from '../tsl/TSLBase.js';
13
+ import { bumpMap } from '../display/BumpMapNode.js';
14
+ import { rotate } from '../utils/RotateNode.js';
15
+ import { frameId, time } from '../utils/Timer.js';
12
16
 
13
17
  export const mx_aastep = ( threshold, value ) => {
14
18
 
@@ -25,6 +29,19 @@ const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() );
25
29
  export const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' );
26
30
  export const mx_ramptb = ( valuet, valueb, texcoord = uv() ) => _ramp( valuet, valueb, texcoord, 'y' );
27
31
 
32
+ // Bilinear ramp: interpolate between four corners (tl, tr, bl, br) using texcoord.x and texcoord.y
33
+ export const mx_ramp4 = (
34
+ valuetl, valuetr, valuebl, valuebr, texcoord = uv()
35
+ ) => {
36
+
37
+ const u = texcoord.x.clamp();
38
+ const v = texcoord.y.clamp();
39
+ const top = mix( valuetl, valuetr, u );
40
+ const bottom = mix( valuebl, valuebr, u );
41
+ return mix( top, bottom, v );
42
+
43
+ };
44
+
28
45
  const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) );
29
46
  export const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' );
30
47
  export const mx_splittb = ( valuet, valueb, center, texcoord = uv() ) => _split( valuet, valueb, center, texcoord, 'y' );
@@ -54,6 +71,9 @@ export const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => {
54
71
 
55
72
  };
56
73
 
74
+ export const mx_unifiednoise2d = ( noiseType, texcoord = uv(), freq = vec2( 1, 1 ), offset = vec2( 0, 0 ), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = .5 ) => unifiednoise2d( noiseType, texcoord.convert( 'vec2|vec3' ), freq, offset, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish );
75
+ export const mx_unifiednoise3d = ( noiseType, texcoord = uv(), freq = vec2( 1, 1 ), offset = vec2( 0, 0 ), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = .5 ) => unifiednoise3d( noiseType, texcoord.convert( 'vec2|vec3' ), freq, offset, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish );
76
+
57
77
  export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => worley_noise_float( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );
58
78
  export const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec2( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );
59
79
  export const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec3( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );
@@ -66,3 +86,112 @@ export const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity
66
86
  export const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec4( position, int( octaves ), lacunarity, diminish ).mul( amplitude );
67
87
 
68
88
  export { mx_hsvtorgb, mx_rgbtohsv, mx_srgb_texture_to_lin_rec709 };
89
+
90
+ // === Moved from MaterialXLoader.js ===
91
+
92
+ // Math ops
93
+ export const mx_add = ( in1, in2 = float( 0 ) ) => add( in1, in2 );
94
+ export const mx_subtract = ( in1, in2 = float( 0 ) ) => sub( in1, in2 );
95
+ export const mx_multiply = ( in1, in2 = float( 1 ) ) => mul( in1, in2 );
96
+ export const mx_divide = ( in1, in2 = float( 1 ) ) => div( in1, in2 );
97
+ export const mx_modulo = ( in1, in2 = float( 1 ) ) => mod( in1, in2 );
98
+ export const mx_power = ( in1, in2 = float( 1 ) ) => pow( in1, in2 );
99
+ export const mx_atan2 = ( in1 = float( 0 ), in2 = float( 1 ) ) => atan( in1, in2 );
100
+ export const mx_timer = () => time;
101
+ export const mx_frame = () => frameId;
102
+ export const mx_invert = ( in1, amount = float( 1 ) ) => sub( amount, in1 );
103
+ export const mx_ifgreater = ( value1, value2, in1, in2 ) => value1.greaterThan( value2 ).mix( in1, in2 );
104
+ export const mx_ifgreatereq = ( value1, value2, in1, in2 ) => value1.greaterThanEqual( value2 ).mix( in1, in2 );
105
+ export const mx_ifequal = ( value1, value2, in1, in2 ) => value1.equal( value2 ).mix( in1, in2 );
106
+
107
+ // Enhanced separate node to support multi-output referencing (outx, outy, outz, outw)
108
+ export const mx_separate = ( in1, channelOrOut = null ) => {
109
+
110
+ if ( typeof channelOrOut === 'string' ) {
111
+
112
+ const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 };
113
+ const c = channelOrOut.replace( /^out/, '' ).toLowerCase();
114
+ if ( map[ c ] !== undefined ) return in1.element( map[ c ] );
115
+
116
+ }
117
+
118
+ if ( typeof channelOrOut === 'number' ) {
119
+
120
+ return in1.element( channelOrOut );
121
+
122
+ }
123
+
124
+ if ( typeof channelOrOut === 'string' && channelOrOut.length === 1 ) {
125
+
126
+ const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 };
127
+ if ( map[ channelOrOut ] !== undefined ) return in1.element( map[ channelOrOut ] );
128
+
129
+ }
130
+
131
+ return in1;
132
+
133
+ };
134
+
135
+ export const mx_place2d = (
136
+ texcoord, pivot = vec2( 0.5, 0.5 ), scale = vec2( 1, 1 ), rotate = float( 0 ), offset = vec2( 0, 0 )/*, operationorder = int( 0 )*/
137
+ ) => {
138
+
139
+ let uv = texcoord;
140
+ if ( pivot ) uv = uv.sub( pivot );
141
+ if ( scale ) uv = uv.mul( scale );
142
+ if ( rotate ) {
143
+
144
+ const rad = rotate.mul( Math.PI / 180.0 );
145
+ const cosR = rad.cos();
146
+ const sinR = rad.sin();
147
+ uv = vec2(
148
+ uv.x.mul( cosR ).sub( uv.y.mul( sinR ) ),
149
+ uv.x.mul( sinR ).add( uv.y.mul( cosR ) )
150
+ );
151
+
152
+ }
153
+
154
+ if ( pivot ) uv = uv.add( pivot );
155
+ if ( offset ) uv = uv.add( offset );
156
+ return uv;
157
+
158
+ };
159
+
160
+ export const mx_rotate2d = ( input, amount ) => {
161
+
162
+ input = vec2( input );
163
+ amount = float( amount );
164
+
165
+ const radians = amount.mul( Math.PI / 180.0 );
166
+ return rotate( input, radians );
167
+
168
+ };
169
+
170
+ export const mx_rotate3d = ( input, amount, axis ) => {
171
+
172
+ input = vec3( input );
173
+ amount = float( amount );
174
+ axis = vec3( axis );
175
+
176
+
177
+ const radians = amount.mul( Math.PI / 180.0 );
178
+ const nAxis = axis.normalize();
179
+ const cosA = radians.cos();
180
+ const sinA = radians.sin();
181
+ const oneMinusCosA = float( 1 ).sub( cosA );
182
+ const rot =
183
+ input.mul( cosA )
184
+ .add( nAxis.cross( input ).mul( sinA ) )
185
+ .add( nAxis.mul( nAxis.dot( input ) ).mul( oneMinusCosA ) );
186
+ return rot;
187
+
188
+ };
189
+
190
+ export const mx_heighttonormal = ( input, scale/*, texcoord*/ ) => {
191
+
192
+ input = vec3( input );
193
+ scale = float( scale );
194
+
195
+ return bumpMap( input, scale );
196
+
197
+ };
@@ -4,7 +4,7 @@
4
4
  import { int, uint, float, vec3, bool, uvec3, vec2, vec4, If, Fn } from '../../tsl/TSLBase.js';
5
5
  import { select } from '../../math/ConditionalNode.js';
6
6
  import { sub, mul } from '../../math/OperatorNode.js';
7
- import { floor, abs, max, dot, min, sqrt } from '../../math/MathNode.js';
7
+ import { floor, abs, max, dot, min, sqrt, clamp } from '../../math/MathNode.js';
8
8
  import { overloadingFn } from '../../utils/FunctionOverloadingNode.js';
9
9
  import { Loop } from '../../utils/LoopNode.js';
10
10
 
@@ -1325,3 +1325,167 @@ export const mx_worley_noise_vec3_1 = /*@__PURE__*/ Fn( ( [ p_immutable, jitter_
1325
1325
  } );
1326
1326
 
1327
1327
  export const mx_worley_noise_vec3 = /*@__PURE__*/ overloadingFn( [ mx_worley_noise_vec3_0, mx_worley_noise_vec3_1 ] );
1328
+
1329
+ // Unified Noise 2D
1330
+ export const mx_unifiednoise2d = /*@__PURE__*/ Fn( ( [
1331
+ noiseType_immutable, texcoord_immutable, freq_immutable, offset_immutable,
1332
+ jitter_immutable, outmin_immutable, outmax_immutable, clampoutput_immutable,
1333
+ octaves_immutable, lacunarity_immutable, diminish_immutable
1334
+ ] ) => {
1335
+
1336
+ const noiseType = int( noiseType_immutable ).toVar();
1337
+ const texcoord = vec2( texcoord_immutable ).toVar();
1338
+ const freq = vec2( freq_immutable ).toVar();
1339
+ const offset = vec2( offset_immutable ).toVar();
1340
+ const jitter = float( jitter_immutable ).toVar();
1341
+ const outmin = float( outmin_immutable ).toVar();
1342
+ const outmax = float( outmax_immutable ).toVar();
1343
+ const clampoutput = bool( clampoutput_immutable ).toVar();
1344
+ const octaves = int( octaves_immutable ).toVar();
1345
+ const lacunarity = float( lacunarity_immutable ).toVar();
1346
+ const diminish = float( diminish_immutable ).toVar();
1347
+
1348
+ // Compute input position
1349
+ const p = texcoord.mul( freq ).add( offset );
1350
+
1351
+ const result = float( 0.0 ).toVar();
1352
+
1353
+ // Perlin
1354
+ If( noiseType.equal( int( 0 ) ), () => {
1355
+
1356
+ result.assign( mx_perlin_noise_vec3( p ) );
1357
+
1358
+ } );
1359
+
1360
+ // Cell
1361
+ If( noiseType.equal( int( 1 ) ), () => {
1362
+
1363
+ result.assign( mx_cell_noise_vec3( p ) );
1364
+
1365
+ } );
1366
+
1367
+ // Worley (metric=0 = euclidean)
1368
+ If( noiseType.equal( int( 2 ) ), () => {
1369
+
1370
+ result.assign( mx_worley_noise_vec3( p, jitter, int( 0 ) ) );
1371
+
1372
+ } );
1373
+
1374
+ // Fractal (use vec3(p, 0.0) for 2D input)
1375
+ If( noiseType.equal( int( 3 ) ), () => {
1376
+
1377
+ result.assign( mx_fractal_noise_vec3( vec3( p, 0.0 ), octaves, lacunarity, diminish ) );
1378
+
1379
+ } );
1380
+
1381
+ // Remap output to [outmin, outmax]
1382
+ result.assign( result.mul( outmax.sub( outmin ) ).add( outmin ) );
1383
+
1384
+ // Clamp if requested
1385
+ If( clampoutput, () => {
1386
+
1387
+ result.assign( clamp( result, outmin, outmax ) );
1388
+
1389
+ } );
1390
+
1391
+ return result;
1392
+
1393
+ } ).setLayout( {
1394
+ name: 'mx_unifiednoise2d',
1395
+ type: 'float',
1396
+ inputs: [
1397
+ { name: 'noiseType', type: 'int' },
1398
+ { name: 'texcoord', type: 'vec2' },
1399
+ { name: 'freq', type: 'vec2' },
1400
+ { name: 'offset', type: 'vec2' },
1401
+ { name: 'jitter', type: 'float' },
1402
+ { name: 'outmin', type: 'float' },
1403
+ { name: 'outmax', type: 'float' },
1404
+ { name: 'clampoutput', type: 'bool' },
1405
+ { name: 'octaves', type: 'int' },
1406
+ { name: 'lacunarity', type: 'float' },
1407
+ { name: 'diminish', type: 'float' }
1408
+ ]
1409
+ } );
1410
+
1411
+ // Unified Noise 3D
1412
+ export const mx_unifiednoise3d = /*@__PURE__*/ Fn( ( [
1413
+ noiseType_immutable, position_immutable, freq_immutable, offset_immutable,
1414
+ jitter_immutable, outmin_immutable, outmax_immutable, clampoutput_immutable,
1415
+ octaves_immutable, lacunarity_immutable, diminish_immutable
1416
+ ] ) => {
1417
+
1418
+ const noiseType = int( noiseType_immutable ).toVar();
1419
+ const position = vec3( position_immutable ).toVar();
1420
+ const freq = vec3( freq_immutable ).toVar();
1421
+ const offset = vec3( offset_immutable ).toVar();
1422
+ const jitter = float( jitter_immutable ).toVar();
1423
+ const outmin = float( outmin_immutable ).toVar();
1424
+ const outmax = float( outmax_immutable ).toVar();
1425
+ const clampoutput = bool( clampoutput_immutable ).toVar();
1426
+ const octaves = int( octaves_immutable ).toVar();
1427
+ const lacunarity = float( lacunarity_immutable ).toVar();
1428
+ const diminish = float( diminish_immutable ).toVar();
1429
+
1430
+ // Compute input position
1431
+ const p = position.mul( freq ).add( offset );
1432
+
1433
+ const result = float( 0.0 ).toVar();
1434
+
1435
+ // Perlin
1436
+ If( noiseType.equal( int( 0 ) ), () => {
1437
+
1438
+ result.assign( mx_perlin_noise_vec3( p ) );
1439
+
1440
+ } );
1441
+
1442
+ // Cell
1443
+ If( noiseType.equal( int( 1 ) ), () => {
1444
+
1445
+ result.assign( mx_cell_noise_vec3( p ) );
1446
+
1447
+ } );
1448
+
1449
+ // Worley (metric=0 = euclidean)
1450
+ If( noiseType.equal( int( 2 ) ), () => {
1451
+
1452
+ result.assign( mx_worley_noise_vec3( p, jitter, int( 0 ) ) );
1453
+
1454
+ } );
1455
+
1456
+ // Fractal
1457
+ If( noiseType.equal( int( 3 ) ), () => {
1458
+
1459
+ result.assign( mx_fractal_noise_vec3( p, octaves, lacunarity, diminish ) );
1460
+
1461
+ } );
1462
+
1463
+ // Remap output to [outmin, outmax]
1464
+ result.assign( result.mul( outmax.sub( outmin ) ).add( outmin ) );
1465
+
1466
+ // Clamp if requested
1467
+ If( clampoutput, () => {
1468
+
1469
+ result.assign( clamp( result, outmin, outmax ) );
1470
+
1471
+ } );
1472
+
1473
+ return result;
1474
+
1475
+ } ).setLayout( {
1476
+ name: 'mx_unifiednoise3d',
1477
+ type: 'float',
1478
+ inputs: [
1479
+ { name: 'noiseType', type: 'int' },
1480
+ { name: 'position', type: 'vec3' },
1481
+ { name: 'freq', type: 'vec3' },
1482
+ { name: 'offset', type: 'vec3' },
1483
+ { name: 'jitter', type: 'float' },
1484
+ { name: 'outmin', type: 'float' },
1485
+ { name: 'outmax', type: 'float' },
1486
+ { name: 'clampoutput', type: 'bool' },
1487
+ { name: 'octaves', type: 'int' },
1488
+ { name: 'lacunarity', type: 'float' },
1489
+ { name: 'diminish', type: 'float' }
1490
+ ]
1491
+ } );
@@ -73,7 +73,7 @@ class ConditionalNode extends Node {
73
73
 
74
74
  // fallback setup
75
75
 
76
- this.setup( builder );
76
+ builder.flowBuildStage( this, 'setup' );
77
77
 
78
78
  return this.getNodeType( builder );
79
79