@aura3d/engine 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/README.md +24 -5
  2. package/dist/animation/AnimationMixer.d.ts +4 -1
  3. package/dist/animation/AnimationMixer.d.ts.map +1 -1
  4. package/dist/animation/AnimationMixer.js +36 -29
  5. package/dist/animation/AnimationMixer.js.map +1 -1
  6. package/dist/animation/FootIk.d.ts +9 -0
  7. package/dist/animation/FootIk.d.ts.map +1 -1
  8. package/dist/animation/FootIk.js +22 -8
  9. package/dist/animation/FootIk.js.map +1 -1
  10. package/dist/animation/HumanoidRetargeting.d.ts +6 -2
  11. package/dist/animation/HumanoidRetargeting.d.ts.map +1 -1
  12. package/dist/animation/HumanoidRetargeting.js +18 -8
  13. package/dist/animation/HumanoidRetargeting.js.map +1 -1
  14. package/dist/animation/LocomotionEvidence.d.ts +34 -0
  15. package/dist/animation/LocomotionEvidence.d.ts.map +1 -0
  16. package/dist/animation/LocomotionEvidence.js +48 -0
  17. package/dist/animation/LocomotionEvidence.js.map +1 -0
  18. package/dist/animation/RootMotion.d.ts +13 -4
  19. package/dist/animation/RootMotion.d.ts.map +1 -1
  20. package/dist/animation/RootMotion.js +21 -1
  21. package/dist/animation/RootMotion.js.map +1 -1
  22. package/dist/animation/index.d.ts +1 -0
  23. package/dist/animation/index.d.ts.map +1 -1
  24. package/dist/animation/index.js +1 -0
  25. package/dist/animation/index.js.map +1 -1
  26. package/dist/assets/GLTFAnimationRuntime.d.ts +84 -4
  27. package/dist/assets/GLTFAnimationRuntime.d.ts.map +1 -1
  28. package/dist/assets/GLTFAnimationRuntime.js +308 -23
  29. package/dist/assets/GLTFAnimationRuntime.js.map +1 -1
  30. package/dist/assets/GLTFCompressionDecoders.d.ts +1 -0
  31. package/dist/assets/GLTFCompressionDecoders.d.ts.map +1 -1
  32. package/dist/assets/GLTFCompressionDecoders.js +20 -5
  33. package/dist/assets/GLTFCompressionDecoders.js.map +1 -1
  34. package/dist/assets/GLTFLoader.d.ts.map +1 -1
  35. package/dist/assets/GLTFLoader.js +21 -7
  36. package/dist/assets/GLTFLoader.js.map +1 -1
  37. package/dist/assets/KTX2BasisTextureTranscoder.d.ts.map +1 -1
  38. package/dist/assets/KTX2BasisTextureTranscoder.js +8 -0
  39. package/dist/assets/KTX2BasisTextureTranscoder.js.map +1 -1
  40. package/dist/controls/MapControls.d.ts +1 -1
  41. package/dist/controls/MapControls.d.ts.map +1 -1
  42. package/dist/controls/MapControls.js +3 -3
  43. package/dist/controls/MapControls.js.map +1 -1
  44. package/dist/controls/OrbitControls.d.ts +17 -3
  45. package/dist/controls/OrbitControls.d.ts.map +1 -1
  46. package/dist/controls/OrbitControls.js +24 -7
  47. package/dist/controls/OrbitControls.js.map +1 -1
  48. package/dist/controls/TrackballControls.d.ts.map +1 -1
  49. package/dist/controls/TrackballControls.js +2 -0
  50. package/dist/controls/TrackballControls.js.map +1 -1
  51. package/dist/create-aura3d/index.js +1 -1
  52. package/dist/engine/agent-api/AnimationController.d.ts +5 -1
  53. package/dist/engine/agent-api/AnimationController.d.ts.map +1 -1
  54. package/dist/engine/agent-api/AnimationController.js +5 -0
  55. package/dist/engine/agent-api/AnimationController.js.map +1 -1
  56. package/dist/engine/agent-api/CameraProjection.d.ts +2 -0
  57. package/dist/engine/agent-api/CameraProjection.d.ts.map +1 -0
  58. package/dist/engine/agent-api/CameraProjection.js +2 -0
  59. package/dist/engine/agent-api/CameraProjection.js.map +1 -0
  60. package/dist/engine/agent-api/DeferredFrameResources.d.ts +2 -0
  61. package/dist/engine/agent-api/DeferredFrameResources.d.ts.map +1 -0
  62. package/dist/engine/agent-api/DeferredFrameResources.js +2 -0
  63. package/dist/engine/agent-api/DeferredFrameResources.js.map +1 -0
  64. package/dist/engine/agent-api/FootPlanting.d.ts +6 -0
  65. package/dist/engine/agent-api/FootPlanting.d.ts.map +1 -1
  66. package/dist/engine/agent-api/FootPlanting.js +2 -1
  67. package/dist/engine/agent-api/FootPlanting.js.map +1 -1
  68. package/dist/engine/agent-api/GameCameraRigs.d.ts.map +1 -1
  69. package/dist/engine/agent-api/GameCameraRigs.js +7 -2
  70. package/dist/engine/agent-api/GameCameraRigs.js.map +1 -1
  71. package/dist/engine/agent-api/LabelTelemetry.d.ts +8 -2
  72. package/dist/engine/agent-api/LabelTelemetry.d.ts.map +1 -1
  73. package/dist/engine/agent-api/LabelTelemetry.js +18 -4
  74. package/dist/engine/agent-api/LabelTelemetry.js.map +1 -1
  75. package/dist/engine/agent-api/ModelInstanceMatrices.d.ts +2 -0
  76. package/dist/engine/agent-api/ModelInstanceMatrices.d.ts.map +1 -0
  77. package/dist/engine/agent-api/ModelInstanceMatrices.js +2 -0
  78. package/dist/engine/agent-api/ModelInstanceMatrices.js.map +1 -0
  79. package/dist/engine/agent-api/NavigationCrowds.d.ts +28 -0
  80. package/dist/engine/agent-api/NavigationCrowds.d.ts.map +1 -1
  81. package/dist/engine/agent-api/NavigationCrowds.js +73 -1
  82. package/dist/engine/agent-api/NavigationCrowds.js.map +1 -1
  83. package/dist/engine/agent-api/PngTexturePixels.d.ts +9 -0
  84. package/dist/engine/agent-api/PngTexturePixels.d.ts.map +1 -0
  85. package/dist/engine/agent-api/PngTexturePixels.js +53 -0
  86. package/dist/engine/agent-api/PngTexturePixels.js.map +1 -0
  87. package/dist/engine/agent-api/RootDiagnosticSnapshot.d.ts +2 -0
  88. package/dist/engine/agent-api/RootDiagnosticSnapshot.d.ts.map +1 -0
  89. package/dist/engine/agent-api/RootDiagnosticSnapshot.js +2 -0
  90. package/dist/engine/agent-api/RootDiagnosticSnapshot.js.map +1 -0
  91. package/dist/engine/agent-api/RootFrameClock.d.ts +2 -0
  92. package/dist/engine/agent-api/RootFrameClock.d.ts.map +1 -0
  93. package/dist/engine/agent-api/RootFrameClock.js +2 -0
  94. package/dist/engine/agent-api/RootFrameClock.js.map +1 -0
  95. package/dist/engine/agent-api/RootPerformanceQuality.d.ts +2 -0
  96. package/dist/engine/agent-api/RootPerformanceQuality.d.ts.map +1 -0
  97. package/dist/engine/agent-api/RootPerformanceQuality.js +2 -0
  98. package/dist/engine/agent-api/RootPerformanceQuality.js.map +1 -0
  99. package/dist/engine/agent-api/RootRuntimeSupport.d.ts +61 -0
  100. package/dist/engine/agent-api/RootRuntimeSupport.d.ts.map +1 -0
  101. package/dist/engine/agent-api/RootRuntimeSupport.js +127 -0
  102. package/dist/engine/agent-api/RootRuntimeSupport.js.map +1 -0
  103. package/dist/engine/agent-api/RuntimeNodeHandle.d.ts +22 -0
  104. package/dist/engine/agent-api/RuntimeNodeHandle.d.ts.map +1 -1
  105. package/dist/engine/agent-api/RuntimeNodeHandle.js.map +1 -1
  106. package/dist/engine/agent-api/WorldLabelRenderer.d.ts +13 -2
  107. package/dist/engine/agent-api/WorldLabelRenderer.d.ts.map +1 -1
  108. package/dist/engine/agent-api/WorldLabelRenderer.js +58 -26
  109. package/dist/engine/agent-api/WorldLabelRenderer.js.map +1 -1
  110. package/dist/engine/agent-api/index.d.ts +103 -8
  111. package/dist/engine/agent-api/index.d.ts.map +1 -1
  112. package/dist/engine/agent-api/index.js +750 -242
  113. package/dist/engine/agent-api/index.js.map +1 -1
  114. package/dist/engine/agent-api/product-viewer-runtime.d.ts.map +1 -1
  115. package/dist/engine/production-runtime/RootGpuParticleWorkload.d.ts +34 -0
  116. package/dist/engine/production-runtime/RootGpuParticleWorkload.d.ts.map +1 -0
  117. package/dist/engine/production-runtime/RootGpuParticleWorkload.js +117 -0
  118. package/dist/engine/production-runtime/RootGpuParticleWorkload.js.map +1 -0
  119. package/dist/engine/production-runtime/RootRenderSourceBridge.d.ts +2 -0
  120. package/dist/engine/production-runtime/RootRenderSourceBridge.d.ts.map +1 -0
  121. package/dist/engine/production-runtime/RootRenderSourceBridge.js +2 -0
  122. package/dist/engine/production-runtime/RootRenderSourceBridge.js.map +1 -0
  123. package/dist/engine/production-runtime/TypedGLBActor.d.ts +6 -0
  124. package/dist/engine/production-runtime/TypedGLBActor.d.ts.map +1 -1
  125. package/dist/engine/production-runtime/TypedGLBActor.js +13 -0
  126. package/dist/engine/production-runtime/TypedGLBActor.js.map +1 -1
  127. package/dist/engine/production-runtime/index.d.ts +2 -0
  128. package/dist/engine/production-runtime/index.d.ts.map +1 -1
  129. package/dist/engine/production-runtime/index.js +2 -0
  130. package/dist/engine/production-runtime/index.js.map +1 -1
  131. package/dist/input/Haptics.d.ts +1 -1
  132. package/dist/input/Haptics.js +1 -1
  133. package/dist/input/InputSystem.d.ts.map +1 -1
  134. package/dist/input/InputSystem.js +1 -0
  135. package/dist/input/InputSystem.js.map +1 -1
  136. package/dist/input/PointerDevice.d.ts +1 -0
  137. package/dist/input/PointerDevice.d.ts.map +1 -1
  138. package/dist/input/PointerDevice.js +1 -1
  139. package/dist/input/PointerDevice.js.map +1 -1
  140. package/dist/input/controls/OrbitControls.d.ts +44 -1
  141. package/dist/input/controls/OrbitControls.d.ts.map +1 -1
  142. package/dist/input/controls/OrbitControls.js +151 -12
  143. package/dist/input/controls/OrbitControls.js.map +1 -1
  144. package/dist/lean/base.d.ts +1 -1
  145. package/dist/lean/base.d.ts.map +1 -1
  146. package/dist/lean/base.js +1 -1
  147. package/dist/lean/base.js.map +1 -1
  148. package/dist/lean/index.js +1 -1
  149. package/dist/lean/index.js.map +1 -1
  150. package/dist/navigation-recast/index.d.ts +116 -0
  151. package/dist/navigation-recast/index.d.ts.map +1 -0
  152. package/dist/navigation-recast/index.js +247 -0
  153. package/dist/navigation-recast/index.js.map +1 -0
  154. package/dist/physics-rapier/HeightfieldLayout.d.ts +12 -0
  155. package/dist/physics-rapier/HeightfieldLayout.d.ts.map +1 -0
  156. package/dist/physics-rapier/HeightfieldLayout.js +19 -0
  157. package/dist/physics-rapier/HeightfieldLayout.js.map +1 -0
  158. package/dist/physics-rapier/index.d.ts.map +1 -1
  159. package/dist/physics-rapier/index.js +2 -1
  160. package/dist/physics-rapier/index.js.map +1 -1
  161. package/dist/rendering/CascadedShadowMaps.d.ts.map +1 -1
  162. package/dist/rendering/CascadedShadowMaps.js +3 -1
  163. package/dist/rendering/CascadedShadowMaps.js.map +1 -1
  164. package/dist/rendering/ExtensionScalarAtlas.d.ts +18 -0
  165. package/dist/rendering/ExtensionScalarAtlas.d.ts.map +1 -0
  166. package/dist/rendering/ExtensionScalarAtlas.js +107 -0
  167. package/dist/rendering/ExtensionScalarAtlas.js.map +1 -0
  168. package/dist/rendering/LeanWebGL2Device.d.ts +265 -0
  169. package/dist/rendering/LeanWebGL2Device.d.ts.map +1 -0
  170. package/dist/rendering/LeanWebGL2Device.js +4001 -0
  171. package/dist/rendering/LeanWebGL2Device.js.map +1 -0
  172. package/dist/rendering/MaterialBinding.js +1 -1
  173. package/dist/rendering/MaterialBinding.js.map +1 -1
  174. package/dist/rendering/PlanarReflection.d.ts +2 -2
  175. package/dist/rendering/PlanarReflection.js +3 -3
  176. package/dist/rendering/PlanarReflection.js.map +1 -1
  177. package/dist/rendering/PostProcessPass.d.ts +19 -0
  178. package/dist/rendering/PostProcessPass.d.ts.map +1 -1
  179. package/dist/rendering/PostProcessPass.js +64 -32
  180. package/dist/rendering/PostProcessPass.js.map +1 -1
  181. package/dist/rendering/ProjectionMath.d.ts +3 -0
  182. package/dist/rendering/ProjectionMath.d.ts.map +1 -0
  183. package/dist/rendering/ProjectionMath.js +26 -0
  184. package/dist/rendering/ProjectionMath.js.map +1 -0
  185. package/dist/rendering/ReflectionSurfaces.d.ts +4 -1
  186. package/dist/rendering/ReflectionSurfaces.d.ts.map +1 -1
  187. package/dist/rendering/ReflectionSurfaces.js +10 -1
  188. package/dist/rendering/ReflectionSurfaces.js.map +1 -1
  189. package/dist/rendering/RenderDevice.d.ts +5 -0
  190. package/dist/rendering/RenderDevice.d.ts.map +1 -1
  191. package/dist/rendering/RenderDevice.js.map +1 -1
  192. package/dist/rendering/Renderer.d.ts +9 -0
  193. package/dist/rendering/Renderer.d.ts.map +1 -1
  194. package/dist/rendering/Renderer.js +94 -8
  195. package/dist/rendering/Renderer.js.map +1 -1
  196. package/dist/rendering/RendererPostprocessPlan.d.ts +16 -3
  197. package/dist/rendering/RendererPostprocessPlan.d.ts.map +1 -1
  198. package/dist/rendering/RendererPostprocessPlan.js +16 -2
  199. package/dist/rendering/RendererPostprocessPlan.js.map +1 -1
  200. package/dist/rendering/ScreenSpaceReflectionPass.d.ts +43 -0
  201. package/dist/rendering/ScreenSpaceReflectionPass.d.ts.map +1 -0
  202. package/dist/rendering/ScreenSpaceReflectionPass.js +58 -0
  203. package/dist/rendering/ScreenSpaceReflectionPass.js.map +1 -0
  204. package/dist/rendering/ShaderLibrary.d.ts.map +1 -1
  205. package/dist/rendering/ShaderLibrary.js +168 -197
  206. package/dist/rendering/ShaderLibrary.js.map +1 -1
  207. package/dist/rendering/ShaderLibraryCore.d.ts +3 -0
  208. package/dist/rendering/ShaderLibraryCore.d.ts.map +1 -1
  209. package/dist/rendering/ShaderLibraryCore.js +3 -0
  210. package/dist/rendering/ShaderLibraryCore.js.map +1 -1
  211. package/dist/rendering/TemporalHistory.d.ts +37 -0
  212. package/dist/rendering/TemporalHistory.d.ts.map +1 -0
  213. package/dist/rendering/TemporalHistory.js +135 -0
  214. package/dist/rendering/TemporalHistory.js.map +1 -0
  215. package/dist/rendering/TemporalMath.d.ts +3 -0
  216. package/dist/rendering/TemporalMath.d.ts.map +1 -0
  217. package/dist/rendering/TemporalMath.js +9 -0
  218. package/dist/rendering/TemporalMath.js.map +1 -0
  219. package/dist/rendering/TexturedPBRMaterial.d.ts +3 -0
  220. package/dist/rendering/TexturedPBRMaterial.d.ts.map +1 -1
  221. package/dist/rendering/TexturedPBRMaterial.js +65 -3
  222. package/dist/rendering/TexturedPBRMaterial.js.map +1 -1
  223. package/dist/rendering/WebGL2Device.d.ts +15 -0
  224. package/dist/rendering/WebGL2Device.d.ts.map +1 -1
  225. package/dist/rendering/WebGL2Device.js +328 -90
  226. package/dist/rendering/WebGL2Device.js.map +1 -1
  227. package/dist/rendering/WebGPUDevice.d.ts +16 -5
  228. package/dist/rendering/WebGPUDevice.d.ts.map +1 -1
  229. package/dist/rendering/WebGPUDevice.js +357 -58
  230. package/dist/rendering/WebGPUDevice.js.map +1 -1
  231. package/dist/rendering/WebGPUExtensionAtlas.d.ts +6 -0
  232. package/dist/rendering/WebGPUExtensionAtlas.d.ts.map +1 -0
  233. package/dist/rendering/WebGPUExtensionAtlas.js +225 -0
  234. package/dist/rendering/WebGPUExtensionAtlas.js.map +1 -0
  235. package/dist/rendering/effects/GPUParticleBackend.d.ts +4 -2
  236. package/dist/rendering/effects/GPUParticleBackend.d.ts.map +1 -1
  237. package/dist/rendering/effects/GPUParticleBackend.js +20 -2
  238. package/dist/rendering/effects/GPUParticleBackend.js.map +1 -1
  239. package/dist/rendering/effects/ResidentGPUParticleRenderer.d.ts +158 -0
  240. package/dist/rendering/effects/ResidentGPUParticleRenderer.d.ts.map +1 -0
  241. package/dist/rendering/effects/ResidentGPUParticleRenderer.js +576 -0
  242. package/dist/rendering/effects/ResidentGPUParticleRenderer.js.map +1 -0
  243. package/dist/rendering/extension-scalar-atlas.d.ts +3 -0
  244. package/dist/rendering/extension-scalar-atlas.d.ts.map +1 -0
  245. package/dist/rendering/extension-scalar-atlas.js +2 -0
  246. package/dist/rendering/extension-scalar-atlas.js.map +1 -0
  247. package/dist/rendering/index.d.ts +1 -0
  248. package/dist/rendering/index.d.ts.map +1 -1
  249. package/dist/rendering/index.js +1 -0
  250. package/dist/rendering/index.js.map +1 -1
  251. package/dist/rendering/lean/LeanProductionRenderer.d.ts.map +1 -1
  252. package/dist/rendering/lean/LeanProductionRenderer.js +2 -2
  253. package/dist/rendering/lean/LeanProductionRenderer.js.map +1 -1
  254. package/dist/rendering/lean-core-runtime.d.ts +13 -0
  255. package/dist/rendering/lean-core-runtime.d.ts.map +1 -0
  256. package/dist/rendering/lean-core-runtime.js +10 -0
  257. package/dist/rendering/lean-core-runtime.js.map +1 -0
  258. package/dist/rendering/postprocess/NativeBloomPyramid.d.ts +17 -1
  259. package/dist/rendering/postprocess/NativeBloomPyramid.d.ts.map +1 -1
  260. package/dist/rendering/postprocess/NativeBloomPyramid.js +31 -1
  261. package/dist/rendering/postprocess/NativeBloomPyramid.js.map +1 -1
  262. package/dist/rendering/production-runtime/ProductionRendererTypes.d.ts +1 -0
  263. package/dist/rendering/production-runtime/ProductionRendererTypes.d.ts.map +1 -1
  264. package/dist/rendering/production-runtime/ProductionRendererTypes.js.map +1 -1
  265. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts +3 -0
  266. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts.map +1 -1
  267. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js +8 -1
  268. package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js.map +1 -1
  269. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts +4 -0
  270. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts.map +1 -1
  271. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js +15 -0
  272. package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js.map +1 -1
  273. package/dist/rendering/production-runtime/ProductionWebGPURenderer.d.ts +7 -1
  274. package/dist/rendering/production-runtime/ProductionWebGPURenderer.d.ts.map +1 -1
  275. package/dist/rendering/production-runtime/ProductionWebGPURenderer.js +28 -2
  276. package/dist/rendering/production-runtime/ProductionWebGPURenderer.js.map +1 -1
  277. package/dist/rendering/production-runtime/framegraph/FrameGraph.d.ts +4 -2
  278. package/dist/rendering/production-runtime/framegraph/FrameGraph.d.ts.map +1 -1
  279. package/dist/rendering/production-runtime/framegraph/FrameGraph.js +62 -4
  280. package/dist/rendering/production-runtime/framegraph/FrameGraph.js.map +1 -1
  281. package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.d.ts +32 -0
  282. package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.d.ts.map +1 -0
  283. package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.js +111 -0
  284. package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.js.map +1 -0
  285. package/dist/rendering/production-runtime/framegraph/RenderPass.d.ts +23 -0
  286. package/dist/rendering/production-runtime/framegraph/RenderPass.d.ts.map +1 -1
  287. package/dist/rendering/production-runtime/framegraph/RenderPass.js +87 -1
  288. package/dist/rendering/production-runtime/framegraph/RenderPass.js.map +1 -1
  289. package/dist/rendering/production-runtime/index.d.ts +2 -0
  290. package/dist/rendering/production-runtime/index.d.ts.map +1 -1
  291. package/dist/rendering/production-runtime/index.js +1 -0
  292. package/dist/rendering/production-runtime/index.js.map +1 -1
  293. package/dist/rendering/production-runtime/passes/DepthPrepass.d.ts +4 -12
  294. package/dist/rendering/production-runtime/passes/DepthPrepass.d.ts.map +1 -1
  295. package/dist/rendering/production-runtime/passes/DepthPrepass.js +3 -11
  296. package/dist/rendering/production-runtime/passes/DepthPrepass.js.map +1 -1
  297. package/dist/rendering/production-runtime/passes/FramegraphTopology.js +1 -1
  298. package/dist/rendering/production-runtime/passes/FramegraphTopology.js.map +1 -1
  299. package/dist/rendering/production-runtime/passes/OpaquePass.d.ts +3 -8
  300. package/dist/rendering/production-runtime/passes/OpaquePass.d.ts.map +1 -1
  301. package/dist/rendering/production-runtime/passes/OpaquePass.js +3 -1
  302. package/dist/rendering/production-runtime/passes/OpaquePass.js.map +1 -1
  303. package/dist/rendering/production-runtime/passes/ShadowPass.d.ts +3 -8
  304. package/dist/rendering/production-runtime/passes/ShadowPass.d.ts.map +1 -1
  305. package/dist/rendering/production-runtime/passes/ShadowPass.js +2 -0
  306. package/dist/rendering/production-runtime/passes/ShadowPass.js.map +1 -1
  307. package/dist/rendering/production-runtime/passes/SkyboxPass.d.ts +3 -7
  308. package/dist/rendering/production-runtime/passes/SkyboxPass.d.ts.map +1 -1
  309. package/dist/rendering/production-runtime/passes/SkyboxPass.js +2 -0
  310. package/dist/rendering/production-runtime/passes/SkyboxPass.js.map +1 -1
  311. package/dist/rendering/production-runtime/passes/ToneMappingPass.d.ts +7 -10
  312. package/dist/rendering/production-runtime/passes/ToneMappingPass.d.ts.map +1 -1
  313. package/dist/rendering/production-runtime/passes/ToneMappingPass.js +9 -0
  314. package/dist/rendering/production-runtime/passes/ToneMappingPass.js.map +1 -1
  315. package/dist/rendering/production-runtime/passes/TransparentPass.d.ts +4 -9
  316. package/dist/rendering/production-runtime/passes/TransparentPass.d.ts.map +1 -1
  317. package/dist/rendering/production-runtime/passes/TransparentPass.js +6 -1
  318. package/dist/rendering/production-runtime/passes/TransparentPass.js.map +1 -1
  319. package/dist/rendering/reflection-surfaces.d.ts +5 -0
  320. package/dist/rendering/reflection-surfaces.d.ts.map +1 -0
  321. package/dist/rendering/reflection-surfaces.js +3 -0
  322. package/dist/rendering/reflection-surfaces.js.map +1 -0
  323. package/dist/rendering/webgpu/WebGPUPostShaders.d.ts +2 -3
  324. package/dist/rendering/webgpu/WebGPUPostShaders.d.ts.map +1 -1
  325. package/dist/rendering/webgpu/WebGPUPostShaders.js +2 -3
  326. package/dist/rendering/webgpu/WebGPUPostShaders.js.map +1 -1
  327. package/dist/rendering/webgpu/WebGPUTemporal.d.ts +17 -0
  328. package/dist/rendering/webgpu/WebGPUTemporal.d.ts.map +1 -0
  329. package/dist/rendering/webgpu/WebGPUTemporal.js +64 -0
  330. package/dist/rendering/webgpu/WebGPUTemporal.js.map +1 -0
  331. package/dist/rendering/webgpu.d.ts +6 -0
  332. package/dist/rendering/webgpu.d.ts.map +1 -1
  333. package/dist/rendering/webgpu.js +4 -0
  334. package/dist/rendering/webgpu.js.map +1 -1
  335. package/package.json +37 -24
  336. package/templates/cinematic-scene/package.json +2 -2
  337. package/templates/cinematic-scene/src/main.ts +14 -2
  338. package/templates/mini-game/package.json +2 -2
  339. package/templates/product-viewer/package.json +2 -2
  340. package/templates/production-asset-inspector/package.json +1 -1
  341. package/templates/production-material-studio/package.json +1 -1
  342. package/templates/production-product-configurator/package.json +1 -1
  343. package/templates/production-product-viewer/package.json +1 -1
  344. package/templates/cinematic-scene/node_modules/.vite/deps/_metadata.json +0 -8
  345. package/templates/cinematic-scene/node_modules/.vite/deps/package.json +0 -3
  346. package/templates/cinematic-scene/test-results/.last-run.json +0 -6
  347. package/templates/cinematic-scene/test-results/route-health-Aura3D-cinematic-scene-reaches-ready-state/error-context.md +0 -64
  348. package/templates/product-viewer/node_modules/.vite/deps/_metadata.json +0 -8
  349. package/templates/product-viewer/node_modules/.vite/deps/package.json +0 -3
