@gnsx/three 0.185.15 → 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 (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,447 @@
1
+ import {
2
+ BoxGeometry,
3
+ CylinderGeometry,
4
+ Float32BufferAttribute,
5
+ InstancedBufferAttribute,
6
+ InterpolationSamplingMode,
7
+ InterpolationSamplingType,
8
+ Group,
9
+ Matrix4,
10
+ Quaternion,
11
+ SphereGeometry,
12
+ TorusGeometry,
13
+ Vector3
14
+ } from '@gnsx/three';
15
+
16
+ import { MeshStandardNodeMaterial } from '@gnsx/three/webgpu';
17
+ import { array, attribute, color, cos, float, fract, mix, normalGeometry, positionGeometry, select, sin, smoothstep, uniform, uv, varying, vec3 } from '@gnsx/three/tsl';
18
+
19
+ import { mergeGeometries, mergeVertices } 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 pedestrian crowd with shaped heads, jackets and lofted limbs.
26
+ * Two shared poses stand or walk, with sleeves and trousers swept through
27
+ * their joints. Each placement gets deterministic proportions and a small
28
+ * seed attribute for its complexion, hairstyle and outfit, in two instanced draws.
29
+ *
30
+ * The material splits the figure into zones on a baked `partId` and hashes
31
+ * the seed per zone, drawing clothes, skin and hair from small palettes.
32
+ * Local UVs keep facial features, cuffs and shoe soles attached to their parts
33
+ * as the figure is posed.
34
+ *
35
+ * The canonical figure stands on `y = 0`, centred in X / Z and ~1.75 m tall,
36
+ * facing `+Z` so a placement turns it to face the road.
37
+ *
38
+ * ```js
39
+ * const people = new PersonGenerator();
40
+ * scene.add( people.build( placements ) ); // placements: Matrix4[]
41
+ * ```
42
+ */
43
+ class PersonGenerator {
44
+
45
+ constructor( parameters = {} ) {
46
+
47
+ this.parameters = Object.assign( {}, PersonGenerator.defaults, parameters );
48
+
49
+ this.material = null;
50
+ this.geometries = null;
51
+ this.mesh = null;
52
+ this._parametersKey = null;
53
+
54
+ }
55
+
56
+ build( placements ) {
57
+
58
+ const parametersKey = JSON.stringify( this.parameters );
59
+
60
+ if ( parametersKey !== this._parametersKey || ( this.mesh && placements.length > this.mesh.children[ 0 ].instanceMatrix.count ) ) {
61
+
62
+ this.dispose();
63
+ this._parametersKey = parametersKey;
64
+
65
+ }
66
+
67
+ if ( this.material === null ) this.material = createPersonMaterial( this.parameters );
68
+ if ( this.geometries === null ) {
69
+
70
+ this.geometries = {
71
+ walk: buildPersonGeometry( this.parameters, 'walk' ),
72
+ stand: buildPersonGeometry( this.parameters, 'stand' )
73
+ };
74
+
75
+ }
76
+
77
+ // deal each placement a pose and proportions from its index, so the crowd
78
+ // varies but rebuilding the same city deals the same crowd
79
+ const buckets = { walk: { matrices: [], seeds: [] }, stand: { matrices: [], seeds: [] } };
80
+ const matrix = new Matrix4();
81
+
82
+ for ( let i = 0; i < placements.length; i ++ ) {
83
+
84
+ const h1 = ( ( i * 2654435761 ) >>> 0 ) % 1000 / 1000;
85
+ const h2 = ( ( i * 1597334677 ) >>> 0 ) % 1000 / 1000;
86
+ const h3 = ( ( i * 3812015801 ) >>> 0 ) % 1000 / 1000;
87
+
88
+ const scale = 0.92 + h2 * 0.15; // ~1.6 m to ~1.9 m
89
+ const width = scale * ( 0.9 + h3 * 0.2 );
90
+ const posed = placements[ i ].clone().multiply( matrix.makeScale( width, scale, width ) );
91
+
92
+ const bucket = buckets[ h1 < 0.65 ? 'walk' : 'stand' ];
93
+ bucket.matrices.push( posed );
94
+ bucket.seeds.push( i );
95
+
96
+ }
97
+
98
+ if ( this.mesh === null ) {
99
+
100
+ this.mesh = new Group();
101
+ this.mesh.name = 'People';
102
+ this.mesh.add(
103
+ createInstances( this.geometries.walk, this.material, placements.length, 'People' ),
104
+ createInstances( this.geometries.stand, this.material, placements.length, 'People' )
105
+ );
106
+ for ( const mesh of this.mesh.children ) {
107
+
108
+ mesh.geometry.setAttribute( 'personSeed', new InstancedBufferAttribute( new Float32Array( mesh.instanceMatrix.count ), 1 ) );
109
+
110
+ }
111
+
112
+ }
113
+
114
+ for ( const [ index, pose ] of [ 'walk', 'stand' ].entries() ) {
115
+
116
+ const mesh = this.mesh.children[ index ];
117
+ const seed = mesh.geometry.attributes.personSeed;
118
+ seed.array.set( buckets[ pose ].seeds );
119
+ seed.needsUpdate = true;
120
+ updateInstances( mesh, buckets[ pose ].matrices );
121
+
122
+ }
123
+
124
+ return this.mesh;
125
+
126
+ }
127
+
128
+ dispose() {
129
+
130
+ if ( this.geometries ) {
131
+
132
+ this.geometries.walk.dispose();
133
+ this.geometries.stand.dispose();
134
+
135
+ }
136
+
137
+ if ( this.mesh ) this.mesh.traverse( ( object ) => object.dispose() );
138
+ if ( this.material ) this.material.dispose();
139
+
140
+ this.geometries = null;
141
+ this.material = null;
142
+ this.mesh = null;
143
+
144
+ }
145
+
146
+ }
147
+
148
+ PersonGenerator.defaults = {
149
+ height: 1.75 // overall standing height
150
+ };
151
+
152
+ // material-zone codes baked per vertex
153
+ const SKIN = 0, HEAD = 1, COAT = 2, LEGS = 3, SHOES = 4, BAG = 5, SLEEVE = 6, HANDLE = 7;
154
+
155
+ // small palettes the material indexes per instance
156
+ const COAT_COLORS = [ 0x2b3a52, 0x33332f, 0x8a6a44, 0x5a2f2f, 0x4f5238, 0x6a6a66, 0x222024, 0x7d3f22 ];
157
+ const SHIRT_COLORS = [ 0xe8e6e0, 0xb8c4d8, 0xcfc8b8, 0x9aa7b8 ];
158
+ const LEG_COLORS = [ 0x22242c, 0x35485b, 0x51473d, 0x7c7160, 0x252526 ];
159
+ const SKIN_COLORS = [ 0xc68863, 0xa96f4c, 0x8a5535, 0x6b3d24, 0xd9a077 ];
160
+ const HAIR_COLORS = [ 0x1a1512, 0x3a2a1a, 0x584022, 0x6e6862, 0x2a2624 ];
161
+
162
+ const _down = /*@__PURE__*/ new Vector3( 0, - 1, 0 );
163
+
164
+ function joint( parent, length, swing, splay ) {
165
+
166
+ const vertical = length * Math.cos( splay );
167
+ return new Vector3( parent.x + length * Math.sin( splay ), parent.y - vertical * Math.cos( swing ), parent.z - vertical * Math.sin( swing ) );
168
+
169
+ }
170
+
171
+ function ring( center, rx, rz, segments = 6, phase = 0 ) {
172
+
173
+ return Array.from( { length: segments }, ( _, i ) => {
174
+
175
+ const a = i / segments * Math.PI * 2 + phase;
176
+ return new Vector3( center.x + Math.cos( a ) * rx, center.y, center.z + Math.sin( a ) * rz );
177
+
178
+ } );
179
+
180
+ }
181
+
182
+ // Rings turn with the limb, keeping the elbow and knee sections round as the
183
+ // pose bends. The radii describe the clothing or anatomy at each joint.
184
+ function limbSections( joints, segments = 6, phase = 0 ) {
185
+
186
+ const rotation = new Quaternion();
187
+ return joints.map( ( [ center, rx, rz ], i ) => {
188
+
189
+ const before = joints[ Math.max( 0, i - 1 ) ][ 0 ];
190
+ const after = joints[ Math.min( joints.length - 1, i + 1 ) ][ 0 ];
191
+ rotation.setFromUnitVectors( _down, after.clone().sub( before ).normalize() );
192
+ return ring( new Vector3(), rx, rz, segments, phase ).map( p => p.applyQuaternion( rotation ).add( center ) );
193
+
194
+ } );
195
+
196
+ }
197
+
198
+ function limb( joints, capEnd = true, segments = 6 ) {
199
+
200
+ return new LoftGeometry( limbSections( joints, segments ), { capEnd } );
201
+
202
+ }
203
+
204
+ // The chest has broad front and back planes with rounded sides.
205
+ function torsoSection( y, width, depth ) {
206
+
207
+ return [
208
+ new Vector3( width, y, depth * 0.45 ),
209
+ new Vector3( width * 0.65, y, depth ),
210
+ new Vector3( - width * 0.65, y, depth ),
211
+ new Vector3( - width, y, depth * 0.45 ),
212
+ new Vector3( - width, y, - depth * 0.45 ),
213
+ new Vector3( - width * 0.65, y, - depth ),
214
+ new Vector3( width * 0.65, y, - depth ),
215
+ new Vector3( width, y, - depth * 0.45 )
216
+ ];
217
+
218
+ }
219
+
220
+ function hipSection( side ) {
221
+
222
+ const profile = [[ 1, 0.5 ], [ - 0.1, 1 ], [ - 0.8, 0.7 ], [ - 1, 0 ], [ - 0.8, - 0.7 ], [ - 0.1, - 1 ], [ 1, - 0.5 ]];
223
+ const points = profile.map( ( [ x, z ], i ) => new Vector3( side * 0.093 - side * x * 0.093, i === 0 || i === 6 ? 0.82 : 0.89, z * 0.1 ) );
224
+ return side > 0 ? points.reverse() : points;
225
+
226
+ }
227
+
228
+ function buildPersonGeometry( p, pose ) {
229
+
230
+ const walking = pose === 'walk';
231
+ const parts = [];
232
+ const add = ( geometry, id ) => parts.push( part( geometry, id ) );
233
+
234
+ const headProfile = [
235
+ [ 1.75, 0.014, 0.014, - 0.012 ],
236
+ [ 1.708, 0.081, 0.081, - 0.01 ],
237
+ [ 1.656, 0.093, 0.086, 0 ],
238
+ [ 1.617, 0.086, 0.077, 0.009 ],
239
+ [ 1.561, 0.072, 0.065, 0.012 ],
240
+ [ 1.532, 0.045, 0.043, 0.005 ]
241
+ ];
242
+ const headSections = headProfile.map( ( [ y, rx, rz, z ] ) => ring( new Vector3( 0, y, z ), rx, rz, 10, Math.PI / 2 ) );
243
+ headSections[ 3 ][ 0 ].z += 0.022;
244
+ const head = new LoftGeometry( headSections, { capStart: true, capEnd: true } );
245
+
246
+ // Store the unposed height alongside the loft's angular UV. Face and hair
247
+ // masks can then follow the head as it turns and tilts.
248
+ for ( let i = 0; i < head.attributes.position.count; i ++ ) head.attributes.uv.setX( i, head.attributes.position.getY( i ) );
249
+
250
+ const heads = [ head ];
251
+ for ( const side of [ - 1, 1 ] ) heads.push( new SphereGeometry( 1, 4, 2 ).scale( 0.016, 0.026, 0.018 ).translate( side * 0.092, 1.62, - 0.004 ) );
252
+ for ( const geometry of heads ) geometry.translate( 0, - 1.535, 0 ).rotateY( walking ? 0.14 : - 0.16 ).rotateZ( walking ? - 0.02 : 0.055 ).translate( 0, 1.535, 0 );
253
+
254
+ head.computeBoundingBox();
255
+ const headOffset = 1.75 - head.boundingBox.max.y;
256
+ for ( const [ index, geometry ] of heads.entries() ) add( geometry.translate( 0, headOffset, 0 ), index === 0 ? HEAD : SKIN );
257
+ add( new CylinderGeometry( 0.045, 0.052, 0.10, 5, 1, true ).translate( 0, 1.515, 0 ), SKIN );
258
+
259
+ const jacket = [
260
+ [ 1.5, 0.055, 0.052 ],
261
+ [ 1.425, 0.20, 0.10 ],
262
+ [ 1.365, 0.195, 0.111 ],
263
+ [ 1.285, 0.18, 0.115 ],
264
+ [ 1.095, 0.152, 0.103 ],
265
+ [ 1.015, 0.166, 0.108 ]
266
+ ];
267
+ add( new LoftGeometry( jacket.map( section => torsoSection( ...section ) ), { capEnd: true } ), COAT );
268
+ const trousers = [];
269
+ const hips = [];
270
+
271
+ for ( const side of [ - 1, 1 ] ) {
272
+
273
+ const swing = walking ? - side * 0.35 : ( side < 0 ? - 0.12 : 0.06 );
274
+ const shoulder = new Vector3( side * 0.197, 1.425, 0.008 );
275
+ const upperArm = joint( shoulder, 0.075, swing, side * 0.08 );
276
+ const elbow = joint( shoulder, 0.285, swing, side * 0.08 );
277
+ const wrist = joint( elbow, 0.255, swing - 0.22, side * 0.03 );
278
+ add( limb( [
279
+ [ new Vector3( side * 0.14, 1.415, 0 ), 0.024, 0.035 ],
280
+ [ upperArm, 0.066, 0.063 ],
281
+ [ elbow, 0.051, 0.048 ],
282
+ [ wrist, 0.029, 0.033 ]
283
+ ], false, 5 ), SLEEVE );
284
+
285
+ const along = wrist.clone().sub( elbow ).normalize();
286
+ const hand = wrist.clone().addScaledVector( along, 0.05 );
287
+ add( limb( [
288
+ [ wrist, 0.029, 0.033 ],
289
+ [ hand, 0.032, 0.039 ],
290
+ [ wrist.clone().addScaledVector( along, 0.095 ), 0.019, 0.025 ]
291
+ ], true, 5 ), SKIN );
292
+
293
+ if ( ! walking && side > 0 ) {
294
+
295
+ add( new BoxGeometry( 0.075, 0.21, 0.22 ).translate( hand.x, hand.y - 0.19, hand.z ), BAG );
296
+ add( new TorusGeometry( 0.045, 0.006, 3, 4, Math.PI ).rotateY( Math.PI / 2 ).translate( hand.x, hand.y - 0.08, hand.z ), HANDLE );
297
+
298
+ }
299
+
300
+ const shoe = new LoftGeometry( [
301
+ shoeSection( - 0.075, 0.044, - 0.008 ),
302
+ shoeSection( 0.015, 0.054, 0.016 ),
303
+ shoeSection( 0.125, 0.055, - 0.025 ),
304
+ shoeSection( 0.18, 0.036, - 0.045 )
305
+ ], { capStart: true, capEnd: true } );
306
+
307
+ // Shoe UVs retain local height and length, keeping soles and laces aligned
308
+ // with the foot after its heel or toe is planted on the ground.
309
+ for ( let i = 0; i < shoe.attributes.position.count; i ++ ) {
310
+
311
+ shoe.attributes.uv.setXY( i, shoe.attributes.position.getY( i ), shoe.attributes.position.getZ( i ) );
312
+
313
+ }
314
+
315
+ shoe.rotateX( walking ? ( side < 0 ? - 0.12 : 0.25 ) : 0 ).rotateY( walking ? side * 0.03 : side * 0.16 );
316
+ shoe.computeBoundingBox();
317
+
318
+ const hip = new Vector3( side * 0.093, 0.89, 0 );
319
+ const ankle = new Vector3( side * ( walking ? 0.105 : 0.12 ), - shoe.boundingBox.min.y, walking ? - side * 0.235 : ( side < 0 ? 0.065 : - 0.025 ) );
320
+ const knee = hip.clone().lerp( ankle, 0.53 );
321
+ knee.z += walking ? ( side > 0 ? 0.095 : 0.015 ) : ( side < 0 ? 0.06 : 0.01 );
322
+ const calf = knee.clone().lerp( ankle, 0.40 );
323
+ const legSections = limbSections( [
324
+ [ hip, 0.087, 0.092 ],
325
+ [ knee, 0.062, 0.067 ],
326
+ [ calf, 0.066, 0.067 ],
327
+ [ ankle.clone().add( new Vector3( 0, - 0.018, 0 ) ), 0.045, 0.046 ]
328
+ ], 7, Math.PI / 7 + ( side > 0 ? Math.PI : 0 ) );
329
+
330
+ // The two upper leg loops share their inner edge at the crotch. Their
331
+ // outer edges together form one loop leading up to the waist.
332
+ legSections[ 0 ] = hipSection( side );
333
+ hips.push( legSections[ 0 ] );
334
+ trousers.push( new LoftGeometry( legSections, { capEnd: true } ) );
335
+ add( shoe.translate( ankle.x, ankle.y, ankle.z ), SHOES );
336
+
337
+ }
338
+
339
+ const crotch = [ ...hips[ 0 ], ...hips[ 1 ].slice( 1, 6 ) ];
340
+ trousers.push( new LoftGeometry( [ ring( new Vector3( 0, 1.04, 0 ), 0.157, 0.1, 12, Math.PI / 2 ), crotch ] ) );
341
+ const pants = mergeGeometries( trousers );
342
+ pants.deleteAttribute( 'normal' );
343
+ pants.deleteAttribute( 'uv' );
344
+ const joinedPants = mergeVertices( pants );
345
+ joinedPants.computeVertexNormals();
346
+ joinedPants.setAttribute( 'uv', new Float32BufferAttribute( new Float32Array( joinedPants.attributes.position.count * 2 ), 2 ) );
347
+ add( joinedPants, LEGS );
348
+
349
+ const geometry = mergeGeometries( parts );
350
+ const scale = p.height / 1.75;
351
+ if ( scale !== 1 ) geometry.scale( scale, scale, scale );
352
+ return geometry;
353
+
354
+ }
355
+
356
+ function shoeSection( z, width, top ) {
357
+
358
+ return [
359
+ new Vector3( width, top - 0.025, z ),
360
+ new Vector3( width * 0.7, top, z ),
361
+ new Vector3( - width * 0.7, top, z ),
362
+ new Vector3( - width, top - 0.025, z ),
363
+ new Vector3( - width * 0.9, - 0.085, z ),
364
+ new Vector3( width * 0.9, - 0.085, z )
365
+ ];
366
+
367
+ }
368
+
369
+ function createPersonMaterial( p ) {
370
+
371
+ const partId = varying( attribute( 'partId', 'float' ) ).setInterpolation( InterpolationSamplingType.FLAT, InterpolationSamplingMode.EITHER );
372
+ const isSkin = partId.equal( SKIN );
373
+ const isHead = partId.equal( HEAD );
374
+ const isCoat = partId.equal( COAT );
375
+ const isSleeve = partId.equal( SLEEVE );
376
+ const isLegs = partId.equal( LEGS );
377
+ const isShoes = partId.equal( SHOES );
378
+ const isBag = partId.equal( BAG );
379
+ const isHandle = partId.equal( HANDLE );
380
+
381
+ // Use the original placement index, so splitting poses into batches does
382
+ // not give their first members identical outfits and complexions.
383
+ const seed = attribute( 'personSeed', 'float' );
384
+ const lane = ( salt ) => fract( sin( seed.add( salt ).mul( 12.9898 ) ).mul( 43758.5453 ) );
385
+ const pick = ( colors, salt ) => array( colors.map( c => color( c ) ) ).element( lane( salt ).mul( colors.length ).floor().min( colors.length - 1 ) );
386
+ const q = positionGeometry.mul( uniform( 1.75 / p.height ) );
387
+ const texcoord = uv();
388
+
389
+ const angle = texcoord.y.mul( Math.PI * 2 );
390
+ const face = vec3( sin( angle ).mul( 0.09 ), texcoord.x, cos( angle ).mul( 0.09 ) );
391
+ const style = lane( 13.0 );
392
+ const hairline = mix( mix( float( 1.55 ), float( 1.61 ), style ), mix( float( 1.67 ), float( 1.71 ), style ), smoothstep( - 0.025, 0.07, face.z ) ).add( face.x.mul( style.sub( 0.5 ) ).mul( 0.35 ) );
393
+ const hair = smoothstep( hairline.sub( 0.003 ), hairline.add( 0.003 ), face.y );
394
+ const forward = smoothstep( 0.045, 0.075, face.z );
395
+ const eyeWidth = smoothstep( 0.013, 0.006, face.x.abs().sub( 0.036 ).abs() );
396
+ const eyes = eyeWidth.mul( smoothstep( 0.005, 0.0015, face.y.sub( 1.651 ).abs() ) ).mul( forward );
397
+ const brows = eyeWidth.mul( smoothstep( 0.0035, 0.001, face.y.sub( 1.665 ).abs() ) ).mul( forward );
398
+ const mouth = smoothstep( 0.030, 0.016, face.x.abs() ).mul( smoothstep( 0.004, 0.001, face.y.sub( 1.58 ).abs() ) ).mul( forward );
399
+ const skin = pick( SKIN_COLORS, 17.0 );
400
+ const head = mix( skin.mul( eyes.mul( 0.65 ).add( brows.mul( 0.35 ) ).add( mouth.mul( 0.25 ) ).oneMinus() ), pick( HAIR_COLORS, 3.0 ), hair );
401
+
402
+ const jacket = lane( 89.0 ).greaterThan( 0.42 );
403
+ const coat = pick( COAT_COLORS, 29.0 );
404
+ const shirt = pick( SHIRT_COLORS, 71.0 );
405
+ const front = smoothstep( 0.03, 0.07, q.z );
406
+ const opening = q.y.sub( 1.33 ).mul( 0.42 );
407
+ const shirtV = smoothstep( 1.33, 1.35, q.y ).mul( smoothstep( 1.5, 1.48, q.y ) ).mul( smoothstep( 0.004, 0, q.x.abs().sub( opening ) ) ).mul( front );
408
+ const lapel = smoothstep( 0.025, 0.009, q.x.abs().sub( opening ).abs() ).mul( shirtV.oneMinus() ).mul( smoothstep( 1.32, 1.37, q.y ) ).mul( front );
409
+ const zipper = smoothstep( 0.008, 0.003, q.x.abs() ).mul( front );
410
+ const hem = smoothstep( 1.065, 1.035, q.y );
411
+ const collar = smoothstep( 1.455, 1.48, q.y );
412
+ const tailored = mix( coat.mul( lapel.mul( 0.25 ).add( zipper.mul( 0.35 ) ).oneMinus() ), shirt, shirtV );
413
+ const casual = coat.mul( hem.max( collar ).mul( 0.18 ).add( zipper.mul( 0.3 ) ).oneMinus() );
414
+ const cuff = smoothstep( 0.94, 0.985, texcoord.x );
415
+ const sleeve = mix( coat, select( jacket, shirt, coat.mul( 0.75 ) ), cuff );
416
+
417
+ const sneaker = lane( 5.0 ).greaterThan( 0.4 );
418
+ const leather = mix( color( 0x201e1c ), color( 0x4a3524 ), lane( 23.0 ) );
419
+ const upper = select( sneaker, mix( color( 0x252b32 ), color( 0xc8c3b8 ), lane( 31.0 ).step( 0.55 ) ), leather );
420
+ const sole = smoothstep( - 0.064, - 0.074, texcoord.x );
421
+ const laceCoord = texcoord.y.mul( 110 );
422
+ const laces = smoothstep( 0.68, 0.78, laceCoord.fract() ).mul( laceCoord.fwidth().oneMinus().clamp() ).mul( smoothstep( - 0.015, 0.005, texcoord.x ) ).mul( smoothstep( - 0.01, 0.015, texcoord.y ) );
423
+ const shoe = mix( mix( upper, select( sneaker, color( 0xd5d1c8 ), color( 0x191816 ) ), sole ), color( 0xaba89f ), laces.mul( 0.45 ) );
424
+
425
+ const bagEdge = texcoord.min( texcoord.oneMinus() );
426
+ const seam = smoothstep( 0.045, 0.02, bagEdge.x.min( bagEdge.y ) );
427
+ const flap = smoothstep( 0.02, 0.008, texcoord.y.sub( 0.72 ).abs() );
428
+ const buckle = smoothstep( 0.06, 0.045, texcoord.x.sub( 0.5 ).abs() ).mul( smoothstep( 0.07, 0.05, texcoord.y.sub( 0.72 ).abs() ) ).mul( select( normalGeometry.x.abs().greaterThan( 0.8 ), 1, 0 ) );
429
+ const bag = mix( color( 0x49372a ).mul( seam.max( flap ).mul( 0.35 ).oneMinus() ), color( 0x8f8878 ), buckle );
430
+
431
+ const material = new MeshStandardNodeMaterial();
432
+ material.colorNode = select( isSkin, skin,
433
+ select( isHead, head,
434
+ select( isCoat, select( jacket, tailored, casual ),
435
+ select( isSleeve, sleeve,
436
+ select( isLegs, pick( LEG_COLORS, 47.0 ),
437
+ select( isShoes, shoe,
438
+ select( isBag, bag, color( 0x30261f ) ) ) ) ) ) ) );
439
+ material.roughnessNode = select( isSkin, float( 0.6 ),
440
+ select( isHead, mix( float( 0.6 ), float( 0.85 ), hair ),
441
+ select( isBag.or( isHandle ), float( 0.55 ), float( 0.85 ) ) ) );
442
+ material.metalness = 0;
443
+ return material;
444
+
445
+ }
446
+
447
+ export { PersonGenerator };
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  ExtrudeGeometry,
3
3
  Group,
4
- InstancedMesh,
5
4
  MeshStandardNodeMaterial,
6
5
  Shape
7
6
  } from '@gnsx/three/webgpu';
