@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,13 +1,26 @@
1
1
  import {
2
+ BoxGeometry,
2
3
  Group,
3
- Matrix4
4
+ InstancedMesh,
5
+ Matrix4,
6
+ Quaternion,
7
+ Vector3
4
8
  } from '@gnsx/three';
5
9
 
6
10
  import { MeshStandardNodeMaterial } from '@gnsx/three/webgpu';
7
- import { cameraPosition, color, float, floor, Fn, fract, fwidth, hash, If, mix, mod, mx_fractal_noise_float, mx_noise_float, normalView, positionView, positionWorld, smoothstep, step, uint, varying, vec4 } from '@gnsx/three/tsl';
11
+ import { cameraPosition, color, float, floor, Fn, fract, fwidth, hash, If, mix, mod, mx_fractal_noise_float, mx_noise_float, positionWorld, smoothstep, step, uint, uniform, varying, vec4 } from '@gnsx/three/tsl';
8
12
 
9
13
  import { SkyscraperGenerator, createSkyscraperMaterial, buildingPalette } from './city/SkyscraperGenerator.js';
10
14
  import { SidewalkGenerator } from './city/SidewalkGenerator.js';
15
+ import { StreetlightGenerator } from './city/StreetlightGenerator.js';
16
+ import { TrafficlightGenerator } from './city/TrafficlightGenerator.js';
17
+ import { TrashcanGenerator } from './city/TrashcanGenerator.js';
18
+ import { BenchGenerator } from './city/BenchGenerator.js';
19
+ import { HydrantGenerator } from './city/HydrantGenerator.js';
20
+ import { StreetTreeGenerator } from './city/StreetTreeGenerator.js';
21
+ import { CarGenerator } from './city/CarGenerator.js';
22
+ import { PersonGenerator } from './city/PersonGenerator.js';
23
+ import { bumpNormal } from './city/CityGeneratorUtils.js';
11
24
 
12
25
  /**
13
26
  * Lays out a grid of city blocks and fills each lot with a {@link SkyscraperGenerator}
@@ -31,30 +44,69 @@ class CityGenerator {
31
44
  this.parameters = Object.assign( {}, CityGenerator.defaults, parameters );
32
45
  this.layout = cityLayout( this.parameters );
33
46
 
47
+ /**
48
+ * The city seed shared by building and proxy materials. Pass this to
49
+ * {@link createBuildingMaterial} to update the palette when rebuilding.
50
+ *
51
+ * @type {UniformNode<uint>}
52
+ */
53
+ this.seedNode = uniform( this.parameters.seed, 'uint' );
54
+
34
55
  this.generators = [];
56
+
57
+ // per-tower box specs recorded during build(), consumed by buildProxy()
58
+ this.towers = [];
59
+
35
60
  this.sidewalk = new SidewalkGenerator( {
36
61
  width: this.layout.blockW,
37
62
  depth: this.layout.blockD,
38
63
  height: this.parameters.curbHeight,
39
64
  radius: this.parameters.curbRadius
40
65
  } );
66
+
67
+ // the street-furniture generators, each instanced across placements the
68
+ // layout hands them ( see buildFurniture )
69
+ this.furniture = {
70
+ streetlight: new StreetlightGenerator(),
71
+ trafficlight: new TrafficlightGenerator(),
72
+ trashcan: new TrashcanGenerator(),
73
+ bench: new BenchGenerator(),
74
+ hydrant: new HydrantGenerator(),
75
+ tree: new StreetTreeGenerator(),
76
+ car: new CarGenerator(),
77
+ person: new PersonGenerator()
78
+ };
79
+
41
80
  this.group = null;
42
81
 
43
82
  }
44
83
 