@@ -1,6 +1,6 @@
1
1
  import { SHADER_CHUNKS, validateShaderChunks } from "./ShaderChunks.js";
2
2
  import { registerAnimationToonShader } from "./animation/AnimationToonMaterial.js";
3
- import { ShaderLibrary, registerLeanUnlitShader, registerLeanPbrShader, registerLeanDepthShader, registerLeanEnvironmentBackgroundShader, DEFAULT_DEPTH_SHADER_MARKER, DEFAULT_DEPTH_SHADER_NAME, DEFAULT_ENVIRONMENT_BACKGROUND_SHADER_MARKER, DEFAULT_ENVIRONMENT_BACKGROUND_SHADER_NAME, DEFAULT_INSTANCED_PBR_SHADER_MARKER, DEFAULT_INSTANCED_PBR_SHADER_NAME, DEFAULT_INSTANCED_UNLIT_SHADER_MARKER, DEFAULT_INSTANCED_UNLIT_SHADER_NAME, DEFAULT_MORPH_UNLIT_SHADER_MARKER, DEFAULT_MORPH_UNLIT_SHADER_NAME, DEFAULT_NORMAL_MAPPED_PBR_SHADER_MARKER, DEFAULT_NORMAL_MAPPED_PBR_SHADER_NAME, DEFAULT_PBR_SHADER_MARKER, DEFAULT_PBR_SHADER_NAME, DEFAULT_SCREEN_SPACE_LINE_SHADER_MARKER, DEFAULT_SCREEN_SPACE_LINE_SHADER_NAME, DEFAULT_SKINNED_LIT_EIGHT_INFLUENCE_SHADER_MARKER, DEFAULT_SKINNED_LIT_EIGHT_INFLUENCE_SHADER_NAME, DEFAULT_SKINNED_LIT_SHADER_MARKER, DEFAULT_SKINNED_LIT_SHADER_NAME, DEFAULT_SKINNED_UNLIT_EIGHT_INFLUENCE_SHADER_MARKER, DEFAULT_SKINNED_UNLIT_EIGHT_INFLUENCE_SHADER_NAME, DEFAULT_SKINNED_UNLIT_SHADER_MARKER, DEFAULT_SKINNED_UNLIT_SHADER_NAME, DEFAULT_TEXTURED_PBR_CLEARCOAT_SPECULAR_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_TRANSMISSION_VOLUME_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_IRIDESCENCE_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_SHADER_MARKER, DEFAULT_TEXTURED_PBR_SHADER_NAME, DEFAULT_TEXTURED_PBR_SPECULAR_SHEEN_ANISOTROPY_IRIDESCENCE_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_TRANSMISSION_VOLUME_TEXTURES_VARIANT, DEFAULT_TEXTURED_UNLIT_SHADER_MARKER, DEFAULT_TEXTURED_UNLIT_SHADER_NAME, DEFAULT_UNLIT_SHADER_MARKER, DEFAULT_UNLIT_SHADER_NAME, } from "./ShaderLibraryCore.js";
3
+ import { ShaderLibrary, registerLeanUnlitShader, registerLeanPbrShader, registerLeanDepthShader, registerLeanEnvironmentBackgroundShader, DEFAULT_DEPTH_SHADER_MARKER, DEFAULT_DEPTH_SHADER_NAME, DEFAULT_ENVIRONMENT_BACKGROUND_SHADER_MARKER, DEFAULT_ENVIRONMENT_BACKGROUND_SHADER_NAME, DEFAULT_INSTANCED_PBR_SHADER_MARKER, DEFAULT_INSTANCED_PBR_SHADER_NAME, DEFAULT_INSTANCED_UNLIT_SHADER_MARKER, DEFAULT_INSTANCED_UNLIT_SHADER_NAME, DEFAULT_MORPH_UNLIT_SHADER_MARKER, DEFAULT_MORPH_UNLIT_SHADER_NAME, DEFAULT_NORMAL_MAPPED_PBR_SHADER_MARKER, DEFAULT_NORMAL_MAPPED_PBR_SHADER_NAME, DEFAULT_PBR_SHADER_MARKER, DEFAULT_PBR_SHADER_NAME, DEFAULT_SCREEN_SPACE_LINE_SHADER_MARKER, DEFAULT_SCREEN_SPACE_LINE_SHADER_NAME, DEFAULT_SKINNED_LIT_EIGHT_INFLUENCE_SHADER_MARKER, DEFAULT_SKINNED_LIT_EIGHT_INFLUENCE_SHADER_NAME, DEFAULT_SKINNED_LIT_SHADER_MARKER, DEFAULT_SKINNED_LIT_SHADER_NAME, DEFAULT_SKINNED_UNLIT_EIGHT_INFLUENCE_SHADER_MARKER, DEFAULT_SKINNED_UNLIT_EIGHT_INFLUENCE_SHADER_NAME, DEFAULT_SKINNED_UNLIT_SHADER_MARKER, DEFAULT_SKINNED_UNLIT_SHADER_NAME, DEFAULT_TEXTURED_PBR_CLEARCOAT_SHEEN_ANISOTROPY_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_IRIDESCENCE_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_EXTENSION_ATLAS_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_SPECULAR_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_CLEARCOAT_TRANSMISSION_VOLUME_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_IRIDESCENCE_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_SHADER_MARKER, DEFAULT_TEXTURED_PBR_SHADER_NAME, DEFAULT_TEXTURED_PBR_SPECULAR_SHEEN_ANISOTROPY_IRIDESCENCE_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES_VARIANT, DEFAULT_TEXTURED_PBR_TRANSMISSION_VOLUME_TEXTURES_VARIANT, DEFAULT_TEXTURED_UNLIT_SHADER_MARKER, DEFAULT_TEXTURED_UNLIT_SHADER_NAME, DEFAULT_UNLIT_SHADER_MARKER, DEFAULT_UNLIT_SHADER_NAME, } from "./ShaderLibraryCore.js";
4
4
  export * from "./ShaderLibraryCore.js";
