@zephyr3d/scene 0.9.24 → 0.9.26

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 (264) hide show
  1. package/dist/animation/hair/gpu_hair_simulation.js +1090 -0
  2. package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
  3. package/dist/animation/joint_dynamics/controller.js +7 -5
  4. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  5. package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
  6. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  7. package/dist/animation/morphtrack.js +3 -4
  8. package/dist/animation/morphtrack.js.map +1 -1
  9. package/dist/animation/skeleton.js +58 -24
  10. package/dist/animation/skeleton.js.map +1 -1
  11. package/dist/animation/spring/multi_chain_spring_system.js +577 -179
  12. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  13. package/dist/animation/spring/spring_collider.js +4 -3
  14. package/dist/animation/spring/spring_collider.js.map +1 -1
  15. package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
  16. package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
  17. package/dist/animation/spring/spring_particle.js +2 -0
  18. package/dist/animation/spring/spring_particle.js.map +1 -1
  19. package/dist/animation/spring/spring_system.js +11 -3
  20. package/dist/animation/spring/spring_system.js.map +1 -1
  21. package/dist/animation/spring_modifier.js +10 -0
  22. package/dist/animation/spring_modifier.js.map +1 -1
  23. package/dist/app/engine.js +53 -43
  24. package/dist/app/engine.js.map +1 -1
  25. package/dist/app/scriptingsystem.js +119 -6
  26. package/dist/app/scriptingsystem.js.map +1 -1
  27. package/dist/app/scriptregistry.js +3 -2
  28. package/dist/app/scriptregistry.js.map +1 -1
  29. package/dist/asset/assetmanager.js +284 -67
  30. package/dist/asset/assetmanager.js.map +1 -1
  31. package/dist/asset/loaders/zhair/zhair_format.js +288 -0
  32. package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
  33. package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
  34. package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
  35. package/dist/asset/model.js +178 -67
  36. package/dist/asset/model.js.map +1 -1
  37. package/dist/camera/camera.js +193 -21
  38. package/dist/camera/camera.js.map +1 -1
  39. package/dist/camera/perspectivecamera.js +3 -1
  40. package/dist/camera/perspectivecamera.js.map +1 -1
  41. package/dist/index.d.ts +4040 -1290
  42. package/dist/index.js +16 -6
  43. package/dist/index.js.map +1 -1
  44. package/dist/material/eye.js +932 -0
  45. package/dist/material/eye.js.map +1 -0
  46. package/dist/material/hair.js +917 -0
  47. package/dist/material/hair.js.map +1 -0
  48. package/dist/material/hairstrand.js +842 -0
  49. package/dist/material/hairstrand.js.map +1 -0
  50. package/dist/material/hairstrand_data.js +162 -0
  51. package/dist/material/hairstrand_data.js.map +1 -0
  52. package/dist/material/lambert.js +5 -2
  53. package/dist/material/lambert.js.map +1 -1
  54. package/dist/material/material.js +338 -300
  55. package/dist/material/material.js.map +1 -1
  56. package/dist/material/meshmaterial.js +120 -19
  57. package/dist/material/meshmaterial.js.map +1 -1
  58. package/dist/material/mixins/albedocolor.js +1 -1
  59. package/dist/material/mixins/albedocolor.js.map +1 -1
  60. package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
  61. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  62. package/dist/material/mixins/lightmodel/lambert.js +5 -4
  63. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  64. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
  65. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  66. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
  67. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  68. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
  69. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  70. package/dist/material/mixins/lit.js +73 -18
  71. package/dist/material/mixins/lit.js.map +1 -1
  72. package/dist/material/mixins/pbr/common.js +4 -4
  73. package/dist/material/mixins/pbr/common.js.map +1 -1
  74. package/dist/material/mixins/texture.js +48 -11
  75. package/dist/material/mixins/texture.js.map +1 -1
  76. package/dist/material/mtoon.js +6 -5
  77. package/dist/material/mtoon.js.map +1 -1
  78. package/dist/material/pbrblueprint.js +146 -28
  79. package/dist/material/pbrblueprint.js.map +1 -1
  80. package/dist/material/pbrblueprint_instance.js +501 -0
  81. package/dist/material/pbrblueprint_instance.js.map +1 -0
  82. package/dist/material/pbrmr.js +15 -16
  83. package/dist/material/pbrmr.js.map +1 -1
  84. package/dist/material/shader/helper.js +766 -456
  85. package/dist/material/shader/helper.js.map +1 -1
  86. package/dist/material/shader/terrain_blend.js +55 -0
  87. package/dist/material/shader/terrain_blend.js.map +1 -0
  88. package/dist/material/skin.js +192 -32
  89. package/dist/material/skin.js.map +1 -1
  90. package/dist/material/spriteblueprint.js +16 -1
  91. package/dist/material/spriteblueprint.js.map +1 -1
  92. package/dist/material/subsurfaceprofile.js +86 -23
  93. package/dist/material/subsurfaceprofile.js.map +1 -1
  94. package/dist/material/water.js +3 -1
  95. package/dist/material/water.js.map +1 -1
  96. package/dist/posteffect/bloom.js +167 -7
  97. package/dist/posteffect/bloom.js.map +1 -1
  98. package/dist/posteffect/coloradjust.js +2 -1
  99. package/dist/posteffect/coloradjust.js.map +1 -1
  100. package/dist/posteffect/compositor.js.map +1 -1
  101. package/dist/posteffect/fxaa.js +2 -1
  102. package/dist/posteffect/fxaa.js.map +1 -1
  103. package/dist/posteffect/grayscale.js +3 -1
  104. package/dist/posteffect/grayscale.js.map +1 -1
  105. package/dist/posteffect/motionblur.js +4 -1
  106. package/dist/posteffect/motionblur.js.map +1 -1
  107. package/dist/posteffect/posteffect.js.map +1 -1
  108. package/dist/posteffect/skinsss.js +368 -69
  109. package/dist/posteffect/skinsss.js.map +1 -1
  110. package/dist/posteffect/ssgi.js +16 -9
  111. package/dist/posteffect/ssgi.js.map +1 -1
  112. package/dist/posteffect/ssr.js +3 -0
  113. package/dist/posteffect/ssr.js.map +1 -1
  114. package/dist/posteffect/sss.js +91 -34
  115. package/dist/posteffect/sss.js.map +1 -1
  116. package/dist/posteffect/taa.js.map +1 -1
  117. package/dist/posteffect/tonemap.js +44 -1
  118. package/dist/posteffect/tonemap.js.map +1 -1
  119. package/dist/render/abuffer_oit.js +45 -39
  120. package/dist/render/abuffer_oit.js.map +1 -1
  121. package/dist/render/cluster_light.js +4 -4
  122. package/dist/render/cluster_light.js.map +1 -1
  123. package/dist/render/cull_visitor.js +19 -0
  124. package/dist/render/cull_visitor.js.map +1 -1
  125. package/dist/render/depthpass.js +36 -2
  126. package/dist/render/depthpass.js.map +1 -1
  127. package/dist/render/drawable_mixin.js +26 -1
  128. package/dist/render/drawable_mixin.js.map +1 -1
  129. package/dist/render/dualdepthpeeling_oit.js +52 -51
  130. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  131. package/dist/render/envlight.js +1 -1
  132. package/dist/render/envlight.js.map +1 -1
  133. package/dist/render/fbm_wavegenerator.js +3 -0
  134. package/dist/render/fbm_wavegenerator.js.map +1 -1
  135. package/dist/render/gerstner_wavegenerator.js +3 -0
  136. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  137. package/dist/render/globalbindgroup_allocator.js +3 -0
  138. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  139. package/dist/render/oit.js +29 -0
  140. package/dist/render/oit.js.map +1 -0
  141. package/dist/render/render_queue.js +3 -0
  142. package/dist/render/render_queue.js.map +1 -1
  143. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  144. package/dist/render/rendergraph/executor.js +2 -0
  145. package/dist/render/rendergraph/executor.js.map +1 -1
  146. package/dist/render/rendergraph/forward_plus_builder.js +61 -1
  147. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  148. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  149. package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
  150. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
  151. package/dist/render/rendergraph/types.js.map +1 -1
  152. package/dist/render/shadow_mask_pass.js +73 -8
  153. package/dist/render/shadow_mask_pass.js.map +1 -1
  154. package/dist/render/sky.js +166 -126
  155. package/dist/render/sky.js.map +1 -1
  156. package/dist/render/weightedblended_oit.js +36 -35
  157. package/dist/render/weightedblended_oit.js.map +1 -1
  158. package/dist/scene/basesprite.js +8 -0
  159. package/dist/scene/basesprite.js.map +1 -1
  160. package/dist/scene/batchgroup.js +3 -0
  161. package/dist/scene/batchgroup.js.map +1 -1
  162. package/dist/scene/environment.js +4 -1
  163. package/dist/scene/environment.js.map +1 -1
  164. package/dist/scene/hair.js +963 -0
  165. package/dist/scene/hair.js.map +1 -0
  166. package/dist/scene/light.js +5 -1
  167. package/dist/scene/light.js.map +1 -1
  168. package/dist/scene/mesh.js +481 -47
  169. package/dist/scene/mesh.js.map +1 -1
  170. package/dist/scene/meshdrawable.js +6 -0
  171. package/dist/scene/meshdrawable.js.map +1 -1
  172. package/dist/scene/msdftext.js +3 -0
  173. package/dist/scene/msdftext.js.map +1 -1
  174. package/dist/scene/msdftextsprite.js +3 -0
  175. package/dist/scene/msdftextsprite.js.map +1 -1
  176. package/dist/scene/particlesys.js +6 -0
  177. package/dist/scene/particlesys.js.map +1 -1
  178. package/dist/scene/scene.js +3 -0
  179. package/dist/scene/scene.js.map +1 -1
  180. package/dist/scene/scene_node.js +6 -1
  181. package/dist/scene/scene_node.js.map +1 -1
  182. package/dist/scene/terrain-cm/grass.js +273 -249
  183. package/dist/scene/terrain-cm/grass.js.map +1 -1
  184. package/dist/scene/terrain-cm/grassmaterial.js +3 -0
  185. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  186. package/dist/scene/terrain-cm/terrain-cm.js +6 -0
  187. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  188. package/dist/scene/terrain-cm/texture_cache.js +309 -0
  189. package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
  190. package/dist/scene/water.js +6 -0
  191. package/dist/scene/water.js.map +1 -1
  192. package/dist/shaders/atmosphere.js.map +1 -1
  193. package/dist/shaders/diffusion.js +54 -0
  194. package/dist/shaders/diffusion.js.map +1 -0
  195. package/dist/shaders/shadow.js +33 -21
  196. package/dist/shaders/shadow.js.map +1 -1
  197. package/dist/shaders/temporal.js +71 -33
  198. package/dist/shaders/temporal.js.map +1 -1
  199. package/dist/shadow/dom.js +546 -0
  200. package/dist/shadow/dom.js.map +1 -0
  201. package/dist/shadow/pcf_opt.js +3 -5
  202. package/dist/shadow/pcf_opt.js.map +1 -1
  203. package/dist/shadow/pcf_pd.js +1 -1
  204. package/dist/shadow/pcf_pd.js.map +1 -1
  205. package/dist/shadow/receiver_bias.js +41 -0
  206. package/dist/shadow/receiver_bias.js.map +1 -0
  207. package/dist/shadow/shader.js +20 -60
  208. package/dist/shadow/shader.js.map +1 -1
  209. package/dist/shadow/shadow_impl.js +89 -0
  210. package/dist/shadow/shadow_impl.js.map +1 -1
  211. package/dist/shadow/shadow_region.js +50 -50
  212. package/dist/shadow/shadow_region.js.map +1 -1
  213. package/dist/shadow/shadowmapper.js +150 -37
  214. package/dist/shadow/shadowmapper.js.map +1 -1
  215. package/dist/shapes/shape.js +11 -2
  216. package/dist/shapes/shape.js.map +1 -1
  217. package/dist/shapes/sphere.js +50 -9
  218. package/dist/shapes/sphere.js.map +1 -1
  219. package/dist/utility/blueprint/common/constants.js +112 -2
  220. package/dist/utility/blueprint/common/constants.js.map +1 -1
  221. package/dist/utility/blueprint/material/func.js +142 -49
  222. package/dist/utility/blueprint/material/func.js.map +1 -1
  223. package/dist/utility/blueprint/material/ir.js +490 -25
  224. package/dist/utility/blueprint/material/ir.js.map +1 -1
  225. package/dist/utility/blueprint/material/texture.js +898 -4
  226. package/dist/utility/blueprint/material/texture.js.map +1 -1
  227. package/dist/utility/serialization/manager.js +431 -100
  228. package/dist/utility/serialization/manager.js.map +1 -1
  229. package/dist/utility/serialization/scene/animation.js +370 -3
  230. package/dist/utility/serialization/scene/animation.js.map +1 -1
  231. package/dist/utility/serialization/scene/batch.js +4 -0
  232. package/dist/utility/serialization/scene/batch.js.map +1 -1
  233. package/dist/utility/serialization/scene/camera.js +133 -1
  234. package/dist/utility/serialization/scene/camera.js.map +1 -1
  235. package/dist/utility/serialization/scene/common.js +26 -5
  236. package/dist/utility/serialization/scene/common.js.map +1 -1
  237. package/dist/utility/serialization/scene/hair.js +1141 -0
  238. package/dist/utility/serialization/scene/hair.js.map +1 -0
  239. package/dist/utility/serialization/scene/light.js +84 -4
  240. package/dist/utility/serialization/scene/light.js.map +1 -1
  241. package/dist/utility/serialization/scene/material.js +1867 -166
  242. package/dist/utility/serialization/scene/material.js.map +1 -1
  243. package/dist/utility/serialization/scene/mesh.js +231 -14
  244. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  245. package/dist/utility/serialization/scene/node.js +141 -7
  246. package/dist/utility/serialization/scene/node.js.map +1 -1
  247. package/dist/utility/serialization/scene/particle.js +4 -0
  248. package/dist/utility/serialization/scene/particle.js.map +1 -1
  249. package/dist/utility/serialization/scene/primitive.js +18 -0
  250. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  251. package/dist/utility/serialization/scene/sprite.js +4 -0
  252. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  253. package/dist/utility/serialization/scene/terrain.js +92 -69
  254. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  255. package/dist/utility/serialization/scene/text.js +4 -0
  256. package/dist/utility/serialization/scene/text.js.map +1 -1
  257. package/dist/utility/serialization/scene/water.js +4 -0
  258. package/dist/utility/serialization/scene/water.js.map +1 -1
  259. package/dist/utility/serialization/types.js.map +1 -1
  260. package/dist/utility/shprojector.js +96 -95
  261. package/dist/utility/shprojector.js.map +1 -1
  262. package/dist/values.js +105 -58
  263. package/dist/values.js.map +1 -1
  264. package/package.json +3 -3