8
7
 
9
- import { cameraPosition, color, float, floor, Fn, fract, fwidth, If, mix, mx_noise_float, normalView, normalWorldGeometry, positionView, positionWorld, sin, smoothstep } from '@gnsx/three/tsl';
8
+ import { cameraPosition, color, float, floor, Fn, fract, fwidth, If, mix, mx_noise_float, normalWorldGeometry, positionWorld, sin, smoothstep } from '@gnsx/three/tsl';
9
+
10
+ import { createInstances, updateInstances } from './InstancedMeshGenerator.js';
11
+ import { bumpNormal } from './CityGeneratorUtils.js';
10
12
 
11
13
  /**
12
14
  * Generates the raised sidewalk for a city's blocks: per block, a rounded-corner concrete
@@ -32,40 +34,40 @@ class SidewalkGenerator {
32
34
  this.material = null; // the procedural concrete, built once and reused across rebuilds
33
35
  this.curbMaterial = null; // the procedural granite curb, likewise
34
36
  this.mesh = null;
37
+ this._parametersKey = null;
35
38
 
36
39
  }
37
40
 
38
41
  build( placements ) {
39
42
 
40
- this.dispose();
43
+ const parametersKey = JSON.stringify( this.parameters );
44
+
45
+ if ( parametersKey !== this._parametersKey || ( this.mesh && placements.length > this.mesh.children[ 0 ].instanceMatrix.count ) ) {
41
46
 
42
- const { width, depth, height, radius, curbWidth, curbLip } = this.parameters;
47
+ this.dispose();
48
+ this._parametersKey = parametersKey;
49
+
50
+ }
43
51
 
44
52
  if ( this.material === null ) this.material = createSidewalkMaterial();
45
53
  if ( this.curbMaterial === null ) this.curbMaterial = createCurbMaterial();
46
54
 
47
- // the walking slab and the curb are separate meshes so each carries its own material
48
- const slab = new InstancedMesh( slabGeometry( width, depth, height, radius, curbWidth ), this.material, placements.length );
49
- const curb = new InstancedMesh( curbGeometry( width, depth, height, radius, curbWidth, curbLip ), this.curbMaterial, placements.length );
55
+ if ( this.mesh === null ) {
50
56
 
51
- for ( let i = 0; i < placements.length; i ++ ) {
57
+ const { width, depth, height, radius, curbWidth, curbLip } = this.parameters;
58
+ const slab = createInstances( slabGeometry( width, depth, height, radius, curbWidth ), this.material, placements.length, '' );
59
+ const curb = createInstances( curbGeometry( width, depth, height, radius, curbWidth, curbLip ), this.curbMaterial, placements.length, '' );
60
+ slab.castShadow = curb.castShadow = false;
52
61
 
53
- slab.setMatrixAt( i, placements[ i ] );
54
- curb.setMatrixAt( i, placements[ i ] );
62
+ this.mesh = new Group();
63
+ this.mesh.name = 'Sidewalk';
64
+ this.mesh.add( slab, curb );
55
65
 
56
66
  }
57
67
 
58
- slab.computeBoundingSphere();
59
- curb.computeBoundingSphere();
60
- slab.receiveShadow = curb.receiveShadow = true;
68
+ for ( const mesh of this.mesh.children ) updateInstances( mesh, placements );
61
69
 
62
- const group = new Group();
63
- group.name = 'Sidewalk';
64
- group.add( slab, curb );
65
-
66
- this.mesh = group;
67
-
68
- return group;
70
+ return this.mesh;
69
71
 
70
72
  }
71
73
 
@@ -73,7 +75,17 @@ class SidewalkGenerator {
73
75
 
74
76
  if ( this.mesh === null ) return;
75
77
 
76
- this.mesh.traverse( ( o ) => o.geometry && o.geometry.dispose() );
78
+ this.mesh.traverse( ( object ) => {
79
+
80
+ if ( object.geometry ) object.geometry.dispose();
81
+ object.dispose();
82
+
83
+ } );
84
+
85
+ this.material.dispose();
86
+ this.curbMaterial.dispose();
87
+ this.material = null;
88
+ this.curbMaterial = null;
77
89
  this.mesh = null;
78
90
 
79
91
  }
@@ -146,23 +158,6 @@ function curbGeometry( width, depth, height, radius, curbWidth, curbLip ) {
146
158
 
147
159
  // --- material ------------------------------------------------------------
148
160
 
149
- // derivative-based bump for a procedural, world-space height field. the built-in bumpMap
150
- // offsets the UV to read its height, so it returns a zero gradient for a height keyed off
151
- // world position; this feeds the hardware screen-space derivatives of the height into
152
- // Mikkelsen's surface-gradient method so the relief actually perturbs the normal.
153
- function bumpNormal( height ) {
154
-
155
- const dpdx = positionView.dFdx();
156
- const dpdy = positionView.dFdy();
157
- const r1 = dpdy.cross( normalView );
158
- const r2 = normalView.cross( dpdx );
159
- const det = dpdx.dot( r1 );
160
- const grad = det.sign().mul( height.dFdx().mul( r1 ).add( height.dFdy().mul( r2 ) ) );
161
-
162
- return det.abs().mul( normalView ).sub( grad ).normalize();
163
-
164
- }
165
-
166
161
  // an antialiased line repeated at every multiple of `period` ( the scored joints )
167
162
  function gridLine( coord, period, halfWidth ) {
168
163