5
5
  export function createDefaultShaderLibrary() {
6
6
  const library = new ShaderLibrary();
@@ -183,15 +183,6 @@ float a3dForwardShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirectio
183
183
  vec3 receiverNormal = normalize(normal);
184
184
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
185
185
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
186
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
187
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
188
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
189
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
190
- // wide kernels acne-free without inflating the constant bias into peter-panning.
191
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
192
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
193
- // gradient grows, so it under-biases exactly the grazing angles that need the most
194
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
195
186
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
196
187
  float slopeTexelBias = slopeTangent * u_shadowMapSlopeBias * max(u_shadowMapTexelSize.x, u_shadowMapTexelSize.y);
197
188
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -224,9 +215,6 @@ float a3dPointShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
224
215
  vec4 rect = u_pointShadowFaceRects[faceIndex];
225
216
  vec2 uv = rect.xy + localUv * rect.zw;
226
217
  float normalDotLight = clamp(abs(dot(normalize(normal), normalize(lightDirection))), 0.0, 1.0);
227
- // Same per-sample, tangent-scaled slope bias as the directional and atlas paths. These
228
- // cubemap-face variants inline the sample fetch, but they share the identical acne
229
- // mechanism: a centre-only, (1 - N.L)-scaled bias under-compensates every outer tap.
230
218
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
231
219
  float slopeTexelBias = slopeTangent * u_pointShadowSlopeBias * max(u_pointShadowTexelSize.x, u_pointShadowTexelSize.y);
232
220
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -259,9 +247,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
259
247
  vec3 receiverNormal = normalize(normal);
260
248
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
261
249
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
262
- // Shared bias-table policy: the same per-sample, tangent-scaled slope bias as the
263
- // directional and point-cube paths. A centre-only bias under-compensates outer PCF
264
- // taps on sloped receivers, so each tap scales by its own texel distance.
265
250
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
266
251
  float slopeTexelBias = slopeTangent * u_spotShadowSlopeBias * max(u_spotShadowTexelSize.x, u_spotShadowTexelSize.y);
267
252
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -283,9 +268,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
283
268
  return mix(1.0, 1.0 - occlusion, clamp(u_spotShadowStrength, 0.0, 1.0));
284
269
  }
285
270
  float a3dResolveSpotShadowOverride(float baseFactor, float kind, float shadowFlag, vec3 worldPosition, vec3 normal, vec3 lightDirection) {
286
- // Spot-kind lights (kind == 2) sample the perspective spot map only when it is
287
- // bound. Every gate term is 0 when no spot map is present, so mix() returns
288
- // baseFactor exactly and scenes without spot lights render unchanged.
289
271
  float spotGate = step(1.5, kind) * (1.0 - step(2.5, kind)) * step(0.5, u_spotShadowMapEnabled) * step(0.5, shadowFlag);
290
272
  return mix(baseFactor, a3dSpotShadowFactor(worldPosition, normal, lightDirection), spotGate);
291
273
  }
