@zephyr3d/scene 0.9.6 → 0.9.8

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 (205) hide show
  1. package/dist/animation/animationset.js +52 -55
  2. package/dist/animation/animationset.js.map +1 -1
  3. package/dist/animation/joint_dynamics/controller.js +92 -32
  4. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  5. package/dist/animation/joint_dynamics/convex_collider.js +320 -0
  6. package/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
  7. package/dist/animation/joint_dynamics/joint_dynamics_system.js +57 -19
  8. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  9. package/dist/animation/joint_dynamics/solver.js +71 -27
  10. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  11. package/dist/animation/joint_dynamics_modifier.js +4 -3
  12. package/dist/animation/joint_dynamics_modifier.js.map +1 -1
  13. package/dist/animation/skeleton.js +7 -10
  14. package/dist/animation/skeleton.js.map +1 -1
  15. package/dist/app/engine.js +3 -9
  16. package/dist/app/engine.js.map +1 -1
  17. package/dist/app/scriptregistry.js +47 -16
  18. package/dist/app/scriptregistry.js.map +1 -1
  19. package/dist/asset/assetmanager.js +3 -1
  20. package/dist/asset/assetmanager.js.map +1 -1
  21. package/dist/asset/model.js +346 -7
  22. package/dist/asset/model.js.map +1 -1
  23. package/dist/avatar/wardrobe.js +7 -3
  24. package/dist/avatar/wardrobe.js.map +1 -1
  25. package/dist/camera/camera.js +240 -34
  26. package/dist/camera/camera.js.map +1 -1
  27. package/dist/index.d.ts +1350 -622
  28. package/dist/index.js +6 -11
  29. package/dist/index.js.map +1 -1
  30. package/dist/material/blinn.js +1 -1
  31. package/dist/material/blinn.js.map +1 -1
  32. package/dist/material/lambert.js +1 -1
  33. package/dist/material/lambert.js.map +1 -1
  34. package/dist/material/material.js +23 -1
  35. package/dist/material/material.js.map +1 -1
  36. package/dist/material/meshmaterial.js +178 -23
  37. package/dist/material/meshmaterial.js.map +1 -1
  38. package/dist/material/mixins/albedocolor.js +4 -4
  39. package/dist/material/mixins/albedocolor.js.map +1 -1
  40. package/dist/material/mixins/lightmodel/blinnphong.js +2 -1
  41. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  42. package/dist/material/mixins/lightmodel/lambert.js +2 -1
  43. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  44. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +63 -16
  45. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  46. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +100 -27
  47. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  48. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +16 -6
  49. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  50. package/dist/material/mixins/lit.js +1 -1
  51. package/dist/material/mixins/lit.js.map +1 -1
  52. package/dist/material/mixins/pbr/common.js +276 -65
  53. package/dist/material/mixins/pbr/common.js.map +1 -1
  54. package/dist/material/mixins/texture.js +3 -3
  55. package/dist/material/mixins/texture.js.map +1 -1
  56. package/dist/material/mixins/vertexcolor.js +2 -2
  57. package/dist/material/mixins/vertexcolor.js.map +1 -1
  58. package/dist/material/mtoon.js +574 -0
  59. package/dist/material/mtoon.js.map +1 -0
  60. package/dist/material/pbrblueprint.js +494 -331
  61. package/dist/material/pbrblueprint.js.map +1 -1
  62. package/dist/material/pbrmr.js +118 -100
  63. package/dist/material/pbrmr.js.map +1 -1
  64. package/dist/material/pbrsg.js +1 -1
  65. package/dist/material/pbrsg.js.map +1 -1
  66. package/dist/material/shader/helper.js +45 -15
  67. package/dist/material/shader/helper.js.map +1 -1
  68. package/dist/material/subsurfaceprofile.js +812 -0
  69. package/dist/material/subsurfaceprofile.js.map +1 -0
  70. package/dist/material/unlit.js +1 -1
  71. package/dist/material/unlit.js.map +1 -1
  72. package/dist/posteffect/compositor.js +46 -11
  73. package/dist/posteffect/compositor.js.map +1 -1
  74. package/dist/posteffect/ssr.js +413 -87
  75. package/dist/posteffect/ssr.js.map +1 -1
  76. package/dist/posteffect/sss.js +1053 -0
  77. package/dist/posteffect/sss.js.map +1 -0
  78. package/dist/posteffect/taa.js +61 -60
  79. package/dist/posteffect/taa.js.map +1 -1
  80. package/dist/render/abuffer_oit.js +63 -12
  81. package/dist/render/abuffer_oit.js.map +1 -1
  82. package/dist/render/cluster_light.js +6 -5
  83. package/dist/render/cluster_light.js.map +1 -1
  84. package/dist/render/drawable.js +1 -5
  85. package/dist/render/drawable.js.map +1 -1
  86. package/dist/render/drawable_mixin.js +2 -1
  87. package/dist/render/drawable_mixin.js.map +1 -1
  88. package/dist/render/fbm_wavegenerator.js +2 -1
  89. package/dist/render/fbm_wavegenerator.js.map +1 -1
  90. package/dist/render/gerstner_wavegenerator.js +2 -1
  91. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  92. package/dist/render/globalbindgroup_allocator.js +2 -1
  93. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  94. package/dist/render/lightpass.js +105 -18
  95. package/dist/render/lightpass.js.map +1 -1
  96. package/dist/render/render_queue.js +51 -8
  97. package/dist/render/render_queue.js.map +1 -1
  98. package/dist/render/renderer.js +73 -59
  99. package/dist/render/renderer.js.map +1 -1
  100. package/dist/render/rendergraph/device_pool_allocator.js +8 -0
  101. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  102. package/dist/render/rendergraph/forward_plus_builder.js +481 -95
  103. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  104. package/dist/render/rendergraph/history_resource_manager.js +55 -0
  105. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  106. package/dist/render/rendergraph/history_resources.js +3 -1
  107. package/dist/render/rendergraph/history_resources.js.map +1 -1
  108. package/dist/render/rendergraph/types.js.map +1 -1
  109. package/dist/render/renderpass.js +10 -4
  110. package/dist/render/renderpass.js.map +1 -1
  111. package/dist/render/sky.js +31 -1
  112. package/dist/render/sky.js.map +1 -1
  113. package/dist/render/weightedblended_oit.js +23 -5
  114. package/dist/render/weightedblended_oit.js.map +1 -1
  115. package/dist/scene/basesprite.js +4 -2
  116. package/dist/scene/basesprite.js.map +1 -1
  117. package/dist/scene/batchgroup.js +3 -1
  118. package/dist/scene/batchgroup.js.map +1 -1
  119. package/dist/scene/environment.js +11 -1
  120. package/dist/scene/environment.js.map +1 -1
  121. package/dist/scene/light.js +21 -3
  122. package/dist/scene/light.js.map +1 -1
  123. package/dist/scene/mesh.js +29 -14
  124. package/dist/scene/mesh.js.map +1 -1
  125. package/dist/scene/meshdrawable.js +6 -0
  126. package/dist/scene/meshdrawable.js.map +1 -1
  127. package/dist/scene/msdftext.js +5 -2
  128. package/dist/scene/msdftext.js.map +1 -1
  129. package/dist/scene/msdftextsprite.js +5 -3
  130. package/dist/scene/msdftextsprite.js.map +1 -1
  131. package/dist/scene/particlesys.js +3 -1
  132. package/dist/scene/particlesys.js.map +1 -1
  133. package/dist/scene/scene.js +6 -5
  134. package/dist/scene/scene.js.map +1 -1
  135. package/dist/scene/terrain-cm/grass.js +4 -2
  136. package/dist/scene/terrain-cm/grass.js.map +1 -1
  137. package/dist/scene/terrain-cm/grassmaterial.js +2 -1
  138. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  139. package/dist/scene/terrain-cm/terrain-cm.js +4 -2
  140. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  141. package/dist/scene/water.js +4 -2
  142. package/dist/scene/water.js.map +1 -1
  143. package/dist/shaders/shadow.js +26 -393
  144. package/dist/shaders/shadow.js.map +1 -1
  145. package/dist/shadow/esm.js +112 -12
  146. package/dist/shadow/esm.js.map +1 -1
  147. package/dist/shadow/pcf_opt.js +2 -2
  148. package/dist/shadow/pcf_opt.js.map +1 -1
  149. package/dist/shadow/pcf_pd.js +19 -10
  150. package/dist/shadow/pcf_pd.js.map +1 -1
  151. package/dist/shadow/shader.js +58 -7
  152. package/dist/shadow/shader.js.map +1 -1
  153. package/dist/shadow/shadow_impl.js +6 -0
  154. package/dist/shadow/shadow_impl.js.map +1 -1
  155. package/dist/shadow/shadow_region.js +229 -0
  156. package/dist/shadow/shadow_region.js.map +1 -0
  157. package/dist/shadow/shadowmapper.js +67 -59
  158. package/dist/shadow/shadowmapper.js.map +1 -1
  159. package/dist/shadow/vsm.js +45 -19
  160. package/dist/shadow/vsm.js.map +1 -1
  161. package/dist/utility/blueprint/common/constants.js +8 -8
  162. package/dist/utility/blueprint/common/constants.js.map +1 -1
  163. package/dist/utility/blueprint/material/pbr.js +31 -4
  164. package/dist/utility/blueprint/material/pbr.js.map +1 -1
  165. package/dist/utility/blueprint/material/texture.js +1 -17
  166. package/dist/utility/blueprint/material/texture.js.map +1 -1
  167. package/dist/utility/serialization/manager.js +66 -98
  168. package/dist/utility/serialization/manager.js.map +1 -1
  169. package/dist/utility/serialization/scene/animation.js +5 -2
  170. package/dist/utility/serialization/scene/animation.js.map +1 -1
  171. package/dist/utility/serialization/scene/batch.js +4 -1
  172. package/dist/utility/serialization/scene/batch.js.map +1 -1
  173. package/dist/utility/serialization/scene/camera.js +249 -54
  174. package/dist/utility/serialization/scene/camera.js.map +1 -1
  175. package/dist/utility/serialization/scene/common.js +37 -1
  176. package/dist/utility/serialization/scene/common.js.map +1 -1
  177. package/dist/utility/serialization/scene/light.js +42 -3
  178. package/dist/utility/serialization/scene/light.js.map +1 -1
  179. package/dist/utility/serialization/scene/material.js +1112 -646
  180. package/dist/utility/serialization/scene/material.js.map +1 -1
  181. package/dist/utility/serialization/scene/mesh.js +7 -4
  182. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  183. package/dist/utility/serialization/scene/node.js +31 -12
  184. package/dist/utility/serialization/scene/node.js.map +1 -1
  185. package/dist/utility/serialization/scene/particle.js +4 -1
  186. package/dist/utility/serialization/scene/particle.js.map +1 -1
  187. package/dist/utility/serialization/scene/primitive.js +3 -1
  188. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  189. package/dist/utility/serialization/scene/scene.js +18 -0
  190. package/dist/utility/serialization/scene/scene.js.map +1 -1
  191. package/dist/utility/serialization/scene/sprite.js +6 -3
  192. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  193. package/dist/utility/serialization/scene/terrain.js +5 -2
  194. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  195. package/dist/utility/serialization/scene/text.js +3 -1
  196. package/dist/utility/serialization/scene/text.js.map +1 -1
  197. package/dist/utility/serialization/scene/water.js +4 -1
  198. package/dist/utility/serialization/scene/water.js.map +1 -1
  199. package/dist/utility/textures/ltcdata.js +6 -0
  200. package/dist/utility/textures/ltcdata.js.map +1 -0
  201. package/dist/utility/textures/ltclut.js +61 -0
  202. package/dist/utility/textures/ltclut.js.map +1 -0
  203. package/dist/values.js +9 -1
  204. package/dist/values.js.map +1 -1
  205. package/package.json +3 -3