@@ -4,100 +4,100 @@ import { RenderBundleWrapper } from '../render/renderbundle_wrapper.js';
4
4
  import { Disposable } from '@zephyr3d/base';
5
5
  import { getEngine } from '../app/api.js';
6
6
 
7
- /**
8
- * Base class for all materials.
9
- *
10
- * Responsibilities:
11
- * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).
12
- * - Builds and caches GPU shader programs per pass and per-render-context hash.
13
- * - Manages a per-material bind group (typically at index 2) for uniforms and resources.
14
- * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).
15
- * - Tracks "option" changes that affect shader variant hashing and render bundles.
16
- *
17
- * Caching and hashing:
18
- * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.
19
- * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).
20
- * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and
21
- * `ctx.shaderVariantHash` when provided, allowing context-sensitive variants without
22
- * coupling shader programs to runtime texture identities.
23
- * - GPU programs are additionally memoized in a global static `_programCache` across materials
24
- * by `constructor.name` + hash, to avoid recompilation of identical variants.
25
- *
26
- * Bind groups and uniforms:
27
- * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),
28
- * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in
29
- * `_applyUniforms()`.
30
- * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on
31
- * `_optionTag` changes (see `optionChanged()`).
32
- *
33
- * Lifecycle:
34
- * - Constructed materials register a persistent ID into a global registry for serialization.
35
- * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,
36
- * and uploads uniforms as needed.
37
- * - `bind(device, pass)` binds the program, bind group (index 2), and render states.
38
- * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.
39
- * - `onDispose()` releases bind groups and registry entries.
40
- *
41
- * Extending:
42
- * - Override `_createProgram(pb, ctx, pass)` to build a shader.
43
- * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.
44
- * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.
45
- * - Override `_createHash()` to encode options that affect program compilation.
46
- * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.
47
- *
48
- * Thread-safety:
49
- * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.
50
- *
51
- * @public
7
+ /**
8
+ * Base class for all materials.
9
+ *
10
+ * Responsibilities:
11
+ * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).
12
+ * - Builds and caches GPU shader programs per pass and per-render-context hash.
13
+ * - Manages a per-material bind group (typically at index 2) for uniforms and resources.
14
+ * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).
15
+ * - Tracks "option" changes that affect shader variant hashing and render bundles.
16
+ *
17
+ * Caching and hashing:
18
+ * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.
19
+ * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).
20
+ * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and
21
+ * `ctx.shaderVariantHash` when provided, allowing context-sensitive variants without
22
+ * coupling shader programs to runtime texture identities.
23
+ * - GPU programs are additionally memoized in a global static `_programCache` across materials
24
+ * by `constructor.name` + hash, to avoid recompilation of identical variants.
25
+ *
26
+ * Bind groups and uniforms:
27
+ * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),
28
+ * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in
29
+ * `_applyUniforms()`.
30
+ * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on
31
+ * `_optionTag` changes (see `optionChanged()`).
32
+ *
33
+ * Lifecycle:
34
+ * - Constructed materials register a persistent ID into a global registry for serialization.
35
+ * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,
36
+ * and uploads uniforms as needed.
37
+ * - `bind(device, pass)` binds the program, bind group (index 2), and render states.
38
+ * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.
39
+ * - `onDispose()` releases bind groups and registry entries.
40
+ *
41
+ * Extending:
42
+ * - Override `_createProgram(pb, ctx, pass)` to build a shader.
43
+ * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.
44
+ * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.
45
+ * - Override `_createHash()` to encode options that affect program compilation.
46
+ * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.
47
+ *
48
+ * Thread-safety:
49
+ * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.
50
+ *
51
+ * @public
52
52
  */ class Material extends Disposable {
53
- /**
54
- * Monotonic instance ID counter.
55
- * @internal
53
+ /**
54
+ * Monotonic instance ID counter.
55
+ * @internal
56
56
  */ static _nextId = 0;
57
- /**
58
- * Global program cache keyed by global hash
57
+ /**
58
+ * Global program cache keyed by global hash
59
59
  */ static _programCache = {};
60
- /**
61
- * Per-material state cache keyed by global hash (material + context + pass).
62
- * @internal
60
+ /**
61
+ * Per-material state cache keyed by global hash (material + context + pass).
62
+ * @internal
63
63
  */ _states;
64
- /**
65
- * Number of rendering passes.
66
- * Subclasses can increase this to implement multi-pass rendering.
67
- * @internal
64
+ /**
65
+ * Number of rendering passes.
66
+ * Subclasses can increase this to implement multi-pass rendering.
67
+ * @internal
68
68
  */ _numPasses;
69
- /**
70
- * Per-pass hash cached results. Length scales with `numPasses`.
71
- * @internal
69
+ /**
70
+ * Per-pass hash cached results. Length scales with `numPasses`.
71
+ * @internal
72
72
  */ _hash;
73
- /**
74
- * Incremented each time options change (via `optionChanged`), used to decide whether
75
- * uniforms need update on next `apply()`.
76
- * @internal
73
+ /**
74
+ * Incremented each time options change (via `optionChanged`), used to decide whether
75
+ * uniforms need update on next `apply()`.
76
+ * @internal
77
77
  */ _optionTag;
78
- /**
79
- * Unique runtime instance ID.
80
- * @internal
78
+ /**
79
+ * Unique runtime instance ID.
80
+ * @internal
81
81
  */ _id;
82
- /**
83
- * Latest computed global hash per pass, set during `apply()`, read in `bind()`.
84
- * @internal
82
+ /**
83
+ * Latest computed global hash per pass, set during `apply()`, read in `bind()`.
84
+ * @internal
85
85
  */ _currentHash;
86
- /**
87
- * Incremented when material states affecting render bundles change (e.g., bind group id changes
88
- * or `optionChanged(true)`), used to trigger re-recording of render bundles.
89
- * @internal
86
+ /**
87
+ * Incremented when material states affecting render bundles change (e.g., bind group id changes
88
+ * or `optionChanged(true)`), used to trigger re-recording of render bundles.
89
+ * @internal
90
90
  */ _changeTag;
91
- /**
92
- * Unique program id counter for naming compiled programs.
93
- * @internal
91
+ /**
92
+ * Unique program id counter for naming compiled programs.
93
+ * @internal
94
94
  */ _nextProgramId = 0;
95
- /**
96
- * Create a new material instance.
97
- *
98
- * - Initializes one pass by default.
99
- * - Prepares per-pass hash storage and change tracking.
100
- * - Registers a persistent ID in the global registry.
95
+ /**
96
+ * Create a new material instance.
97
+ *
98
+ * - Initializes one pass by default.
99
+ * - Prepares per-pass hash storage and change tracking.
100
+ * - Registers a persistent ID in the global registry.
101
101
  */ constructor(){
102
102
  super();
103
103
  this._id = ++Material._nextId;
@@ -111,46 +111,46 @@ import { getEngine } from '../app/api.js';
111
111
  this._changeTag = 0;
112
112
  this._currentHash = [];
113
113
  }
114
- /**
115
- * Create a shallow clone of this material.
116
- *
117
- * Note: The base implementation returns a base `Material`. Subclasses should
118
- * override to return their own type and copy custom fields.
114
+ /**
115
+ * Create a shallow clone of this material.
116
+ *
117
+ * Note: The base implementation returns a base `Material`. Subclasses should
118
+ * override to return their own type and copy custom fields.
119
119
  */ clone() {
120
120
  const other = new Material();
121
121
  other.copyFrom(this);
122
122
  return other;
123
123
  }
124
- /**
125
- * Copy basic properties from another material.
126
- *
127
- * Disposes existing bind groups/states, copies `numPasses`. Subclasses should
128
- * extend this to copy their own fields and call `optionChanged(true)` if
129
- * shader-affecting options differ.
130
- *
131
- * @param other - Source material.
124
+ /**
125
+ * Copy basic properties from another material.
126
+ *
127
+ * Disposes existing bind groups/states, copies `numPasses`. Subclasses should
128
+ * extend this to copy their own fields and call `optionChanged(true)` if
129
+ * shader-affecting options differ.
130
+ *
131
+ * @param other - Source material.
132
132
  */ copyFrom(other) {
133
133
  this.clearCache();
134
134
  this._numPasses = other._numPasses;
135
135
  getEngine().resourceManager.setAssetId(this, getEngine().resourceManager.getAssetId(other.coreMaterial));
136
136
  }
137
- /**
138
- * Incremented when the material’s GPU-relevant state changes and render bundles
139
- * may need to be rebuilt.
137
+ /**
138
+ * Incremented when the material’s GPU-relevant state changes and render bundles
139
+ * may need to be rebuilt.
140
140
  */ get changeTag() {
141
141
  return this._changeTag;
142
142
  }
143
- /**
144
- * Runtime-unique numeric identifier for the material instance.
143
+ /**
144
+ * Runtime-unique numeric identifier for the material instance.
145
145
  */ get instanceId() {
146
146
  return this._id;
147
147
  }
148
- /**
149
- * Number of rendering passes this material uses.
150
- *
151
- * Increasing this will expand the per-pass hash cache; make sure to implement
152
- * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`
153
- * accordingly for each pass.
148
+ /**
149
+ * Number of rendering passes this material uses.
150
+ *
151
+ * Increasing this will expand the per-pass hash cache; make sure to implement
152
+ * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`
153
+ * accordingly for each pass.
154
154
  */ get numPasses() {
155
155
  return this._numPasses;
156
156
  }
@@ -160,92 +160,103 @@ import { getEngine } from '../app/api.js';
160
160
  }
