@gnsx/three 0.185.16 → 0.186.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 (418) hide show
  1. package/build/three.cjs +10 -82600
  2. package/build/three.core.js +1309 -807
  3. package/build/three.module.js +439 -338
  4. package/build/three.tsl.js +74 -44
  5. package/build/three.webgpu.js +6036 -2184
  6. package/build/three.webgpu.nodes.js +6020 -2184
  7. package/examples/jsm/Addons.js +6 -6
  8. package/examples/jsm/controls/ArcballControls.js +1 -1
  9. package/examples/jsm/controls/FirstPersonControls.js +44 -20
  10. package/examples/jsm/controls/OrbitControls.js +9 -0
  11. package/examples/jsm/controls/TrackballControls.js +109 -4
  12. package/examples/jsm/csm/CSMShadowNode.js +13 -0
  13. package/examples/jsm/exporters/GLTFExporter.js +23 -7
  14. package/examples/jsm/exporters/USDZExporter.js +2 -2
  15. package/examples/jsm/generators/CityGenerator.js +377 -45
  16. package/examples/jsm/generators/ForestGenerator.js +12 -12
  17. package/examples/jsm/generators/TerrainGenerator.js +49 -37
  18. package/examples/jsm/generators/TreeGenerator.js +70 -76
  19. package/examples/jsm/generators/city/BenchGenerator.js +127 -0
  20. package/examples/jsm/generators/city/CarGenerator.js +479 -0
  21. package/examples/jsm/generators/city/CityGeneratorUtils.js +31 -0
  22. package/examples/jsm/generators/city/HydrantGenerator.js +106 -0
  23. package/examples/jsm/generators/city/InstancedMeshGenerator.js +86 -0
  24. package/examples/jsm/generators/city/PersonGenerator.js +447 -0
  25. package/examples/jsm/generators/city/SidewalkGenerator.js +33 -38
  26. package/examples/jsm/generators/city/SkyscraperGenerator.js +448 -48
  27. package/examples/jsm/generators/city/StreetTreeGenerator.js +231 -0
  28. package/examples/jsm/generators/city/StreetlightGenerator.js +100 -0
  29. package/examples/jsm/generators/city/TrafficlightGenerator.js +106 -0
  30. package/examples/jsm/generators/city/TrashcanGenerator.js +100 -0
  31. package/examples/jsm/geometries/BoxLineGeometry.js +1 -1
  32. package/examples/jsm/geometries/ParametricGeometry.js +1 -1
  33. package/examples/jsm/geometries/RoundedBoxGeometry.js +1 -1
  34. package/examples/jsm/gpgpu/CountingSort.js +271 -0
  35. package/examples/jsm/helpers/LightProbeGridHelper.js +60 -239
  36. package/examples/jsm/helpers/LightProbeGridHelperWebGL.js +221 -0
  37. package/examples/jsm/inspector/Extension.js +94 -0
  38. package/examples/jsm/inspector/Inspector.js +145 -41
  39. package/examples/jsm/inspector/RendererInspector.js +100 -52
  40. package/examples/jsm/inspector/extensions/color-grading/ColorGrading.js +2609 -0
  41. package/examples/jsm/inspector/extensions/color-grading/ColorWheel.js +352 -0
  42. package/examples/jsm/inspector/extensions/color-grading/CurveEditor.js +599 -0
  43. package/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js +1201 -0
  44. package/examples/jsm/inspector/extensions/color-grading/LUTMath.js +788 -0
  45. package/examples/jsm/inspector/extensions/color-grading/modules/BrightnessModule.js +72 -0
  46. package/examples/jsm/inspector/extensions/color-grading/modules/ColorWheelModule.js +112 -0
  47. package/examples/jsm/inspector/extensions/color-grading/modules/ContrastModule.js +82 -0
  48. package/examples/jsm/inspector/extensions/color-grading/modules/CurvesModule.js +109 -0
  49. package/examples/jsm/inspector/extensions/color-grading/modules/ExposureHueModule.js +110 -0
  50. package/examples/jsm/inspector/extensions/color-grading/modules/ExposureModule.js +73 -0
  51. package/examples/jsm/inspector/extensions/color-grading/modules/HueModule.js +78 -0
  52. package/examples/jsm/inspector/extensions/color-grading/modules/ImportedCubeModule.js +89 -0
  53. package/examples/jsm/inspector/extensions/color-grading/modules/Module.js +285 -0
  54. package/examples/jsm/inspector/extensions/color-grading/modules/OutputModule.js +101 -0
  55. package/examples/jsm/inspector/extensions/color-grading/modules/RendererModule.js +225 -0
  56. package/examples/jsm/inspector/extensions/color-grading/modules/SatVibranceModule.js +102 -0
  57. package/examples/jsm/inspector/extensions/color-grading/modules/SaturationModule.js +76 -0
  58. package/examples/jsm/inspector/extensions/color-grading/modules/VibranceModule.js +76 -0
  59. package/examples/jsm/inspector/extensions/color-grading/modules/WhiteBalanceModule.js +86 -0
  60. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js +26 -31
  61. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphLoader.js +1 -0
  62. package/examples/jsm/inspector/tabs/Memory.js +0 -2
  63. package/examples/jsm/inspector/tabs/Settings.js +4 -0
  64. package/examples/jsm/inspector/tabs/Timeline.js +223 -171
  65. package/examples/jsm/inspector/tabs/Viewer.js +515 -21
  66. package/examples/jsm/inspector/ui/List.js +15 -9
  67. package/examples/jsm/inspector/ui/Profiler.js +170 -14
  68. package/examples/jsm/inspector/ui/Style.js +269 -23
  69. package/examples/jsm/inspector/ui/Tab.js +2 -0
  70. package/examples/jsm/inspector/ui/Values.js +14 -2
  71. package/examples/jsm/interactive/HTMLMesh.js +19 -3
  72. package/examples/jsm/lighting/LightProbeGrid.js +484 -889
  73. package/examples/jsm/lighting/LightProbeGridUtils.js +107 -0
  74. package/examples/jsm/lighting/LightProbeGridWebGL.js +841 -0
  75. package/examples/jsm/lighting/vxgi/VXGIConeTracer.js +194 -0
  76. package/examples/jsm/lighting/vxgi/VXGINode.js +660 -0
  77. package/examples/jsm/lighting/vxgi/VXGISceneCollector.js +478 -0
  78. package/examples/jsm/lighting/vxgi/VXGIVolume.js +1430 -0
  79. package/examples/jsm/lights/SunLight.js +95 -0
  80. package/examples/jsm/lights/SunLightNode.js +56 -0
  81. package/examples/jsm/lights/SunLightShadow.js +319 -0
  82. package/examples/jsm/lights/SunShadowNode.js +312 -0
  83. package/examples/jsm/loaders/3DMLoader.js +150 -49
  84. package/examples/jsm/loaders/3MFLoader.js +202 -1
  85. package/examples/jsm/loaders/FBXLoader.js +81 -5
  86. package/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js +330 -0
  87. package/examples/jsm/loaders/GLTFLoader.js +79 -14
  88. package/examples/jsm/loaders/GaussianSplatPLYLoader.js +386 -0
  89. package/examples/jsm/loaders/KSPLATLoader.js +463 -0
  90. package/examples/jsm/loaders/MaterialXLoader.js +111 -1010
  91. package/examples/jsm/loaders/PCDLoader.js +1 -1
  92. package/examples/jsm/loaders/SPLATLoader.js +139 -0
  93. package/examples/jsm/loaders/SPZLoader.js +561 -0
  94. package/examples/jsm/loaders/materialx/MaterialXArchive.js +108 -0
  95. package/examples/jsm/loaders/materialx/MaterialXDocument.js +878 -0
  96. package/examples/jsm/loaders/materialx/MaterialXHextile.js +183 -0
  97. package/examples/jsm/loaders/materialx/MaterialXInterfaceValidation.js +376 -0
  98. package/examples/jsm/loaders/materialx/MaterialXLog.js +75 -0
  99. package/examples/jsm/loaders/materialx/MaterialXNodeInterfaceRegistry.js +4 -0
  100. package/examples/jsm/loaders/materialx/MaterialXNodeLibrary.js +1021 -0
  101. package/examples/jsm/loaders/materialx/MaterialXSurfaceMappings.js +661 -0
  102. package/examples/jsm/loaders/materialx/MaterialXUtils.js +57 -0
  103. package/examples/jsm/loaders/materialx/compile/MaterialXCompileRegistry.js +997 -0
  104. package/examples/jsm/loaders/materialx/parse/MaterialXParser.js +28 -0
  105. package/examples/jsm/loaders/usd/USDAParser.js +15 -2
  106. package/examples/jsm/loaders/usd/USDCParser.js +1 -4
  107. package/examples/jsm/loaders/usd/USDComposer.js +80 -42
  108. package/examples/jsm/materials/WoodNodeMaterial.js +6 -108
  109. package/examples/jsm/misc/RollerCoaster.js +2 -2
  110. package/examples/jsm/misc/SculptGL.LICENSE.txt +21 -0
  111. package/examples/jsm/misc/Sculptor.js +1679 -0
  112. package/examples/jsm/misc/SculptorMesh.js +1504 -0
  113. package/examples/jsm/misc/SculptorTools.js +1180 -0
  114. package/examples/jsm/misc/SculptorUtils.js +345 -0
  115. package/examples/jsm/misc/TubePainter.js +28 -16
  116. package/examples/jsm/misc/VolumeSlice.js +24 -24
  117. package/examples/jsm/modifiers/SimplifyModifier.js +63 -556
  118. package/examples/jsm/objects/GaussianSplat.js +1039 -0
  119. package/examples/jsm/objects/Sky.js +66 -45
  120. package/examples/jsm/objects/SkyMesh.js +70 -51
  121. package/examples/jsm/physics/JoltPhysics.js +1 -1
  122. package/examples/jsm/postprocessing/AfterimagePass.js +4 -2
  123. package/examples/jsm/postprocessing/BloomPass.js +2 -2
  124. package/examples/jsm/postprocessing/GTAOPass.js +1 -1
  125. package/examples/jsm/postprocessing/OutlinePass.js +5 -5
  126. package/examples/jsm/postprocessing/SAOPass.js +1 -1
  127. package/examples/jsm/postprocessing/SSAOPass.js +1 -1
  128. package/examples/jsm/postprocessing/SSRPass.js +4 -2
  129. package/examples/jsm/postprocessing/SavePass.js +1 -1
  130. package/examples/jsm/postprocessing/TAARenderPass.js +1 -1
  131. package/examples/jsm/postprocessing/UnrealBloomPass.js +30 -13
  132. package/examples/jsm/renderers/CSS2DRenderer.js +29 -5
  133. package/examples/jsm/shaders/DepthLimitedBlurShader.js +4 -1
  134. package/examples/jsm/shaders/ExposureShader.js +1 -1
  135. package/examples/jsm/shaders/FilmShader.js +2 -1
  136. package/examples/jsm/transpiler/AST.js +21 -2
  137. package/examples/jsm/transpiler/GLSLDecoder.js +498 -8
  138. package/examples/jsm/transpiler/TSLEncoder.js +82 -10
  139. package/examples/jsm/transpiler/WGSLEncoder.js +33 -4
  140. package/examples/jsm/tsl/WebGLNodesHandler.js +29 -39
  141. package/examples/jsm/tsl/display/AfterImageNode.js +2 -0
  142. package/examples/jsm/tsl/display/AnaglyphPassNode.js +3 -2
  143. package/examples/jsm/tsl/display/BilateralBlurNode.js +5 -2
  144. package/examples/jsm/tsl/display/BloomNode.js +55 -30
  145. package/examples/jsm/tsl/display/DenoiseNode.js +21 -1
  146. package/examples/jsm/tsl/display/DepthOfFieldNode.js +24 -6
  147. package/examples/jsm/tsl/display/DotScreenNode.js +11 -11
  148. package/examples/jsm/tsl/display/FSR1Node.js +8 -4
  149. package/examples/jsm/tsl/display/GTAONode.js +199 -86
  150. package/examples/jsm/tsl/display/GaussianBlurNode.js +65 -52
  151. package/examples/jsm/tsl/display/GodraysNode.js +5 -2
  152. package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +2 -2
  153. package/examples/jsm/tsl/display/LensflareNode.js +5 -2
  154. package/examples/jsm/tsl/display/OITPassNode.js +352 -0
  155. package/examples/jsm/tsl/display/OutlineNode.js +2 -0
  156. package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +3 -2
  157. package/examples/jsm/tsl/display/RGBShiftNode.js +9 -9
  158. package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +7 -4
  159. package/examples/jsm/tsl/display/RetroPassNode.js +1 -1
  160. package/examples/jsm/tsl/display/SMAANode.js +22 -61
  161. package/examples/jsm/tsl/display/SSAAPassNode.js +2 -4
  162. package/examples/jsm/tsl/display/SSAONode.js +436 -0
  163. package/examples/jsm/tsl/display/SSGINode.js +5 -2
  164. package/examples/jsm/tsl/display/SSRNode.js +7 -2
  165. package/examples/jsm/tsl/display/SSSNode.js +5 -2
  166. package/examples/jsm/tsl/display/SharpenNode.js +5 -4
  167. package/examples/jsm/tsl/display/StereoCompositePassNode.js +1 -3
  168. package/examples/jsm/tsl/display/StereoPassNode.js +1 -3
  169. package/examples/jsm/tsl/display/TAAUNode.js +22 -125
  170. package/examples/jsm/tsl/display/TRAANode.js +16 -142
  171. package/examples/jsm/tsl/display/TemporalReprojectNode.js +21 -15
  172. package/examples/jsm/tsl/display/depthAwareBlur.js +63 -0
  173. package/examples/jsm/tsl/display/hashBlur.js +3 -2
  174. package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +38 -27
  175. package/examples/jsm/tsl/lighting/LightProbeGridNode.js +136 -0
  176. package/examples/jsm/tsl/math/voronoiNoise.js +112 -0
  177. package/examples/jsm/tsl/shadows/TileShadowNode.js +4 -6
  178. package/examples/jsm/tsl/utils/Raymarching.js +5 -5
  179. package/examples/jsm/tsl/utils/SoftParticles.js +60 -0
  180. package/examples/jsm/tsl/utils/TAAUtils.js +195 -0
  181. package/examples/jsm/utils/BufferGeometryUtils.js +14 -14
  182. package/examples/jsm/utils/GaussianSplatUtils.js +229 -0
  183. package/examples/jsm/utils/WebGLTextureUtils.js +1 -1
  184. package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
  185. package/examples/jsm/webxr/WebGLXRFallback.js +2 -16
  186. package/examples/jsm/webxr/XRControllerModelFactory.js +16 -4
  187. package/package.json +9 -16
  188. package/src/Three.Core.js +2 -1
  189. package/src/Three.TSL.js +73 -43
  190. package/src/Three.WebGPU.Nodes.js +1 -0
  191. package/src/Three.WebGPU.js +1 -0
  192. package/src/animation/AnimationClip.js +15 -2
  193. package/src/animation/AnimationObjectGroup.js +18 -6
  194. package/src/animation/AnimationUtils.js +26 -0
  195. package/src/animation/KeyframeTrack.js +37 -0
  196. package/src/constants.js +23 -1
  197. package/src/core/BufferAttribute.js +3 -2
  198. package/src/core/BufferGeometry.js +1 -1
  199. package/src/core/InterleavedBuffer.js +5 -1
  200. package/src/core/Object3D.js +40 -12
  201. package/src/core/Raycaster.js +4 -0
  202. package/src/core/RenderTarget.js +99 -9
  203. package/src/core/RenderTarget3D.js +12 -8
  204. package/src/extras/Controls.js +0 -8
  205. package/src/extras/PMREMGenerator.js +99 -205
  206. package/src/geometries/TorusGeometry.js +1 -1
  207. package/src/helpers/ArrowHelper.js +2 -0
  208. package/src/helpers/AxesHelper.js +2 -0
  209. package/src/helpers/Box3Helper.js +2 -0
  210. package/src/helpers/BoxHelper.js +2 -0
  211. package/src/helpers/CameraHelper.js +2 -0
  212. package/src/helpers/DirectionalLightHelper.js +2 -0
  213. package/src/helpers/GridHelper.js +2 -0
  214. package/src/helpers/HemisphereLightHelper.js +2 -0
  215. package/src/helpers/PlaneHelper.js +2 -0
  216. package/src/helpers/PointLightHelper.js +2 -0
  217. package/src/helpers/PolarGridHelper.js +2 -0
  218. package/src/helpers/SkeletonHelper.js +2 -0
  219. package/src/helpers/SpotLightHelper.js +2 -0
  220. package/src/lights/Light.js +0 -10
  221. package/src/lights/LightShadow.js +43 -12
  222. package/src/lights/SpotLightShadow.js +18 -0
  223. package/src/loaders/BufferGeometryLoader.js +5 -0
  224. package/src/loaders/ImageBitmapLoader.js +3 -1
  225. package/src/loaders/ObjectLoader.js +8 -5
  226. package/src/materials/Material.js +80 -57
  227. package/src/materials/MeshPhysicalMaterial.js +32 -0
  228. package/src/materials/nodes/Line2NodeMaterial.js +17 -8
  229. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +42 -5
  230. package/src/materials/nodes/NodeMaterial.js +19 -13
  231. package/src/materials/nodes/PointsNodeMaterial.js +2 -1
  232. package/src/materials/nodes/manager/NodeMaterialObserver.js +282 -55
  233. package/src/math/Frustum.js +9 -0
  234. package/src/math/FrustumArray.js +1 -1
  235. package/src/math/MathUtils.js +5 -3
  236. package/src/math/Matrix4.js +2 -9
  237. package/src/math/Plane.js +30 -1
  238. package/src/math/Quaternion.js +0 -10
  239. package/src/math/Ray.js +95 -45
  240. package/src/math/Triangle.js +0 -2
  241. package/src/math/Vector3.js +2 -2
  242. package/src/math/Vector4.js +0 -4
  243. package/src/math/interpolants/BezierInterpolant.js +36 -23
  244. package/src/nodes/Nodes.js +2 -0
  245. package/src/nodes/TSL.js +11 -3
  246. package/src/nodes/accessors/Batch.js +85 -13
  247. package/src/nodes/accessors/BufferAttributeNode.js +1 -1
  248. package/src/nodes/accessors/BuiltinNode.js +1 -1
  249. package/src/nodes/accessors/Instance.js +19 -18
  250. package/src/nodes/accessors/MaterialNode.js +9 -0
  251. package/src/nodes/accessors/ModelNode.js +85 -9
  252. package/src/nodes/accessors/ReferenceBaseNode.js +1 -70
  253. package/src/nodes/accessors/ReferenceElementNode.js +72 -0
  254. package/src/nodes/accessors/ReferenceNode.js +1 -70
  255. package/src/nodes/accessors/Skinning.js +124 -12
  256. package/src/nodes/accessors/StorageTextureNode.js +7 -3
  257. package/src/nodes/accessors/Texture3DNode.js +1 -1
  258. package/src/nodes/accessors/TextureNode.js +51 -21
  259. package/src/nodes/accessors/TextureSizeNode.js +4 -2
  260. package/src/nodes/accessors/UniformArrayNode.js +30 -5
  261. package/src/nodes/code/CodeNode.js +1 -1
  262. package/src/nodes/code/FunctionNode.js +12 -2
  263. package/src/nodes/core/ArrayNode.js +2 -2
  264. package/src/nodes/core/ContextNode.js +57 -4
  265. package/src/nodes/core/IndexNode.js +69 -4
  266. package/src/nodes/core/InspectorNode.js +2 -2
  267. package/src/nodes/core/MRTNode.js +44 -2
  268. package/src/nodes/core/Node.js +6 -3
  269. package/src/nodes/core/NodeBuilder.js +65 -50
  270. package/src/nodes/core/NodeFrame.js +11 -3
  271. package/src/nodes/core/NodeUtils.js +88 -0
  272. package/src/nodes/core/PropertyNode.js +8 -0
  273. package/src/nodes/core/StackNode.js +0 -1
  274. package/src/nodes/core/StructNode.js +4 -3
  275. package/src/nodes/core/UniformGroupNode.js +3 -2
  276. package/src/nodes/core/UniformNode.js +26 -12
  277. package/src/nodes/core/VarNode.js +0 -1
  278. package/src/nodes/display/BumpMapNode.js +2 -2
  279. package/src/nodes/display/ColorAdjustment.js +1 -1
  280. package/src/nodes/display/PassNode.js +76 -15
  281. package/src/nodes/display/ScreenNode.js +22 -65
  282. package/src/nodes/fog/Fog.js +4 -4
  283. package/src/nodes/functions/BSDF/BRDF_GGX.js +6 -6
  284. package/src/nodes/functions/BSDF/BRDF_Sheen.js +1 -1
  285. package/src/nodes/functions/BSDF/DFGLUT.js +2 -1
  286. package/src/nodes/functions/BSDF/LTC.js +1 -1
  287. package/src/nodes/functions/PhongLightingModel.js +1 -1
  288. package/src/nodes/functions/PhysicalLightingModel.js +83 -25
  289. package/src/nodes/functions/ToonLightingModel.js +2 -2
  290. package/src/nodes/functions/material/getParallaxCorrectNormal.js +3 -3
  291. package/src/nodes/gpgpu/AtomicFunctionNode.js +64 -13
  292. package/src/nodes/gpgpu/BarrierNode.js +13 -4
  293. package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -1
  294. package/src/nodes/gpgpu/ComputeNode.js +20 -17
  295. package/src/nodes/gpgpu/SubgroupFunctionNode.js +165 -37
  296. package/src/nodes/gpgpu/WorkgroupInfoNode.js +44 -6
  297. package/src/nodes/lighting/EnvironmentNode.js +40 -4
  298. package/src/nodes/lighting/LightsNode.js +20 -4
  299. package/src/nodes/lighting/ShadowBaseNode.js +158 -1
  300. package/src/nodes/lighting/ShadowFilterNode.js +2 -106
  301. package/src/nodes/lighting/ShadowNode.js +22 -91
  302. package/src/nodes/materialx/{lib/mx_hsv.js → MaterialXColor.js} +3 -6
  303. package/src/nodes/materialx/{lib/mx_transform_color.js → MaterialXColorTransform.js} +3 -6
  304. package/src/nodes/materialx/MaterialXCore.js +37 -0
  305. package/src/nodes/materialx/MaterialXNodes.js +64 -72
  306. package/src/nodes/materialx/{lib/mx_noise.js → MaterialXNoise.js} +426 -197
  307. package/src/nodes/math/BitcountNode.js +24 -4
  308. package/src/nodes/math/MathNode.js +4 -4
  309. package/src/nodes/math/MathUtils.js +15 -4
  310. package/src/nodes/math/OperatorNode.js +2 -2
  311. package/src/nodes/math/PackFloatNode.js +29 -1
  312. package/src/nodes/math/Packed4x8IntegerNode.js +433 -0
  313. package/src/nodes/math/UnpackFloatNode.js +30 -2
  314. package/src/nodes/parsers/GLSLNodeFunction.js +1 -1
  315. package/src/nodes/pmrem/PMREMNode.js +1 -1
  316. package/src/nodes/pmrem/PMREMUtils.js +31 -74
  317. package/src/nodes/shapes/Shapes.js +1 -1
  318. package/src/nodes/tsl/TSLCore.js +1 -31
  319. package/src/nodes/utils/EventNode.js +75 -0
  320. package/src/nodes/utils/LoopNode.js +54 -13
  321. package/src/nodes/utils/PostProcessingUtils.js +23 -2
  322. package/src/nodes/utils/RTTNode.js +97 -32
  323. package/src/nodes/utils/ReflectorNode.js +8 -4
  324. package/src/nodes/utils/RotateNode.js +85 -8
  325. package/src/nodes/utils/SpriteUtils.js +58 -23
  326. package/src/objects/BatchedMesh.js +6 -0
  327. package/src/objects/InstancedMesh.js +1 -1
  328. package/src/objects/LOD.js +1 -1
  329. package/src/objects/Line.js +12 -0
  330. package/src/objects/Mesh.js +12 -0
  331. package/src/objects/Points.js +12 -0
  332. package/src/objects/Sprite.js +12 -0
  333. package/src/renderers/WebGLRenderer.js +93 -27
  334. package/src/renderers/common/Animation.js +12 -2
  335. package/src/renderers/common/Backend.js +38 -10
  336. package/src/renderers/common/BindGroup.js +0 -1
  337. package/src/renderers/common/Bindings.js +50 -4
  338. package/src/renderers/common/BundleGroup.js +4 -0
  339. package/src/renderers/common/ClippingContext.js +11 -1
  340. package/src/renderers/common/Color4.js +9 -0
  341. package/src/renderers/common/Constants.js +0 -5
  342. package/src/renderers/common/DirectRenderPipeline.js +233 -0
  343. package/src/renderers/common/Geometries.js +24 -3
  344. package/src/renderers/common/Info.js +3 -3
  345. package/src/renderers/common/InspectorBase.js +37 -8
  346. package/src/renderers/common/Lighting.js +11 -4
  347. package/src/renderers/common/Pipelines.js +6 -4
  348. package/src/renderers/common/QuadMesh.js +16 -2
  349. package/src/renderers/common/RenderContext.js +8 -0
  350. package/src/renderers/common/RenderList.js +53 -19
  351. package/src/renderers/common/RenderLists.js +58 -11
  352. package/src/renderers/common/RenderObject.js +14 -0
  353. package/src/renderers/common/RenderObjects.js +14 -9
  354. package/src/renderers/common/RenderPipeline.js +52 -44
  355. package/src/renderers/common/Renderer.js +226 -55
  356. package/src/renderers/common/Storage3DTexture.js +16 -0
  357. package/src/renderers/common/Textures.js +3 -3
  358. package/src/renderers/common/XRManager.js +79 -72
  359. package/src/renderers/common/extras/PMREMGenerator.js +76 -144
  360. package/src/renderers/common/nodes/NodeManager.js +144 -6
  361. package/src/renderers/common/nodes/NodeStorageBuffer.js +3 -1
  362. package/src/renderers/common/nodes/NodeUniformBuffer.js +3 -1
  363. package/src/renderers/shaders/DFGLUTData.js +2 -1
  364. package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +4 -2
  365. package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +48 -0
  366. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +53 -4
  367. package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +20 -2
  368. package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +20 -0
  369. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +6 -0
  370. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +61 -57
  371. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +82 -0
  372. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js +9 -0
  373. package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +8 -1
  374. package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +15 -0
  375. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -0
  376. package/src/renderers/shaders/ShaderLib.js +1 -0
  377. package/src/renderers/shaders/UniformsLib.js +16 -0
  378. package/src/renderers/webgl/WebGLAnimation.js +2 -2
  379. package/src/renderers/webgl/WebGLCapabilities.js +2 -2
  380. package/src/renderers/webgl/WebGLLights.js +74 -4
  381. package/src/renderers/webgl/WebGLMaterials.js +6 -0
  382. package/src/renderers/webgl/WebGLOutput.js +36 -24
  383. package/src/renderers/webgl/WebGLProgram.js +3 -0
  384. package/src/renderers/webgl/WebGLPrograms.js +8 -0
  385. package/src/renderers/webgl/WebGLRenderLists.js +6 -10
  386. package/src/renderers/webgl/WebGLShadowMap.js +47 -44
  387. package/src/renderers/webgl/WebGLTextures.js +7 -7
  388. package/src/renderers/webgl-fallback/WebGLBackend.js +153 -45
  389. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +83 -29
  390. package/src/renderers/webgl-fallback/utils/WebGLState.js +163 -17
  391. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +32 -5
  392. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +11 -4
  393. package/src/renderers/webgpu/WebGPUBackend.js +513 -145
  394. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +99 -20
  395. package/src/renderers/webgpu/nodes/WGSLNodeFunction.js +2 -1
  396. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +3 -12
  397. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +24 -14
  398. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +80 -14
  399. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +62 -7
  400. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +9 -3
  401. package/src/renderers/webgpu/utils/WebGPUUtils.js +16 -4
  402. package/src/renderers/webxr/WebXRManager.js +25 -2
  403. package/src/scenes/Scene.js +3 -3
  404. package/src/textures/CompressedArrayTexture.js +16 -0
  405. package/src/textures/Data3DTexture.js +16 -0
  406. package/src/textures/DataArrayTexture.js +16 -0
  407. package/src/textures/DepthTexture.js +3 -3
  408. package/src/textures/Texture.js +3 -3
  409. package/src/textures/{Source.js → TextureSource.js} +39 -8
  410. package/src/utils.js +6 -79
  411. package/build/three.core.min.js +0 -6
  412. package/build/three.module.min.js +0 -6
  413. package/build/three.tsl.min.js +0 -6
  414. package/build/three.webgpu.min.js +0 -6
  415. package/build/three.webgpu.nodes.min.js +0 -6
  416. package/examples/jsm/libs/ecsy.module.js +0 -1792
  417. package/examples/jsm/loaders/LottieLoader.js +0 -130
  418. package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +0 -52