@@ -334,11 +316,6 @@ vec3 a3dPbrEnvironmentDiffuseInput(vec3 normal) {
334
316
  float horizonBlend = 1.0 - abs(normal.y);
335
317
  vec3 proceduralDiffuse = mix(u_environmentGroundColor, u_environmentSkyColor, skyBlend);
336
318
  proceduralDiffuse = mix(proceduralDiffuse, u_environmentHorizonColor, clamp(horizonBlend, 0.0, 1.0) * 0.55);
337
- // The ambient term must be added to the procedural contribution, not replaced by it. A mix
338
- // here discarded u_environmentColor * u_environmentIntensity entirely whenever a procedural
339
- // map was present, which is the normal case: raising ambient intensity from 0.18 to 3.0 on
340
- // the product-turntable kit produced a byte-identical frame. Ambient and a sky gradient are
341
- // separate physical contributions, so they sum.
342
319
  vec3 environmentDiffuse = ambientEnvironment + proceduralDiffuse * u_environmentMapIntensity * proceduralEnvironmentWeight;
343
320
  float sampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
344
321
  float diffuseEnvironmentLod = max(u_environmentMapTextureMipCount - 1.0, 0.0);
@@ -481,9 +458,6 @@ void main() {
481
458
  float c = cos(u_baseColorTextureRotation);
482
459
  float s = sin(u_baseColorTextureRotation);
483
460
  v_uv = vec2(scaledUv.x * c - scaledUv.y * s, scaledUv.x * s + scaledUv.y * c) + u_baseColorTextureOffset;
484
- // P2 instanced-GLB path (muse3jsparity-PRD): the u_instanceCount branch is
485
- // taken only for items carrying instanceTransforms; every other draw keeps
486
- // the legacy math bit-exact.
487
461
  if (u_instanceCount > 0.5) {
488
462
  int instanceIndex = clamp(gl_InstanceID, 0, max(int(u_instanceCount) - 1, 0));
489
463
  mat4 attributeMatrix = mat4(a_instanceMatrix0, a_instanceMatrix1, a_instanceMatrix2, a_instanceMatrix3);
@@ -780,15 +754,6 @@ float a3dForwardShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirectio
780
754
  vec3 receiverNormal = normalize(normal);
781
755
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
782
756
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
783
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
784
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
785
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
786
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
787
- // wide kernels acne-free without inflating the constant bias into peter-panning.
788
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
789
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
790
- // gradient grows, so it under-biases exactly the grazing angles that need the most
791
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
792
757
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
793
758
  float slopeTexelBias = slopeTangent * u_shadowMapSlopeBias * max(u_shadowMapTexelSize.x, u_shadowMapTexelSize.y);
794
759
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -830,15 +795,6 @@ float a3dPointShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
830
795
  vec3 receiverNormal = normalize(normal);
831
796
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
832
797
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
833
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
834
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
835
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
836
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
837
- // wide kernels acne-free without inflating the constant bias into peter-panning.
838
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
839
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
840
- // gradient grows, so it under-biases exactly the grazing angles that need the most
841
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
842
798
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
843
799
  float slopeTexelBias = slopeTangent * u_pointShadowSlopeBias * max(u_pointShadowTexelSize.x, u_pointShadowTexelSize.y);
844
800
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -873,9 +829,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
873
829
  vec3 receiverNormal = normalize(normal);
874
830
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
875
831
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
876
- // Shared bias-table policy: the same per-sample, tangent-scaled slope bias as the
877
- // directional and point-cube paths. A centre-only bias under-compensates outer PCF
878
- // taps on sloped receivers, so each tap scales by its own texel distance.
879
832
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
880
833
  float slopeTexelBias = slopeTangent * u_spotShadowSlopeBias * max(u_spotShadowTexelSize.x, u_spotShadowTexelSize.y);
881
834
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -897,9 +850,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
897
850
  return mix(1.0, 1.0 - occlusion, clamp(u_spotShadowStrength, 0.0, 1.0));
898
851
  }
899
852
  float a3dResolveSpotShadowOverride(float baseFactor, float kind, float shadowFlag, vec3 worldPosition, vec3 normal, vec3 lightDirection) {
900
- // Spot-kind lights (kind == 2) sample the perspective spot map only when it is
901
- // bound. Every gate term is 0 when no spot map is present, so mix() returns
902
- // baseFactor exactly and scenes without spot lights render unchanged.
903
853
  float spotGate = step(1.5, kind) * (1.0 - step(2.5, kind)) * step(0.5, u_spotShadowMapEnabled) * step(0.5, shadowFlag);
904
854
  return mix(baseFactor, a3dSpotShadowFactor(worldPosition, normal, lightDirection), spotGate);
905
855
  }
@@ -963,11 +913,6 @@ void main() {
963
913
  float horizonBlend = 1.0 - abs(normal.y);
964
914
  vec3 proceduralDiffuse = mix(u_environmentGroundColor, u_environmentSkyColor, skyBlend);
965
915
  proceduralDiffuse = mix(proceduralDiffuse, u_environmentHorizonColor, clamp(horizonBlend, 0.0, 1.0) * 0.55);
966
- // The ambient term must be added to the procedural contribution, not replaced by it. A mix
967
- // here discarded u_environmentColor * u_environmentIntensity entirely whenever a procedural
968
- // map was present, which is the normal case: raising ambient intensity from 0.18 to 3.0 on
969
- // the product-turntable kit produced a byte-identical frame. Ambient and a sky gradient are
970
- // separate physical contributions, so they sum.
971
916
  vec3 environmentDiffuse = ambientEnvironment + proceduralDiffuse * u_environmentMapIntensity * proceduralEnvironmentWeight;
972
917
  vec3 reflectionDirection = reflect(-viewDirection, normal);
973
918
  float sampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
@@ -1134,8 +1079,6 @@ void main() {
1134
1079
  a_weights.x + a_weights.y + a_weights.z + a_weights.w +
1135
1080
  a_weights1.x + a_weights1.y + a_weights1.z + a_weights1.w;
1136
1081
  vec4 skinnedPosition = v_weightSum > 0.0001 ? skin * vec4(a_position, 1.0) : vec4(a_position, 1.0);
1137
- // Normals and tangents use the same skin matrix with w = 0 so translation is
1138
- // excluded; renormalizing happens in the fragment stage.
1139
1082
  vec3 skinnedNormal = (v_weightSum > 0.0001 ? skin * vec4(a_normal, 0.0) : vec4(a_normal, 0.0)).xyz;
1140
1083
  vec3 skinnedTangent = (v_weightSum > 0.0001 ? skin * vec4(a_tangent.xyz, 0.0) : vec4(a_tangent.xyz, 0.0)).xyz;
1141
1084
  v_normal = mat3(u_normalMatrix) * skinnedNormal;
@@ -1341,15 +1284,6 @@ float a3dForwardShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirectio
1341
1284
  vec3 receiverNormal = normalize(normal);
1342
1285
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
1343
1286
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
1344
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
1345
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
1346
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
1347
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
1348
- // wide kernels acne-free without inflating the constant bias into peter-panning.
1349
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
1350
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
1351
- // gradient grows, so it under-biases exactly the grazing angles that need the most
1352
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
1353
1287
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1354
1288
  float slopeTexelBias = slopeTangent * u_shadowMapSlopeBias * max(u_shadowMapTexelSize.x, u_shadowMapTexelSize.y);
1355
1289
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1391,15 +1325,6 @@ float a3dPointShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1391
1325
  vec3 receiverNormal = normalize(normal);
1392
1326
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
1393
1327
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
1394
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
1395
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
1396
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
1397
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
1398
- // wide kernels acne-free without inflating the constant bias into peter-panning.
1399
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
1400
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
1401
- // gradient grows, so it under-biases exactly the grazing angles that need the most
1402
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
1403
1328
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1404
1329
  float slopeTexelBias = slopeTangent * u_pointShadowSlopeBias * max(u_pointShadowTexelSize.x, u_pointShadowTexelSize.y);
1405
1330
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1434,9 +1359,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1434
1359
  vec3 receiverNormal = normalize(normal);
1435
1360
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
1436
1361
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
1437
- // Shared bias-table policy: the same per-sample, tangent-scaled slope bias as the
1438
- // directional and point-cube paths. A centre-only bias under-compensates outer PCF
1439
- // taps on sloped receivers, so each tap scales by its own texel distance.
1440
1362
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1441
1363
  float slopeTexelBias = slopeTangent * u_spotShadowSlopeBias * max(u_spotShadowTexelSize.x, u_spotShadowTexelSize.y);
1442
1364
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1458,9 +1380,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1458
1380
  return mix(1.0, 1.0 - occlusion, clamp(u_spotShadowStrength, 0.0, 1.0));
1459
1381
  }
1460
1382
  float a3dResolveSpotShadowOverride(float baseFactor, float kind, float shadowFlag, vec3 worldPosition, vec3 normal, vec3 lightDirection) {
1461
- // Spot-kind lights (kind == 2) sample the perspective spot map only when it is
1462
- // bound. Every gate term is 0 when no spot map is present, so mix() returns
1463
- // baseFactor exactly and scenes without spot lights render unchanged.
1464
1383
  float spotGate = step(1.5, kind) * (1.0 - step(2.5, kind)) * step(0.5, u_spotShadowMapEnabled) * step(0.5, shadowFlag);
1465
1384
  return mix(baseFactor, a3dSpotShadowFactor(worldPosition, normal, lightDirection), spotGate);
1466
1385
  }
@@ -1524,11 +1443,6 @@ void main() {
1524
1443
  float horizonBlend = 1.0 - abs(normal.y);
1525
1444
  vec3 proceduralDiffuse = mix(u_environmentGroundColor, u_environmentSkyColor, skyBlend);
1526
1445
  proceduralDiffuse = mix(proceduralDiffuse, u_environmentHorizonColor, clamp(horizonBlend, 0.0, 1.0) * 0.55);
1527
- // The ambient term must be added to the procedural contribution, not replaced by it. A mix
1528
- // here discarded u_environmentColor * u_environmentIntensity entirely whenever a procedural
1529
- // map was present, which is the normal case: raising ambient intensity from 0.18 to 3.0 on
1530
- // the product-turntable kit produced a byte-identical frame. Ambient and a sky gradient are
1531
- // separate physical contributions, so they sum.
1532
1446
  vec3 environmentDiffuse = ambientEnvironment + proceduralDiffuse * u_environmentMapIntensity * proceduralEnvironmentWeight;
1533
1447
  vec3 reflectionDirection = reflect(-viewDirection, normal);
1534
1448
  float sampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
@@ -1632,18 +1546,15 @@ void main() {
1632
1546
  precision highp float;
1633
1547
  layout(location = 0) in vec3 a_position;
1634
1548
  uniform mat4 u_modelViewProjection;
1635
- // Uniform fast path (<= 4 targets / 64 verts):
1636
1549
  uniform vec4 u_morphPositionDeltas[256];
1637
1550
  uniform vec4 u_morphWeights;
1638
1551
  uniform float u_morphTargetCount;
1639
- // Texture-backed path (lifts the 4/64 cap; see MorphTargetPlan.ts createMorphTargetPlan):
1640
1552
  uniform sampler2D u_morphDeltaTexture;
1641
- uniform float u_morphUsesTexture; // > 0.5 => sample deltas from the texture
1642
- uniform float u_morphTextureWidth; // = vertexCount
1643
- uniform float u_morphRowsPerTarget; // 1 = positions only, 2 = positions + normals
1644
- uniform float u_morphWeightArray[64]; // per-target weights for the texture path
1553
+ uniform float u_morphUsesTexture;
1554
+ uniform float u_morphTextureWidth;
1555
+ uniform float u_morphRowsPerTarget;
1556
+ uniform float u_morphWeightArray[64];
1645
1557
  vec3 sampleMorphTexel(float row, float vertex) {
1646
- // Fetch RGBA float texel at (x=vertex, y=row) using normalized coords + nearest filtering.
1647
1558
  float u = (vertex + 0.5) / max(1.0, u_morphTextureWidth);
1648
1559
  float height = u_morphTargetCount * u_morphRowsPerTarget;
1649
1560
  float v = (row + 0.5) / max(1.0, height);
@@ -1710,9 +1621,6 @@ out vec3 v_worldPosition;
1710
1621
  out vec2 v_uv;
1711
1622
  out vec4 v_vertexColor;
1712
1623
  void main() {
1713
- // P2 instanced-GLB path (muse3jsparity-PRD): the u_instanceCount branch is
1714
- // taken only for items carrying instanceTransforms; every other draw keeps
1715
- // the legacy math bit-exact. Mirrors the instanced-PBR vertex convention.
1716
1624
  if (u_instanceCount > 0.5) {
1717
1625
  int instanceIndex = clamp(gl_InstanceID, 0, max(int(u_instanceCount) - 1, 0));
1718
1626
  mat4 attributeMatrix = mat4(a_instanceMatrix0, a_instanceMatrix1, a_instanceMatrix2, a_instanceMatrix3);
@@ -1864,15 +1772,6 @@ float a3dForwardShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirectio
1864
1772
  vec3 receiverNormal = normalize(normal);
1865
1773
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
1866
1774
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
1867
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
1868
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
1869
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
1870
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
1871
- // wide kernels acne-free without inflating the constant bias into peter-panning.
1872
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
1873
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
1874
- // gradient grows, so it under-biases exactly the grazing angles that need the most
1875
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
1876
1775
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1877
1776
  float slopeTexelBias = slopeTangent * u_shadowMapSlopeBias * max(u_shadowMapTexelSize.x, u_shadowMapTexelSize.y);
1878
1777
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1905,9 +1804,6 @@ float a3dPointShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1905
1804
  vec4 rect = u_pointShadowFaceRects[faceIndex];
1906
1805
  vec2 uv = rect.xy + localUv * rect.zw;
1907
1806
  float normalDotLight = clamp(abs(dot(normalize(normal), normalize(lightDirection))), 0.0, 1.0);
1908
- // Same per-sample, tangent-scaled slope bias as the directional and atlas paths. These
1909
- // cubemap-face variants inline the sample fetch, but they share the identical acne
1910
- // mechanism: a centre-only, (1 - N.L)-scaled bias under-compensates every outer tap.
1911
1807
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1912
1808
  float slopeTexelBias = slopeTangent * u_pointShadowSlopeBias * max(u_pointShadowTexelSize.x, u_pointShadowTexelSize.y);
1913
1809
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1940,9 +1836,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1940
1836
  vec3 receiverNormal = normalize(normal);
1941
1837
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
1942
1838
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
1943
- // Shared bias-table policy: the same per-sample, tangent-scaled slope bias as the
1944
- // directional and point-cube paths. A centre-only bias under-compensates outer PCF
1945
- // taps on sloped receivers, so each tap scales by its own texel distance.
1946
1839
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
1947
1840
  float slopeTexelBias = slopeTangent * u_spotShadowSlopeBias * max(u_spotShadowTexelSize.x, u_spotShadowTexelSize.y);
1948
1841
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -1964,9 +1857,6 @@ float a3dSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDirection)
1964
1857
  return mix(1.0, 1.0 - occlusion, clamp(u_spotShadowStrength, 0.0, 1.0));
1965
1858
  }
1966
1859
  float a3dResolveSpotShadowOverride(float baseFactor, float kind, float shadowFlag, vec3 worldPosition, vec3 normal, vec3 lightDirection) {
1967
- // Spot-kind lights (kind == 2) sample the perspective spot map only when it is
1968
- // bound. Every gate term is 0 when no spot map is present, so mix() returns
1969
- // baseFactor exactly and scenes without spot lights render unchanged.
1970
1860
  float spotGate = step(1.5, kind) * (1.0 - step(2.5, kind)) * step(0.5, u_spotShadowMapEnabled) * step(0.5, shadowFlag);
1971
1861
  return mix(baseFactor, a3dSpotShadowFactor(worldPosition, normal, lightDirection), spotGate);
1972
1862
  }
@@ -2015,11 +1905,6 @@ vec3 a3dPbrEnvironmentDiffuseInput(vec3 normal) {
2015
1905
  float horizonBlend = 1.0 - abs(normal.y);
2016
1906
  vec3 proceduralDiffuse = mix(u_environmentGroundColor, u_environmentSkyColor, skyBlend);
2017
1907
  proceduralDiffuse = mix(proceduralDiffuse, u_environmentHorizonColor, clamp(horizonBlend, 0.0, 1.0) * 0.55);
2018
- // The ambient term must be added to the procedural contribution, not replaced by it. A mix
2019
- // here discarded u_environmentColor * u_environmentIntensity entirely whenever a procedural
2020
- // map was present, which is the normal case: raising ambient intensity from 0.18 to 3.0 on
2021
- // the product-turntable kit produced a byte-identical frame. Ambient and a sky gradient are
2022
- // separate physical contributions, so they sum.
2023
1908
  vec3 environmentDiffuse = ambientEnvironment + proceduralDiffuse * u_environmentMapIntensity * proceduralEnvironmentWeight;
2024
1909
  float sampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
2025
1910
  float diffuseEnvironmentLod = max(u_environmentMapTextureMipCount - 1.0, 0.0);
@@ -2131,6 +2016,9 @@ void main() {
2131
2016
  name: DEFAULT_TEXTURED_PBR_SHADER_NAME,
2132
2017
  marker: DEFAULT_TEXTURED_PBR_SHADER_MARKER,
2133
2018
  variants: [
2019
+ { name: DEFAULT_TEXTURED_PBR_EXTENSION_ATLAS_VARIANT, defines: { A3D_PBR_EXTENSION_ATLAS: true, A3D_PBR_CLEARCOAT_TEXTURES: true, A3D_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES: true, A3D_PBR_IRIDESCENCE_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true } },
2020
+ { name: DEFAULT_TEXTURED_PBR_CLEARCOAT_SHEEN_ANISOTROPY_TEXTURES_VARIANT, defines: { A3D_PBR_CLEARCOAT_TEXTURES: true, A3D_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true, A3D_PBR_NO_SPOT_SHADOW: true } },
2021
+ { name: DEFAULT_TEXTURED_PBR_CLEARCOAT_IRIDESCENCE_TEXTURES_VARIANT, defines: { A3D_PBR_CLEARCOAT_TEXTURES: true, A3D_PBR_IRIDESCENCE_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true } },
2134
2022
  { name: DEFAULT_TEXTURED_PBR_CLEARCOAT_TEXTURES_VARIANT, defines: { A3D_PBR_CLEARCOAT_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true } },
2135
2023
  { name: DEFAULT_TEXTURED_PBR_TRANSMISSION_VOLUME_TEXTURES_VARIANT, defines: { A3D_PBR_TRANSMISSION_VOLUME_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true } },
2136
2024
  { name: DEFAULT_TEXTURED_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES_VARIANT, defines: { A3D_PBR_SPECULAR_TEXTURES: true, A3D_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES: true, A3D_PBR_DISABLE_TRANSMISSION_BACKDROP: true, A3D_PBR_DISABLE_CLUSTERED_LIGHTING: true } },
@@ -2168,10 +2056,6 @@ out vec4 v_vertexColor;
2168
2056
  void main() {
2169
2057
  v_uv = a_uv;
2170
2058
  v_uv1 = a_uv1;
2171
- // P2 instanced-GLB path (muse3jsparity-PRD): the u_instanceCount branch is
2172
- // taken only for items carrying instanceTransforms (applyInstanceBinding
2173
- // stamps a count >= 1); every other draw keeps the legacy math bit-exact.
2174
- // Mirrors the instanced-PBR vertex convention (MVP carries the base model).
2175
2059
  if (u_instanceCount > 0.5) {
2176
2060
  int instanceIndex = clamp(gl_InstanceID, 0, max(int(u_instanceCount) - 1, 0));
2177
2061
  mat4 attributeMatrix = mat4(a_instanceMatrix0, a_instanceMatrix1, a_instanceMatrix2, a_instanceMatrix3);
@@ -2287,11 +2171,6 @@ uniform float u_pointShadowSlopeBias;
2287
2171
  uniform vec2 u_pointShadowTexelSize;
2288
2172
  uniform float u_pointShadowPcfSampleCount;
2289
2173
  uniform vec4 u_pointShadowPcfSamples[32];
2290
- // B1 spot path (muse3jsparity-PRD): the two A3D_PBR_NO_SPOT_SHADOW variants
2291
- // (clearcoat-transmission-volume, specular-sheen-anisotropy-iridescence) sit at
2292
- // the 16-sampler WebGL2 minimum without it, so they sample spot lights through
2293
- // the legacy directional factor while every other lit program takes the spot
2294
- // override. ForwardPass binds spot uniforms only when reflection declares them.
2295
2174
  #ifndef A3D_PBR_NO_SPOT_SHADOW
2296
2175
  uniform sampler2D u_spotShadowMapTexture;
2297
2176
  uniform float u_spotShadowMapEnabled;
@@ -2345,14 +2224,26 @@ uniform vec2 u_occlusionTextureWrap;
2345
2224
  uniform float u_occlusionStrength;
2346
2225
  uniform float u_clearcoatNormalScale;
2347
2226
  #ifdef A3D_PBR_CLEARCOAT_TEXTURES
2227
+ #ifndef A3D_PBR_EXTENSION_ATLAS
2348
2228
  uniform sampler2D u_clearcoatTexture;
2229
+ #else
2230
+ uniform vec4 u_clearcoatAtlasRect;
2231
+ uniform float u_clearcoatAtlasY;
2232
+ uniform vec4 u_clearcoatAtlasFilter;
2233
+ #endif
2349
2234
  uniform float u_clearcoatTextureEnabled;
2350
2235
  uniform vec2 u_clearcoatTextureOffset;
2351
2236
  uniform vec2 u_clearcoatTextureScale;
2352
2237
  uniform float u_clearcoatTextureRotation;
2353
2238
  uniform float u_clearcoatTextureTexCoord;
2354
2239
  uniform vec2 u_clearcoatTextureWrap;
2240
+ #ifndef A3D_PBR_EXTENSION_ATLAS
2355
2241
  uniform sampler2D u_clearcoatRoughnessTexture;
2242
+ #else
2243
+ uniform vec4 u_clearcoatRoughnessAtlasRect;
2244
+ uniform float u_clearcoatRoughnessAtlasY;
2245
+ uniform vec4 u_clearcoatRoughnessAtlasFilter;
2246
+ #endif
2356
2247
  uniform float u_clearcoatRoughnessTextureEnabled;
2357
2248
  uniform vec2 u_clearcoatRoughnessTextureOffset;
2358
2249
  uniform vec2 u_clearcoatRoughnessTextureScale;
@@ -2421,7 +2312,13 @@ uniform vec2 u_sheenColorTextureScale;
2421
2312
  uniform float u_sheenColorTextureRotation;
2422
2313
  uniform float u_sheenColorTextureTexCoord;
2423
2314
  uniform vec2 u_sheenColorTextureWrap;
2315
+ #ifndef A3D_PBR_EXTENSION_ATLAS
2424
2316
  uniform sampler2D u_sheenRoughnessTexture;
2317
+ #else
2318
+ uniform vec4 u_sheenRoughnessAtlasRect;
2319
+ uniform float u_sheenRoughnessAtlasY;
2320
+ uniform vec4 u_sheenRoughnessAtlasFilter;
2321
+ #endif
2425
2322
  uniform float u_sheenRoughnessTextureEnabled;
2426
2323
  uniform vec2 u_sheenRoughnessTextureOffset;
2427
2324
  uniform vec2 u_sheenRoughnessTextureScale;
@@ -2437,14 +2334,26 @@ uniform float u_anisotropyTextureTexCoord;
2437
2334
  uniform vec2 u_anisotropyTextureWrap;
2438
2335
  #endif
2439
2336
  #ifdef A3D_PBR_IRIDESCENCE_TEXTURES
2337
+ #ifndef A3D_PBR_EXTENSION_ATLAS
2440
2338
  uniform sampler2D u_iridescenceTexture;
2339
+ #else
2340
+ uniform vec4 u_iridescenceAtlasRect;
2341
+ uniform float u_iridescenceAtlasY;
2342
+ uniform vec4 u_iridescenceAtlasFilter;
2343
+ #endif
2441
2344
  uniform float u_iridescenceTextureEnabled;
2442
2345
  uniform vec2 u_iridescenceTextureOffset;
2443
2346
  uniform vec2 u_iridescenceTextureScale;
2444
2347
  uniform float u_iridescenceTextureRotation;
2445
2348
  uniform float u_iridescenceTextureTexCoord;
2446
2349
  uniform vec2 u_iridescenceTextureWrap;
2350
+ #ifndef A3D_PBR_EXTENSION_ATLAS
2447
2351
  uniform sampler2D u_iridescenceThicknessTexture;
2352
+ #else
2353
+ uniform vec4 u_iridescenceThicknessAtlasRect;
2354
+ uniform float u_iridescenceThicknessAtlasY;
2355
+ uniform vec4 u_iridescenceThicknessAtlasFilter;
2356
+ #endif
2448
2357
  uniform float u_iridescenceThicknessTextureEnabled;
2449
2358
  uniform vec2 u_iridescenceThicknessTextureOffset;
2450
2359
  uniform vec2 u_iridescenceThicknessTextureScale;
@@ -2553,15 +2462,6 @@ float a3dTexturedPbrShadowFactor(vec3 worldPosition, vec3 normal, vec3 lightDire
2553
2462
  vec3 receiverNormal = normalize(normal);
2554
2463
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
2555
2464
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
2556
- // Slope-scaled depth bias must be evaluated per PCF sample, not once for the kernel
2557
- // centre. A sample offset N texels away on a receiver sloped relative to the light sees a
2558
- // depth difference proportional to N, so a centre-only bias under-compensates every outer
2559
- // tap and the receiver shadows itself. Scaling by each sample's own texel distance keeps
2560
- // wide kernels acne-free without inflating the constant bias into peter-panning.
2561
- // The depth gradient across one shadow texel is tan(angle between receiver normal and
2562
- // light), not (1 - N.L). The linear form collapses toward zero far faster than the real
2563
- // gradient grows, so it under-biases exactly the grazing angles that need the most
2564
- // compensation. Clamped so a near-perpendicular receiver cannot demand unbounded bias.
2565
2465
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
2566
2466
  float slopeTexelBias = slopeTangent * u_shadowMapSlopeBias * max(u_shadowMapTexelSize.x, u_shadowMapTexelSize.y);
2567
2467
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -2594,9 +2494,6 @@ float a3dTexturedPbrPointShadowFactor(vec3 worldPosition, vec3 normal, vec3 ligh
2594
2494
  vec4 rect = u_pointShadowFaceRects[faceIndex];
2595
2495
  vec2 uv = rect.xy + localUv * rect.zw;
2596
2496
  float normalDotLight = clamp(abs(dot(normalize(normal), normalize(lightDirection))), 0.0, 1.0);
2597
- // Same per-sample, tangent-scaled slope bias as the directional and atlas paths. These
2598
- // cubemap-face variants inline the sample fetch, but they share the identical acne
2599
- // mechanism: a centre-only, (1 - N.L)-scaled bias under-compensates every outer tap.
2600
2497
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
2601
2498
  float slopeTexelBias = slopeTangent * u_pointShadowSlopeBias * max(u_pointShadowTexelSize.x, u_pointShadowTexelSize.y);
2602
2499
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -2630,9 +2527,6 @@ float a3dTexturedPbrSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 light
2630
2527
  vec3 receiverNormal = normalize(normal);
2631
2528
  vec3 receiverLightDirection = lightDirection / max(length(lightDirection), 0.0001);
2632
2529
  float normalDotLight = clamp(abs(dot(receiverNormal, receiverLightDirection)), 0.0, 1.0);
2633
- // Shared bias-table policy: the same per-sample, tangent-scaled slope bias as the
2634
- // directional and point-cube paths. A centre-only bias under-compensates outer PCF
2635
- // taps on sloped receivers, so each tap scales by its own texel distance.
2636
2530
  float slopeTangent = min(sqrt(max(1.0 - normalDotLight * normalDotLight, 0.0)) / max(normalDotLight, 0.05), 8.0);
2637
2531
  float slopeTexelBias = slopeTangent * u_spotShadowSlopeBias * max(u_spotShadowTexelSize.x, u_spotShadowTexelSize.y);
2638
2532
  float projectedDepth = projected.z * 0.5 + 0.5;
@@ -2654,9 +2548,6 @@ float a3dTexturedPbrSpotShadowFactor(vec3 worldPosition, vec3 normal, vec3 light
2654
2548
  return mix(1.0, 1.0 - occlusion, clamp(u_spotShadowStrength, 0.0, 1.0));
2655
2549
  }
2656
2550
  float a3dTexturedPbrResolveSpotShadowOverride(float baseFactor, float kind, float shadowFlag, vec3 worldPosition, vec3 normal, vec3 lightDirection) {
2657
- // Spot-kind lights (kind == 2) sample the perspective spot map only when it is
2658
- // bound. Every gate term is 0 when no spot map is present, so mix() returns
2659
- // baseFactor exactly and scenes without spot lights render unchanged.
2660
2551
  float spotGate = step(1.5, kind) * (1.0 - step(2.5, kind)) * step(0.5, u_spotShadowMapEnabled) * step(0.5, shadowFlag);
2661
2552
  return mix(baseFactor, a3dTexturedPbrSpotShadowFactor(worldPosition, normal, lightDirection), spotGate);
2662
2553
  }
@@ -2700,11 +2591,6 @@ vec3 a3dTexturedPbrEnvironmentDiffuseInput(vec3 normal) {
2700
2591
  float horizonBlend = 1.0 - abs(normal.y);
2701
2592
  vec3 proceduralDiffuse = mix(u_environmentGroundColor, u_environmentSkyColor, skyBlend);
2702
2593
  proceduralDiffuse = mix(proceduralDiffuse, u_environmentHorizonColor, clamp(horizonBlend, 0.0, 1.0) * 0.55);
2703
- // The ambient term must be added to the procedural contribution, not replaced by it. A mix
2704
- // here discarded u_environmentColor * u_environmentIntensity entirely whenever a procedural
2705
- // map was present, which is the normal case: raising ambient intensity from 0.18 to 3.0 on
2706
- // the product-turntable kit produced a byte-identical frame. Ambient and a sky gradient are
2707
- // separate physical contributions, so they sum.
2708
2594
  vec3 environmentDiffuse = ambientEnvironment + proceduralDiffuse * u_environmentMapIntensity * proceduralEnvironmentWeight;
2709
2595
  float sampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
2710
2596
  float diffuseEnvironmentLod = max(u_environmentMapTextureMipCount - 1.0, 0.0);
@@ -2719,11 +2605,6 @@ vec3 a3dTexturedPbrEnvironmentSpecularInput(vec3 normal, vec3 viewDirection, flo
2719
2605
  float clampedRoughness = clamp(roughness, 0.0, 1.0);
2720
2606
  float nDotV = clamp(dot(normal, viewDirection), 0.0, 1.0);
2721
2607
  float reflectionBand = pow(clamp(reflectionDirection.y * 0.5 + 0.5, 0.0, 1.0), mix(18.0, 2.0, clampedRoughness));
2722
- // Keep the procedural environment from becoming a uniform white veil on
2723
- // saturated textured base colors. A high roughness floor spread neutral
2724
- // specular over every fragment, while image-based lighting and Three.js keep
2725
- // the strongest neutral energy in reflection bands and glancing highlights.
2726
- // The lower floor preserves ambient readability without erasing texture chroma.
2727
2608
  float roughEnvironmentFloor = mix(0.012, 0.16, clampedRoughness);
2728
2609
  float proceduralSpecularResponse = max(reflectionBand, roughEnvironmentFloor);
2729
2610
  float horizonStripe = pow(clamp(1.0 - abs(reflectionDirection.y), 0.0, 1.0), mix(14.0, 3.0, clampedRoughness));
@@ -2743,13 +2624,25 @@ vec3 a3dTexturedPbrEnvironmentSpecularInput(vec3 normal, vec3 viewDirection, flo
2743
2624
  float sampledSpecularScale = materialEnvironmentSpecularScale;
2744
2625
  return proceduralSpecular * proceduralSpecularScale + sampledSpecular * sampledSpecularScale;
2745
2626
  }
2746
- vec3 a3dTexturedPbrIridescenceColor(float minimumThickness, float maximumThickness, float iridescenceIor, float nDotV) {
2747
- float thickness = clamp((minimumThickness + maximumThickness) * 0.5, 0.0, 1200.0);
2748
- float opticalThicknessPhase = clamp((thickness - 100.0) / 1100.0, 0.0, 1.0) * 6.2831853;
2749
- float iorShift = clamp((iridescenceIor - 1.0) / 2.0, 0.0, 1.0) * 0.65;
2750
- float viewPhase = pow(1.0 - clamp(nDotV, 0.0, 1.0), 1.25) * (3.2 + iridescenceIor * 1.4);
2751
- float phase = opticalThicknessPhase + iorShift + viewPhase;
2752
- return clamp(0.5 + 0.5 * cos(phase + vec3(0.0, 2.0943951, 4.1887902)), vec3(0.0), vec3(1.0));
2627
+ vec3 a3dTexturedPbrThinFilmFresnel(vec3 substrateF0, float filmIor, float thickness, float cosine) {
2628
+ float c1 = clamp(cosine, 0.0001, 1.0);
2629
+ if (thickness <= 0.0) return a3dFresnelSchlick(substrateF0, c1);
2630
+ float n2 = max(filmIor, 1.0001);
2631
+ vec3 rootF0 = sqrt(clamp(substrateF0, vec3(0.0), vec3(0.98)));
2632
+ vec3 n3 = (vec3(1.0) + rootF0) / max(vec3(1.0) - rootF0, vec3(0.0001));
2633
+ float sinSquared = 1.0 - c1 * c1;
2634
+ float c2 = sqrt(max(0.0, 1.0 - sinSquared / (n2 * n2)));
2635
+ vec3 c3 = sqrt(max(vec3(0.0), vec3(1.0) - sinSquared / (n3 * n3)));
2636
+ float r12s = (c1 - n2 * c2) / max(c1 + n2 * c2, 0.0001);
2637
+ float r12p = (n2 * c1 - c2) / max(n2 * c1 + c2, 0.0001);
2638
+ vec3 r23s = (n2 * c2 - n3 * c3) / max(n2 * c2 + n3 * c3, vec3(0.0001));
2639
+ vec3 r23p = (n3 * c2 - n2 * c3) / max(n3 * c2 + n2 * c3, vec3(0.0001));
2640
+ vec3 phase = 4.0 * A3D_PI * n2 * max(thickness, 0.0) * c2 / vec3(650.0, 510.0, 475.0);
2641
+ vec3 crossS = 2.0 * r12s * r23s * cos(phase);
2642
+ vec3 crossP = 2.0 * r12p * r23p * cos(phase);
2643
+ vec3 Rs = (r12s * r12s + r23s * r23s + crossS) / max(vec3(1.0) + r12s * r12s * r23s * r23s + crossS, vec3(0.0001));
2644
+ vec3 Rp = (r12p * r12p + r23p * r23p + crossP) / max(vec3(1.0) + r12p * r12p * r23p * r23p + crossP, vec3(0.0001));
2645
+ return clamp((Rs + Rp) * 0.5, vec3(0.0), vec3(1.0));
2753
2646
  }
2754
2647
  float a3dTexturedPbrCharlieSheen(float nDotH, float sheenRoughness) {
2755
2648
  float alpha = max(0.07, sheenRoughness * sheenRoughness);
@@ -2800,7 +2693,10 @@ vec3 a3dTexturedPbrExtensionDirectLight(
2800
2693
  float iridescence,
2801
2694
  float iridescenceIor,
2802
2695
  float iridescenceThicknessMinimum,
2803
- float iridescenceThicknessMaximum
2696
+ float iridescenceThicknessMaximum,
2697
+ vec3 substrateF0,
2698
+ vec3 substrateNormal,
2699
+ float substrateRoughness
2804
2700
  ) {
2805
2701
  vec3 N = normalize(normal);
2806
2702
  vec3 V = normalize(viewDirection);
@@ -2823,9 +2719,14 @@ vec3 a3dTexturedPbrExtensionDirectLight(
2823
2719
  float anisotropicDistribution = a3dTexturedPbrAnisotropicDistribution(N, H, tangentFrame, clearcoatRough, anisotropy, anisotropyRotation);
2824
2720
  float anisotropyShape = anisotropicDistribution / (anisotropicDistribution + 3.0);
2825
2721
  vec3 anisotropyLobe = vec3(clamp(anisotropy, 0.0, 1.0) * anisotropyShape * 0.72);
2826
- vec3 iridescenceColor = a3dTexturedPbrIridescenceColor(iridescenceThicknessMinimum, iridescenceThicknessMaximum, iridescenceIor, nDotV);
2827
- vec3 iridescenceLobe = iridescenceColor * clamp(iridescence, 0.0, 1.0) * clearcoatF * pow(a3dSaturate(1.0 - nDotV), 2.0) * 0.12;
2828
- return (clearcoatLobe + sheenLobe + anisotropyLobe + iridescenceLobe) * lightColor * lightIntensity * nDotL;
2722
+ vec3 filmF = a3dTexturedPbrThinFilmFresnel(substrateF0, iridescenceIor, (iridescenceThicknessMinimum + iridescenceThicknessMaximum) * 0.5, vDotH);
2723
+ vec3 filmN = normalize(substrateNormal);
2724
+ float filmNdotV = max(a3dSaturate(dot(filmN, V)), A3D_EPSILON);
2725
+ float filmNdotL = a3dSaturate(dot(filmN, L));
2726
+ float filmD = a3dDistributionGGX(a3dSaturate(dot(filmN, H)), substrateRoughness);
2727
+ float filmG = a3dGeometrySmithGGXCorrelated(filmNdotV, filmNdotL, substrateRoughness);
2728
+ vec3 iridescenceLobe = (filmF - a3dFresnelSchlick(substrateF0, vDotH)) * clamp(iridescence, 0.0, 1.0) * filmD * filmG;
2729
+ return ((clearcoatLobe + sheenLobe + anisotropyLobe) * nDotL + iridescenceLobe * filmNdotL) * lightColor * lightIntensity;
2829
2730
  }
2830
2731
  vec3 a3dTexturedPbrExtensionEnvironmentLight(
2831
2732
  vec3 normal,
@@ -2841,7 +2742,10 @@ vec3 a3dTexturedPbrExtensionEnvironmentLight(
2841
2742
  float iridescence,
2842
2743
  float iridescenceIor,
2843
2744
  float iridescenceThicknessMinimum,
2844
- float iridescenceThicknessMaximum
2745
+ float iridescenceThicknessMaximum,
2746
+ vec3 substrateF0,
2747
+ vec3 substrateNormal,
2748
+ vec3 substrateSpecularRadiance
2845
2749
  ) {
2846
2750
  float nDotV = max(a3dSaturate(dot(normalize(normal), normalize(viewDirection))), A3D_EPSILON);
2847
2751
  vec3 clearcoatF = a3dFresnelSchlickRoughness(vec3(0.04), nDotV, clamp(clearcoatRoughness, 0.18, 1.0));
@@ -2858,10 +2762,66 @@ vec3 a3dTexturedPbrExtensionEnvironmentLight(
2858
2762
  float anisotropicDistribution = a3dTexturedPbrAnisotropicDistribution(N, environmentHalf, tangentFrame, clearcoatRoughness, anisotropy, anisotropyRotation);
2859
2763
  float anisotropyShape = anisotropicDistribution / (anisotropicDistribution + 3.0);
2860
2764
  vec3 anisotropyLobe = boundedSpecularRadiance * clamp(anisotropy, 0.0, 1.0) * anisotropyShape * 0.72;
2861
- vec3 iridescenceColor = a3dTexturedPbrIridescenceColor(iridescenceThicknessMinimum, iridescenceThicknessMaximum, iridescenceIor, nDotV);
2862
- vec3 iridescenceLobe = boundedSpecularRadiance * iridescenceColor * clamp(iridescence, 0.0, 1.0) * pow(a3dSaturate(1.0 - nDotV), 2.0) * 0.09;
2765
+ float filmNdotV = max(a3dSaturate(dot(normalize(substrateNormal), normalize(viewDirection))), A3D_EPSILON);
2766
+ vec3 filmF = a3dTexturedPbrThinFilmFresnel(substrateF0, iridescenceIor, (iridescenceThicknessMinimum + iridescenceThicknessMaximum) * 0.5, filmNdotV);
2767
+ vec3 iridescenceLobe = substrateSpecularRadiance * (filmF - a3dFresnelSchlick(substrateF0, filmNdotV)) * clamp(iridescence, 0.0, 1.0);
2863
2768
  return clearcoatLobe + sheenLobe + anisotropyLobe + iridescenceLobe;
2864
2769
  }
2770
+
2771
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2772
+ uniform sampler2D u_extensionScalarAtlas;
2773
+ int a3dAtlasWrapIndex(int x, int size, float mode) {
2774
+ if (mode < 0.5) return clamp(x, 0, size - 1);
2775
+ int period = mode < 1.5 ? size : 2 * size;
2776
+ int index = ((x % period) + period) % period;
2777
+ return mode < 1.5 ? index : (index < size ? index : period - 1 - index);
2778
+ }
2779
+ vec4 a3dAtlasFetch(ivec2 point, ivec2 size, ivec2 origin, vec2 wrapMode) {
2780
+ ivec2 wrapped = ivec2(a3dAtlasWrapIndex(point.x,size.x,wrapMode.x), a3dAtlasWrapIndex(point.y,size.y,wrapMode.y));
2781
+ return texelFetch(u_extensionScalarAtlas, origin + wrapped, 0);
2782
+ }
2783
+ vec4 a3dAtlasLevel(vec2 uv, vec4 rect, float originY, vec2 wrapMode, int level, bool nearestFilter) {
2784
+ ivec2 size = ivec2(rect.yz);
2785
+ ivec2 origin = ivec2(int(rect.x),int(originY));
2786
+ for (int i=0; i<16; i++) {
2787
+ if (i >= level) break;
2788
+ origin.y += size.y;
2789
+ size = max(size / 2, ivec2(1));
2790
+ }
2791
+ vec2 pixel = uv * vec2(size) - 0.5;
2792
+ if (nearestFilter) return a3dAtlasFetch(ivec2(floor(pixel + 0.5)),size,origin,wrapMode);
2793
+ ivec2 low = ivec2(floor(pixel));
2794
+ vec2 fraction = fract(pixel);
2795
+ return mix(mix(a3dAtlasFetch(low,size,origin,wrapMode),a3dAtlasFetch(low+ivec2(1,0),size,origin,wrapMode),fraction.x),
2796
+ mix(a3dAtlasFetch(low+ivec2(0,1),size,origin,wrapMode),a3dAtlasFetch(low+ivec2(1,1),size,origin,wrapMode),fraction.x),fraction.y);
2797
+ }
2798
+ vec4 a3dAtlasSample(vec2 uv, vec4 rect, float originY, vec2 wrapMode, vec4 filterMode) {
2799
+ vec2 dx=dFdx(uv), dy=dFdy(uv);
2800
+ float lx=length(dx*rect.yz), ly=length(dy*rect.yz);
2801
+ float major=max(lx,ly), minor=max(min(lx,ly),0.000001);
2802
+ bool magnify=major<=1.0;
2803
+ float taps=magnify ? 1.0 : clamp(ceil(major/max(minor,1.0)),1.0,floor(filterMode.w));
2804
+ vec2 axis=lx>=ly ? dx : dy;
2805
+ float lod=clamp(log2(max(major/taps,1.0)),0.0,rect.w);
2806
+ if (filterMode.z<0.5) lod=0.0;
2807
+ else if (filterMode.z<1.5) lod=floor(lod+0.5);
2808
+ int low=int(floor(lod)), high=min(low+1,int(rect.w));
2809
+ bool nearestFilter=magnify ? filterMode.x>0.5 : filterMode.y>0.5;
2810
+ vec4 total=vec4(0.0);
2811
+ for (int i=0;i<16;i++) {
2812
+ if (float(i)>=taps) break;
2813
+ vec2 sampleUv=uv+axis*((float(i)+0.5)/taps-0.5);
2814
+ total+=mix(a3dAtlasLevel(sampleUv,rect,originY,wrapMode,low,nearestFilter),a3dAtlasLevel(sampleUv,rect,originY,wrapMode,high,nearestFilter),fract(lod));
2815
+ }
2816
+ return total/taps;
2817
+ }
2818
+ #endif
2819
+
2820
+
2821
+
2822
+
2823
+
2824
+
2865
2825
  void main() {
2866
2826
  vec2 baseColorUv = a3dTexturedPbrUv(u_baseColorTextureTexCoord, u_baseColorTextureOffset, u_baseColorTextureScale, u_baseColorTextureRotation);
2867
2827
  vec2 normalUv = a3dTexturedPbrUv(u_normalTextureTexCoord, u_normalTextureOffset, u_normalTextureScale, u_normalTextureRotation);
@@ -2975,10 +2935,18 @@ void main() {
2975
2935
  float anisotropy = clamp(u_anisotropyStrength, 0.0, 1.0);
2976
2936
  float anisotropyRotation = u_anisotropyRotation;
2977
2937
  float iridescence = clamp(u_iridescenceFactor, 0.0, 1.0);
2978
- float iridescenceThickness = mix(u_iridescenceThicknessMinimum, u_iridescenceThicknessMaximum, 0.5);
2938
+ float iridescenceThickness = u_iridescenceThicknessMaximum;
2979
2939
  #ifdef A3D_PBR_CLEARCOAT_TEXTURES
2940
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2941
+ clearcoat = clamp(clearcoat * mix(1.0, a3dAtlasSample(clearcoatUv, u_clearcoatAtlasRect, u_clearcoatAtlasY, u_clearcoatTextureWrap, u_clearcoatAtlasFilter).r, step(0.5, u_clearcoatTextureEnabled)), 0.0, 1.0);
2942
+ #else
2980
2943
  clearcoat = clamp(clearcoat * mix(1.0, texture(u_clearcoatTexture, a3dTexturedPbrWrapUv(clearcoatUv, u_clearcoatTextureWrap)).r, step(0.5, u_clearcoatTextureEnabled)), 0.0, 1.0);
2944
+ #endif
2945
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2946
+ clearcoatRoughness = clamp(clearcoatRoughness * mix(1.0, a3dAtlasSample(clearcoatRoughnessUv, u_clearcoatRoughnessAtlasRect, u_clearcoatRoughnessAtlasY, u_clearcoatRoughnessTextureWrap, u_clearcoatRoughnessAtlasFilter).g, step(0.5, u_clearcoatRoughnessTextureEnabled)), 0.0, 1.0);
2947
+ #else
2981
2948
  clearcoatRoughness = clamp(clearcoatRoughness * mix(1.0, texture(u_clearcoatRoughnessTexture, a3dTexturedPbrWrapUv(clearcoatRoughnessUv, u_clearcoatRoughnessTextureWrap)).g, step(0.5, u_clearcoatRoughnessTextureEnabled)), 0.0, 1.0);
2949
+ #endif
2982
2950
  clearcoatRoughness = max(clearcoatRoughness, 0.19 + (1.0 - clearcoatNormalBoost) * 0.12);
2983
2951
  #endif
2984
2952
  #ifdef A3D_PBR_TRANSMISSION_VOLUME_TEXTURES
@@ -2993,12 +2961,29 @@ void main() {
2993
2961
  #endif
2994
2962
  #ifdef A3D_PBR_SPECULAR_SHEEN_ANISOTROPY_TEXTURES
2995
2963
  sheenColor *= mix(vec3(1.0), a3dTexturedPbrDecodeSrgb(texture(u_sheenColorTexture, a3dTexturedPbrWrapUv(sheenColorUv, u_sheenColorTextureWrap)).rgb), step(0.5, u_sheenColorTextureEnabled));
2964
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2965
+ sheenRoughness = clamp(sheenRoughness * mix(1.0, a3dAtlasSample(sheenRoughnessUv, u_sheenRoughnessAtlasRect, u_sheenRoughnessAtlasY, u_sheenRoughnessTextureWrap, u_sheenRoughnessAtlasFilter).a, step(0.5, u_sheenRoughnessTextureEnabled)), 0.0, 1.0);
2966
+ #else
2996
2967
  sheenRoughness = clamp(sheenRoughness * mix(1.0, texture(u_sheenRoughnessTexture, a3dTexturedPbrWrapUv(sheenRoughnessUv, u_sheenRoughnessTextureWrap)).a, step(0.5, u_sheenRoughnessTextureEnabled)), 0.0, 1.0);
2997
- anisotropy = clamp(anisotropy * mix(1.0, texture(u_anisotropyTexture, a3dTexturedPbrWrapUv(anisotropyUv, u_anisotropyTextureWrap)).b, step(0.5, u_anisotropyTextureEnabled)), 0.0, 1.0);
2968
+ #endif
2969
+ vec3 anisotropySample = texture(u_anisotropyTexture, a3dTexturedPbrWrapUv(anisotropyUv, u_anisotropyTextureWrap)).rgb;
2970
+ anisotropy = clamp(anisotropy * mix(1.0, anisotropySample.b, step(0.5, u_anisotropyTextureEnabled)), 0.0, 1.0);
2971
+ vec2 anisotropyDirection = anisotropySample.rg * 2.0 - 1.0;
2972
+ if (u_anisotropyTextureEnabled > 0.5 && dot(anisotropyDirection, anisotropyDirection) > 0.000001) {
2973
+ anisotropyRotation += atan(anisotropyDirection.y, anisotropyDirection.x);
2974
+ }
2998
2975
  #endif
2999
2976
  #ifdef A3D_PBR_IRIDESCENCE_TEXTURES
2977
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2978
+ iridescence = clamp(iridescence * mix(1.0, a3dAtlasSample(iridescenceUv, u_iridescenceAtlasRect, u_iridescenceAtlasY, u_iridescenceTextureWrap, u_iridescenceAtlasFilter).r, step(0.5, u_iridescenceTextureEnabled)), 0.0, 1.0);
2979
+ #else
3000
2980
  iridescence = clamp(iridescence * mix(1.0, texture(u_iridescenceTexture, a3dTexturedPbrWrapUv(iridescenceUv, u_iridescenceTextureWrap)).r, step(0.5, u_iridescenceTextureEnabled)), 0.0, 1.0);
2981
+ #endif
2982
+ #ifdef A3D_PBR_EXTENSION_ATLAS
2983
+ iridescenceThickness = mix(iridescenceThickness, mix(u_iridescenceThicknessMinimum, u_iridescenceThicknessMaximum, a3dAtlasSample(iridescenceThicknessUv, u_iridescenceThicknessAtlasRect, u_iridescenceThicknessAtlasY, u_iridescenceThicknessTextureWrap, u_iridescenceThicknessAtlasFilter).g), step(0.5, u_iridescenceThicknessTextureEnabled));
2984
+ #else
3001
2985
  iridescenceThickness = mix(iridescenceThickness, mix(u_iridescenceThicknessMinimum, u_iridescenceThicknessMaximum, texture(u_iridescenceThicknessTexture, a3dTexturedPbrWrapUv(iridescenceThicknessUv, u_iridescenceThicknessTextureWrap)).g), step(0.5, u_iridescenceThicknessTextureEnabled));
2986
+ #endif
3002
2987
  #endif
3003
2988
  vec3 base = a3dApplyAdvancedPbrLobes(
3004
2989
  texturedBase.rgb,
@@ -3018,13 +3003,14 @@ void main() {
3018
3003
  sheenRoughness,
3019
3004
  anisotropy,
3020
3005
  anisotropyRotation,
3021
- iridescence,
3006
+ 0.0,
3022
3007
  u_iridescenceIor,
3023
3008
  iridescenceThickness,
3024
3009
  iridescenceThickness,
3025
3010
  u_dispersion
3026
3011
  );
3027
3012
  vec3 viewDirection = normalize(u_cameraPosition - v_worldPosition);
3013
+ vec3 iridescenceSubstrateF0 = mix(vec3(pow((u_ior - 1.0) / max(u_ior + 1.0, 0.0001), 2.0)) * specularColor * specular, texturedBase.rgb, metallic);
3028
3014
  float materialRedPaintGate = smoothstep(0.28, 0.72, texturedBase.r)
3029
3015
  * (1.0 - smoothstep(0.05, 0.18, max(texturedBase.g, texturedBase.b)))
3030
3016
  * smoothstep(0.015, 0.07, u_materialEnvironmentSpecularScale);
@@ -3059,7 +3045,10 @@ void main() {
3059
3045
  iridescence,
3060
3046
  u_iridescenceIor,
3061
3047
  iridescenceThickness,
3062
- iridescenceThickness
3048
+ iridescenceThickness,
3049
+ iridescenceSubstrateF0,
3050
+ mappedNormal,
3051
+ a3dTexturedPbrEnvironmentSpecularInput(mappedNormal, viewDirection, roughness)
3063
3052
  );
3064
3053
  float texturedTransmissionAmount = clamp(max(transmission, diffuseTransmission), 0.0, 1.0);
3065
3054
  float texturedSampledEnvironmentWeight = step(0.0001, u_environmentMapTextureEnabled * u_environmentMapTextureIntensity);
@@ -3092,10 +3081,6 @@ void main() {
3092
3081
  vec2 backdropOffset = normalize(texturedRefractionDirection.xy + vec2(0.0001)) * u_transmissionBackdropRefractionScale * mix(1.25, 0.55, roughness) * clamp(u_ior - 1.0, 0.0, 2.5);
3093
3082
  float backdropLod = clamp((roughness + volumeThickness * 0.08) * max(u_transmissionBackdropMipCount - 1.0, 0.0), 0.0, max(u_transmissionBackdropMipCount - 1.0, 0.0));
3094
3083
  vec3 backdropRadiance = a3dTexturedPbrDecodeSrgb(textureLod(u_transmissionBackdropTexture, clamp(backdropUv + backdropOffset, vec2(0.001), vec2(0.999)), backdropLod).rgb);
3095
- // Scene-color refraction travels through the same participating volume as
3096
- // environment refraction. Omitting texturedVolumeTint here made thickness,
3097
- // attenuationDistance, and attenuationColor byte-identical whenever the
3098
- // renderer-owned backdrop path was active.
3099
3084
  texturedRefractionRadiance = mix(
3100
3085
  texturedRefractionRadiance,
3101
3086
  backdropRadiance * texturedVolumeTint * texturedTransmissionAmount * mix(1.0, 1.22, texturedBackdropWeight),
@@ -3190,7 +3175,10 @@ void main() {
3190
3175
  iridescence,
3191
3176
  u_iridescenceIor,
3192
3177
  iridescenceThickness,
3193
- iridescenceThickness
3178
+ iridescenceThickness,
3179
+ iridescenceSubstrateF0,
3180
+ mappedNormal,
3181
+ roughness
3194
3182
  ) * directExtensionSpecularScale;
3195
3183
  }
3196
3184
  float alpha = texturedBase.a;
@@ -3225,28 +3213,18 @@ out float v_lineDistance;
3225
3213
  out float v_halfWidthPixels;
3226
3214
 
3227
3215
  void main() {
3228
- // a_position holds this vertex's anchor endpoint in world space. It is referenced
3229
- // with zero weight so the attribute is not optimized out of the linked program:
3230
- // bounds computation, frustum culling, and the material's attribute contract all
3231
- // depend on the geometry declaring a real position stream.
3232
3216
  vec3 anchorWorld = a_position;
3233
3217
  vec4 clipStart = u_modelViewProjection * vec4(a_lineStart + anchorWorld * 0.0, 1.0);
3234
3218
  vec4 clipEnd = u_modelViewProjection * vec4(a_lineEnd, 1.0);
3235
3219
 
3236
- // Guard against a zero or negative w: a vertex behind the eye would otherwise
3237
- // produce a wildly wrong NDC position and a smeared quad.
3238
3220
  float wStart = max(abs(clipStart.w), 1e-5);
3239
3221
  float wEnd = max(abs(clipEnd.w), 1e-5);
3240
3222
 
3241
- // Project to device pixels. Expansion happens here, so the resulting width is a
3242
- // pixel quantity and is therefore independent of depth, FOV, and viewport size.
3243
3223
  vec2 pixelStart = (clipStart.xy / wStart) * 0.5 * u_lineResolution;
3244
3224
  vec2 pixelEnd = (clipEnd.xy / wEnd) * 0.5 * u_lineResolution;
3245
3225
 
3246
3226
  vec2 pixelDirection = pixelEnd - pixelStart;
3247
3227
  float pixelLength = length(pixelDirection);
3248
- // A segment that projects to a single pixel has no screen direction; pick an
3249
- // arbitrary axis so the cap still renders instead of collapsing.
3250
3228
  vec2 direction = pixelLength > 1e-4 ? pixelDirection / pixelLength : vec2(1.0, 0.0);
3251
3229
  vec2 normal = vec2(-direction.y, direction.x);
3252
3230
 
@@ -3255,14 +3233,10 @@ void main() {
3255
3233
 
3256
3234
  float along = a_lineCorner.y;
3257
3235
  vec2 anchorPixel = mix(pixelStart, pixelEnd, along);
3258
- // Square caps push the quad outward along the segment direction so the stroke
3259
- // extends half a width past each endpoint, matching Three.js LineMaterial behaviour.
3260
3236
  float capExtension = u_lineSquareCaps > 0.5 ? halfWidth : 0.0;
3261
3237
  vec2 capOffset = direction * (along > 0.5 ? capExtension : -capExtension);
3262
3238
  vec2 pixelPosition = anchorPixel + normal * (a_lineCorner.x * halfWidth) + capOffset;
3263
3239
 
3264
- // Back to clip space, preserving the anchor endpoint's own depth so the line
3265
- // depth-sorts against the rest of the scene correctly.
3266
3240
  vec4 anchorClip = along > 0.5 ? clipEnd : clipStart;
3267
3241
  float anchorW = along > 0.5 ? wEnd : wStart;
3268
3242
  vec2 ndc = pixelPosition / (0.5 * u_lineResolution);
@@ -3291,12 +3265,9 @@ void main() {
3291
3265
  if (u_lineDashSize > 0.0) {
3292
3266
  float period = u_lineDashSize + max(u_lineGapSize, 0.0);
3293
3267
  float phase = mod(v_lineDistance + u_lineDashOffset, period);
3294
- // Discard the gap portion of each dash period.
3295
3268
  if (phase > u_lineDashSize) discard;
3296
3269
  }
3297
3270
  if (u_lineRoundCaps > 0.5) {
3298
- // Round caps: reject fragments outside the unit half-disc at each end. The
3299
- // corner's x component already spans -1..1 across the stroke width.
3300
3271
  float acrossStroke = v_lineCorner.x;
3301
3272
  if (abs(acrossStroke) > 1.0) discard;
3302
3273
  }