161
161
  this._numPasses = val;
162
162
  }
163
- /**
164
- * Get or compute the per-pass shader hash used for program caching.
165
- *
166
- * Calls `createHash(pass)` lazily and caches the result.
167
- * @internal
163
+ /**
164
+ * Get the number of passes this material will render for the given draw context.
165
+ *
166
+ * Default returns `numPasses`. Subclasses may override to skip passes based on context flags.
167
+ * @param _ctx - Draw context (device, flags, pass hash, instance data, etc.).
168
+ * @returns Number of passes to render for this context.
169
+ */ getNumPassesForRender(_ctx) {
170
+ return this._numPasses;
171
+ }
172
+ /**
173
+ * Get or compute the per-pass shader hash used for program caching.
174
+ *
175
+ * Calls `createHash(pass)` lazily and caches the result.
176
+ * @internal
168
177
  */ getHash(pass) {
169
178
  if (this._hash[pass] === null) {
170
179
  this._hash[pass] = this.createHash(pass);
171
180
  }
172
181
  return this._hash[pass];
173
182
  }
174
- /**
175
- * Return the queue type to which this material belongs.
176
- *
177
- * Override this in transparent or special materials (e.g., post-process).
183
+ /**
184
+ * Return the queue type to which this material belongs.
185
+ *
186
+ * Override this in transparent or special materials (e.g., post-process).
178
187
  */ getQueueType() {
179
188
  return QUEUE_OPAQUE;
180
189
  }
