@gnsx/three 0.185.16 → 0.186.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/build/three.cjs +10 -82600
  2. package/build/three.core.js +1303 -728
  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/build/three.core.min.js +0 -6
  411. package/build/three.module.min.js +0 -6
  412. package/build/three.tsl.min.js +0 -6
  413. package/build/three.webgpu.min.js +0 -6
  414. package/build/three.webgpu.nodes.min.js +0 -6
  415. package/examples/jsm/libs/ecsy.module.js +0 -1792
  416. package/examples/jsm/loaders/LottieLoader.js +0 -130
  417. package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +0 -52
@@ -0,0 +1,479 @@
1
+ import {
2
+ BoxGeometry,
3
+ BufferGeometry,
4
+ CircleGeometry,
5
+ Color,
6
+ Float32BufferAttribute,
7
+ Group,
8
+ InstancedBufferAttribute,
9
+ InterpolationSamplingMode,
10
+ InterpolationSamplingType,
11
+ LatheGeometry,
12
+ Vector2,
13
+ Vector3
14
+ } from '@gnsx/three';
15
+
16
+ import { MeshStandardNodeMaterial } from '@gnsx/three/webgpu';
17
+ import { atan, attribute, color, float, mix, normalGeometry, positionGeometry, select, smoothstep, uniform, uniformArray, uv, varying, vec2 } from '@gnsx/three/tsl';
18
+
19
+ import { mergeGeometries } from '../../utils/BufferGeometryUtils.js';
20
+ import { LoftGeometry } from '../../geometries/LoftGeometry.js';
21
+ import { createInstances, updateInstances } from './InstancedMeshGenerator.js';
22
+ import { part } from './CityGeneratorUtils.js';
23
+
24
+ /**
25
+ * A low-poly car fleet with lofted bodies, circular wheel arches, curved
26
+ * windscreens and recessed alloy wheels. Separate cabin panels define the
27
+ * windows and their frames. Two body types ( sedan and SUV ) are mixed
28
+ * deterministically across the fleet, and the taxi colour gets its own sedan with
29
+ * a roof sign, so a parked row reads as different vehicles rather than one mould.
30
+ *
31
+ * Each geometry is built once per type and shared; cars are grouped by body
32
+ * type with per-instance paint, so each group is a single instanced draw that
33
+ * assigns paint, glass, tyres and lamps using a baked `partId`, panel UVs and
34
+ * canonical-space masks.
35
+ *
36
+ * The canonical model stands with its wheels on `y = 0`, centred in X / Z, facing
37
+ * `+Z`, so a placement whose local `+Z` faces the road parks it nose-out.
38
+ *
39
+ * ```js
40
+ * const cars = new CarGenerator();
41
+ * scene.add( cars.build( placements ) ); // placements: { matrix: Matrix4, color }[]
42
+ * ```
43
+ */
44
+ class CarGenerator {
45
+
46
+ constructor( parameters = {} ) {
47
+
48
+ this.parameters = Object.assign( {}, CarGenerator.defaults, parameters );
49
+
50
+ this.geometries = new Map(); // one shared shell per body type
51
+ this.materials = new Map(); // one material per body type
52
+ this.mesh = null;
53
+
54
+ }
55
+
56
+ build( cars ) {
57
+
58
+ if ( this.mesh && this.mesh.children.some( ( mesh ) => mesh.instanceMatrix.count < cars.length ) ) this.dispose();
59
+
60
+ // bucket the fleet by body type for one instanced draw per shell.
61
+ // the taxi colour always gets the signed sedan;
62
+ // the rest split deterministically between sedan and SUV
63
+ const buckets = new Map();
64
+
65
+ for ( let i = 0; i < cars.length; i ++ ) {
66
+
67
+ const car = cars[ i ];
68
+ const type = car.color === CarGenerator.taxiColor ? 'taxi' : ( ( ( i * 2654435761 ) >>> 0 ) % 100 < 42 ? 'suv' : 'sedan' );
69
+ if ( ! buckets.has( type ) ) buckets.set( type, [] );
70
+ buckets.get( type ).push( car );
71
+
72
+ }
73
+
74
+ if ( this.mesh === null ) {
75
+
76
+ this.mesh = new Group();
77
+ this.mesh.name = 'Cars';
78
+
79
+ }
80
+
81
+ const group = this.mesh;
82
+ for ( const mesh of group.children ) updateInstances( mesh, [] );
83
+ const paint = new Color();
84
+
85
+ for ( const [ type, instances ] of buckets ) {
86
+
87
+ let geometry = this.geometries.get( type );
88
+ if ( geometry === undefined ) {
89
+
90
+ geometry = buildCarGeometry( BODY_SPECS[ type ] );
91
+ this.geometries.set( type, geometry );
92
+
93
+ }
94
+
95
+ let material = this.materials.get( type );
96
+ if ( material === undefined ) {
97
+
98
+ material = createCarMaterial( BODY_SPECS[ type ] );
99
+ this.materials.set( type, material );
100
+
101
+ }
102
+
103
+ let mesh = group.children.find( ( child ) => child.geometry === geometry );
104
+
105
+ if ( mesh === undefined ) {
106
+
107
+ mesh = createInstances( geometry, material, cars.length, 'Car' );
108
+ geometry.setAttribute( 'paintColor', new InstancedBufferAttribute( new Float32Array( mesh.instanceMatrix.count * 3 ), 3 ) );
109
+ group.add( mesh );
110
+
111
+ }
112
+
113
+ const colors = geometry.getAttribute( 'paintColor' );
114
+
115
+ for ( let i = 0; i < instances.length; i ++ ) {
116
+
117
+ paint.set( instances[ i ].color ).toArray( colors.array, i * 3 );
118
+
119
+ }
120
+
121
+ colors.needsUpdate = true;
122
+ updateInstances( mesh, instances.map( ( car ) => car.matrix ) );
123
+
124
+ }
125
+
126
+ return group;
127
+
128
+ }
129
+
130
+ dispose() {
131
+
132
+ for ( const geometry of this.geometries.values() ) geometry.dispose();
133
+ this.geometries.clear();
134
+
135
+ if ( this.mesh ) this.mesh.traverse( ( object ) => object.dispose() );
136
+
137
+ for ( const material of this.materials.values() ) material.dispose();
138
+ this.materials.clear();
139
+
140
+ this.mesh = null;
141
+
142
+ }
143
+
144
+ }
145
+
146
+ CarGenerator.defaults = {};
147
+
148
+ // the paint colour that gets the roof-signed taxi shell
149
+ CarGenerator.taxiColor = 0xf5c518;
150
+
151
+ const BODY = 0, WINDOW = 1, TYRE = 2, ALLOY = 3, TRIM = 4, MIRROR = 5, SIGN = 6, FRONT = 7, REAR = 8;
152
+
153
+ // Body sections are [ z, half-width, shoulder height, deck height ]. The cabin
154
+ // has separate base and roof corners, so changing its shape also moves its panes.
155
+ const BODY_SPECS = {
156
+
157
+ sedan: {
158
+ body: [
159
+ [ 2.25, 0.79, 0.67, 0.79 ],
160
+ [ 2.11, 0.89, 0.78, 0.91 ],
161
+ [ 1.38, 0.94, 0.87, 1.00 ],
162
+ [ 0.75, 0.92, 0.89, 1.025 ],
163
+ [ - 0.45, 0.92, 0.91, 1.04 ],
164
+ [ - 1.38, 0.94, 0.88, 1.06 ],
165
+ [ - 2.10, 0.89, 0.77, 0.97 ],
166
+ [ - 2.25, 0.81, 0.70, 0.85 ]
167
+ ],
168
+ front: { base: [ 0.82, 0.99, 0.78 ], roof: [ 0.69, 1.45, 0.12 ] },
169
+ rear: { base: [ 0.83, 1.02, - 1.15 ], roof: [ 0.71, 1.47, - 0.72 ] },
170
+ wheelRadius: 0.35, wheelZ: 1.38, wheelX: 0.83,
171
+ pillars: [ - 0.30 ], lamps: [ 0.71, 0.76 ],
172
+ sign: false, rails: false
173
+ },
174
+
175
+ suv: {
176
+ body: [
177
+ [ 2.30, 0.84, 0.84, 0.99 ],
178
+ [ 2.15, 0.94, 0.94, 1.10 ],
179
+ [ 1.40, 0.98, 1.02, 1.17 ],
180
+ [ 0.76, 0.96, 1.04, 1.19 ],
181
+ [ - 0.45, 0.96, 1.05, 1.20 ],
182
+ [ - 1.40, 0.98, 1.03, 1.21 ],
183
+ [ - 2.16, 0.94, 0.94, 1.16 ],
184
+ [ - 2.30, 0.84, 0.86, 1.03 ]
185
+ ],
186
+ front: { base: [ 0.86, 1.15, 0.78 ], roof: [ 0.76, 1.73, 0.18 ] },
187
+ rear: { base: [ 0.87, 1.15, - 2.12 ], roof: [ 0.77, 1.75, - 1.66 ] },
188
+ wheelRadius: 0.39, wheelZ: 1.40, wheelX: 0.87,
189
+ pillars: [ - 0.30, - 1.16 ], lamps: [ 0.91, 0.94 ],
190
+ sign: false, rails: true
191
+ }
192
+
193
+ };
194
+
195
+ BODY_SPECS.taxi = Object.assign( {}, BODY_SPECS.sedan, { sign: true } );
196
+
197
+ function buildBody( spec ) {
198
+
199
+ const profile = spec.body;
200
+ const radius = spec.wheelRadius + 0.055;
201
+ const stations = new Set( profile.map( section => section[ 0 ] ) );
202
+
203
+ // Sample the arches around the axle, then interpolate the body profile at
204
+ // those stations. Wheel size and placement no longer need hand-shaped cuts.
205
+ for ( const axle of [ - spec.wheelZ, spec.wheelZ ] ) {
206
+
207
+ for ( let i = 0; i <= 6; i ++ ) stations.add( axle + radius * Math.cos( i / 6 * Math.PI ) );
208
+
209
+ }
210
+
211
+ const sections = Array.from( stations ).sort( ( a, b ) => b - a ).map( z => {
212
+
213
+ let index = 0;
214
+ while ( index < profile.length - 2 && z < profile[ index + 1 ][ 0 ] ) index ++;
215
+
216
+ const a = profile[ index ], b = profile[ index + 1 ];
217
+ const t = ( z - a[ 0 ] ) / ( b[ 0 ] - a[ 0 ] );
218
+ const w = a[ 1 ] + ( b[ 1 ] - a[ 1 ] ) * t;
219
+ const shoulder = a[ 2 ] + ( b[ 2 ] - a[ 2 ] ) * t;
220
+ const deck = a[ 3 ] + ( b[ 3 ] - a[ 3 ] ) * t;
221
+ const distance = Math.abs( Math.abs( z ) - spec.wheelZ );
222
+ const sill = distance <= radius ? spec.wheelRadius + Math.sqrt( Math.max( 0, radius * radius - distance * distance ) ) : 0.28;
223
+
224
+ const right = [
225
+ new Vector3( w * 0.82, sill, z ),
226
+ new Vector3( w * 0.97, sill + ( shoulder - sill ) * 0.12, z ),
227
+ new Vector3( w, shoulder, z ),
228
+ new Vector3( w * 0.91, deck - 0.025, z ),
229
+ new Vector3( w * 0.52, deck, z )
230
+ ];
231
+
232
+ return [ ...right, ...right.slice().reverse().map( p => new Vector3( - p.x, p.y, p.z ) ) ].reverse();
233
+
234
+ } );
235
+
236
+ const geometry = part( new LoftGeometry( sections, { capStart: true, capEnd: true } ), BODY );
237
+ const normals = geometry.attributes.normal;
238
+ const ids = geometry.attributes.partId;
239
+ for ( let i = 0; i < normals.count; i ++ ) {
240
+
241
+ if ( normals.getZ( i ) > 0.9999 ) ids.setX( i, FRONT );
242
+ if ( normals.getZ( i ) < - 0.9999 ) ids.setX( i, REAR );
243
+
244
+ }
245
+
246
+ return geometry;
247
+
248
+ }
249
+
250
+ // Independent panel vertices preserve the crease at each pillar and roof edge.
251
+ // Their UVs also give the material an exact outline for the window seals.
252
+ function panel( corners, id, curved = false ) {
253
+
254
+ const geometry = new BufferGeometry();
255
+ const columns = curved ? 4 : 1, rows = curved ? 2 : 1;
256
+ const positions = [], uvs = [], indices = [];
257
+ const normal = corners[ 1 ].clone().sub( corners[ 0 ] ).cross( corners[ 3 ].clone().sub( corners[ 0 ] ) ).normalize();
258
+
259
+ for ( let y = 0; y <= rows; y ++ ) {
260
+
261
+ const v = y / rows;
262
+ for ( let x = 0; x <= columns; x ++ ) {
263
+
264
+ const u = x / columns;
265
+ const p = corners[ 0 ].clone().lerp( corners[ 1 ], u ).lerp( corners[ 3 ].clone().lerp( corners[ 2 ], u ), v );
266
+ if ( curved ) {
267
+
268
+ const arch = 4 * u * ( 1 - u );
269
+ p.y += arch * v * 0.035;
270
+ p.addScaledVector( normal, arch * 4 * v * ( 1 - v ) * 0.025 );
271
+
272
+ }
273
+
274
+ p.toArray( positions, positions.length );
275
+ uvs.push( u, v );
276
+
277
+ if ( x < columns && y < rows ) {
278
+
279
+ const a = y * ( columns + 1 ) + x, b = a + 1, d = a + columns + 1, c = d + 1;
280
+ indices.push( a, b, d, b, c, d );
281
+
282
+ }
283
+
284
+ }
285
+
286
+ }
287
+
288
+ geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
289
+ geometry.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
290
+ geometry.setIndex( indices );
291
+ geometry.computeVertexNormals();
292
+ return part( geometry, id );
293
+
294
+ }
295
+
296
+ function buildCarGeometry( spec ) {
297
+
298
+ const parts = [ buildBody( spec ) ];
299
+ const corner = ( point, side ) => new Vector3( point[ 0 ] * side, point[ 1 ], point[ 2 ] );
300
+ const fl = corner( spec.front.base, - 1 ), fr = corner( spec.front.base, 1 );
301
+ const rl = corner( spec.rear.base, - 1 ), rr = corner( spec.rear.base, 1 );
302
+ const tfl = corner( spec.front.roof, - 1 ), tfr = corner( spec.front.roof, 1 );
303
+ const trl = corner( spec.rear.roof, - 1 ), trr = corner( spec.rear.roof, 1 );
304
+
305
+ parts.push(
306
+ panel( [ fl, fr, tfr, tfl ], WINDOW, true ),
307
+ panel( [ rr, rl, trl, trr ], WINDOW, true ),
308
+ panel( [ fr, rr, trr, tfr ], WINDOW ),
309
+ panel( [ rl, fl, tfl, trl ], WINDOW )
310
+ );
311
+
312
+ const roof = [ spec.front.roof, spec.rear.roof ].map( ( [ width, y, z ] ) => Array.from( { length: 5 }, ( _, i ) => {
313
+
314
+ const u = i / 4;
315
+ return new Vector3( ( u * 2 - 1 ) * width, y + 4 * u * ( 1 - u ) * 0.035, z );
316
+
317
+ } ) );
318
+ parts.push( part( new LoftGeometry( roof, { closed: false } ), BODY ) );
319
+
320
+ const r = spec.wheelRadius;
321
+ const rim = r * 0.64;
322
+ const width = r * 0.68;
323
+ const wheelProfile = [
324
+ new Vector2( r * 0.93, - width * 0.44 ),
325
+ new Vector2( r, - width * 0.12 ),
326
+ new Vector2( r * 0.98, width * 0.27 ),
327
+ new Vector2( rim + 0.014, width * 0.44 )
328
+ ];
329
+
330
+ for ( const side of [ - 1, 1 ] ) {
331
+
332
+ for ( const z of [ - spec.wheelZ, spec.wheelZ ] ) {
333
+
334
+ const x = side * spec.wheelX;
335
+ const tyre = new LatheGeometry( wheelProfile, 24 ).rotateZ( - side * Math.PI / 2 ).translate( x, r, z );
336
+ const lip = new LatheGeometry( [ new Vector2( rim + 0.014, width * 0.44 ), new Vector2( rim, width * 0.29 ) ], 24 ).rotateZ( - side * Math.PI / 2 ).translate( x, r, z );
337
+ const hub = new CircleGeometry( rim, 24 );
338
+ hub.attributes.position.setZ( 0, - 0.015 );
339
+ hub.computeVertexNormals();
340
+ hub.rotateY( side * Math.PI / 2 ).translate( x + side * width * 0.29, r, z );
341
+ const well = new CircleGeometry( r + 0.06, 8, 0, Math.PI ).rotateY( side * Math.PI / 2 ).translate( x - side * ( width * 0.5 + 0.02 ), r, z );
342
+
343
+ parts.push( part( tyre, TYRE ), part( lip, ALLOY ), part( hub, ALLOY ), part( well, TRIM ) );
344
+
345
+ }
346
+
347
+ const mirror = new BoxGeometry( 0.16, 0.1, 0.2 ).rotateY( side * 0.2 ).translate( side * ( spec.body[ 2 ][ 1 ] + 0.06 ), spec.front.base[ 1 ] + 0.05, spec.front.base[ 2 ] - 0.16 );
348
+ parts.push( part( mirror, MIRROR ) );
349
+
350
+ if ( spec.rails ) {
351
+
352
+ const sections = [ 0.06, 0.13, 0.87, 0.94 ].map( ( t, i ) => {
353
+
354
+ const z = tfr.z + ( trr.z - tfr.z ) * t;
355
+ const roofWidth = tfr.x + ( trr.x - tfr.x ) * t;
356
+ const y = tfr.y + ( trr.y - tfr.y ) * t + ( 1 - ( 0.63 / roofWidth ) ** 2 ) * 0.035 + ( i === 0 || i === 3 ? 0.005 : 0.05 );
357
+ const x = side * 0.63;
358
+ return [ new Vector3( x - 0.022, y - 0.018, z ), new Vector3( x + 0.022, y - 0.018, z ), new Vector3( x + 0.022, y + 0.018, z ), new Vector3( x - 0.022, y + 0.018, z ) ].reverse();
359
+
360
+ } );
361
+ parts.push( part( new LoftGeometry( sections, { capStart: true, capEnd: true } ), TRIM ) );
362
+
363
+ }
364
+
365
+ }
366
+
367
+ if ( spec.sign ) {
368
+
369
+ const roofY = ( tfr.y + trr.y ) / 2 + 0.04;
370
+ const section = ( w, d, y ) => [ new Vector3( w, y, d ), new Vector3( - w, y, d ), new Vector3( - w, y, - d ), new Vector3( w, y, - d ) ];
371
+ const sign = new LoftGeometry( [ section( 0.16, 0.065, roofY + 0.1 ), section( 0.20, 0.095, roofY ) ], { capStart: true, capEnd: true } ).translate( 0, 0, - 0.2 );
372
+ parts.push( part( sign, SIGN ) );
373
+
374
+ }
375
+
376
+ return mergeGeometries( parts );
377
+
378
+ }
379
+
380
+ function roundedRect( point, halfSize, radius ) {
381
+
382
+ const q = point.abs().sub( halfSize ).add( radius );
383
+ const distance = q.max( 0 ).length().add( q.x.max( q.y ).min( 0 ) ).sub( radius );
384
+ const edge = distance.fwidth().max( 0.001 );
385
+ return smoothstep( edge, edge.negate(), distance );
386
+
387
+ }
388
+
389
+ function createCarMaterial( spec ) {
390
+
391
+ // Dimensions are uniforms, keeping one shader pipeline across body types.
392
+ const paint = attribute( 'paintColor', 'vec3' );
393
+ const axle = uniform( spec.wheelZ );
394
+ const radius = uniform( spec.wheelRadius );
395
+ const lamps = uniform( new Vector2( ...spec.lamps ) );
396
+ const belt = uniform( spec.front.base[ 1 ] );
397
+ const doorEnd = spec.rails ? spec.pillars[ 1 ] - 0.08 : spec.rear.base[ 2 ] + 0.1;
398
+ const seams = uniform( new Vector3( spec.front.base[ 2 ] - 0.04, spec.pillars[ 0 ], doorEnd ) );
399
+ const handles = uniform( new Vector2( spec.pillars[ 0 ] + 0.17, doorEnd + 0.17 ) );
400
+ const pillars = uniformArray( [ spec.pillars[ 0 ], spec.pillars[ 1 ] ?? 9 ] );
401
+
402
+ const partId = varying( attribute( 'partId', 'float' ) ).setInterpolation( InterpolationSamplingType.FLAT, InterpolationSamplingMode.EITHER );
403
+ const isWindow = partId.equal( WINDOW );
404
+ const isTyre = partId.equal( TYRE );
405
+ const isAlloy = partId.equal( ALLOY );
406
+ const isTrim = partId.equal( TRIM );
407
+ const isMirror = partId.equal( MIRROR );
408
+ const isSign = partId.equal( SIGN );
409
+ const p = positionGeometry;
410
+ const side = normalGeometry.x.abs().greaterThan( 0.5 );
411
+
412
+ // Rounded panes and their rubber seals follow the panel UVs. Only the side
413
+ // panes receive pillars, leaving both windscreens uninterrupted.
414
+ const paneUV = uv().sub( 0.5 );
415
+ let glass = roundedRect( paneUV, vec2( 0.455, 0.405 ), 0.035 );
416
+ let seal = roundedRect( paneUV, vec2( 0.47, 0.43 ), 0.045 );
417
+ for ( let i = 0; i < 2; i ++ ) {
418
+
419
+ const distance = p.z.sub( pillars.element( i ) ).abs();
420
+ glass = glass.mul( select( side, smoothstep( 0.043, 0.053, distance ), 1 ) );
421
+ seal = seal.mul( select( side, smoothstep( 0.026, 0.035, distance ), 1 ) );
422
+
423
+ }
424
+
425
+ const windowColor = mix( mix( paint, color( 0x13191c ), seal ), color( 0x1d2b35 ), glass );
426
+ const mirrorGlass = isMirror.and( normalGeometry.z.lessThan( - 0.5 ) );
427
+ const glazing = select( isWindow, glass, select( mirrorGlass, 1, 0 ) );
428
+
429
+ const wheel = vec2( p.z.abs().sub( axle ), p.y.sub( radius ) );
430
+ const wheelDistance = wheel.length();
431
+ const flank = smoothstep( 0.65, 0.85, p.x.abs() );
432
+ const archShade = smoothstep( radius.add( 0.025 ), radius.add( 0.095 ), wheelDistance );
433
+ const shading = mix( float( 1 ), archShade.mul( 0.28 ).add( 0.72 ), flank ).mul( smoothstep( 0.25, 0.65, p.y ).mul( 0.3 ).add( 0.7 ) );
434
+
435
+ let seam = float( 0 );
436
+ for ( const z of [ seams.x, seams.y, seams.z ] ) seam = seam.max( smoothstep( 0.012, 0.004, p.z.sub( z ).abs() ) );
437
+ for ( const z of [ handles.x, handles.y ] ) seam = seam.max( roundedRect( vec2( p.z.sub( z ), p.y.sub( belt.sub( 0.10 ) ) ), vec2( 0.06, 0.011 ), 0.006 ) );
438
+ seam = seam.mul( flank ).mul( smoothstep( 0.36, 0.43, p.y ) ).mul( smoothstep( belt, belt.sub( 0.025 ), p.y ) );
439
+ let bodyColor = paint.mul( shading ).mul( seam.mul( 0.5 ).oneMinus() );
440
+
441
+ // Lamps, grille, number plates and bumper inlets are inset into the fascia.
442
+ // The front and rear caps supply their silhouettes without floating boxes.
443
+ const front = partId.equal( FRONT );
444
+ const rear = partId.equal( REAR );
445
+ const end = front.or( rear );
446
+ const lampY = select( front, lamps.x, lamps.y );
447
+ const light = roundedRect( vec2( p.x.abs().sub( 0.61 ), p.y.sub( lampY ) ), vec2( 0.19, 0.055 ), 0.018 ).mul( select( end, 1, 0 ) );
448
+ const grille = roundedRect( vec2( p.x, p.y.sub( lamps.x.sub( 0.025 ) ) ), vec2( 0.30, 0.075 ), 0.025 ).mul( select( front, 1, 0 ) );
449
+ const intake = roundedRect( vec2( p.x, p.y.sub( lampY.sub( 0.29 ) ) ), vec2( 0.66, 0.045 ), 0.03 ).mul( select( end, 1, 0 ) );
450
+ const plateY = select( front, lamps.x.sub( 0.20 ), lamps.y.sub( 0.17 ) );
451
+ const plate = roundedRect( vec2( p.x, p.y.sub( plateY ) ), vec2( 0.155, 0.055 ), 0.008 ).mul( select( end, 1, 0 ) );
452
+ const slats = p.y.mul( 65 ).fract().step( 0.5 ).mul( 0.35 ).add( 0.65 );
453
+ bodyColor = mix( bodyColor, color( 0x161a1c ).mul( slats ), grille.max( intake ) );
454
+ bodyColor = mix( bodyColor, color( 0xd8d9d3 ), plate );
455
+ bodyColor = mix( bodyColor, select( front, color( 0xd1e4eb ), color( 0x7b1015 ) ), light );
456
+
457
+ const spokeAngle = atan( wheel.y, wheel.x ).mul( 5 / ( Math.PI * 2 ) );
458
+ const spokes = smoothstep( 0.62, 0.42, spokeAngle.fract().sub( 0.5 ).abs().mul( 2 ) );
459
+ const rim = smoothstep( radius.mul( 0.53 ), radius.mul( 0.59 ), wheelDistance );
460
+ const hub = smoothstep( 0.06, 0.035, wheelDistance );
461
+ const alloy = mix( color( 0x171b20 ), color( 0xafb6ba ), spokes.max( rim ).max( hub ) );
462
+ const tyre = color( 0x18191b ).mul( smoothstep( radius.mul( 0.85 ), radius.mul( 0.94 ), wheelDistance ).mul( 0.2 ).add( 0.8 ) );
463
+
464
+ const material = new MeshStandardNodeMaterial();
465
+ material.colorNode = select( isTyre, tyre,
466
+ select( isAlloy, alloy,
467
+ select( isTrim, color( 0x202326 ),
468
+ select( isSign, color( 0xffd66a ),
469
+ select( isWindow, windowColor,
470
+ select( mirrorGlass, color( 0x70808a ), bodyColor ) ) ) ) ) );
471
+ material.roughnessNode = select( isTyre.or( isTrim ), float( 0.85 ), mix( float( 0.32 ), float( 0.055 ), glazing ) );
472
+ material.metalnessNode = select( isAlloy, float( 0.8 ), select( isTyre.or( isTrim ).or( isSign ), float( 0 ), mix( float( 0.25 ), float( 0.85 ), glazing ) ) );
473
+ material.emissiveNode = select( front, color( 0xd9efff ).mul( 4 ), color( 0xf00008 ).mul( 1.5 ) ).mul( light ).add( select( isSign, color( 0xffd77b ).mul( 2 ), color( 0x000000 ) ) );
474
+
475
+ return material;
476
+
477
+ }
478
+
479
+ export { CarGenerator };
@@ -0,0 +1,31 @@
1
+ import { BufferAttribute } from '@gnsx/three';
2
+ import { normalView, positionView } from '@gnsx/three/tsl';
3
+ import { mergeVertices } from '../../utils/BufferGeometryUtils.js';
4
+
5
+ // Keep parts indexed and tag their material zone before merging.
6
+ function part( geometry, id ) {
7
+
8
+ const g = geometry.index ? geometry : mergeVertices( geometry );
9
+ g.setAttribute( 'partId', new BufferAttribute( new Float32Array( g.attributes.position.count ).fill( id ), 1 ) );
10
+ return g;
11
+
12
+ }
13
+
14
+ // derivative-based bump for a procedural, world-space height field. the built-in bumpMap
15
+ // offsets the UV to read its height, so it returns a zero gradient for a height keyed off
16
+ // world position; this feeds the hardware screen-space derivatives of the height into
17
+ // Mikkelsen's surface-gradient method so the relief actually perturbs the normal.
18
+ function bumpNormal( height ) {
19
+
20
+ const dpdx = positionView.dFdx();
21
+ const dpdy = positionView.dFdy();
22
+ const r1 = dpdy.cross( normalView );
23
+ const r2 = normalView.cross( dpdx );
24
+ const det = dpdx.dot( r1 );
25
+ const grad = det.sign().mul( height.dFdx().mul( r1 ).add( height.dFdy().mul( r2 ) ) );
26
+
27
+ return det.abs().mul( normalView ).sub( grad ).normalize();
28
+
29
+ }
30
+
31
+ export { part, bumpNormal };
@@ -0,0 +1,106 @@
1
+ import {
2
+ CylinderGeometry,
3
+ InterpolationSamplingMode,
4
+ InterpolationSamplingType,
5
+ SphereGeometry
6
+ } from '@gnsx/three';
7
+
8
+ import { MeshStandardNodeMaterial } from '@gnsx/three/webgpu';
9
+ import { attribute, color, float, mix, mx_fractal_noise_float, positionGeometry, select, smoothstep, varying } from '@gnsx/three/tsl';
10
+
11
+ import { mergeGeometries } from '../../utils/BufferGeometryUtils.js';
12
+
13
+ import { InstancedMeshGenerator } from './InstancedMeshGenerator.js';
14
+ import { part } from './CityGeneratorUtils.js';
15
+
16
+ /**
17
+ * A classic cast-iron fire hydrant: a stout barrel on a flared footing, capped by a
18
+ * domed bonnet and a hex operating nut, with two side outlet nozzles and a larger
19
+ * front pumper nozzle. Built once and instanced across a list of placements, dressed
20
+ * with one cheap material that branches on a baked `partId` ( weathered red iron,
21
+ * bare metal caps ).
22
+ *
23
+ * The canonical model stands on `y = 0`, centred in X / Z, with the pumper nozzle
24
+ * facing `+Z`, so a placement whose local `+Z` faces the road presents it to traffic.
25
+ *
26
+ * ```js
27
+ * const hydrants = new HydrantGenerator();
28
+ * scene.add( hydrants.build( placements ) ); // placements: Matrix4[]
29
+ * ```
30
+ */
31
+ class HydrantGenerator extends InstancedMeshGenerator {
32
+
33
+ constructor( parameters = {} ) {
34
+
35
+ super( parameters, buildHydrantGeometry, createHydrantMaterial, 'Hydrants' );
36
+
37
+ }
38
+
39
+ }
40
+
41
+ HydrantGenerator.defaults = {
42
+ radius: 0.13, // barrel radius
43
+ height: 0.55 // barrel height ( footing, bonnet and nut bring the total to ~0.9 m )
44
+ };
45
+
46
+ // material-zone codes baked per vertex
47
+ const BODY = 0, CAP = 1;
48
+
49
+ function buildHydrantGeometry( p ) {
50
+
51
+ const r = p.radius, h = p.height;
52
+
53
+ const footing = new CylinderGeometry( r * 1.5, r * 1.7, 0.08, 12 ).translate( 0, 0.04, 0 );
54
+ const barrel = new CylinderGeometry( r, r * 1.1, h, 12 ).translate( 0, 0.08 + h / 2, 0 );
55
+ const shoulder = new CylinderGeometry( r * 0.65, r, 0.12, 12 ).translate( 0, 0.69, 0 ); // taper up to the bonnet
56
+ const dome = new SphereGeometry( r * 0.65, 10, 4, 0, Math.PI * 2, 0, Math.PI / 2 ).translate( 0, 0.75, 0 );
57
+ const nut = new CylinderGeometry( 0.05, 0.05, 0.07, 6 ).translate( 0, 0.87, 0 ); // hex operating nut on top
58
+
59
+ // bolted flange rings where the castings meet: at the bonnet and above the footing
60
+ const bonnetFlange = new CylinderGeometry( r * 1.18, r * 1.18, 0.035, 12 ).translate( 0, 0.645, 0 );
61
+ const baseFlange = new CylinderGeometry( r * 1.28, r * 1.28, 0.04, 12 ).translate( 0, 0.11, 0 );
62
+
63
+ // left and right outlet nozzles, stubs finished with a bare cap, set just below mid-barrel
64
+ const nozzleL = new CylinderGeometry( 0.06, 0.06, 0.12, 8 ).rotateZ( Math.PI / 2 ).translate( - ( r + 0.03 ), 0.45, 0 );
65
+ const capL = new CylinderGeometry( 0.07, 0.07, 0.025, 8 ).rotateZ( Math.PI / 2 ).translate( - ( r + 0.102 ), 0.45, 0 );
66
+ const nozzleR = new CylinderGeometry( 0.06, 0.06, 0.12, 8 ).rotateZ( Math.PI / 2 ).translate( r + 0.03, 0.45, 0 );
67
+ const capR = new CylinderGeometry( 0.07, 0.07, 0.025, 8 ).rotateZ( Math.PI / 2 ).translate( r + 0.102, 0.45, 0 );
68
+
69
+ // larger front pumper nozzle, faces +Z toward the road
70
+ const pumper = new CylinderGeometry( 0.075, 0.075, 0.12, 8 ).rotateX( Math.PI / 2 ).translate( 0, 0.4, r + 0.03 );
71
+ const pumperCap = new CylinderGeometry( 0.085, 0.085, 0.025, 8 ).rotateX( Math.PI / 2 ).translate( 0, 0.4, r + 0.102 );
72
+
73
+ return mergeGeometries( [
74
+ part( footing, BODY ), part( barrel, BODY ), part( shoulder, BODY ), part( dome, BODY ),
75
+ part( bonnetFlange, BODY ), part( baseFlange, BODY ),
76
+ part( nozzleL, BODY ), part( nozzleR, BODY ), part( pumper, BODY ),
77
+ part( capL, CAP ), part( capR, CAP ), part( pumperCap, CAP ), part( nut, CAP )
78
+ ] );
79
+
80
+ }
81
+
82
+ function createHydrantMaterial() {
83
+
84
+ const partId = varying( attribute( 'partId', 'float' ) ).setInterpolation( InterpolationSamplingType.FLAT, InterpolationSamplingMode.EITHER );
85
+ const isCap = partId.equal( CAP );
86
+
87
+ const p = positionGeometry;
88
+
89
+ // decades of repaints: the red fades patchily, and rust blooms up from the
90
+ // footing and wherever the paint has flaked through
91
+ const wear = mx_fractal_noise_float( p.mul( 9 ), 3 ).mul( 0.5 ).add( 0.5 );
92
+ const faded = mix( color( 0x8f2f1e ), color( 0xb85a38 ), wear.mul( 0.6 ) );
93
+
94
+ const rustMask = smoothstep( 0.28, 0.02, p.y ).max( smoothstep( 0.55, 0.85, wear ).mul( 0.5 ) );
95
+ const body = mix( faded, color( 0x4a2c1a ), rustMask.mul( 0.8 ) );
96
+
97
+ const material = new MeshStandardNodeMaterial();
98
+ material.colorNode = select( isCap, color( 0x8a8a80 ), body ); // bare metal caps over the weathered red
99
+ material.roughnessNode = select( isCap, float( 0.45 ), wear.mul( 0.3 ).add( rustMask.mul( 0.25 ) ).add( 0.5 ) );
100
+ material.metalnessNode = select( isCap, float( 0.8 ), float( 0.15 ) );
101
+
102
+ return material;
103
+
104
+ }
105
+
106
+ export { HydrantGenerator };
@@ -0,0 +1,86 @@
1
+ import { InstancedMesh, MathUtils } from '@gnsx/three';
2
+
3
+ // Shared lifecycle for street furniture with one geometry and material.
4
+ class InstancedMeshGenerator {
5
+
6
+ constructor( parameters, createGeometry, createMaterial, name, receiveShadow = true ) {
7
+
8
+ this.parameters = Object.assign( {}, this.constructor.defaults, parameters );
9
+ this.geometry = null;
10
+ this.material = null;
11
+ this.mesh = null;
12
+
13
+ this._createGeometry = createGeometry;
14
+ this._createMaterial = createMaterial;
15
+ this._name = name;
16
+ this._receiveShadow = receiveShadow;
17
+ this._parametersKey = null;
18
+
19
+ }
20
+
21
+ build( placements ) {
22
+
23
+ const parametersKey = JSON.stringify( this.parameters );
24
+
25
+ if ( parametersKey !== this._parametersKey || ( this.mesh && placements.length > this.mesh.instanceMatrix.count ) ) {
26
+
27
+ this.dispose();
28
+ this._parametersKey = parametersKey;
29
+
30
+ }
31
+
32
+ if ( this.geometry === null ) this.geometry = this._createGeometry( this.parameters );
33
+ if ( this.material === null ) this.material = this._createMaterial();
34
+
35
+ if ( this.mesh === null ) {
36
+
37
+ this.mesh = createInstances( this.geometry, this.material, placements.length, this._name );
38
+ this.mesh.receiveShadow = this._receiveShadow;
39
+
40
+ }
41
+
42
+ updateInstances( this.mesh, placements );
43
+
44
+ return this.mesh;
45
+
46
+ }
47
+
48
+ dispose() {
49
+
50
+ if ( this.geometry ) this.geometry.dispose();
51
+ if ( this.mesh ) this.mesh.dispose();
52
+ if ( this.material ) this.material.dispose();
53
+
54
+ this.geometry = null;
55
+ this.material = null;
56
+ this.mesh = null;
57
+
58
+ }
59
+
60
+ }
61
+
62
+ function createInstances( geometry, material, count, name ) {
63
+
64
+ const capacity = MathUtils.ceilPowerOfTwo( Math.max( 1, count ) );
65
+ const mesh = new InstancedMesh( geometry, material, capacity );
66
+ mesh.castShadow = mesh.receiveShadow = true;
67
+ mesh.name = name;
68
+
69
+ return mesh;
70
+
71
+ }
72
+
73
+ function updateInstances( mesh, placements ) {
74
+
75
+ mesh.count = placements.length;
76
+ mesh.visible = placements.length > 0;
77
+
78
+ for ( let i = 0; i < placements.length; i ++ ) mesh.setMatrixAt( i, placements[ i ] );
79
+
80
+ mesh.instanceMatrix.needsUpdate = true;
81
+ mesh.boundingBox = null;
82
+ mesh.computeBoundingSphere();
83
+
84
+ }
85
+
86
+ export { InstancedMeshGenerator, createInstances, updateInstances };