@@ -1,5 +1,5 @@
1
1
  import { ProgramBuilder } from '@zephyr3d/device';
2
- import { RENDER_PASS_TYPE_OBJECT_COLOR, QUEUE_OPAQUE, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags, RENDER_PASS_TYPE_DEPTH, QUEUE_TRANSPARENT } from '../values.js';
2
+ import { RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, QUEUE_OPAQUE, MaterialVaryingFlags, RENDER_PASS_TYPE_DEPTH, QUEUE_TRANSPARENT } from '../values.js';
3
3
  import { Material } from './material.js';
4
4
  import { encodeNormalizedFloatToRGBA } from '../shaders/misc.js';
5
5
  import { ShaderHelper } from './shader/helper.js';
@@ -67,6 +67,7 @@ let FEATURE_DISABLE_TAA = 0;
67
67
  *
68
68
  * @public
69
69
  */ class MeshMaterial extends Material {
70
+ static SHADER_VERSION = 3;
70
71
  /**
71
72
  * Registered instance uniforms for this material class.
72
73
  *
@@ -89,6 +90,8 @@ let FEATURE_DISABLE_TAA = 0;
89
90
  /** @internal Alpha test cutoff in [0, 1]. */ _alphaCutoff;
90
91
  /** @internal Whether alpha-test uses temporal dither coverage. */ _alphaDither;
91
92
  /** @internal Blending mode. */ _blendMode;
93
+ /** @internal Whether transparent materials cast shadow through a masked shadow-only path. */ _transparentShadowCaster;
94
+ /** @internal Alpha cutoff used by the shadow-only masked caster path. */ _shadowAlphaCutoff;
92
95
  /** @internal Face culling mode. */ _cullMode;
93
96
  /** @internal Opacity in [0, 1]. */ _opacity;
94
97
  /**
@@ -113,6 +116,8 @@ let FEATURE_DISABLE_TAA = 0;
113
116
  this._alphaCutoff = 0;
114
117
  this._alphaDither = false;
115
118
  this._blendMode = 'none';
119
+ this._transparentShadowCaster = false;
120
+ this._shadowAlphaCutoff = 0.5;
116
121
  this._cullMode = 'back';
117
122
  this._opacity = 1;
118
123
  this._taaStrength = 1 - 1 / 16;
@@ -141,11 +146,27 @@ let FEATURE_DISABLE_TAA = 0;
141
146
  this.alphaCutoff = other.alphaCutoff;
142
147
  this.alphaDither = other.alphaDither;
143
148
  this.blendMode = other.blendMode;
149
+ this.transparentShadowCaster = other.transparentShadowCaster;
150
+ this.shadowAlphaCutoff = other.shadowAlphaCutoff;
144
151
  this.cullMode = other.cullMode;
145
152
  this.opacity = other.opacity;
146
153
  this.objectColor = other.objectColor;
147
154
  }
148
155
  /**
156
+ * Capture the active draw context for both cached and freshly-built program paths.
157
+ *
158
+ * The shader-building hooks access `this.drawContext`, but uniform application may also
159
+ * consult it on subsequent frames when the GPU program is reused from cache. Updating it
160
+ * here keeps material mixins in sync even when `createProgram()` is skipped.
161
+ *
162
+ * @param ctx - Current draw context.
163
+ * @returns Whether material preparation succeeded.
164
+ */ apply(ctx) {
165
+ this._ctx = ctx;
166
+ this._materialPass = -1;
167
+ return super.apply(ctx);
168
+ }
169
+ /**
149
170
  * Mark uniform-only changes so uniforms are re-uploaded on next apply, without
150
171
  * rebuilding shader programs.
151
172
  */ uniformChanged() {
@@ -480,6 +501,31 @@ let FEATURE_DISABLE_TAA = 0;
480
501
  }
481
502
  }