181
- /**
182
- * Whether the given pass is transparent.
183
- *
184
- * Used to place draw calls into appropriate render queues and set blending states.
190
+ /**
191
+ * Whether the given pass is transparent.
192
+ *
193
+ * Used to place draw calls into appropriate render queues and set blending states.
185
194
  */ isTransparentPass(_pass) {
186
195
  return false;
187
196
  }
188
- /**
189
- * Whether this material's shading is affected by scene lights.
190
- *
191
- * Override and return `false` for unlit materials.
197
+ /**
198
+ * Whether this material's shading is affected by scene lights.
199
+ *
200
+ * Override and return `false` for unlit materials.
192
201
  */ supportLighting() {
193
202
  return true;
194
203
  }
195
- /**
196
- * Whether this material supports hardware instancing.
197
- *
198
- * Override and return `false` if per-instance data is not supported in the shader.
204
+ /**
205
+ * Whether this material supports hardware instancing.
206
+ *
207
+ * Override and return `false` if per-instance data is not supported in the shader.
199
208
  */ supportInstancing() {
200
209
  return true;
201
210
  }
202
211
  /** Returns true if this is a instance of material */ isBatchable() {
203
212
  return false;
204
213
  }
205
- /**
206
- * Whether this material requires the scene color texture (e.g., for refraction).
214
+ /**
215
+ * Whether this material requires the scene color texture (e.g., for refraction).
207
216
  */ needSceneColor() {
208
217
  return false;
209
218
  }