@@ -1,6 +1,6 @@
1
1
  import {
2
+ BufferAttribute,
2
3
  BufferGeometry,
3
- Float32BufferAttribute,
4
4
  Group,
5
5
  Mesh
6
6
  } from '@gnsx/three';
@@ -11,22 +11,12 @@ import { cameraPosition, color, float, Fn, If, mix, mx_noise_float, normalView,
11
11
  import { ImprovedNoise } from '../math/ImprovedNoise.js';
12
12
 
13
13
  /**
14
- * Bakes a procedural mountain range into a single {@link THREE.BufferGeometry} and
15
- * returns a `THREE.Group` ready to add to a scene.
14
+ * Bakes a procedural mountain range into a single mesh, returned in a `THREE.Group`.
15
+ * Domain-warped, derivative-damped noise shapes the ridges; thermal erosion relaxes
16
+ * steep slopes. A TSL material shades grass, rock and snow from altitude and slope.
16
17
  *
17
- * The heightfield is a derivative-damped fractal sum ( Quilez's fake erosion ): each
18
- * octave is suppressed where the running slope is already steep, concentrating detail
19
- * into weathered ridgelines, and a low-frequency domain warp makes those ridges
20
- * meander. A few passes of thermal ( talus ) erosion then relax any slope past the
21
- * angle of repose, settling the fractal's needle-spikes into real crests.
22
- *
23
- * The grid is triangulated with alternating quad diagonals ( a diamond pattern ), so a
24
- * coarse mesh holds its silhouette without a one-way grain. The surface shades itself
25
- * from altitude and slope in TSL — grass, forest, rock, scree and snow, with detail
26
- * normals and aerial perspective — so no material or textures are needed.
27
- *
28
- * The baked height grid is exposed through {@link TerrainGenerator#sampleHeight} so a
29
- * scattered forest ( or anything else ) can sit exactly on the surface.
18
+ * The baked grid is available through {@link TerrainGenerator#sampleHeight} for
19
+ * placing a forest or other objects on the terrain.
30
20
  *
31
21
  * ```js
32
22
  * const terrain = new TerrainGenerator( { seed: 1 } );
@@ -82,6 +72,8 @@ class TerrainGenerator {
82
72
 
83
73
  // lay the grid out flat in the XZ plane ( Y-up ) and find the height range
84
74
  const positions = new Float32Array( N * N * 3 );
75
+ const normals = new Float32Array( N * N * 3 );
76
+ const cellSize = p.size / p.segments;
85
77
  let min = Infinity, max = - Infinity;
86
78
 
87
79
  for ( let iz = 0; iz < N; iz ++ ) {
@@ -95,6 +87,16 @@ class TerrainGenerator {
95
87
  positions[ o * 3 + 1 ] = y;
96
88
  positions[ o * 3 + 2 ] = coord[ iz ];
97
89
 
90
+ // Sample the grid's gradient so alternating triangle fans have equal weight.
91
+ const left = Math.max( 0, ix - 1 ), right = Math.min( N - 1, ix + 1 );
92
+ const back = Math.max( 0, iz - 1 ), front = Math.min( N - 1, iz + 1 );
93
+ const nx = ( heights[ iz * N + left ] - heights[ iz * N + right ] ) / ( ( right - left ) * cellSize );
94
+ const nz = ( heights[ back * N + ix ] - heights[ front * N + ix ] ) / ( ( front - back ) * cellSize );
95
+ const length = Math.hypot( nx, 1, nz );
96
+ normals[ o * 3 ] = nx / length;
97
+ normals[ o * 3 + 1 ] = 1 / length;
98
+ normals[ o * 3 + 2 ] = nz / length;
99
+
98
100
  if ( y < min ) min = y;
99
101
  if ( y > max ) max = y;
100
102
 
@@ -104,25 +106,32 @@ class TerrainGenerator {
104
106
 
105
107
  // flip the quad diagonal on every other quad, so the mesh reads as diamonds
106
108
  // rather than a one-way grain
107
- const indices = [];
109
+ const IndexArray = N * N > 65535 ? Uint32Array : Uint16Array;
110
+ const indices = new IndexArray( p.segments * p.segments * 6 );
111
+ let index = 0;
108
112
 
109
113
  for ( let iz = 0; iz < p.segments; iz ++ ) {
110
114
 
111
115
  for ( let ix = 0; ix < p.segments; ix ++ ) {
112
116
 
113
117
  const a = iz * N + ix, b = a + 1, c = a + N, d = c + 1;
118
+ const even = ( ix + iz ) % 2 === 0;
114
119
 
115
- if ( ( ix + iz ) % 2 === 0 ) indices.push( a, c, b, b, c, d );
116
- else indices.push( a, c, d, a, d, b );
120
+ indices[ index ++ ] = a;
121
+ indices[ index ++ ] = c;
122
+ indices[ index ++ ] = even ? b : d;
123
+ indices[ index ++ ] = even ? b : a;
124
+ indices[ index ++ ] = even ? c : d;
125
+ indices[ index ++ ] = even ? d : b;
117
126
 
118
127
  }
119
128
 
120
129
  }
121
130
 
122
131
  const geometry = new BufferGeometry();
123
- geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
124
- geometry.setIndex( indices );
125
- geometry.computeVertexNormals();
132
+ geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
133
+ geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
134
+ geometry.setIndex( new BufferAttribute( indices, 1 ) );
126
135
 
127
136
  this.heights = heights;
128
137
  this.gridSize = N;
@@ -384,7 +393,7 @@ function thermalErode( h, N, cellSize, talus, passes ) {
384
393
  // method. the built-in bumpMap reads height by offsetting the UV — a no-op for a
385
394
  // world-keyed height — so the height's screen-space derivatives are fed in directly.
386
395
  // returns a view-space normal.
387
- function bumpNormal( height ) {
396
+ function bumpNormal( height, strength ) {
388
397
 
389
398
  const dpdx = positionView.dFdx();
390
399
  const dpdy = positionView.dFdy();
@@ -393,7 +402,7 @@ function bumpNormal( height ) {
393
402
  const det = dpdx.dot( r1 );
394
403
  const grad = det.sign().mul( height.dFdx().mul( r1 ).add( height.dFdy().mul( r2 ) ) );
395
404
 
396
- return det.abs().mul( normalView ).sub( grad ).normalize();
405
+ return det.abs().mul( normalView ).sub( grad.mul( strength ) ).normalize();
397
406
 
398
407
  }
399
408
 
@@ -420,7 +429,7 @@ function terrainMaterial( minHeight, maxHeight ) {
420
429
  const grass = color( 0x6e7253 ); // dry sage-olive meadow ( not video-game green )
421
430
  const dryGrass = color( 0x8a8550 );
422
431
  const forest = color( 0x39402f ); // dark forested mid-slope band, under the trees
423
- const rock = color( 0x736a5f ); // warm grey-brown rock
432
+ const rock = color( 0x716e68 ); // weathered grey-brown rock
424
433
  const scree = color( 0x837a6f ); // brighter broken rock below the cliffs
425
434
  const lichen = color( 0x6c7355 ); // muted green-grey, patched onto lower rock
426
435
  const snow = color( 0xe9ecf0 ); // fresh snow; warm-sun / cool-sky cast is from the lighting
@@ -428,13 +437,13 @@ function terrainMaterial( minHeight, maxHeight ) {
428
437
 
429
438
  // two band frequencies of lighter / darker stone, wobbled by noise, so cliff faces
430
439
  // read as layered bedding instead of flat grey
431
- const bandA = positionWorld.y.mul( 0.5 ).add( detail.mul( 3 ) ).add( macro.mul( 4 ) ).sin();
440
+ const bandA = positionWorld.y.mul( 0.5 ).add( positionWorld.x.mul( 0.08 ) ).add( positionWorld.z.mul( 0.05 ) ).add( detail.mul( 3 ) ).add( macro.mul( 4 ) ).sin();
432
441
  const bandB = positionWorld.y.mul( 1.4 ).add( grain.mul( 2 ) ).sin();
433
442
  const strata = bandA.mul( 0.6 ).add( bandB.mul( 0.4 ) ).mul( 0.5 ).add( 0.5 );
434
443
 
435
444
  // lichen creeps onto the lower, gentler rock; cliffs and high ground stay bare grey
436
445
  const lichenMask = smoothstep( 0.45, 0.72, grain ).mul( smoothstep( 0.62, 0.32, steep ) ).mul( smoothstep( 0.66, 0.34, altitude ) );
437
- const rockShade = mix( rock, lichen, lichenMask.mul( 0.45 ) ).mul( strata.mul( 0.36 ).add( 0.8 ) );
446
+ const rockShade = mix( rock, lichen, lichenMask.mul( 0.45 ) ).mul( strata.mul( 0.36 ).add( 0.8 ) ).mul( grain.mul( 0.18 ).add( 1 ) );
438
447
 
439
448
  // meadow, drifting to dry grass in macro-noise patches over a mid band
440
449
  let surface = mix( grass, dryGrass, smoothstep( 0.15, 0.75, macro ).mul( smoothstep( 0.22, 0.5, altitude ) ) );
@@ -452,7 +461,7 @@ function terrainMaterial( minHeight, maxHeight ) {
452
461
 
453
462
  // snow on high, flat ground; the grain noise breaks the line so rock pokes through
454
463
  // near the snowline instead of stopping on a clean contour
455
- const snowMask = smoothstep( 0.56, 0.78, altitude.add( detail.mul( 0.08 ) ).add( grain.mul( 0.05 ) ) ).mul( smoothstep( 0.3, 0.6, flatness ) );
464
+ const snowMask = smoothstep( 0.56, 0.78, altitude.add( detail.mul( 0.08 ) ).add( grain.mul( 0.05 ) ) ).mul( smoothstep( 0.45, 0.75, flatness ) );
456
465
  const snowColor = mix( snow, snowDeep, smoothstep( 0.2, 0.7, grain ).mul( 0.6 ) ); // patchy, not a flat sheet
457
466
  surface = mix( surface, snowColor, snowMask );
458
467
 
@@ -473,21 +482,23 @@ function terrainMaterial( minHeight, maxHeight ) {
473
482
  material.colorNode = surface;
474
483
  material.roughnessNode = mix( float( 0.95 ), float( 0.72 ), snowMask );
475
484
 
476
- // detail normals: three octaves of world-space relief, faded out with distance so
477
- // they can't alias into fireflies in the haze. gating the noise behind the fade ( a
478
- // real branch ) lets the far majority of this fragment-bound terrain skip the taps.
485
+ // Volumetric noise keeps relief consistent on cliffs. Skip fine grain in the distance.
479
486
  const detailFade = smoothstep( 420, 60, distance );
480
- const reliefStrength = mix( float( 0.25 ), float( 0.55 ), steep ); // more on rock, less on grass
487
+ const grainFade = smoothstep( 180, 40, distance );
488
+ const reliefStrength = mix( mix( float( 0.25 ), float( 0.55 ), steep ), float( 0.04 ), snowMask );
481
489
  const relief = Fn( () => {
482
490
 
483
491
  const r = float( 0 ).toVar();
484
492
 
485
493
  If( detailFade.greaterThan( 0.01 ), () => {
486
494
 
487
- r.assign( mx_noise_float( positionWorld.xz.mul( 0.6 ) )
488
- .add( mx_noise_float( positionWorld.xz.mul( 1.7 ) ).mul( 0.5 ) )
489
- .add( mx_noise_float( positionWorld.xz.mul( 4.0 ) ).mul( 0.25 ) )
490
- .mul( reliefStrength ).mul( detailFade ).mul( 0.25 ) );
495
+ r.assign( mx_noise_float( positionWorld.mul( 0.6 ) ) );
496
+
497
+ If( grainFade.greaterThan( 0.01 ), () => {
498
+
499
+ r.addAssign( mx_noise_float( positionWorld.mul( 1.7 ) ).mul( 0.5 ).mul( grainFade ) );
500
+
501
+ } );
491
502
 
492
503
  } );
493
504
 
@@ -495,7 +506,8 @@ function terrainMaterial( minHeight, maxHeight ) {
495
506
 
496
507
  } )();
497
508
 
498
- material.normalNode = bumpNormal( relief );
509
+ // Apply strength after differentiating the noise; slope derivatives reveal triangles.
510
+ material.normalNode = bumpNormal( relief, reliefStrength.mul( detailFade ).mul( 0.25 ) );
499
511
 
500
512
  return material;
501
513
 
@@ -17,12 +17,9 @@ const TAU = Math.PI * 2;
17
17
  const UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
18
18
  const _axis = /*@__PURE__*/ new Vector3();
19
19
 
20
- // reusable scratch for one tube's ring vertices ( grows to the largest tube seen )
21
- let _ring = new Float32Array( 0 );
22
-
23
20
  /**
24
21
  * Grows a procedural tree skeleton — trunk, branches and twigs, each swept as a tapered
25
- * tube — and bakes it into one non-indexed {@link BufferGeometry} (position and normal
22
+ * tube — and bakes it into one indexed {@link BufferGeometry} (position and normal
26
23
  * only), ready to instance into a forest. It produces *branches only*; add foliage as a
27
24
  * separate layer.
28
25
  *
@@ -58,26 +55,10 @@ class TreeGenerator {
58
55
  const p = Object.assign( {}, TreeGenerator.defaults, this.parameters );
59
56
  const random = createRandom( p.seed );
60
57
 
61
- // grow the skeleton into a flat list of tubes, then size and fill the geometry in
62
- // one pass — no per-vertex objects, no array growth
63
-
64
58
  const tubes = [];
65
59
  growBranch( tubes, new Vector3(), UP, p.trunkLength, p.trunkRadius, 0, p, random );
66
60
 
67
- let vertexCount = 0;
68
- for ( const tube of tubes ) vertexCount += ( tube.rings.length - 1 ) * tube.radial * 6;
69
-
70
- const positions = new Float32Array( vertexCount * 3 );
71
- const normals = new Float32Array( vertexCount * 3 );
72
-
73
- let offset = 0;
74
- for ( const tube of tubes ) offset = emitTube( positions, normals, offset, tube.rings, tube.radial );
75
-
76
- const geometry = new BufferGeometry();
77
- geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
78
- geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
79
- geometry.computeBoundingSphere();
80
-
61
+ const geometry = createGeometry( tubes );
81
62
  const mesh = new Mesh( geometry, this.material || createTreeMaterial() );
82
63
  mesh.name = 'Tree';
83
64
 
@@ -94,6 +75,8 @@ TreeGenerator.defaults = {
94
75
  branchAngle: [ 38, 50, 58 ], // degrees a child tilts off its parent axis, per level
95
76
  angleVariance: 14, // degrees of random jitter on the branch angle, breaks fractal regularity
96
77
  lengthRatio: 0.62, // child length / parent length
78
+ lengthVariance: 0, // fractional variation in child length
79
+ branchLengthFalloff: 0, // shorten children toward the tip of their parent
97
80
  trunkLength: 9, // trunk length in world units; sets the tree's height
98
81
  trunkRadius: 0.42, // base radius of the trunk
99
82
  taper: 0.55, // a branch thins to ( 1 - taper ) of its base radius along its own length
@@ -162,7 +145,6 @@ function growBranch( tubes, base, dir, length, baseRadius, level, p, random ) {
162
145
  pos: pos.clone(),
163
146
  tangent: tangent.clone(),
164
147
  normal: normal.clone(),
165
- binormal: new Vector3().crossVectors( tangent, normal ),
166
148
  radius
167
149
  } );
168
150
 
@@ -212,7 +194,10 @@ function growBranch( tubes, base, dir, length, baseRadius, level, p, random ) {
212
194
  // the pipe-model drop, but never fatter than the wood it leaves nor below the floor
213
195
  const childBase = Math.max( p.minRadius, Math.min( baseRadius * pipeDrop, ring.radius ) );
214
196
 
215
- growBranch( tubes, ring.pos, childDir, length * p.lengthRatio, childBase, level + 1, p, random );
197
+ let childLength = length * p.lengthRatio * ( 1 - p.branchLengthFalloff * t );
198
+ if ( p.lengthVariance > 0 ) childLength *= 1 + ( random() * 2 - 1 ) * p.lengthVariance;
199
+
200
+ growBranch( tubes, ring.pos, childDir, childLength, childBase, level + 1, p, random );
216
201
 
217
202
  }
218
203
 
@@ -244,7 +229,7 @@ function ringAt( rings, t ) {
244
229
  const i = Math.floor( f );
245
230
  const frac = f - i;
246
231
  const a = rings[ i ];
247
- const b = rings[ Math.min( i + 1, rings.length - 1 ) ];
232
+ const b = rings[ i + 1 ];
248
233
 
249
234
  return {
250
235
  pos: a.pos.clone().lerp( b.pos, frac ),
@@ -257,79 +242,87 @@ function ringAt( rings, t ) {
257
242
 
258
243
  // --- geometry ------------------------------------------------------------
259
244
 
260
- // Sweeps a tube through the rings: each ring is a loop of `radial` vertices in its
261
- // ( normal, binormal ) plane, the outward radial direction being the vertex normal.
262
- // Ring vertices are computed once into a reused scratch, then stitched straight into the
263
- // preallocated geometry arrays — no per-vertex objects.
264
- function emitTube( positions, normals, offset, rings, radial ) {
245
+ // Write each ring vertex once, then join adjacent rings with indexed triangles.
246
+ function createGeometry( tubes ) {
265
247
 
266
- const stride = ( radial + 1 ) * 6; // one ring loop: ( position, normal ) per vertex
267
- const needed = rings.length * stride;
268
- if ( _ring.length < needed ) _ring = new Float32Array( needed );
248
+ let vertexCount = 0;
249
+ let indexCount = 0;
269
250
 
270
- const ring = _ring;
251
+ for ( const { rings, radial } of tubes ) {
271
252
 
272
- for ( let r = 0; r < rings.length; r ++ ) {
253
+ vertexCount += rings.length * radial;
254
+ indexCount += ( rings.length - 1 ) * radial * 6;
273
255
 
274
- const { pos, normal, binormal, radius } = rings[ r ];
275
- let o = r * stride;
256
+ }
276
257
 
277
- for ( let j = 0; j <= radial; j ++ ) {
258
+ const positions = new Float32Array( vertexCount * 3 );
259
+ const normals = new Float32Array( vertexCount * 3 );
260
+ const indices = new ( vertexCount > 65535 ? Uint32Array : Uint16Array )( indexCount );
261
+ const binormal = new Vector3();
278
262
 
279
- const a = j / radial * TAU;
280
- const c = Math.cos( a );
281
- const s = Math.sin( a );
282
- const nx = c * normal.x + s * binormal.x;
283
- const ny = c * normal.y + s * binormal.y;
284
- const nz = c * normal.z + s * binormal.z;
263
+ let vertexOffset = 0;
264
+ let indexOffset = 0;
285
265
 
286
- ring[ o ++ ] = pos.x + nx * radius;
287
- ring[ o ++ ] = pos.y + ny * radius;
288
- ring[ o ++ ] = pos.z + nz * radius;
289
- ring[ o ++ ] = nx;
290
- ring[ o ++ ] = ny;
291
- ring[ o ++ ] = nz;
266
+ for ( const { rings, radial } of tubes ) {
292
267
 
293
- }
268
+ let offset = vertexOffset * 3;
294
269
 
295
- }
270
+ for ( const { pos, tangent, normal, radius } of rings ) {
296
271
 
297
- // stitch consecutive rings into quads ( two triangles ), wound so normals face out
272
+ binormal.crossVectors( tangent, normal );
298
273
 
299
- for ( let r = 0; r < rings.length - 1; r ++ ) {
274
+ for ( let j = 0; j < radial; j ++ ) {
300
275
 
301
- const a = r * stride;
302
- const b = ( r + 1 ) * stride;
276
+ const angle = j / radial * TAU;
277
+ const c = Math.cos( angle );
278
+ const s = Math.sin( angle );
279
+ const nx = c * normal.x + s * binormal.x;
280
+ const ny = c * normal.y + s * binormal.y;
281
+ const nz = c * normal.z + s * binormal.z;
303
282
 
304
- for ( let j = 0; j < radial; j ++ ) {
283
+ positions[ offset ] = pos.x + nx * radius;
284
+ positions[ offset + 1 ] = pos.y + ny * radius;
285
+ positions[ offset + 2 ] = pos.z + nz * radius;
286
+ normals[ offset ] = nx;
287
+ normals[ offset + 1 ] = ny;
288
+ normals[ offset + 2 ] = nz;
289
+ offset += 3;
305
290
 
306
- const aL = a + j * 6, aR = a + ( j + 1 ) * 6;
307
- const bL = b + j * 6, bR = b + ( j + 1 ) * 6;
291
+ }
308
292
 
309
- offset = copyVertex( positions, normals, offset, ring, aL );
310
- offset = copyVertex( positions, normals, offset, ring, bR );
311
- offset = copyVertex( positions, normals, offset, ring, bL );
293
+ }
312
294
 
313
- offset = copyVertex( positions, normals, offset, ring, aL );
314
- offset = copyVertex( positions, normals, offset, ring, aR );
315
- offset = copyVertex( positions, normals, offset, ring, bR );
295
+ for ( let r = 0; r < rings.length - 1; r ++ ) {
316
296
 
317
- }
297
+ const a = vertexOffset + r * radial;
298
+ const b = a + radial;
318
299
 
319
- }
300
+ for ( let j = 0; j < radial; j ++ ) {
320
301
 
321
- return offset;
302
+ const next = ( j + 1 ) % radial; // wrap the seam back to the first vertex
322
303
 
323
- }
304
+ indices[ indexOffset ++ ] = a + j;
305
+ indices[ indexOffset ++ ] = b + next;
306
+ indices[ indexOffset ++ ] = b + j;
307
+ indices[ indexOffset ++ ] = a + j;
308
+ indices[ indexOffset ++ ] = a + next;
309
+ indices[ indexOffset ++ ] = b + next;
310
+
311
+ }
324
312
 
325
- // copies one ( position, normal ) vertex from the ring scratch into the geometry arrays
326
- function copyVertex( positions, normals, offset, ring, i ) {
313
+ }
314
+
315
+ vertexOffset += rings.length * radial;
316
+
317
+ }
327
318
 
328
- const o = offset * 3;
329
- positions[ o ] = ring[ i ]; positions[ o + 1 ] = ring[ i + 1 ]; positions[ o + 2 ] = ring[ i + 2 ];
330
- normals[ o ] = ring[ i + 3 ]; normals[ o + 1 ] = ring[ i + 4 ]; normals[ o + 2 ] = ring[ i + 5 ];
319
+ const geometry = new BufferGeometry();
320
+ geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
321
+ geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
322
+ geometry.setIndex( new BufferAttribute( indices, 1 ) );
323
+ geometry.computeBoundingSphere();
331
324
 
332
- return offset + 1;
325
+ return geometry;
333
326
 
334
327
  }
335
328
 
@@ -356,7 +349,7 @@ function createRandom( seed ) {
356
349
  * A simple bark material for a {@link TreeGenerator} mesh: a low-saturation brown with a
357
350
  * faint, vertically-stretched grain, so trunks read near-black against bright fog.
358
351
  *
359
- * @param {Object} [parameters] - `barkColor` ( a hex, THREE.Color or TSL node ).
352
+ * @param {Object} [parameters] - `barkColor` ( a hex, THREE.Color or TSL node ) and `barkScale` ( a THREE.Vector3 ).
360
353
  * @return {MeshStandardNodeMaterial}
361
354
  */
362
355
  function createTreeMaterial( parameters = {} ) {
@@ -365,7 +358,8 @@ function createTreeMaterial( parameters = {} ) {
365
358
  const barkColor = c === undefined ? color( 0x4b3a2b ) : ( c.isColor || typeof c === 'number' ? color( c ) : c );
366
359
 
367
360
  const material = new MeshStandardNodeMaterial();
368
- const grain = mx_fractal_noise_float( positionLocal.mul( vec3( 2.5, 0.4, 2.5 ) ), 3 ).mul( 0.18 );
361
+ const barkScale = parameters.barkScale ? vec3( parameters.barkScale ) : vec3( 2.5, 0.4, 2.5 );
362
+ const grain = mx_fractal_noise_float( positionLocal.mul( barkScale ), 3 ).mul( 0.18 );
369
363
  material.colorNode = barkColor.mul( grain.add( 0.9 ) );
370
364
  material.roughnessNode = float( 0.95 );
371
365
  material.metalnessNode = float( 0 );
@@ -0,0 +1,127 @@
1
+ import {
2
+ BoxGeometry,
3
+ InterpolationSamplingMode,
4
+ InterpolationSamplingType
5
+ } from '@gnsx/three';
6
+
7
+ import { MeshStandardNodeMaterial } from '@gnsx/three/webgpu';
8
+ import { attribute, color, float, floor, fract, mix, mx_fractal_noise_float, positionGeometry, select, sin, varying, vec3 } from '@gnsx/three/tsl';
9
+
10
+ import { mergeGeometries } from '../../utils/BufferGeometryUtils.js';
11
+
12
+ import { InstancedMeshGenerator } from './InstancedMeshGenerator.js';
13
+ import { part } from './CityGeneratorUtils.js';
14
+
15
+ /**
16
+ * A public street bench: timber slats carried on two cast-iron end frames that
17
+ * curl into armrests, with a reclined slatted backrest. Built once and instanced
18
+ * across a list of placements, dressed with one cheap material that branches on a
19
+ * baked `partId` ( warm stained wood, dark iron ).
20
+ *
21
+ * The canonical model stands on `y = 0`, centred in X / Z, runs along X and seats
22
+ * toward `+Z`, so a placement whose local `+Z` faces the road sits a passer-by
23
+ * looking out over it.
24
+ *
25
+ * ```js
26
+ * const benches = new BenchGenerator();
27
+ * scene.add( benches.build( placements ) ); // placements: Matrix4[]
28
+ * ```
29
+ */
30
+ class BenchGenerator extends InstancedMeshGenerator {
31
+
32
+ constructor( parameters = {} ) {
33
+
34
+ super( parameters, buildBenchGeometry, createBenchMaterial, 'Benches' );
35
+
36
+ }
37
+
38
+ }
39
+
40
+ BenchGenerator.defaults = {
41
+ length: 1.8, // spans X
42
+ depth: 0.55, // front-to-back
43
+ seatHeight: 0.45,
44
+ backHeight: 0.85
45
+ };
46
+
47
+ // material-zone codes baked per vertex
48
+ const WOOD = 0, IRON = 1;
49
+
50
+ function buildBenchGeometry( p ) {
51
+
52
+ const halfLength = p.length / 2;
53
+ const halfDepth = p.depth / 2;
54
+ const seatY = p.seatHeight;
55
+ const backY = p.backHeight;
56
+
57
+ const frontZ = halfDepth - 0.075; // legs set just inside the depth
58
+ const backZ = - frontZ;
59
+
60
+ const parts = [];
61
+
62
+ // two cast-iron end frames brace the slats and curl into armrests
63
+ for ( const side of [ - 1, 1 ] ) {
64
+
65
+ const x = side * ( halfLength - 0.07 );
66
+
67
+ const frontLeg = new BoxGeometry( 0.05, seatY, 0.06 ).translate( x, seatY / 2, frontZ );
68
+ const backLeg = new BoxGeometry( 0.05, backY, 0.06 ).translate( x, backY / 2, backZ ); // doubles as the backrest post
69
+ const seatRail = new BoxGeometry( 0.06, 0.05, frontZ - backZ + 0.1 ).translate( x, seatY - 0.04, 0 );
70
+ const armPost = new BoxGeometry( 0.05, 0.22, 0.05 ).translate( x, seatY + 0.11, frontZ );
71
+ const armRest = new BoxGeometry( 0.05, 0.05, frontZ - backZ + 0.06 ).translate( x, seatY + 0.22, 0 );
72
+ const armCurl = new BoxGeometry( 0.05, 0.16, 0.05 ).rotateX( - 0.6 ).translate( x, seatY + 0.18, frontZ + 0.07 ); // front scroll of the armrest
73
+
74
+ parts.push( part( frontLeg, IRON ), part( backLeg, IRON ), part( seatRail, IRON ), part( armPost, IRON ), part( armRest, IRON ), part( armCurl, IRON ) );
75
+
76
+ }
77
+
78
+ // timber seat slats spaced front-to-back
79
+ const slatLength = p.length - 0.1;
80
+ const z0 = backZ + 0.02, z1 = frontZ - 0.02;
81
+ for ( let i = 0; i < 5; i ++ ) {
82
+
83
+ const z = z0 + ( z1 - z0 ) * ( i / 4 );
84
+ parts.push( part( new BoxGeometry( slatLength, 0.03, 0.07 ).translate( 0, seatY, z ), WOOD ) );
85
+
86
+ }
87
+
88
+ // backrest slats climb the rear posts, reclined a touch
89
+ for ( let i = 0; i < 3; i ++ ) {
90
+
91
+ const t = i / 2;
92
+ const y = seatY + 0.13 + t * 0.27;
93
+ const z = backZ + 0.01 - t * 0.06;
94
+ parts.push( part( new BoxGeometry( slatLength, 0.09, 0.025 ).rotateX( 0.18 ).translate( 0, y, z ), WOOD ) );
95
+
96
+ }
97
+
98
+ return mergeGeometries( parts );
99
+
100
+ }
101
+
102
+ function createBenchMaterial() {
103
+
104
+ const partId = varying( attribute( 'partId', 'float' ) ).setInterpolation( InterpolationSamplingType.FLAT, InterpolationSamplingMode.EITHER );
105
+ const isWood = partId.equal( WOOD );
106
+
107
+ const p = positionGeometry;
108
+
109
+ // timber: grain streaks stretched along the slats, each slat cut from its own
110
+ // board ( a tone hashed from the slat's row position ) and greyed by weathering
111
+ const grain = mx_fractal_noise_float( p.mul( vec3( 3, 60, 60 ) ), 2 ).mul( 0.5 ).add( 0.5 );
112
+ const board = fract( sin( floor( p.z.mul( 10.5 ) ).add( floor( p.y.mul( 8.0 ) ).mul( 7.3 ) ).mul( 17.53 ) ).mul( 43758.5453 ) );
113
+ const weather = mx_fractal_noise_float( p.mul( 1.6 ), 2 ).mul( 0.5 ).add( 0.5 );
114
+
115
+ const stained = mix( color( 0x5e412a ), color( 0x8a6242 ), grain.mul( 0.7 ).add( board.mul( 0.3 ) ) );
116
+ const wood = mix( stained, color( 0x7c7468 ), weather.mul( 0.45 ) ); // sun-bleached grey where the stain has worn
117
+
118
+ const material = new MeshStandardNodeMaterial();
119
+ material.colorNode = select( isWood, wood, color( 0x232322 ) ); // weathered timber, dark cast iron
120
+ material.roughnessNode = select( isWood, grain.mul( 0.25 ).add( 0.65 ), float( 0.5 ) );
121
+ material.metalnessNode = select( isWood, float( 0 ), float( 0.6 ) );
122
+
123
+ return material;
124
+
125
+ }
126
+
127
+ export { BenchGenerator };