482
503
  /**
504
+ * Whether transparent visible materials cast shadow through a masked shadow-only path.
505
+ * - Visible rendering stays blended.
506
+ * - Shadow-map rendering is treated like a cutout material using `shadowAlphaCutoff`.
507
+ */ get transparentShadowCaster() {
508
+ return this._transparentShadowCaster;
509
+ }
510
+ set transparentShadowCaster(val) {
511
+ if (this._transparentShadowCaster !== !!val) {
512
+ this._transparentShadowCaster = !!val;
513
+ this.optionChanged(true);
514
+ }
515
+ }
516
+ /**
517
+ * Alpha cutoff used by the shadow-only masked caster path.
518
+ */ get shadowAlphaCutoff() {
519
+ return this._shadowAlphaCutoff;
520
+ }
521
+ set shadowAlphaCutoff(val) {
522
+ val = val > 1 ? 1 : val < 0 ? 0 : val;
523
+ if (this._shadowAlphaCutoff !== val) {
524
+ this._shadowAlphaCutoff = val;
525
+ this.uniformChanged();
526
+ }
527
+ }
528
+ /**
483
529
  * Face culling mode: 'none' | 'front' | 'back'.
484
530
  * - Does not force shader rebuild; affects rasterizer state.
485
531
  */ get cullMode() {
@@ -525,6 +571,43 @@ let FEATURE_DISABLE_TAA = 0;
525
571
  return false;
526
572
  }