210
- /**
211
- * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).
219
+ /**
220
+ * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).
212
221
  */ needSceneDepth() {
213
222
  return false;
214
223
  }
215
- /**
216
- * Create a material instance (instance-uniform-driven variant).
217
- *
218
- * Base returns `null`. Subclasses that support instancing can return a lightweight instance.
224
+ /**
225
+ * Create a material instance (instance-uniform-driven variant).
226
+ *
227
+ * Base returns `null`. Subclasses that support instancing can return a lightweight instance.
219
228
  */ createInstance() {
220
229
  throw new Error('Abstract function call');
221
230
  }
222
- /**
223
- * Returns the core material that owns GPU state.
224
- *
225
- * Instances may delegate to a shared core to reuse compiled programs and caches.
226
- * @public
231
+ /**
232
+ * Returns the core material that owns GPU state.
233
+ *
234
+ * Instances may delegate to a shared core to reuse compiled programs and caches.
235
+ * @public
227
236
  */ get coreMaterial() {
228
237
  return this;
229
238
  }
230
- /**
231
- * Prepare the material for drawing across all passes for the given draw context.
232
- *
233
- * Steps per pass:
234
- * - Compute global hash (material variant + context).
235
- * - Retrieve or build the GPU program, cache in `_programCache`.
236
- * - Create per-material bind group (index 2) if the program exposes it.
237
- * - Update uniforms if `_optionTag` indicates changes since last apply.
238
- * - Update and cache render states for the pass.
239
- * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.
240
- *
241
- * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).
242
- * @returns `true` if successful; `false` if any pass lacks a valid program.
239
+ /**
240
+ * Prepare the material for drawing across all passes for the given draw context.
241
+ *
242
+ * Steps per pass:
243
+ * - Compute global hash (material variant + context).
244
+ * - Retrieve or build the GPU program, cache in `_programCache`.
245
+ * - Create per-material bind group (index 2) if the program exposes it.
246
+ * - Update uniforms if `_optionTag` indicates changes since last apply.
247
+ * - Update and cache render states for the pass.
248
+ * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.
249
+ *
250
+ * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).
251
+ * @returns `true` if successful; `false` if any pass lacks a valid program.
243
252
  */ apply(ctx) {
244
- for(let pass = 0; pass < this._numPasses; pass++){
253
+ const numPasses = this.getNumPassesForRender(ctx);
254
+ for(let pass = 0; pass < numPasses; pass++){
245
255
  const hash = this.calcGlobalHash(ctx, pass);
246
256
  let state = this._states[hash];
247
257
  if (!state) {
248
- let program = Material._programCache[hash];
258
+ let programEntry = Material._programCache[hash];
259
+ let program = programEntry?.program;
249
260
  if (!program) {
250
261
  program = this.createProgram(ctx, pass) ?? null;
251
262
  if (!program) {
@@ -265,21 +276,30 @@ import { getEngine } from '../app/api.js';
265
276
  bindGroup: null,
266
277
  bindGroupTag: '',
267
278
  renderStateSet: ctx.device.createRenderStateSet(),
268
- materialTag: -1
279
+ materialTag: -1,
280
+ OIT: null,
281
+ oitUniformTag: -1
269
282
  };
270
283
  this._states[hash] = state;
271
284
  return false;
272
285
  }
273
286
  program.name = `@${this.constructor.name}_program_${this._nextProgramId++}`;
274
- Material._programCache[hash] = program;
287
+ programEntry = {
288
+ program,
289
+ refCount: 0
290
+ };
291
+ Material._programCache[hash] = programEntry;
275
292
  }
293
+ programEntry.refCount++;
276
294
  const bindGroup = program.bindGroupLayouts.length > 2 ? ctx.device.createBindGroup(program.bindGroupLayouts[2]) : null;
277
295
  state = {
278
296
  program,
279
297
  bindGroup,
280
298
  bindGroupTag: bindGroup?.getVersion() ?? '',
281
299
  renderStateSet: ctx.device.createRenderStateSet(),
282
- materialTag: -1
300
+ materialTag: -1,
301
+ OIT: null,
302
+ oitUniformTag: -1
283
303
  };
284
304
  this._states[hash] = state;
285
305
  }
@@ -287,6 +307,11 @@ import { getEngine } from '../app/api.js';
287
307
  return false;
288
308
  }
289
309
  if (state.bindGroup) {
310
+ if (ctx.oit && (state.OIT !== ctx.oit || state.oitUniformTag !== ctx.oit.uniformTag)) {
311
+ state.OIT = ctx.oit;
312
+ state.oitUniformTag = ctx.oit.uniformTag;
313
+ ctx.oit.applyUniforms(ctx, state.bindGroup);
314
+ }
290
315
  this.applyUniforms(state.bindGroup, ctx, state.materialTag !== this._optionTag, pass);
291
316
  }
292
317
  state.materialTag = this._optionTag;
@@ -303,15 +328,15 @@ import { getEngine } from '../app/api.js';
303
328
  }