45
84
  build( materials = {} ) {
46
85
 
47
- this.dispose();
86
+ this.seedNode.value = this.parameters.seed;
87
+
88
+ for ( const generator of this.generators ) generator.dispose();
89
+ this.generators.length = 0;
90
+
91
+ if ( this.group ) {
92
+
93
+ this.group.clear();
94
+ this.group.dispose();
95
+
96
+ }
48
97
 
49
98
  const group = new Group();
50
99
  group.name = 'City';
51
100
 
101
+ this.towers = [];
102
+
52
103
  const L = this.layout;
53
104
  const random = createRandom( this.parameters.seed );
54
105
 
55
106
  // raise the lots onto rounded sidewalk slabs ( curbs ) when curbHeight > 0
56
107
 
57
108
  const curb = this.parameters.curbHeight;
109
+ const sw = this.parameters.sidewalkWidth;
58
110
  const slabs = [];
59
111
 
60
112
  for ( let bx = 0; bx < L.blocksX; bx ++ ) {
@@ -70,6 +122,11 @@ class CityGenerator {
70
122
 
71
123
  }
72
124
 
125
+ // the lots sit in an inner zone set back from the block edge by the
126
+ // sidewalk width, so a real walking strip is left between the street
127
+ // wall and the curb. buildings front onto that building line.
128
+ const zoneX = blockX + sw, zoneZ = blockZ + sw;
129
+
73
130
  for ( let lx = 0; lx < L.lotsX; lx ++ ) {
74
131
 
75
132
  for ( let lz = 0; lz < L.lotsZ; lz ++ ) {
@@ -83,10 +140,17 @@ class CityGenerator {
83
140
 
84
141
  const tall = random();
85
142
 
143
+ // nearly fill the lot so neighbours abut into a continuous street
144
+ // wall; the small slack goes to the interior side ( a light well )
145
+ const fw = L.innerLotX - ( 0.4 + random() * 1 );
146
+ const fd = L.innerLotZ - ( 0.4 + random() * 1 );
147
+
148
+ const totalHeight = 38 + tall * tall * 114; // a few tall towers, mostly mid-rise
149
+
86
150
  const generator = new SkyscraperGenerator( {
87
151
  seed: Math.floor( random() * 100000 ),
88
- totalHeight: 38 + tall * tall * 114, // a few tall towers, mostly mid-rise
89
- footprint: { width: L.lot - 1 - random() * 4, depth: L.lot - 1 - random() * 4 }, // nearly fill the lot so neighbours sit close; width and depth vary independently
152
+ totalHeight,
153
+ footprint: { width: fw, depth: fd },
90
154
  floorHeight: 3.4 + random() * 1.8,
91
155
  bayWidth: 1.9 + random() * 2.1,
92
156
  pierWidth: 0.4 + random() * 0.5,
@@ -99,12 +163,21 @@ class CityGenerator {
99
163
  }, materials.building );
100
164
 
101
165
  const building = generator.build();
102
- building.position.set( blockX + ( lx + 0.5 ) * L.lot, curb, blockZ + ( lz + 0.5 ) * L.lot );
166
+
167
+ // place within the lot, fronted toward the streets it borders so its
168
+ // outer faces land on the building line; interior columns stay centred
169
+ const lotLeft = zoneX + lx * L.innerLotX, lotNear = zoneZ + lz * L.innerLotZ;
170
+ const cx = cornerX === - 1 ? lotLeft + fw / 2 : ( cornerX === 1 ? lotLeft + L.innerLotX - fw / 2 : lotLeft + L.innerLotX / 2 );
171
+ const cz = cornerZ === - 1 ? lotNear + fd / 2 : ( cornerZ === 1 ? lotNear + L.innerLotZ - fd / 2 : lotNear + L.innerLotZ / 2 );
172
+ building.position.set( cx, curb, cz );
103
173
  building.castShadow = building.receiveShadow = true;
104
174
 
105
175
  group.add( building );
106
176
  this.generators.push( generator );
107
177
 
178
+ // record a plain box matching this tower for the GI proxy
179
+ this.towers.push( { x: cx, y: curb + totalHeight / 2, z: cz, w: fw, h: totalHeight, d: fd } );
180
+
108
181
  }
109
182
 
110
183
  }
@@ -113,7 +186,9 @@ class CityGenerator {
113
186
 
114
187
  }
115
188
 
116
- if ( slabs.length > 0 ) group.add( this.sidewalk.build( slabs ) );
189
+ group.add( this.sidewalk.build( slabs ) );
190
+
191
+ group.add( this.buildFurniture( random ) );
117
192
 
118
193
  this.group = group;
119
194
 
@@ -121,6 +196,181 @@ class CityGenerator {
121
196
 
122
197
  }
123
198
 
199
+ /**
200
+ * Builds a lightweight stand-in for the city: one instanced box per tower,
201
+ * sized to match, in a single draw call. Intended for cheap global-illumination
202
+ * bakes, where the detailed facades and street furniture are unnecessary and the
203
+ * boxes still cast the same street shadows and bounce the same warm fill.
204
+ *
205
+ * Call after {@link CityGenerator#build}, which records the tower boxes.
206
+ *
207
+ * @return {InstancedMesh} The proxy mesh.
208
+ */
209
+ buildProxy() {
210
+
211
+ const towers = this.towers;
212
+
213
+ // each box takes its tower's own masonry colour ( same node, keyed off world
214
+ // position ), so the GI bleeds the real per-building tints. mid roughness / metalness
215
+ // give the boxes a soft, part-glazed sky reflection.
216
+ const material = new MeshStandardNodeMaterial( { roughness: 0.4, metalness: 0.4 } );
217
+ material.colorNode = buildingColorNode( this.layout, this.seedNode );
218
+ const mesh = new InstancedMesh( new BoxGeometry( 1, 1, 1 ), material, towers.length );
219
+ mesh.name = 'CityProxy';
220
+
221
+ const matrix = new Matrix4();
222
+
223
+ for ( let i = 0; i < towers.length; i ++ ) {
224
+
225
+ const t = towers[ i ];
226
+ matrix.makeScale( t.w, t.h, t.d );
227
+ matrix.setPosition( t.x, t.y, t.z );
228
+ mesh.setMatrixAt( i, matrix );
229
+
230
+ }
231
+
232
+ mesh.castShadow = true;
233
+ mesh.receiveShadow = true;
234
+
235
+ return mesh;
236
+
237
+ }
238
+
239
+ // dresses the sidewalks and roadway with instanced street furniture, walking the
240
+ // curb edge of every block so poles, baskets, trees, pedestrians and parked cars
241
+ // all align to the same grid the buildings and road markings use
242
+ buildFurniture( random ) {
243
+
244
+ const L = this.layout;
245
+ const top = this.parameters.curbHeight; // sidewalk surface the furniture stands on
246
+ const sw = this.parameters.sidewalkWidth;
247
+ const group = new Group();
248
+ group.name = 'StreetFurniture';
249
+
250
+ const lights = [], signals = [], cans = [], benches = [], hydrants = [], trees = [], people = [], cars = [];
251
+
252
+ // the kerbside mix of a New York street: yellow cabs over an almost
253
+ // entirely grayscale fleet ( black livery cars, whites, silvers,
254
+ // graphites ), with a dark navy, a burgundy or a bronze only here and
255
+ // there. cumulative weights, so common colours repeat like they do kerb
256
+ // to kerb
257
+ const carColor = () => {
258
+
259
+ const r = random();
260
+ for ( const [ threshold, color ] of CAR_COLORS ) if ( r < threshold ) return color;
261
+ return CAR_COLORS[ CAR_COLORS.length - 1 ][ 1 ];
262
+
263
+ };
264
+
265
+ for ( let bx = 0; bx < L.blocksX; bx ++ ) {
266
+
267
+ for ( let bz = 0; bz < L.blocksZ; bz ++ ) {
268
+
269
+ const blockX = - L.cityW / 2 + bx * ( L.blockW + L.street );
270
+ const blockZ = - L.cityD / 2 + bz * ( L.blockD + L.street );
271
+ const edges = blockEdges( blockX, blockZ, L.blockW, L.blockD );
272
+
273
+ for ( const e of edges ) {
274
+
275
+ const len = e.length;
276
+
277
+ // cars on opposite kerbs of a street face opposite ways ( with the
278
+ // traffic on their side ), keyed off which way the kerb faces
279
+ const fdir = Math.sign( e.nx + e.nz ) || 1;
280
+
281
+ // a point on the sidewalk, `lateral` metres in from the curb
282
+ const onWalk = ( t, lateral ) => place( e.x0 + e.dx * t - e.nx * lateral, top, e.z0 + e.dz * t - e.nz * lateral, e.nx, e.nz );
283
+
284
+ // streetlights spaced along the curb, facing the road so the arm reaches over it
285
+ const lc = Math.max( 1, Math.round( len / 30 ) );
286
+ for ( let i = 0; i < lc; i ++ ) lights.push( onWalk( len * ( i + 0.5 ) / lc, 0.8 ) );
287
+
288
+ // street trees in curbside pits, offset from the lights, clear of the corners
289
+ const tc = Math.max( 1, Math.round( len / 16 ) );
290
+ for ( let i = 0; i < tc; i ++ ) {
291
+
292
+ const t = len * ( i + 0.5 ) / tc + 5;
293
+ if ( t > 7 && t < len - 7 && random() < 0.85 ) {
294
+
295
+ // random yaw and height so no two street trees read as copies
296
+ trees.push( placeYawScale( e.x0 + e.dx * t - e.nx * 1.5, top, e.z0 + e.dz * t - e.nz * 1.5, random() * Math.PI * 2, 0.8 + random() * 0.5 ) );
297
+
298
+ }
299
+
300
+ }
301
+
302
+ // a single hydrant on the kerb, its no-parking zone honoured below
303
+ const hydT = len * ( 0.25 + random() * 0.5 );
304
+ hydrants.push( onWalk( hydT, 0.7 ) );
305
+
306
+ // a bench facing the street on some edges
307
+ if ( random() < 0.4 ) benches.push( onWalk( len * ( 0.3 + random() * 0.4 ), 1.7 ) );
308
+
309
+ // pedestrians scattered across the walking strip, facing any way
310
+ const pc = Math.max( 2, Math.round( len / 9 ) );
311
+ for ( let i = 0; i < pc; i ++ ) {
312
+
313
+ if ( random() < 0.7 ) {
314
+
315
+ const t = len * ( i + random() ) / pc;
316
+ const lateral = 0.9 + random() * ( sw - 2 );
317
+ people.push( placeYawScale( e.x0 + e.dx * t - e.nx * lateral, top, e.z0 + e.dz * t - e.nz * lateral, random() * Math.PI * 2, 0.92 + random() * 0.16 ) );
318
+
319
+ }
320
+
321
+ }
322
+
323
+ // parked cars in the kerb lane, nose-to-tail with gaps, clear of the
324
+ // corners ( daylighting ) and the hydrant
325
+ for ( let t = 9; t < len - 9; t += 5.8 ) {
326
+
327
+ if ( Math.abs( t - hydT ) > 3 && random() < 0.72 ) {
328
+
329
+ cars.push( { matrix: place( e.x0 + e.dx * t + e.nx * 1.5, 0, e.z0 + e.dz * t + e.nz * 1.5, e.dx * fdir, e.dz * fdir ), color: carColor() } );
330
+
331
+ }
332
+
333
+ }
334
+
335
+ // the occasional vehicle out in a travel lane
336
+ for ( let t = 14; t < len - 14; t += 13 ) {
337
+
338
+ if ( random() < 0.4 ) cars.push( { matrix: place( e.x0 + e.dx * t + e.nx * 5.5, 0, e.z0 + e.dz * t + e.nz * 5.5, e.dx * fdir, e.dz * fdir ), color: carColor() } );
339
+
340
+ }
341
+
342
+ }
343
+
344
+ // at two opposite corners: a mast-arm signal reaching over the crossing,
345
+ // and a litter basket on every corner just along the kerb
346
+ const corners = [[ 0, 0 ], [ 1, 0 ], [ 0, 1 ], [ 1, 1 ]];
347
+ for ( const [ cx, cz ] of corners ) {
348
+
349
+ const x = blockX + cx * L.blockW, z = blockZ + cz * L.blockD;
350
+ const ix = cx ? - 1 : 1, iz = cz ? - 1 : 1; // inward, toward the block centre
351
+
352
+ if ( cx === cz ) signals.push( place( x + ix * 1.4, top, z + iz * 1.4, - ix, - iz ) );
353
+ cans.push( place( x + ix * 2.2, top, z + iz * 2.2, ix, iz ) );
354
+
355
+ }
356
+
357
+ }
358
+
359
+ }
360
+
361
+ group.add( this.furniture.streetlight.build( lights ) );
362
+ group.add( this.furniture.trafficlight.build( signals ) );
363
+ group.add( this.furniture.trashcan.build( cans ) );
364
+ group.add( this.furniture.bench.build( benches ) );
365
+ group.add( this.furniture.hydrant.build( hydrants ) );
366
+ group.add( this.furniture.tree.build( trees ) );
367
+ group.add( this.furniture.person.build( people ) );
368
+ group.add( this.furniture.car.build( cars ) );
369
+
370
+ return group;
371
+
372
+ }
373
+
124
374
  dispose() {
125
375
 
126
376
  for ( const generator of this.generators ) generator.dispose();
@@ -128,6 +378,10 @@ class CityGenerator {
128
378
 
129
379
  this.sidewalk.dispose();
130
380
 
381
+ for ( const key in this.furniture ) this.furniture[ key ].dispose();
382
+
383
+ if ( this.group ) this.group.dispose();
384
+
131
385
  this.group = null;
132
386
 
133
387
  }
@@ -143,19 +397,39 @@ CityGenerator.defaults = {
143
397
  blocksX: 2,
144
398
  blocksZ: 2,
145
399
  curbHeight: 0.15, // ~6 in standard curb reveal / sidewalk height above the road
146
- curbRadius: 5
400
+ curbRadius: 5,
401
+ sidewalkWidth: 5 // walkable strip between the street wall and the curb ( NYC ~15 ft )
147
402
  };
148
403
 
404
+ // kerbside paint mix sampled from Manhattan street photos: cumulative
405
+ // probability thresholds and the paint they select
406
+ const CAR_COLORS = [
407
+ [ 0.22, 0xf5c518 ], // yellow cab
408
+ [ 0.42, 0x111216 ], // black ( livery sedans and SUVs )
409
+ [ 0.59, 0xe9e8e3 ], // white
410
+ [ 0.72, 0xb2b5b8 ], // silver
411
+ [ 0.84, 0x3e4247 ], // graphite
412
+ [ 0.90, 0x74787c ], // mid grey
413
+ [ 0.95, 0x1c2a3f ], // dark navy
414
+ [ 0.98, 0x571f1f ], // burgundy
415
+ [ 1.01, 0x5c4834 ] // bronze
416
+ ];
417
+
149
418
  // derives the block / street dimensions from the parameters
150
419
  function cityLayout( parameters ) {
151
420
 
152
- const { street, lot, lotsX, lotsZ, blocksX, blocksZ } = parameters;
421
+ const { street, lot, lotsX, lotsZ, blocksX, blocksZ, sidewalkWidth } = parameters;
153
422
 
154
423
  const blockW = lotsX * lot;
155
424
  const blockD = lotsZ * lot;
156
425
 
426
+ // the lots tile the inner zone left after the sidewalk strip is taken from
427
+ // every edge; buildings front onto its perimeter ( the building line )
428
+ const innerLotX = ( blockW - 2 * sidewalkWidth ) / lotsX;
429
+ const innerLotZ = ( blockD - 2 * sidewalkWidth ) / lotsZ;
430
+
157
431
  return {
158
- street, lot, lotsX, lotsZ, blocksX, blocksZ, blockW, blockD,
432
+ street, lot, lotsX, lotsZ, blocksX, blocksZ, blockW, blockD, sidewalkWidth, innerLotX, innerLotZ,
159
433
  cityW: blocksX * blockW + ( blocksX - 1 ) * street,
160
434
  cityD: blocksZ * blockD + ( blocksZ - 1 ) * street
161
435
  };
@@ -178,25 +452,51 @@ function createRandom( seed ) {
178
452
 
179
453
  }
180
454
 
181
- // --- road material -------------------------------------------------------
455
+ // --- furniture placement -------------------------------------------------
456
+
457
+ // the four curb edges of a block: each carries a start corner, a unit direction
458
+ // along the edge, the outward normal ( toward the road ) and a length. furniture
459
+ // walks these, insetting against the normal to sit on the sidewalk.
460
+ function blockEdges( x, z, w, d ) {
461
+
462
+ return [
463
+ { x0: x, z0: z, dx: 1, dz: 0, nx: 0, nz: - 1, length: w },
464
+ { x0: x, z0: z + d, dx: 1, dz: 0, nx: 0, nz: 1, length: w },
465
+ { x0: x, z0: z, dx: 0, dz: 1, nx: - 1, nz: 0, length: d },
466
+ { x0: x + w, z0: z, dx: 0, dz: 1, nx: 1, nz: 0, length: d }
467
+ ];
468
+
469
+ }
182
470
 
183
- // derivative-based bump for a procedural, world-space height field. the built-in bumpMap
184
- // offsets the UV to read its height, so it returns a zero gradient for a height keyed off
185
- // world position; this feeds the hardware screen-space derivatives of the height into
186
- // Mikkelsen's surface-gradient method so the relief actually perturbs the normal.
187
- function bumpNormal( height ) {
471
+ const _f = /*@__PURE__*/ new Vector3();
472
+ const _r = /*@__PURE__*/ new Vector3();
473
+ const _up = /*@__PURE__*/ new Vector3( 0, 1, 0 );
188
474
 
189
- const dpdx = positionView.dFdx();
190
- const dpdy = positionView.dFdy();
191
- const r1 = dpdy.cross( normalView );
192
- const r2 = normalView.cross( dpdx );
193
- const det = dpdx.dot( r1 );
194
- const grad = det.sign().mul( height.dFdx().mul( r1 ).add( height.dFdy().mul( r2 ) ) );
475
+ // a placement matrix at ( x, y, z ) whose local +Z faces ( faceX, faceZ ) in the
476
+ // XZ plane, so a canonical model authored facing +Z turns to face that way
477
+ function place( x, y, z, faceX, faceZ ) {
195
478
 
196
- return det.abs().mul( normalView ).sub( grad ).normalize();
479
+ _f.set( faceX, 0, faceZ ).normalize();
480
+ _r.crossVectors( _up, _f ).normalize();
481
+ return new Matrix4().makeBasis( _r, _up, _f ).setPosition( x, y, z );
197
482
 
198
483
  }
199
484
 
485
+ const _q = /*@__PURE__*/ new Quaternion();
486
+ const _pos = /*@__PURE__*/ new Vector3();
487
+ const _sca = /*@__PURE__*/ new Vector3();
488
+
489
+ // a placement with a free yaw and a uniform scale, so repeated instances ( trees,
490
+ // pedestrians ) read as individuals rather than copies
491
+ function placeYawScale( x, y, z, yaw, scale ) {
492
+
493
+ _q.setFromAxisAngle( _up, yaw );
494
+ return new Matrix4().compose( _pos.set( x, y, z ), _q, _sca.set( scale, scale, scale ) );
495
+
496
+ }
497
+
498
+ // --- road material -------------------------------------------------------
499
+
200
500
  // antialiased filled band: 1 where |coord| < halfWidth, edge sized to the
201
501
  // pixel footprint ( fwidth ) so thin road paint stays crisp and doesn't shimmer
202
502
  function lineAA( coord, halfWidth ) {
@@ -218,13 +518,19 @@ function gridLine( coord, period, halfWidth ) {
218
518
  }
219
519
 
220
520
  /**
221
- * The shared material every tower in a {@link CityGenerator} is dressed with: one flat
222
- * masonry colour per lot, picked from a palette by hashing the lot's grid cell.
521
+ * The per-tower flat masonry colour: one palette entry per lot, picked by hashing the
522
+ * lot's grid cell from world position. Keyed off `positionWorld`, so it colours anything
523
+ * standing on the city grid identically, the towers and their {@link CityGenerator#buildProxy}
524
+ * boxes alike.
525
+ *
526
+ * @param {Object} layout - The city layout.
527
+ * @param {number|Node<uint>} [seed=0] - The city seed or a shared seed node.
528
+ * @return {Node<vec3>} The tower colour.
223
529
  */
224
- function createBuildingMaterial( layout, seed = 0 ) {
530
+ function buildingColorNode( layout, seed = 0 ) {
225
531
 
226
- // every tower takes one flat colour, picked by hashing its lot — one shared material
227
- // dresses the whole skyline; common tones repeat so the equal-probability pick feels real
532
+ // every tower takes one flat colour, picked by hashing its lot; common tones repeat
533
+ // so the equal-probability pick feels real
228
534
  const palette = buildingPalette.map( hex => color( hex ) );
229
535
 
230
536
  const periodX = layout.blockW + layout.street;
@@ -233,9 +539,14 @@ function createBuildingMaterial( layout, seed = 0 ) {
233
539
  const gz = positionWorld.z.add( layout.cityD / 2 );
234
540
  const blockIX = floor( gx.div( periodX ) );
235
541
  const blockIZ = floor( gz.div( periodZ ) );
236
- const cellX = blockIX.mul( layout.lotsX ).add( floor( gx.sub( blockIX.mul( periodX ) ).div( layout.lot ) ) );
237
- const cellZ = blockIZ.mul( layout.lotsZ ).add( floor( gz.sub( blockIZ.mul( periodZ ) ).div( layout.lot ) ) );
238
- const cellKey = uint( cellX.add( 4096 ) ).mul( uint( 73856093 ) ).bitXor( uint( cellZ.add( 4096 ) ).mul( uint( 19349663 ) ) ).bitXor( uint( ( seed * 2654435761 ) >>> 0 ) ).toVar();
542
+ // cells align to the inner-lot grid each tower sits in, so an inset, fronted
543
+ // tower maps wholly to its own cell and reads as one flat colour
544
+ const lotIX = floor( gx.sub( blockIX.mul( periodX ) ).sub( layout.sidewalkWidth ).div( layout.innerLotX ) ).clamp( 0, layout.lotsX - 1 );
545
+ const lotIZ = floor( gz.sub( blockIZ.mul( periodZ ) ).sub( layout.sidewalkWidth ).div( layout.innerLotZ ) ).clamp( 0, layout.lotsZ - 1 );
546
+ const cellX = blockIX.mul( layout.lotsX ).add( lotIX );
547
+ const cellZ = blockIZ.mul( layout.lotsZ ).add( lotIZ );
548
+ const seedHash = typeof seed === 'number' ? uint( ( seed * 2654435761 ) >>> 0 ) : uint( seed ).toVar().mul( uint( 2654435761 ) );
549
+ const cellKey = uint( cellX.add( 4096 ) ).mul( uint( 73856093 ) ).bitXor( uint( cellZ.add( 4096 ) ).mul( uint( 19349663 ) ) ).bitXor( seedHash ).toVar();
239
550
  const cellHash = ( a, b ) => hash( cellKey.add( uint( Math.round( ( a + b * 7 ) * 100 ) ) ) );
240
551
 
241
552
  const pick = cellHash( 127.1, 311.7 );
@@ -243,8 +554,22 @@ function createBuildingMaterial( layout, seed = 0 ) {
243
554
  for ( let i = 1; i < palette.length; i ++ ) buildingBase = mix( buildingBase, palette[ i ], step( i / palette.length, pick ) );
244
555
  buildingBase = buildingBase.mul( cellHash( 269.5, 183.3 ).mul( 0.12 ).add( 0.94 ) ); // subtle per-building brightness
245
556
 
557
+ return buildingBase;
558
+
559
+ }
560
+
561
+ /**
562
+ * The shared material every tower in a {@link CityGenerator} is dressed with: the per-lot
563
+ * {@link buildingColorNode} resolved once per vertex on a skyscraper material.
564
+ *
565
+ * @param {Object} layout - The city layout.
566
+ * @param {number|Node<uint>} [seed=0] - A fixed seed, or {@link CityGenerator#seedNode} for a changing city.
567
+ * @return {MeshStandardNodeMaterial} The building material.
568
+ */
569
+ function createBuildingMaterial( layout, seed = 0 ) {
570
+
246
571
  // the pick is constant across a tower, so resolve it once per vertex ( varying )
247
- return createSkyscraperMaterial( varying( buildingBase ) );
572
+ return createSkyscraperMaterial( varying( buildingColorNode( layout, seed ) ) );
248
573
 
249
574
  }
250
575
 
@@ -255,41 +580,48 @@ function createBuildingMaterial( layout, seed = 0 ) {
255
580
  function createRoadMaterial( layout ) {
256
581
 
257
582
  // wet asphalt: a warm-grey base in patchwork pours, two-scale aggregate
258
- // grit, oily wear stains, hairline cracks and low-frequency wet patches
259
- // that turn glossy and mirror the sky. detail fades in as the camera nears.
583
+ // grit, oily wear stains and low-frequency wet patches that turn glossy and
584
+ // mirror the sky. detail fades in as the camera nears.
260
585
 
261
586
  const p = positionWorld;
262
- const detail = smoothstep( 240, 25, p.distance( cameraPosition ) );
587
+ const dist = p.distance( cameraPosition );
588
+ const detail = smoothstep( 240, 25, dist );
589
+ const microFade = smoothstep( 22, 4, dist ); // the finest grit only resolves right under the camera, so fade it out fast to avoid shimmer
263
590
 
264
591
  const blotch = mx_fractal_noise_float( p.mul( 0.2 ), 3 ).mul( 0.5 ).add( 0.5 );
265
592
 
266
- // close-range detail — aggregate grit, oily wear pools, hairline cracks and worn
267
- // paint — only resolves near the camera, so its noise is sampled ( inside the branch )
268
- // only where detail is non-zero and skipped across the far majority of the road
593
+ // close-range detail — aggregate grit, oily wear pools and worn paint — only
594
+ // resolves near the camera, so its noise is sampled ( inside the branch ) only
595
+ // where detail is non-zero and skipped across the far majority of the road
269
596
  const near = Fn( () => {
270
597
 
271
598
  const grit = float( 0 ).toVar(); // two scales of aggregate, -1..1
272
599
  const stain = float( 0 ).toVar(); // oily wear pools
273
- const crack = float( 0 ).toVar();
274
600
  const worn = float( 1 ).toVar(); // paint rubbed thin and patchy, more so where tyres cross it
601
+ const micro = float( 0 ).toVar(); // fine, high-frequency grain for the close-up bump
275
602
 
276
603
  If( detail.greaterThan( 0 ), () => {
277
604
 
278
605
  grit.assign( mx_noise_float( p.mul( 7 ) ).add( mx_noise_float( p.mul( 23 ) ) ).mul( 0.5 ) );
279
606
  stain.assign( smoothstep( 0.5, 0.85, mx_fractal_noise_float( p.mul( 0.45 ), 3 ).mul( 0.5 ).add( 0.5 ) ) );
280
- crack.assign( smoothstep( 0.88, 1, mx_fractal_noise_float( p.mul( 1.1 ), 4 ).abs().oneMinus() ).mul( detail ) );
281
607
  worn.assign( smoothstep( 0.25, 0.7, mx_fractal_noise_float( p.mul( 0.7 ), 3 ).mul( 0.5 ).add( 0.5 ) ).mul( 0.55 ).add( 0.35 ) );
282
608
 
283
609
  } );
284
610
 
285
- return vec4( grit, stain, crack, worn );
611
+ If( microFade.greaterThan( 0 ), () => {
612
+
613
+ micro.assign( mx_noise_float( p.mul( 45 ) ).mul( 0.6 ).add( mx_noise_float( p.mul( 80 ) ).mul( 0.4 ) ) );
614
+
615
+ } );
616
+
617
+ return vec4( grit, stain, worn, micro );
286
618
 
287
619
  } )();
288
620
 
289
621
  const grit = near.x;
290
622
  const stain = near.y;
291
- const crack = near.z;
292
- const worn = near.w;
623
+ const worn = near.z;
624
+ const micro = near.w;
293
625
 
294
626
  const base = mix( color( 0x24262b ), color( 0x3b3f46 ), blotch );
295
627
  const gritty = base.mul( grit.mul( 0.22 ).mul( detail ).add( 1 ) );
@@ -334,10 +666,10 @@ function createRoadMaterial( layout ) {
334
666
  const paint = laneV.max( laneH ).max( crossV ).max( crossH ).mul( detail ).mul( worn );
335
667
 
336
668
  const material = new MeshStandardNodeMaterial();
337
- const surface = mix( asphalt, asphalt.mul( 0.6 ), wet ).mul( crack.mul( 0.5 ).oneMinus() );
669
+ const surface = mix( asphalt, asphalt.mul( 0.6 ), wet );
338
670
  material.colorNode = mix( surface, color( 0xd0ccc0 ), paint ); // worn white paint
339
671
  material.roughnessNode = mix( float( 0.95 ).sub( paint.mul( 0.2 ) ), float( 0.32 ), wet );
340
- material.normalNode = bumpNormal( grit.mul( 0.003 ).sub( crack.mul( 0.01 ) ).mul( detail ) ); // world units: ~3 mm aggregate, ~10 mm cracks
672
+ material.normalNode = bumpNormal( grit.mul( 0.003 ).mul( detail ).add( micro.mul( 0.0016 ).mul( microFade ) ) ); // world units: ~3 mm aggregate, ~1.6 mm fine grain up close
341
673
 
342
674
  return material;
343
675
 
@@ -15,18 +15,12 @@ import { ImprovedNoise } from '../math/ImprovedNoise.js';
15
15
  import { mergeVertices } from '../utils/BufferGeometryUtils.js';
16
16
 
17
17
  /**
18
- * Carpets a {@link TerrainGenerator} ( or anything exposing `sampleHeight`,
19
- * `sampleSlope`, `minY`, `maxY` and `parameters.size` ) with a forest of hundreds
20
- * of thousands of trees in a single draw call.
18
+ * Carpets a {@link TerrainGenerator} with trees in a single instanced draw call.
19
+ * Each tree is a distorted icosphere with a baked crown gradient. Altitude, slope
20
+ * and a density mask control placement; rotation and scale vary between trees.
21
21
  *
22
- * Each tree is the cheapest thing that still reads as a tree: a ~20-face icosphere
23
- * squashed into a tapered teardrop and lumped with a little noise, carrying a baked
24
- * dark-base / bright-top gradient. Tens of triangles each, so a single
25
- * {@link THREE.InstancedMesh} of half a million of them costs one draw call. Trees
26
- * are placed by rejection sampling against ecological rules — a min/max altitude
27
- * band ( above the mist floor, below the snowline ), a slope limit ( none on
28
- * cliffs ) and a low-frequency density mask that opens clearings — then jittered in
29
- * yaw, lean and ( squared-biased ) scale so the stand never reads as copies.
22
+ * Compatible terrain objects expose `sampleHeight`, `sampleSlope`, `minY`, `maxY`
23
+ * and `parameters.size`.
30
24
  *
31
25
  * ```js
32
26
  * const forest = new ForestGenerator( { count: 500000 } );
@@ -154,7 +148,13 @@ class ForestGenerator {
154
148
 
155
149
  dispose() {
156
150
 
157
- if ( this.mesh ) this.mesh.geometry.dispose();
151
+ if ( this.mesh ) {
152
+
153
+ this.mesh.dispose();
154
+ this.mesh.geometry.dispose();
155
+
156
+ }
157
+
158
158
  this.mesh = null;
159
159
  this.group = null;
160
160