527
573
  /**
574
+ * Returns the effective blend mode for the current pass.
575
+ * Transparent-shadow-caster materials stay blended in visible passes, but become masked in shadow passes.
576
+ */ getEffectiveBlendMode(pass, ctx) {
577
+ if (ctx && this.useTransparentShadowCasterForPass(ctx.renderPass?.type) && this.featureUsed(FEATURE_ALPHABLEND) !== 'none') {
578
+ return 'none';
579
+ }
580
+ return this.featureUsed(FEATURE_ALPHABLEND);
581
+ }
582
+ /**
583
+ * Returns the alpha cutoff that should be used for the current pass.
584
+ */ getActiveAlphaCutoff(ctx, pass = this.pass) {
585
+ return ctx && this.useTransparentShadowCaster(ctx, pass) ? this._shadowAlphaCutoff : this._alphaCutoff;
586
+ }
587
+ /**
588
+ * Whether the current pass should use the shadow-only masked caster path.
589
+ */ useTransparentShadowCaster(ctx, _pass = this.pass) {
590
+ return !!ctx && this.useTransparentShadowCasterForPass(ctx.renderPass?.type);
591
+ }
592
+ /**
593
+ * Whether the specified render pass type should reinterpret this transparent material as a masked shadow caster.
594
+ */ useTransparentShadowCasterForPass(renderPassType) {
595
+ return !!this._transparentShadowCaster && renderPassType === RENDER_PASS_TYPE_SHADOWMAP && this.featureUsed(FEATURE_ALPHABLEND) !== 'none';
596
+ }
597
+ /**
598
+ * Whether this pass needs an alpha-cutoff uniform bound.
599
+ */ usesAlphaCutoff(ctx, pass = this.pass) {
600
+ return this._alphaCutoff > 0 || !!ctx && this.useTransparentShadowCaster(ctx, pass);
601
+ }
602
+ /**
603
+ * Whether this pass needs fragment color inputs.
604
+ * This stays aligned with the historical meaning of `needFragmentColor`,
605
+ * but also allows shadow-only transparent casters to fetch alpha sources.
606
+ */ needFragmentColorInput(ctx) {
607
+ const drawContext = ctx ?? this.drawContext;
608
+ return this.needFragmentColor(drawContext) || this.useTransparentShadowCaster(drawContext, this.pass);
609
+ }
610
+ /**
528
611
  * Update render states per pass and draw context.
529
612
  * Sets blending, alpha-to-coverage, depth test/write, cull mode, color mask, and cooperates with OIT.
530
613
  *
@@ -534,16 +617,17 @@ let FEATURE_DISABLE_TAA = 0;
534
617
  * @returns void
535
618
  */ updateRenderStates(pass, stateSet, ctx) {
536
619
  const isObjectColorPass = ctx.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR;
537
- const blending = !isObjectColorPass && (this.featureUsed(FEATURE_ALPHABLEND) !== 'none' || ctx.lightBlending);
538
- const a2c = !isObjectColorPass && this.featureUsed(FEATURE_ALPHATOCOVERAGE);
539
- const ztestEq = ctx.queue === QUEUE_OPAQUE && !!ctx.depthTexture && !ctx.sceneColorTexture;
620
+ const blendMode = this.getEffectiveBlendMode(pass, ctx);
621
+ const blending = !isObjectColorPass && (blendMode !== 'none' || ctx.lightBlending);
622
+ const a2c = !isObjectColorPass && this.featureUsed(FEATURE_ALPHATOCOVERAGE) && !this.useTransparentShadowCaster(ctx, pass);
623
+ const ztestEq = ctx.renderPass.type === RENDER_PASS_TYPE_LIGHT && ctx.queue === QUEUE_OPAQUE && !!ctx.depthPrepassAttachment && !ctx.sceneColorTexture;
540
624
  if (blending || a2c) {
541
625
  const blendingState = stateSet.useBlendingState();
542
626
  if (blending) {
543
627
  blendingState.enable(true);
544
628
  blendingState.setBlendFuncAlpha('zero', 'one');
545
629
  blendingState.setBlendEquation('add', 'add');
546
- if (this._blendMode === 'additive' || ctx.lightBlending) {
630
+ if (blendMode === 'additive' || ctx.lightBlending) {
547
631
  blendingState.setBlendFuncRGB('one', 'one');
548
632
  } else {
549
633
  blendingState.setBlendFuncRGB('one', 'inv-src-alpha');
@@ -593,10 +677,10 @@ let FEATURE_DISABLE_TAA = 0;
593
677
  * @param pass - Current material pass index.
594
678
  * @returns void
595
679
  */ applyUniformValues(bindGroup, ctx, pass) {
596
- if (this.featureUsed(FEATURE_ALPHATEST)) {
597
- bindGroup.setValue('zAlphaCutoff', this._alphaCutoff);
680
+ if (this.usesAlphaCutoff(ctx, pass)) {
681
+ bindGroup.setValue('zAlphaCutoff', this.getActiveAlphaCutoff(ctx, pass));
598
682
  }
599
- if (this.isTransparentPass(pass) && ctx.renderPass.type === RENDER_PASS_TYPE_LIGHT && !(ctx.materialFlags & MaterialVaryingFlags.INSTANCING)) {
683
+ if (this.isTransparentPass(pass, ctx) && ctx.renderPass.type === RENDER_PASS_TYPE_LIGHT && !(ctx.materialFlags & MaterialVaryingFlags.INSTANCING)) {
600
684
  bindGroup.setValue('zOpacity', this._opacity);
601
685
  }
602
686
  if (ctx.oit) {
@@ -620,8 +704,8 @@ let FEATURE_DISABLE_TAA = 0;
620
704
  *
621
705
  * @param pass - Material pass index.
622
706
  * @returns True if the pass is transparent; otherwise false.
623
- */ isTransparentPass(_pass) {
624
- return this.featureUsed(FEATURE_ALPHABLEND) !== 'none';
707
+ */ isTransparentPass(pass, ctx) {
708
+ return this.getEffectiveBlendMode(pass, ctx) !== 'none';
625
709
  }
626
710
  /**
627
711
  * Create the GPU program for a given pass and draw context.
@@ -668,7 +752,7 @@ let FEATURE_DISABLE_TAA = 0;
668
752
  * @returns The hash fragment string.
669
753
  * @internal
670
754
  */ _createHash() {
671
- return this._featureStates.map((val)=>val === undefined ? '' : val).join('|');
755
+ return `${MeshMaterial.SHADER_VERSION}|${this._featureStates.map((val)=>val === undefined ? '' : val).join('|')}|${Number(this._transparentShadowCaster)}`;
672
756
  }
673
757
  /**
674
758
  * Apply material uniforms to the bind group (set 2).
@@ -690,7 +774,11 @@ let FEATURE_DISABLE_TAA = 0;
690
774
  * @param ctx - Optional draw context; defaults to the last captured `drawContext`.
691
775
  * @returns True if fragment color computation is needed; otherwise false.
692
776
  */ needFragmentColor(ctx) {
693
- return (ctx ?? this.drawContext).renderPass.type === RENDER_PASS_TYPE_LIGHT || this._alphaCutoff > 0 || this.alphaToCoverage;
777
+ const drawContext = ctx ?? this.drawContext;
778
+ if (!drawContext?.renderPass) {
779
+ return this._alphaCutoff > 0 || this.alphaToCoverage;
780
+ }
781
+ return drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT || this._alphaCutoff > 0 || this.alphaToCoverage;
694
782
  }
695
783
  /**
696
784
  * Vertex shader hook.
@@ -714,7 +802,7 @@ let FEATURE_DISABLE_TAA = 0;
714
802
  if (this.drawContext.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR) {
715
803
  scope.$outputs.zObjectColor = this.getInstancedUniform(scope, MeshMaterial.OBJECT_COLOR_UNIFORM);
716
804
  }
717
- if (this.isTransparentPass(this.pass)) {
805
+ if (this.isTransparentPass(this.pass, this.drawContext)) {
718
806
  scope.$outputs.zOpacity = this.getInstancedUniform(scope, MeshMaterial.OPACITY_UNIFORM);
719
807
  }
720
808
  } else {
@@ -733,11 +821,11 @@ let FEATURE_DISABLE_TAA = 0;
733
821
  */ fragmentShader(scope) {
734
822
  const pb = scope.$builder;
735
823
  ShaderHelper.prepareFragmentShader(pb, this.drawContext);
736
- if (this._alphaCutoff > 0) {
824
+ if (this.usesAlphaCutoff(this.drawContext, this.pass)) {
737
825
  scope.zAlphaCutoff = pb.float().uniform(2);
738
826
  }
739
827
  if (this.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
740
- if (this.isTransparentPass(this.pass) && !(this.drawContext.materialFlags & MaterialVaryingFlags.INSTANCING)) {
828
+ if (this.isTransparentPass(this.pass, this.drawContext) && !(this.drawContext.materialFlags & MaterialVaryingFlags.INSTANCING)) {
741
829
  scope.zOpacity = pb.float().uniform(2);
742
830
  }
743
831
  }
@@ -768,8 +856,20 @@ let FEATURE_DISABLE_TAA = 0;
768
856
  this.$outputs.zFragmentOutput = pb.vec4();
769
857
  if (ctx.materialFlags & MaterialVaryingFlags.SSR_STORE_ROUGHNESS) {
770
858
  this.$outputs.zSSRRoughness = pb.vec4();
859
+ }
860
+ if (ctx.materialFlags & (MaterialVaryingFlags.SSR_STORE_ROUGHNESS | MaterialVaryingFlags.SSS_STORE_NORMAL)) {
771
861
  this.$outputs.zSSRNormal = pb.vec4();
772
862
  }
863
+ if (ctx.materialFlags & MaterialVaryingFlags.SSS_STORE_PROFILE) {
864
+ this.$outputs.zSSSProfile = pb.vec4();
865
+ this.$outputs.zSSSParams = pb.vec4();
866
+ }
867
+ if (ctx.materialFlags & MaterialVaryingFlags.SSS_STORE_DIFFUSE) {
868
+ this.$outputs.zSSSDiffuse = pb.vec4();
869
+ }
870
+ if (ctx.materialFlags & MaterialVaryingFlags.SSS_STORE_TRANSMISSION) {
871
+ this.$outputs.zSSSTransmission = pb.vec4();
872
+ }
773
873
  if (ctx.renderPass.type === RENDER_PASS_TYPE_DEPTH && ctx.motionVectors) {
774
874
  this.$outputs.zMotionVector = pb.vec4();
775
875
  this.zTAAStrength = pb.float().uniform(2);
@@ -801,8 +901,13 @@ let FEATURE_DISABLE_TAA = 0;
801
901
  * @param color - Lit fragment color expression; may be undefined for depth-only paths.
802
902
  * @param ssrRoughness - Optional SSR roughness output expression.
803
903
  * @param ssrNormal - Optional SSR normal output expression.
904
+ * @param sssProfile - Optional SSS profile output expression.
905
+ * @param sssParams - Optional SSS packed params output expression.
906
+ * @param sssProfileEnabled - True only when this material should write SSS profile data.
907
+ * @param sssDiffuse - Optional diffuse-only lighting color for SSS composition.
908
+ * @param sssTransmission - Optional thin-shell transmission lighting color for SSS composition.
804
909
  * @returns void
805
- */ outputFragmentColor(scope, worldPos, color, ssrRoughness, ssrNormal) {
910
+ */ outputFragmentColor(scope, worldPos, color, ssrRoughness, ssrNormal, sssProfile, sssParams, sssDiffuse, sssTransmission, sssProfileEnabled = false) {
806
911
  const pb = scope.$builder;
807
912
  const that = this;
808
913
  const funcName = 'Z_outputFragmentColor';
@@ -811,7 +916,40 @@ let FEATURE_DISABLE_TAA = 0;
811
916
  pb.float('alpha'),
812
917
  pb.float('cutoff')
813
918
  ], function() {
814
- if (that.featureUsed(FEATURE_ALPHADITHER) && !that.isTransparentPass(that.pass)) {
919
+ const shadowMaskedCaster = that.useTransparentShadowCaster(that.drawContext, that.pass);
920
+ const shadowAlphaClip = pb.getDevice().type !== 'webgl' && that.drawContext.renderPass.type === RENDER_PASS_TYPE_SHADOWMAP && (shadowMaskedCaster || !that.isTransparentPass(that.pass, that.drawContext));
921
+ if (shadowAlphaClip) {
922
+ if (!pb.getGlobalScope().Z_shadowDither4x4) {
923
+ pb.getGlobalScope().Z_shadowDither4x4 = [
924
+ pb.float(0 / 16),
925
+ pb.float(8 / 16),
926
+ pb.float(2 / 16),
927
+ pb.float(10 / 16),
928
+ pb.float(12 / 16),
929
+ pb.float(4 / 16),
930
+ pb.float(14 / 16),
931
+ pb.float(6 / 16),
932
+ pb.float(3 / 16),
933
+ pb.float(11 / 16),
934
+ pb.float(1 / 16),
935
+ pb.float(9 / 16),
936
+ pb.float(15 / 16),
937
+ pb.float(7 / 16),
938
+ pb.float(13 / 16),
939
+ pb.float(5 / 16)
940
+ ];
941
+ }
942
+ this.$l.alphaWidth = pb.max(pb.fwidth(this.alpha), 1e-4);
943
+ this.$l.shadowCutoff = pb.max(pb.sub(this.cutoff, pb.min(0.18, pb.mul(this.alphaWidth, 2))), 0);
944
+ this.$l.coverage = pb.clamp(pb.add(pb.div(pb.sub(this.alpha, this.shadowCutoff), this.alphaWidth), 0.5), 0, 1);
945
+ this.$l.pixel = pb.mod(pb.floor(this.$builtins.fragCoord.xy), pb.vec2(4));
946
+ // Scramble the ordered dither with shadow depth so overlapping masked layers
947
+ // at the same texel do not all discard the exact same coverage bits.
948
+ this.$l.layerJitter = pb.floor(pb.mul(pb.fract(pb.mul(this.$builtins.fragCoord.z, 131.37)), 16));
949
+ this.$l.ditherIndex = pb.mod(pb.add(pb.add(pb.mul(this.pixel.y, 4), this.pixel.x), this.layerJitter), 16);
950
+ this.$l.noise = this.Z_shadowDither4x4.at(pb.uint(this.ditherIndex));
951
+ this.$return(pb.lessThan(this.coverage, this.noise));
952
+ } else if (that.featureUsed(FEATURE_ALPHADITHER) && !that.isTransparentPass(that.pass, that.drawContext)) {
815
953
  this.$l.frame = pb.float(ShaderHelper.getFramestamp(this));
816
954
  this.$l.phase = pb.add(this.$builtins.fragCoord.xy, pb.vec2(this.frame, pb.mul(this.frame, 0.754877666)));
817
955
  this.$l.noise = pb.fract(pb.mul(pb.sin(pb.dot(this.phase, pb.vec2(12.9898, 78.233))), 43758.5453));
@@ -830,19 +968,19 @@ let FEATURE_DISABLE_TAA = 0;
830
968
  this.$l.outColor = color ? this.color : pb.vec4();
831
969
  if (that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
832
970
  let output = true;
833
- if (!that.isTransparentPass(that.pass) && !that.alphaToCoverage) {
971
+ if (!that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage) {
834
972
  this.outColor.a = 1;
835
- } else if (that.isTransparentPass(that.pass)) {
973
+ } else if (that.isTransparentPass(that.pass, that.drawContext)) {
836
974
  const opacity = that.drawContext.materialFlags & MaterialVaryingFlags.INSTANCING ? this.$inputs.zOpacity : this.zOpacity;
837
975
  this.outColor.a = pb.mul(this.outColor.a, opacity);
838
976
  }
839
- if (that.isTransparentPass(that.pass)) {
977
+ if (that.isTransparentPass(that.pass, that.drawContext)) {
840
978
  if (this.zAlphaCutoff) {
841
979
  this.$if(pb.getGlobalScope()[alphaClipFuncName](this.outColor.a, this.zAlphaCutoff), function() {
842
980
  pb.discard();
843
981
  });
844
982
  }
845
- if (that.drawContext.oit && that.drawContext.lightBlending) {
983
+ if (that.drawContext.oit && that.drawContext.lightBlending && that.drawContext.oit.getType() !== 'ab') {
846
984
  // For OIT with multi-light decomposition, keep additive light passes
847
985
  // color-only to avoid duplicating per-fragment transmittance.
848
986
  this.outColor = pb.vec4(this.outColor.rgb, 0);
@@ -914,15 +1052,32 @@ let FEATURE_DISABLE_TAA = 0;
914
1052
  if (that.drawContext.materialFlags & MaterialVaryingFlags.SSR_STORE_ROUGHNESS) {
915
1053
  // Transparent/blended passes (and materials that depend on scene color like transmission)
916
1054
  // do not have a stable depth match for SSR, so force-disable SSR contribution on those pixels.
917
- const disableSSR = that.isTransparentPass(that.pass) && that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT;
1055
+ const disableSSR = that.isTransparentPass(that.pass, that.drawContext) && that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT;
918
1056
  const disableSceneColorSSR = that.needSceneColor() && that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT;
919
1057
  if (disableSSR || disableSceneColorSSR) {
920
1058
  scope.$outputs.zSSRRoughness = pb.vec4(0, 0, 0, 1);
921
1059
  scope.$outputs.zSSRNormal = pb.vec4(0);
922
1060
  } else {
923
- scope.$outputs.zSSRRoughness = ssrRoughness ?? pb.vec4(1, 0, 0, 1);
1061
+ scope.$outputs.zSSRRoughness = ssrRoughness ?? pb.vec4(1, 1, 0, 1);
924
1062
  scope.$outputs.zSSRNormal = ssrNormal ? ssrNormal : scope.$inputs.wNorm ? pb.vec4(pb.add(pb.mul(pb.normalize(scope.$inputs.wNorm), 0.5), pb.vec3(0.5)), 1) : pb.vec4(0.5, 0.5, 1, 1);
925
1063
  }
1064
+ } else if (that.drawContext.materialFlags & MaterialVaryingFlags.SSS_STORE_NORMAL) {
1065
+ const disableNormal = that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT && (that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage || that.needSceneColor());
1066
+ scope.$outputs.zSSRNormal = disableNormal ? pb.vec4(0) : ssrNormal ? ssrNormal : scope.$inputs.wNorm ? pb.vec4(pb.add(pb.mul(pb.normalize(scope.$inputs.wNorm), 0.5), pb.vec3(0.5)), 1) : pb.vec4(0.5, 0.5, 1, 1);
1067
+ }
1068
+ if (that.drawContext.materialFlags & MaterialVaryingFlags.SSS_STORE_PROFILE) {
1069
+ const disableSSS = that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT && (that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage || that.needSceneColor());
1070
+ const writeSSSProfile = sssProfileEnabled && !disableSSS;
1071
+ scope.$outputs.zSSSProfile = writeSSSProfile ? sssProfile ?? pb.vec4(0) : pb.vec4(0);
1072
+ scope.$outputs.zSSSParams = writeSSSProfile ? sssParams ?? pb.vec4(0) : pb.vec4(0);
1073
+ }
1074
+ if (that.drawContext.materialFlags & MaterialVaryingFlags.SSS_STORE_DIFFUSE) {
1075
+ const disableSSS = that.drawContext.renderPass.type !== RENDER_PASS_TYPE_LIGHT || that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage || that.needSceneColor();
1076
+ scope.$outputs.zSSSDiffuse = disableSSS ? pb.vec4(0) : sssDiffuse ?? pb.vec4(0);
1077
+ }
1078
+ if (that.drawContext.materialFlags & MaterialVaryingFlags.SSS_STORE_TRANSMISSION) {
1079
+ const disableSSS = that.drawContext.renderPass.type !== RENDER_PASS_TYPE_LIGHT || that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage || that.needSceneColor();
1080
+ scope.$outputs.zSSSTransmission = disableSSS ? pb.vec4(0) : sssTransmission ?? pb.vec4(0);
926
1081
  }
927
1082
  }
928
1083
  }