304
329
  return true;
305
330
  }
306
- /**
307
- * Bind the program, bind group, and render states for the specified pass.
308
- *
309
- * Must be called after `apply(ctx)` for the same pass.
310
- *
311
- * @param device - Rendering device.
312
- * @param pass - Pass index to bind.
313
- * @returns `true` on success; `false` if state or program missing.
314
- * @internal
331
+ /**
332
+ * Bind the program, bind group, and render states for the specified pass.
333
+ *
334
+ * Must be called after `apply(ctx)` for the same pass.
335
+ *
336
+ * @param device - Rendering device.
337
+ * @param pass - Pass index to bind.
338
+ * @returns `true` on success; `false` if state or program missing.
339
+ * @internal
315
340
  */ bind(device, pass) {
316
341
  const hash = this._currentHash[pass];
317
342
  const state = this._states[hash];
@@ -329,58 +354,59 @@ import { getEngine } from '../app/api.js';
329
354
  device.setRenderStates(state.renderStateSet);
330
355
  return true;
331
356
  }
332
- /**
333
- * Compute the global hash for the given pass and draw context.
334
- *
335
- * Includes:
336
- * - Per-pass material hash from `getHash(pass)`.
337
- * - `ctx.materialFlags` for context-dependent toggles.
338
- * - `ctx.shaderVariantHash` for shader layout/feature variants, falling back
339
- * to `ctx.renderPassHash` for passes without a shader-only hash.
340
- * @internal
357
+ /**
358
+ * Compute the global hash for the given pass and draw context.
359
+ *
360
+ * Includes:
361
+ * - Per-pass material hash from `getHash(pass)`.
362
+ * - `ctx.materialFlags` for context-dependent toggles.
363
+ * - `ctx.shaderVariantHash` for shader layout/feature variants, falling back
364
+ * to `ctx.renderPassHash` for passes without a shader-only hash.
365
+ * @internal
341
366
  */ calcGlobalHash(ctx, pass) {
342
367
  const shaderVariantHash = ctx.shaderVariantHash ?? ctx.renderPassHash;
343
368
  return `${this.getHash(pass)}:${ctx.materialFlags}:${shaderVariantHash}:${ctx.drawEnvLight ? 1 : 0}:${ctx.currentShadowLight ? 1 : 0}:${ctx.lightBlending ? 1 : 0}`;
344
369
  }
345
- /**
346
- * Draw a primitive for all passes using this material.
347
- *
348
- * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,
349
- * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.
350
- *
351
- * @param primitive - Geometry to draw.
352
- * @param ctx - Draw context.
353
- * @param numInstances - Instance count; 0 means auto-detect from context.
354
- * @internal
370
+ /**
371
+ * Draw a primitive for all passes using this material.
372
+ *
373
+ * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,
374
+ * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.
375
+ *
376
+ * @param primitive - Geometry to draw.
377
+ * @param ctx - Draw context.
378
+ * @param numInstances - Instance count; 0 means auto-detect from context.
379
+ * @internal
355
380
  */ draw(primitive, ctx, numInstances = 0) {
356
- for(let pass = 0; pass < this._numPasses; pass++){
381
+ const numPasses = this.getNumPassesForRender(ctx);
382
+ for(let pass = 0; pass < numPasses; pass++){
357
383
  this.bind(ctx.device, pass);
358
384
  this.drawPrimitive(pass, primitive, ctx, numInstances);
359
385
  }
360
386
  }
361
- /**
362
- * Conditionally update uniforms/resources into the material bind group.
363
- *
364
- * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).
365
- *
366
- * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).
367
- * @param ctx - Draw context.
368
- * @param needUpdate - Whether uniforms need to be refreshed.
369
- * @param pass - Pass index.
387
+ /**
388
+ * Conditionally update uniforms/resources into the material bind group.
389
+ *
390
+ * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).
391
+ *
392
+ * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).
393
+ * @param ctx - Draw context.
394
+ * @param needUpdate - Whether uniforms need to be refreshed.
395
+ * @param pass - Pass index.
370
396
  */ applyUniforms(bindGroup, ctx, needUpdate, pass) {
371
397
  if (needUpdate) {
372
398
  this._applyUniforms(bindGroup, ctx, pass);
373
399
  }
374
400
  }
375
- /**
376
- * Notify the material that some option changed.
377
- *
378
- * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.
379
- * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,
380
- * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.
381
- *
382
- * @param changeHash - Set true if the change affects shader compilation or render states.
383
- * @internal
401
+ /**
402
+ * Notify the material that some option changed.
403
+ *
404
+ * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.
405
+ * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,
406
+ * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.
407
+ *
408
+ * @param changeHash - Set true if the change affects shader compilation or render states.
409
+ * @internal
384
410
  */ optionChanged(changeHash) {
385
411
  this._optionTag++;
386
412
  if (changeHash) {
@@ -392,46 +418,58 @@ import { getEngine } from '../app/api.js';
392
418
  }
393
419
  }
394
420
  clearCache() {
395
- for(const k in this._states){
396
- this._states[k]?.bindGroup?.dispose();
397
- Material._programCache[k]?.dispose();
398
- delete Material._programCache[k];
421
+ const hashes = Object.keys(this._states);
422
+ if (hashes.length > 0) {
423
+ this._changeTag++;
424
+ RenderBundleWrapper.materialChanged(this.coreMaterial);
425
+ }
426
+ for (const k of hashes){
427
+ const state = this._states[k];
428
+ state?.bindGroup?.dispose();
429
+ const programEntry = Material._programCache[k];
430
+ if (state?.program && programEntry?.program === state.program) {
431
+ programEntry.refCount--;
432
+ if (programEntry.refCount <= 0) {
433
+ programEntry.program.dispose();
434
+ delete Material._programCache[k];
435
+ }
436
+ }
399
437
  }
400
438
  this._states = {};
401
439
  }
402
- /**
403
- * Convert a pass index to a hash seed string.
404
- *
405
- * Subclasses may override to encode per-pass role (e.g., "depth", "forward", "shadow").
406
- *
407
- * @param pass - Pass number.
408
- * @returns String used when building full hash.
440
+ /**
441
+ * Convert a pass index to a hash seed string.
442
+ *
443
+ * Subclasses may override to encode per-pass role (e.g., "depth", "forward", "shadow").
444
+ *
445
+ * @param pass - Pass number.
446
+ * @returns String used when building full hash.
409
447
  */ passToHash(pass) {
410
448
  return String(pass);
411
449
  }
412
- /**
413
- * Build the material hash for a pass (excluding context-dependent parts).
414
- *
415
- * Default formula: `${constructor.name}|${pass}|${_createHash()}`
416
- *
417
- * @param pass - Pass number.
418
- * @returns Hash string used in program caching.
419
- * @internal
450
+ /**
451
+ * Build the material hash for a pass (excluding context-dependent parts).
452
+ *
453
+ * Default formula: `${constructor.name}|${pass}|${_createHash()}`
454
+ *
455
+ * @param pass - Pass number.
456
+ * @returns Hash string used in program caching.
457
+ * @internal
420
458
  */ createHash(pass) {
421
459
  return `${this.constructor.name}|${this.passToHash(pass)}|${this._createHash()}`;
422
460
  }
423
- /**
424
- * Issue the actual draw call for a pass.
425
- *
426
- * Override for custom per-pass draw behavior if necessary. The default implementation:
427
- * - Draws instanced if `numInstances > 0`.
428
- * - Else uses `ctx.instanceData.numInstances` if available.
429
- * - Else issues a non-instanced draw.
430
- *
431
- * @param pass - Pass number.
432
- * @param primitive - Primitive to draw.
433
- * @param ctx - Draw context.
434
- * @param numInstances - Explicit instance count (0 = auto).
461
+ /**
462
+ * Issue the actual draw call for a pass.
463
+ *
464
+ * Override for custom per-pass draw behavior if necessary. The default implementation:
465
+ * - Draws instanced if `numInstances > 0`.
466
+ * - Else uses `ctx.instanceData.numInstances` if available.
467
+ * - Else issues a non-instanced draw.
468
+ *
469
+ * @param pass - Pass number.
470
+ * @param primitive - Primitive to draw.
471
+ * @param ctx - Draw context.
472
+ * @param numInstances - Explicit instance count (0 = auto).
435
473
  */ drawPrimitive(pass, primitive, ctx, numInstances) {
436
474
  if (numInstances > 0) {
437
475
  primitive.drawInstanced(numInstances);
@@ -441,88 +479,88 @@ import { getEngine } from '../app/api.js';
441
479
  primitive.draw();
442
480
  }
443
481
  }
444
- /**
445
- * Dispose the material and release GPU-side resource references.
446
- *
447
- * - Unregisters from the global registry.
448
- * - Disposes the per-material bind groups kept in `_states`.
482
+ /**
483
+ * Dispose the material and release GPU-side resource references.
484
+ *
485
+ * - Unregisters from the global registry.
486
+ * - Disposes the per-material bind groups kept in `_states`.
449
487
  */ onDispose() {
450
488
  super.onDispose();
451
489
  this.clearCache();
452
490
  }
453
- /**
454
- * Build the GPU program for a pass.
455
- *
456
- * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.
457
- * Subclasses should override `_createProgram` instead of this method unless
458
- * they need to replace builder instantiation.
459
- *
460
- * @param ctx - Draw context.
461
- * @param pass - Pass number.
462
- * @returns The compiled `GPUProgram`, or `null` on failure.
463
- * @internal
491
+ /**
492
+ * Build the GPU program for a pass.
493
+ *
494
+ * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.
495
+ * Subclasses should override `_createProgram` instead of this method unless
496
+ * they need to replace builder instantiation.
497
+ *
498
+ * @param ctx - Draw context.
499
+ * @param pass - Pass number.
500
+ * @returns The compiled `GPUProgram`, or `null` on failure.
501
+ * @internal
464
502
  */ createProgram(ctx, pass) {
465
503
  const pb = new ProgramBuilder(ctx.device);
466
504
  return this._createProgram(pb, ctx, pass);
467
505
  }
468
- /**
469
- * Create and compile the shader program for this material/pass.
470
- *
471
- * Implement in subclasses:
472
- * - Define shader stages, entry points, macros/defines, and resource layouts.
473
- * - Return a compiled `GPUProgram`.
474
- *
475
- * @param pb - Program builder.
476
- * @param ctx - Draw context.
477
- * @param _pass - Pass number.
478
- * @returns The created program, or `null` on failure.
506
+ /**
507
+ * Create and compile the shader program for this material/pass.
508
+ *
509
+ * Implement in subclasses:
510
+ * - Define shader stages, entry points, macros/defines, and resource layouts.
511
+ * - Return a compiled `GPUProgram`.
512
+ *
513
+ * @param pb - Program builder.
514
+ * @param ctx - Draw context.
515
+ * @param _pass - Pass number.
516
+ * @returns The created program, or `null` on failure.
479
517
  */ _createProgram(_pb, _ctx, _pass) {
480
518
  throw new Error('Abstract function call');
481
519
  }
482
- /**
483
- * Upload uniforms and bind resources to the per-material bind group (index 2).
484
- *
485
- * Implement in subclasses to:
486
- * - Write uniform buffers/textures/samplers to the `bindGroup`.
487
- * - Respect the current `pass` and `ctx`.
488
- *
489
- * @param _bindGroup - The bind group to populate.
490
- * @param _ctx - Draw context.
491
- * @param _pass - Pass number.
520
+ /**
521
+ * Upload uniforms and bind resources to the per-material bind group (index 2).
522
+ *
523
+ * Implement in subclasses to:
524
+ * - Write uniform buffers/textures/samplers to the `bindGroup`.
525
+ * - Respect the current `pass` and `ctx`.
526
+ *
527
+ * @param _bindGroup - The bind group to populate.
528
+ * @param _ctx - Draw context.
529
+ * @param _pass - Pass number.
492
530
  */ _applyUniforms(_bindGroup, _ctx, _pass) {}
493
- /**
494
- * Update render states (depth/stencil, blending, rasterization) for the pass.
495
- *
496
- * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,
497
- * color mask, stencil ops, etc., and any context flags in `ctx`.
498
- *
499
- * @param _pass - Current pass index.
500
- * @param _renderStates - Render state set to mutate.
501
- * @param _ctx - Draw context.
531
+ /**
532
+ * Update render states (depth/stencil, blending, rasterization) for the pass.
533
+ *
534
+ * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,
535
+ * color mask, stencil ops, etc., and any context flags in `ctx`.
536
+ *
537
+ * @param _pass - Current pass index.
538
+ * @param _renderStates - Render state set to mutate.
539
+ * @param _ctx - Draw context.
502
540
  */ updateRenderStates(_pass, _renderStates, _ctx) {}
503
- /**
504
- * Compute the material-specific portion of the shader hash for the current options.
505
- *
506
- * Subclasses should override to include macro/define sets that influence program compilation.
507
- * Example return: `"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1"`.
508
- *
509
- * @returns Hash fragment string (no context/pass info).
541
+ /**
542
+ * Compute the material-specific portion of the shader hash for the current options.
543
+ *
544
+ * Subclasses should override to include macro/define sets that influence program compilation.
545
+ * Example return: `"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1"`.
546
+ *
547
+ * @returns Hash fragment string (no context/pass info).
510
548
  */ _createHash() {
511
549
  return '';
512
550
  }
513
- /**
514
- * Whether this is a lightweight instance of a core material.
515
- *
516
- * Instances typically share GPU programs with a core and only override instance uniforms.
517
- * @internal
551
+ /**
552
+ * Whether this is a lightweight instance of a core material.
553
+ *
554
+ * Instances typically share GPU programs with a core and only override instance uniforms.
555
+ * @internal
518
556
  */ get $isInstance() {
519
557
  return false;
520
558
  }
521
- /**
522
- * Instance-uniform buffer for material instances, if supported.
523
- *
524
- * Returned as a typed Float32 view over a backing ArrayBuffer.
525
- * @internal
559
+ /**
560
+ * Instance-uniform buffer for material instances, if supported.
561
+ *
562
+ * Returned as a typed Float32 view over a backing ArrayBuffer.
563
+ * @internal
526
564
  */ get $instanceUniforms() {
527
565
  throw new Error('Abstract function call');
528
566
  }