@meimu/mutracer 0.0.0-stage → 0.1.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 (536) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/Apache-2.0.txt +202 -0
  3. package/LICENSES/GLSL-PathTracer-MIT.txt +21 -0
  4. package/LICENSES/GlMatrix-MIT.txt +19 -0
  5. package/LICENSES/KinoBloom-MIT.txt +21 -0
  6. package/LICENSES/OIDNWeb-MIT.txt +21 -0
  7. package/LICENSES/Octicons-MIT.txt +21 -0
  8. package/LICENSES/RayTracingRenderer-MIT.txt +21 -0
  9. package/LICENSES/TinyBVH-MIT.txt +21 -0
  10. package/LICENSES/WebGPUUtils-MIT.txt +21 -0
  11. package/LICENSES/ZetaRay-MIT.txt +21 -0
  12. package/README.md +240 -2
  13. package/THIRD_PARTY_NOTICES.md +160 -0
  14. package/dist/assets/bvh.worker.js +1 -0
  15. package/dist/mutracer.umd.js +14360 -0
  16. package/docs/api.md +394 -0
  17. package/docs/bvh.md +141 -0
  18. package/docs/denoising.md +301 -0
  19. package/docs/getting-started.md +308 -0
  20. package/docs/materials.md +281 -0
  21. package/docs/performance.md +85 -0
  22. package/docs/post-processing.md +87 -0
  23. package/docs/progressive-rendering.md +160 -0
  24. package/docs/sampling.md +40 -0
  25. package/docs/threejs.md +274 -0
  26. package/docs/todo.md +61 -0
  27. package/docs/updates.md +208 -0
  28. package/lib/Display.d.ts +72 -0
  29. package/lib/Display.js +123 -0
  30. package/lib/Display.js.map +1 -0
  31. package/lib/Engine.d.ts +161 -0
  32. package/lib/Engine.js +681 -0
  33. package/lib/Engine.js.map +1 -0
  34. package/lib/Render.d.ts +265 -0
  35. package/lib/Render.js +742 -0
  36. package/lib/Render.js.map +1 -0
  37. package/lib/RenderLoop.d.ts +79 -0
  38. package/lib/RenderLoop.js +236 -0
  39. package/lib/RenderLoop.js.map +1 -0
  40. package/lib/Sync.d.ts +19 -0
  41. package/lib/Sync.js +19 -0
  42. package/lib/Sync.js.map +1 -0
  43. package/lib/constants.d.ts +2 -0
  44. package/lib/constants.js +3 -0
  45. package/lib/constants.js.map +1 -0
  46. package/lib/main.d.ts +56 -0
  47. package/lib/main.js +43 -0
  48. package/lib/main.js.map +1 -0
  49. package/lib/math.d.ts +23 -0
  50. package/lib/math.js +56 -0
  51. package/lib/math.js.map +1 -0
  52. package/lib/oidn.d.ts +45 -0
  53. package/lib/oidn.js +42 -0
  54. package/lib/oidn.js.map +1 -0
  55. package/lib/oidnBundledWeights.cdn.d.ts +2 -0
  56. package/lib/oidnBundledWeights.cdn.js +5 -0
  57. package/lib/oidnBundledWeights.cdn.js.map +1 -0
  58. package/lib/oidnBundledWeights.d.ts +2 -0
  59. package/lib/oidnBundledWeights.js +4 -0
  60. package/lib/oidnBundledWeights.js.map +1 -0
  61. package/lib/renderer/DisplayPostProcess.d.ts +14 -0
  62. package/lib/renderer/DisplayPostProcess.js +41 -0
  63. package/lib/renderer/DisplayPostProcess.js.map +1 -0
  64. package/lib/renderer/MaterialTable.d.ts +119 -0
  65. package/lib/renderer/MaterialTable.js +550 -0
  66. package/lib/renderer/MaterialTable.js.map +1 -0
  67. package/lib/renderer/OfflineAdaptiveSampling.d.ts +47 -0
  68. package/lib/renderer/OfflineAdaptiveSampling.js +36 -0
  69. package/lib/renderer/OfflineAdaptiveSampling.js.map +1 -0
  70. package/lib/renderer/RenderingPipeline.d.ts +232 -0
  71. package/lib/renderer/RenderingPipeline.js +18 -0
  72. package/lib/renderer/RenderingPipeline.js.map +1 -0
  73. package/lib/renderer/ScratchPool.d.ts +13 -0
  74. package/lib/renderer/ScratchPool.js +21 -0
  75. package/lib/renderer/ScratchPool.js.map +1 -0
  76. package/lib/renderer/TileRender.d.ts +44 -0
  77. package/lib/renderer/TileRender.js +283 -0
  78. package/lib/renderer/TileRender.js.map +1 -0
  79. package/lib/renderer/WGPUBloomPass.d.ts +17 -0
  80. package/lib/renderer/WGPUBloomPass.js +243 -0
  81. package/lib/renderer/WGPUBloomPass.js.map +1 -0
  82. package/lib/renderer/WGPUCanvasSurface.d.ts +21 -0
  83. package/lib/renderer/WGPUCanvasSurface.js +48 -0
  84. package/lib/renderer/WGPUCanvasSurface.js.map +1 -0
  85. package/lib/renderer/WGPUComputePass.d.ts +73 -0
  86. package/lib/renderer/WGPUComputePass.js +317 -0
  87. package/lib/renderer/WGPUComputePass.js.map +1 -0
  88. package/lib/renderer/WGPUFullQuadPass.d.ts +73 -0
  89. package/lib/renderer/WGPUFullQuadPass.js +389 -0
  90. package/lib/renderer/WGPUFullQuadPass.js.map +1 -0
  91. package/lib/renderer/WGPUHDRPeakMeter.d.ts +19 -0
  92. package/lib/renderer/WGPUHDRPeakMeter.js +112 -0
  93. package/lib/renderer/WGPUHDRPeakMeter.js.map +1 -0
  94. package/lib/renderer/WGPUJNLMDenoiser.d.ts +61 -0
  95. package/lib/renderer/WGPUJNLMDenoiser.js +412 -0
  96. package/lib/renderer/WGPUJNLMDenoiser.js.map +1 -0
  97. package/lib/renderer/WGPURayTraceOutput.d.ts +44 -0
  98. package/lib/renderer/WGPURayTraceOutput.js +368 -0
  99. package/lib/renderer/WGPURayTraceOutput.js.map +1 -0
  100. package/lib/renderer/WGPURayTracePass.d.ts +284 -0
  101. package/lib/renderer/WGPURayTracePass.js +2323 -0
  102. package/lib/renderer/WGPURayTracePass.js.map +1 -0
  103. package/lib/renderer/WGPURenderingPipeline.d.ts +9 -0
  104. package/lib/renderer/WGPURenderingPipeline.js +1448 -0
  105. package/lib/renderer/WGPURenderingPipeline.js.map +1 -0
  106. package/lib/renderer/WGPUSceneFeatures.d.ts +3 -0
  107. package/lib/renderer/WGPUSceneFeatures.js +20 -0
  108. package/lib/renderer/WGPUSceneFeatures.js.map +1 -0
  109. package/lib/renderer/WGPUScratchBuffer.d.ts +9 -0
  110. package/lib/renderer/WGPUScratchBuffer.js +21 -0
  111. package/lib/renderer/WGPUScratchBuffer.js.map +1 -0
  112. package/lib/renderer/WGPUScratchTexture.d.ts +10 -0
  113. package/lib/renderer/WGPUScratchTexture.js +27 -0
  114. package/lib/renderer/WGPUScratchTexture.js.map +1 -0
  115. package/lib/renderer/WGPUShaderCache.d.ts +26 -0
  116. package/lib/renderer/WGPUShaderCache.js +103 -0
  117. package/lib/renderer/WGPUShaderCache.js.map +1 -0
  118. package/lib/renderer/WebGLBloomPass.d.ts +18 -0
  119. package/lib/renderer/WebGLBloomPass.js +113 -0
  120. package/lib/renderer/WebGLBloomPass.js.map +1 -0
  121. package/lib/renderer/WebGLFullQuadPass.d.ts +65 -0
  122. package/lib/renderer/WebGLFullQuadPass.js +208 -0
  123. package/lib/renderer/WebGLFullQuadPass.js.map +1 -0
  124. package/lib/renderer/WebGLJNLMDenoiser.d.ts +32 -0
  125. package/lib/renderer/WebGLJNLMDenoiser.js +328 -0
  126. package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -0
  127. package/lib/renderer/WebGLRayTraceOutputPass.d.ts +20 -0
  128. package/lib/renderer/WebGLRayTraceOutputPass.js +106 -0
  129. package/lib/renderer/WebGLRayTraceOutputPass.js.map +1 -0
  130. package/lib/renderer/WebGLRayTracePass.d.ts +142 -0
  131. package/lib/renderer/WebGLRayTracePass.js +845 -0
  132. package/lib/renderer/WebGLRayTracePass.js.map +1 -0
  133. package/lib/renderer/WebGLReadback.d.ts +4 -0
  134. package/lib/renderer/WebGLReadback.js +75 -0
  135. package/lib/renderer/WebGLReadback.js.map +1 -0
  136. package/lib/renderer/WebGLRenderingPipeline.d.ts +4 -0
  137. package/lib/renderer/WebGLRenderingPipeline.js +510 -0
  138. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -0
  139. package/lib/renderer/WebGLScratchCopy.d.ts +10 -0
  140. package/lib/renderer/WebGLScratchCopy.js +27 -0
  141. package/lib/renderer/WebGLScratchCopy.js.map +1 -0
  142. package/lib/renderer/accumulationTarget.d.ts +26 -0
  143. package/lib/renderer/accumulationTarget.js +2 -0
  144. package/lib/renderer/accumulationTarget.js.map +1 -0
  145. package/lib/renderer/binnedSahBvh.d.ts +31 -0
  146. package/lib/renderer/binnedSahBvh.js +263 -0
  147. package/lib/renderer/binnedSahBvh.js.map +1 -0
  148. package/lib/renderer/bvh.worker.d.ts +1 -0
  149. package/lib/renderer/bvh.worker.js +16 -0
  150. package/lib/renderer/bvh.worker.js.map +1 -0
  151. package/lib/renderer/bvhAccel.d.ts +81 -0
  152. package/lib/renderer/bvhAccel.js +621 -0
  153. package/lib/renderer/bvhAccel.js.map +1 -0
  154. package/lib/renderer/bvhWorkerBuild.d.ts +12 -0
  155. package/lib/renderer/bvhWorkerBuild.js +17 -0
  156. package/lib/renderer/bvhWorkerBuild.js.map +1 -0
  157. package/lib/renderer/bvhWorkerClient.d.ts +57 -0
  158. package/lib/renderer/bvhWorkerClient.js +166 -0
  159. package/lib/renderer/bvhWorkerClient.js.map +1 -0
  160. package/lib/renderer/cameraLens.d.ts +5 -0
  161. package/lib/renderer/cameraLens.js +15 -0
  162. package/lib/renderer/cameraLens.js.map +1 -0
  163. package/lib/renderer/cameraSnapshot.d.ts +3 -0
  164. package/lib/renderer/cameraSnapshot.js +7 -0
  165. package/lib/renderer/cameraSnapshot.js.map +1 -0
  166. package/lib/renderer/committedScene.d.ts +13 -0
  167. package/lib/renderer/committedScene.js +126 -0
  168. package/lib/renderer/committedScene.js.map +1 -0
  169. package/lib/renderer/dataTextureUtil.d.ts +32 -0
  170. package/lib/renderer/dataTextureUtil.js +46 -0
  171. package/lib/renderer/dataTextureUtil.js.map +1 -0
  172. package/lib/renderer/denoiser.d.ts +65 -0
  173. package/lib/renderer/denoiser.js +2 -0
  174. package/lib/renderer/denoiser.js.map +1 -0
  175. package/lib/renderer/depthQuery.d.ts +14 -0
  176. package/lib/renderer/depthQuery.js +14 -0
  177. package/lib/renderer/depthQuery.js.map +1 -0
  178. package/lib/renderer/deviceRequirements.d.ts +23 -0
  179. package/lib/renderer/deviceRequirements.js +50 -0
  180. package/lib/renderer/deviceRequirements.js.map +1 -0
  181. package/lib/renderer/envMapCreation.d.ts +10 -0
  182. package/lib/renderer/envMapCreation.js +96 -0
  183. package/lib/renderer/envMapCreation.js.map +1 -0
  184. package/lib/renderer/envMapDistribution.d.ts +9 -0
  185. package/lib/renderer/envMapDistribution.js +107 -0
  186. package/lib/renderer/envMapDistribution.js.map +1 -0
  187. package/lib/renderer/float16.d.ts +1 -0
  188. package/lib/renderer/float16.js +19 -0
  189. package/lib/renderer/float16.js.map +1 -0
  190. package/lib/renderer/geometryBvh.d.ts +11 -0
  191. package/lib/renderer/geometryBvh.js +24 -0
  192. package/lib/renderer/geometryBvh.js.map +1 -0
  193. package/lib/renderer/geometryUpdates.d.ts +28 -0
  194. package/lib/renderer/geometryUpdates.js +131 -0
  195. package/lib/renderer/geometryUpdates.js.map +1 -0
  196. package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +2 -0
  197. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +37 -0
  198. package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -0
  199. package/lib/renderer/glsl/chunks/common.glsl.d.ts +2 -0
  200. package/lib/renderer/glsl/chunks/common.glsl.js +17 -0
  201. package/lib/renderer/glsl/chunks/common.glsl.js.map +1 -0
  202. package/lib/renderer/glsl/chunks/envMap.glsl.d.ts +2 -0
  203. package/lib/renderer/glsl/chunks/envMap.glsl.js +192 -0
  204. package/lib/renderer/glsl/chunks/envMap.glsl.js.map +1 -0
  205. package/lib/renderer/glsl/chunks/intersect.glsl.d.ts +2 -0
  206. package/lib/renderer/glsl/chunks/intersect.glsl.js +1091 -0
  207. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -0
  208. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +2 -0
  209. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +371 -0
  210. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -0
  211. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.d.ts +2 -0
  212. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +1767 -0
  213. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js.map +1 -0
  214. package/lib/renderer/glsl/chunks/rand.glsl.d.ts +2 -0
  215. package/lib/renderer/glsl/chunks/rand.glsl.js +26 -0
  216. package/lib/renderer/glsl/chunks/rand.glsl.js.map +1 -0
  217. package/lib/renderer/glsl/chunks/random.glsl.d.ts +2 -0
  218. package/lib/renderer/glsl/chunks/random.glsl.js +27 -0
  219. package/lib/renderer/glsl/chunks/random.glsl.js.map +1 -0
  220. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +2 -0
  221. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +287 -0
  222. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -0
  223. package/lib/renderer/glsl/chunks/sampleLight.glsl.d.ts +2 -0
  224. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +254 -0
  225. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -0
  226. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +2 -0
  227. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +279 -0
  228. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -0
  229. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.d.ts +2 -0
  230. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +48 -0
  231. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js.map +1 -0
  232. package/lib/renderer/glsl/chunks/sampling.glsl.d.ts +2 -0
  233. package/lib/renderer/glsl/chunks/sampling.glsl.js +194 -0
  234. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -0
  235. package/lib/renderer/glsl/chunks/sobol.glsl.d.ts +2 -0
  236. package/lib/renderer/glsl/chunks/sobol.glsl.js +170 -0
  237. package/lib/renderer/glsl/chunks/sobol.glsl.js.map +1 -0
  238. package/lib/renderer/glsl/chunks/textureLinear.glsl.d.ts +2 -0
  239. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +27 -0
  240. package/lib/renderer/glsl/chunks/textureLinear.glsl.js.map +1 -0
  241. package/lib/renderer/glsl/chunks/uvProjection.glsl.d.ts +2 -0
  242. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +72 -0
  243. package/lib/renderer/glsl/chunks/uvProjection.glsl.js.map +1 -0
  244. package/lib/renderer/glsl/depthQuery.frag.d.ts +3 -0
  245. package/lib/renderer/glsl/depthQuery.frag.js +55 -0
  246. package/lib/renderer/glsl/depthQuery.frag.js.map +1 -0
  247. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.d.ts +6 -0
  248. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +46 -0
  249. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js.map +1 -0
  250. package/lib/renderer/glsl/rayTrace.frag.d.ts +2 -0
  251. package/lib/renderer/glsl/rayTrace.frag.js +623 -0
  252. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -0
  253. package/lib/renderer/glsl/shadowCatcher.frag.d.ts +3 -0
  254. package/lib/renderer/glsl/shadowCatcher.frag.js +119 -0
  255. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -0
  256. package/lib/renderer/glsl/webglPipeline.frag.d.ts +4 -0
  257. package/lib/renderer/glsl/webglPipeline.frag.js +208 -0
  258. package/lib/renderer/glsl/webglPipeline.frag.js.map +1 -0
  259. package/lib/renderer/gpuMemory.d.ts +2 -0
  260. package/lib/renderer/gpuMemory.js +10 -0
  261. package/lib/renderer/gpuMemory.js.map +1 -0
  262. package/lib/renderer/halton.d.ts +1 -0
  263. package/lib/renderer/halton.js +15 -0
  264. package/lib/renderer/halton.js.map +1 -0
  265. package/lib/renderer/jnlm.d.ts +85 -0
  266. package/lib/renderer/jnlm.js +87 -0
  267. package/lib/renderer/jnlm.js.map +1 -0
  268. package/lib/renderer/lightSampling.d.ts +75 -0
  269. package/lib/renderer/lightSampling.js +305 -0
  270. package/lib/renderer/lightSampling.js.map +1 -0
  271. package/lib/renderer/lightsUtil.d.ts +26 -0
  272. package/lib/renderer/lightsUtil.js +154 -0
  273. package/lib/renderer/lightsUtil.js.map +1 -0
  274. package/lib/renderer/materialChanges.d.ts +13 -0
  275. package/lib/renderer/materialChanges.js +59 -0
  276. package/lib/renderer/materialChanges.js.map +1 -0
  277. package/lib/renderer/materialComparison.generated.d.ts +5 -0
  278. package/lib/renderer/materialComparison.generated.js +655 -0
  279. package/lib/renderer/materialComparison.generated.js.map +1 -0
  280. package/lib/renderer/materialConstants.d.ts +6 -0
  281. package/lib/renderer/materialConstants.js +3 -0
  282. package/lib/renderer/materialConstants.js.map +1 -0
  283. package/lib/renderer/materialEmission.d.ts +9 -0
  284. package/lib/renderer/materialEmission.js +21 -0
  285. package/lib/renderer/materialEmission.js.map +1 -0
  286. package/lib/renderer/materialIndices.d.ts +7 -0
  287. package/lib/renderer/materialIndices.js +34 -0
  288. package/lib/renderer/materialIndices.js.map +1 -0
  289. package/lib/renderer/materialLayout.d.ts +102 -0
  290. package/lib/renderer/materialLayout.js +189 -0
  291. package/lib/renderer/materialLayout.js.map +1 -0
  292. package/lib/renderer/materialTextureSlots.d.ts +537 -0
  293. package/lib/renderer/materialTextureSlots.js +219 -0
  294. package/lib/renderer/materialTextureSlots.js.map +1 -0
  295. package/lib/renderer/mergeMeshesToGeometry.d.ts +8 -0
  296. package/lib/renderer/mergeMeshesToGeometry.js +236 -0
  297. package/lib/renderer/mergeMeshesToGeometry.js.map +1 -0
  298. package/lib/renderer/meshInstances.d.ts +23 -0
  299. package/lib/renderer/meshInstances.js +66 -0
  300. package/lib/renderer/meshInstances.js.map +1 -0
  301. package/lib/renderer/meshMembership.d.ts +10 -0
  302. package/lib/renderer/meshMembership.js +72 -0
  303. package/lib/renderer/meshMembership.js.map +1 -0
  304. package/lib/renderer/oidnNetwork.d.ts +20 -0
  305. package/lib/renderer/oidnNetwork.js +123 -0
  306. package/lib/renderer/oidnNetwork.js.map +1 -0
  307. package/lib/renderer/openPbrEnergyLut.d.ts +32 -0
  308. package/lib/renderer/openPbrEnergyLut.js +965 -0
  309. package/lib/renderer/openPbrEnergyLut.js.map +1 -0
  310. package/lib/renderer/pathLimits.d.ts +4 -0
  311. package/lib/renderer/pathLimits.js +7 -0
  312. package/lib/renderer/pathLimits.js.map +1 -0
  313. package/lib/renderer/prepareMeshBVH.d.ts +110 -0
  314. package/lib/renderer/prepareMeshBVH.js +857 -0
  315. package/lib/renderer/prepareMeshBVH.js.map +1 -0
  316. package/lib/renderer/progressiveScheduler.d.ts +11 -0
  317. package/lib/renderer/progressiveScheduler.js +19 -0
  318. package/lib/renderer/progressiveScheduler.js.map +1 -0
  319. package/lib/renderer/renderPipeline.d.ts +57 -0
  320. package/lib/renderer/renderPipeline.js +49 -0
  321. package/lib/renderer/renderPipeline.js.map +1 -0
  322. package/lib/renderer/sampling.d.ts +10 -0
  323. package/lib/renderer/sampling.js +28 -0
  324. package/lib/renderer/sampling.js.map +1 -0
  325. package/lib/renderer/sceneChangeDetector.d.ts +29 -0
  326. package/lib/renderer/sceneChangeDetector.js +232 -0
  327. package/lib/renderer/sceneChangeDetector.js.map +1 -0
  328. package/lib/renderer/sceneLightChanges.d.ts +14 -0
  329. package/lib/renderer/sceneLightChanges.js +34 -0
  330. package/lib/renderer/sceneLightChanges.js.map +1 -0
  331. package/lib/renderer/scratchSampling.d.ts +3 -0
  332. package/lib/renderer/scratchSampling.js +39 -0
  333. package/lib/renderer/scratchSampling.js.map +1 -0
  334. package/lib/renderer/shader.d.ts +37 -0
  335. package/lib/renderer/shader.js +41 -0
  336. package/lib/renderer/shader.js.map +1 -0
  337. package/lib/renderer/staticBvhPreparation.d.ts +24 -0
  338. package/lib/renderer/staticBvhPreparation.js +116 -0
  339. package/lib/renderer/staticBvhPreparation.js.map +1 -0
  340. package/lib/renderer/textureRegion.d.ts +8 -0
  341. package/lib/renderer/textureRegion.js +9 -0
  342. package/lib/renderer/textureRegion.js.map +1 -0
  343. package/lib/renderer/texturesFromMaterials.d.ts +6 -0
  344. package/lib/renderer/texturesFromMaterials.js +37 -0
  345. package/lib/renderer/texturesFromMaterials.js.map +1 -0
  346. package/lib/renderer/util.d.ts +17 -0
  347. package/lib/renderer/util.js +56 -0
  348. package/lib/renderer/util.js.map +1 -0
  349. package/lib/renderer/webgl.d.ts +131 -0
  350. package/lib/renderer/webgl.js +586 -0
  351. package/lib/renderer/webgl.js.map +1 -0
  352. package/lib/renderer/webglShaders.d.ts +4 -0
  353. package/lib/renderer/webglShaders.js +41 -0
  354. package/lib/renderer/webglShaders.js.map +1 -0
  355. package/lib/renderer/wgsl/chunks/common.wgsl.d.ts +2 -0
  356. package/lib/renderer/wgsl/chunks/common.wgsl.js +23 -0
  357. package/lib/renderer/wgsl/chunks/common.wgsl.js.map +1 -0
  358. package/lib/renderer/wgsl/chunks/envMap.wgsl.d.ts +2 -0
  359. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +128 -0
  360. package/lib/renderer/wgsl/chunks/envMap.wgsl.js.map +1 -0
  361. package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -0
  362. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +1441 -0
  363. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -0
  364. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +8 -0
  365. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +85 -0
  366. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -0
  367. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +7 -0
  368. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +315 -0
  369. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -0
  370. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.d.ts +3 -0
  371. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +1737 -0
  372. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js.map +1 -0
  373. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.d.ts +4 -0
  374. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +352 -0
  375. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js.map +1 -0
  376. package/lib/renderer/wgsl/chunks/rand.wgsl.d.ts +2 -0
  377. package/lib/renderer/wgsl/chunks/rand.wgsl.js +25 -0
  378. package/lib/renderer/wgsl/chunks/rand.wgsl.js.map +1 -0
  379. package/lib/renderer/wgsl/chunks/random.wgsl.d.ts +1 -0
  380. package/lib/renderer/wgsl/chunks/random.wgsl.js +2 -0
  381. package/lib/renderer/wgsl/chunks/random.wgsl.js.map +1 -0
  382. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +5 -0
  383. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +328 -0
  384. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -0
  385. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +2 -0
  386. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +400 -0
  387. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -0
  388. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +3 -0
  389. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +439 -0
  390. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -0
  391. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +2 -0
  392. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +40 -0
  393. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -0
  394. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +2 -0
  395. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +198 -0
  396. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -0
  397. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.d.ts +8 -0
  398. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js +16 -0
  399. package/lib/renderer/wgsl/chunks/shadowCatcherAccumulation.wgsl.js.map +1 -0
  400. package/lib/renderer/wgsl/chunks/sobol.wgsl.d.ts +2 -0
  401. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +170 -0
  402. package/lib/renderer/wgsl/chunks/sobol.wgsl.js.map +1 -0
  403. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.d.ts +2 -0
  404. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +42 -0
  405. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js.map +1 -0
  406. package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +5 -0
  407. package/lib/renderer/wgsl/compose.frag.wgsl.js +218 -0
  408. package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -0
  409. package/lib/renderer/wgsl/customDenoise.wgsl.d.ts +4 -0
  410. package/lib/renderer/wgsl/customDenoise.wgsl.js +28 -0
  411. package/lib/renderer/wgsl/customDenoise.wgsl.js.map +1 -0
  412. package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +3 -0
  413. package/lib/renderer/wgsl/depthQuery.wgsl.js +34 -0
  414. package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -0
  415. package/lib/renderer/wgsl/offlineAdaptive.compute.d.ts +2 -0
  416. package/lib/renderer/wgsl/offlineAdaptive.compute.js +108 -0
  417. package/lib/renderer/wgsl/offlineAdaptive.compute.js.map +1 -0
  418. package/lib/renderer/wgsl/rayTrace.compute.d.ts +16 -0
  419. package/lib/renderer/wgsl/rayTrace.compute.js +927 -0
  420. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -0
  421. package/lib/scene/AmbientLight.d.ts +17 -0
  422. package/lib/scene/AmbientLight.js +15 -0
  423. package/lib/scene/AmbientLight.js.map +1 -0
  424. package/lib/scene/Camera.d.ts +78 -0
  425. package/lib/scene/Camera.js +111 -0
  426. package/lib/scene/Camera.js.map +1 -0
  427. package/lib/scene/DirectionalLight.d.ts +18 -0
  428. package/lib/scene/DirectionalLight.js +17 -0
  429. package/lib/scene/DirectionalLight.js.map +1 -0
  430. package/lib/scene/EnvironmentLight.d.ts +14 -0
  431. package/lib/scene/EnvironmentLight.js +14 -0
  432. package/lib/scene/EnvironmentLight.js.map +1 -0
  433. package/lib/scene/Geometry.d.ts +87 -0
  434. package/lib/scene/Geometry.js +108 -0
  435. package/lib/scene/Geometry.js.map +1 -0
  436. package/lib/scene/IESProfile.d.ts +19 -0
  437. package/lib/scene/IESProfile.js +165 -0
  438. package/lib/scene/IESProfile.js.map +1 -0
  439. package/lib/scene/InstancedMesh.d.ts +43 -0
  440. package/lib/scene/InstancedMesh.js +79 -0
  441. package/lib/scene/InstancedMesh.js.map +1 -0
  442. package/lib/scene/Mesh.d.ts +14 -0
  443. package/lib/scene/Mesh.js +17 -0
  444. package/lib/scene/Mesh.js.map +1 -0
  445. package/lib/scene/OpenPBRMaterial.d.ts +224 -0
  446. package/lib/scene/OpenPBRMaterial.js +240 -0
  447. package/lib/scene/OpenPBRMaterial.js.map +1 -0
  448. package/lib/scene/RectLight.d.ts +31 -0
  449. package/lib/scene/RectLight.js +26 -0
  450. package/lib/scene/RectLight.js.map +1 -0
  451. package/lib/scene/Scene.d.ts +55 -0
  452. package/lib/scene/Scene.js +2 -0
  453. package/lib/scene/Scene.js.map +1 -0
  454. package/lib/scene/SceneNode.d.ts +16 -0
  455. package/lib/scene/SceneNode.js +33 -0
  456. package/lib/scene/SceneNode.js.map +1 -0
  457. package/lib/scene/SphereLight.d.ts +22 -0
  458. package/lib/scene/SphereLight.js +20 -0
  459. package/lib/scene/SphereLight.js.map +1 -0
  460. package/lib/scene/SpotLight.d.ts +35 -0
  461. package/lib/scene/SpotLight.js +29 -0
  462. package/lib/scene/SpotLight.js.map +1 -0
  463. package/lib/scene/Texture.d.ts +38 -0
  464. package/lib/scene/Texture.js +37 -0
  465. package/lib/scene/Texture.js.map +1 -0
  466. package/lib/scene/anisotropyParameters.d.ts +1 -0
  467. package/lib/scene/anisotropyParameters.js +13 -0
  468. package/lib/scene/anisotropyParameters.js.map +1 -0
  469. package/lib/scene/geometryChanges.d.ts +5 -0
  470. package/lib/scene/geometryChanges.js +18 -0
  471. package/lib/scene/geometryChanges.js.map +1 -0
  472. package/lib/scene/materialTextureNames.d.ts +2 -0
  473. package/lib/scene/materialTextureNames.js +9 -0
  474. package/lib/scene/materialTextureNames.js.map +1 -0
  475. package/lib/scene/openPbrSchema.d.ts +400 -0
  476. package/lib/scene/openPbrSchema.js +149 -0
  477. package/lib/scene/openPbrSchema.js.map +1 -0
  478. package/lib/scene/thinFilmParameters.d.ts +4 -0
  479. package/lib/scene/thinFilmParameters.js +12 -0
  480. package/lib/scene/thinFilmParameters.js.map +1 -0
  481. package/lib/settings/display.d.ts +118 -0
  482. package/lib/settings/display.js +34 -0
  483. package/lib/settings/display.js.map +1 -0
  484. package/lib/settings/engine.d.ts +37 -0
  485. package/lib/settings/engine.js +26 -0
  486. package/lib/settings/engine.js.map +1 -0
  487. package/lib/settings/render.d.ts +178 -0
  488. package/lib/settings/render.js +36 -0
  489. package/lib/settings/render.js.map +1 -0
  490. package/lib/tinybvh/LICENSE +21 -0
  491. package/lib/tinybvh/TinyBvhBuilder.d.ts +17 -0
  492. package/lib/tinybvh/TinyBvhBuilder.js +211 -0
  493. package/lib/tinybvh/TinyBvhBuilder.js.map +1 -0
  494. package/lib/tinybvh/tinybvh.wasm +0 -0
  495. package/lib/types.d.ts +13 -0
  496. package/lib/types.js +2 -0
  497. package/lib/types.js.map +1 -0
  498. package/lib/util/canvas.d.ts +2 -0
  499. package/lib/util/canvas.js +13 -0
  500. package/lib/util/canvas.js.map +1 -0
  501. package/lib/util/commonGeometry.d.ts +15 -0
  502. package/lib/util/commonGeometry.js +240 -0
  503. package/lib/util/commonGeometry.js.map +1 -0
  504. package/lib/util/events.d.ts +7 -0
  505. package/lib/util/events.js +23 -0
  506. package/lib/util/events.js.map +1 -0
  507. package/lib/util/frame.d.ts +2 -0
  508. package/lib/util/frame.js +10 -0
  509. package/lib/util/frame.js.map +1 -0
  510. package/lib/util/fromTHREE.d.ts +105 -0
  511. package/lib/util/fromTHREE.js +1111 -0
  512. package/lib/util/fromTHREE.js.map +1 -0
  513. package/lib/util/geometry.d.ts +13 -0
  514. package/lib/util/geometry.js +292 -0
  515. package/lib/util/geometry.js.map +1 -0
  516. package/lib/util/loadRGBE.d.ts +7 -0
  517. package/lib/util/loadRGBE.js +168 -0
  518. package/lib/util/loadRGBE.js.map +1 -0
  519. package/lib/util/math.d.ts +8 -0
  520. package/lib/util/math.js +64 -0
  521. package/lib/util/math.js.map +1 -0
  522. package/lib/util/mesh.d.ts +7 -0
  523. package/lib/util/mesh.js +20 -0
  524. package/lib/util/mesh.js.map +1 -0
  525. package/lib/util/threeDeformation.d.ts +20 -0
  526. package/lib/util/threeDeformation.js +218 -0
  527. package/lib/util/threeDeformation.js.map +1 -0
  528. package/lib/version.d.ts +2 -0
  529. package/lib/version.js +3 -0
  530. package/lib/version.js.map +1 -0
  531. package/llms.txt +62 -0
  532. package/oidn/weights/LICENSE.txt +202 -0
  533. package/oidn/weights/README.md +43 -0
  534. package/oidn/weights/rt_hdr_alb_nrm.tza +0 -0
  535. package/oidn/weights/rt_hdr_alb_nrm_small.tza +0 -0
  536. package/package.json +124 -4
@@ -0,0 +1,1111 @@
1
+ import { specularAnisotropyModelIndex } from '../scene/anisotropyParameters.js';
2
+ import { normalizeMaterialParams } from '../scene/openPbrSchema.js';
3
+ import { thinFilmMapChannelIndex } from '../scene/thinFilmParameters.js';
4
+ import { snapshotMaterialParameters, materialParametersEqual } from '../renderer/sceneChangeDetector.js';
5
+ import InstancedMesh from '../scene/InstancedMesh.js';
6
+ import Sync from '../Sync.js';
7
+ import { markDeformedGeometry } from '../scene/geometryChanges.js';
8
+ import Mesh from '../scene/Mesh.js';
9
+ import OpenPBRMaterial, { getMaterialHashKey, materialKeys } from '../scene/OpenPBRMaterial.js';
10
+ import Geometry, { Attribute } from '../scene/Geometry.js';
11
+ import Texture from '../scene/Texture.js';
12
+ import DirectionalLight from '../scene/DirectionalLight.js';
13
+ import AmbientLight from '../scene/AmbientLight.js';
14
+ import EnvironmentLight from '../scene/EnvironmentLight.js';
15
+ import RectLight from '../scene/RectLight.js';
16
+ import SphereLight from '../scene/SphereLight.js';
17
+ import SpotLight from '../scene/SpotLight.js';
18
+ import IESProfile from '../scene/IESProfile.js';
19
+ import Camera from '../scene/Camera.js';
20
+ import { mat4 } from '../math.js';
21
+ import { generateVertexNormals, updateBoundingBox, updateDynamicTangents } from './geometry.js';
22
+ import { THREEDeformation, isDeformingMesh } from './threeDeformation.js';
23
+ import { snapshotsEqual, snapshotFields } from '../renderer/sceneChangeDetector.js';
24
+ function convertTexture(threeTexture, textureStore) {
25
+ if (!threeTexture)
26
+ return;
27
+ const state = [threeTexture.version, threeTexture.image, threeTexture.flipY,
28
+ threeTexture.repeat.x, threeTexture.repeat.y, threeTexture.offset.x,
29
+ threeTexture.offset.y, threeTexture.channel];
30
+ const cached = textureStore.get(threeTexture);
31
+ if (cached && snapshotsEqual(cached.state, state))
32
+ return cached.texture;
33
+ const image = threeTexture.image;
34
+ const texture = cached?.texture ?? new Texture(image);
35
+ texture.image = image;
36
+ texture.source = threeTexture;
37
+ texture.flipY = threeTexture.flipY;
38
+ texture.uvScale = [threeTexture.repeat.x, threeTexture.repeat.y];
39
+ texture.uvOffset = [threeTexture.offset.x, threeTexture.offset.y];
40
+ texture.uvChannel = threeTexture.channel === 1 ? 1 : 0;
41
+ if (cached)
42
+ texture.markUpdated();
43
+ else
44
+ texture.version = threeTexture.version;
45
+ textureStore.set(threeTexture, { texture, state });
46
+ return texture;
47
+ }
48
+ function halfFloatToFloat(value) {
49
+ const sign = value & 0x8000 ? -1 : 1;
50
+ const exponent = (value >> 10) & 0x1f;
51
+ const fraction = value & 0x03ff;
52
+ if (exponent === 0) {
53
+ return sign * Math.pow(2, -14) * (fraction / 0x400);
54
+ }
55
+ if (exponent === 0x1f) {
56
+ return fraction ? NaN : sign * Infinity;
57
+ }
58
+ return sign * Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
59
+ }
60
+ function convertDataTexture(threeTexture, textureStore) {
61
+ if (!threeTexture?.image?.data || !threeTexture.image.width || !threeTexture.image.height)
62
+ return;
63
+ const previous = textureStore.get(threeTexture);
64
+ const texture = convertTexture(threeTexture, textureStore);
65
+ if (previous?.state === textureStore.get(threeTexture)?.state)
66
+ return texture;
67
+ const source = threeTexture.image.data;
68
+ const data = source instanceof Uint16Array
69
+ ? Float32Array.from(source, halfFloatToFloat)
70
+ : source instanceof Float32Array || source instanceof Uint8Array || source instanceof Int32Array
71
+ ? source : Float32Array.from(source);
72
+ texture.image = { data, width: threeTexture.image.width, height: threeTexture.image.height };
73
+ return texture;
74
+ }
75
+ function convertMaterial(threeMaterial, textureCache) {
76
+ const material = new OpenPBRMaterial();
77
+ if (threeMaterial.userData.mutracerShadowCatcher === true) {
78
+ material.shadowCatcher = true;
79
+ return material;
80
+ }
81
+ if (threeMaterial.isMeshBasicMaterial) {
82
+ const basic = threeMaterial;
83
+ // GLTFLoader represents KHR_materials_unlit as MeshBasicMaterial. Keep its
84
+ // base-color texture's alpha while displaying RGB without scene lighting.
85
+ material.unlit = true;
86
+ material.baseWeight = 0;
87
+ material.specularWeight = 0;
88
+ material.baseColor = basic.color.toArray();
89
+ material.emissionColor = material.baseColor;
90
+ material.emissionLuminance = 1;
91
+ material.map = convertTexture(basic.map, textureCache);
92
+ material.emissiveMap = material.map;
93
+ material.alphaMap = convertTexture(basic.alphaMap, textureCache);
94
+ material.geometryOpacity = basic.opacity;
95
+ material.alphaCutoff = Math.max(0, basic.alphaTest);
96
+ material.alphaMode = basic.alphaTest > 0
97
+ ? 'mask'
98
+ : basic.transparent || basic.opacity < 1 || !!basic.alphaMap
99
+ ? 'blend'
100
+ : 'opaque';
101
+ material.mapAlphaUsage = material.alphaMode === 'opaque'
102
+ ? "opaque"
103
+ : "alpha";
104
+ material.doubleSided = basic.side === 2;
105
+ return material;
106
+ }
107
+ const standardMaterial = threeMaterial;
108
+ material.baseColor = standardMaterial.color.toArray();
109
+ material.emissionColor =
110
+ standardMaterial.emissive &&
111
+ standardMaterial.emissive.toArray();
112
+ material.specularRoughness = standardMaterial.roughness;
113
+ material.baseMetalness = standardMaterial.metalness;
114
+ material.emissionLuminance = standardMaterial.emissiveIntensity;
115
+ material.normalScale =
116
+ standardMaterial.normalScale && standardMaterial.normalScale.toArray();
117
+ const materialUvProjection = standardMaterial.userData
118
+ .mutracerUvProjection;
119
+ if (materialUvProjection === 'triplanar' ||
120
+ materialUvProjection === 'spherical' ||
121
+ materialUvProjection === 'cylindrical' ||
122
+ materialUvProjection === 'none') {
123
+ material.uvProjection = materialUvProjection;
124
+ }
125
+ const materialUvScale = standardMaterial.userData.mutracerUvProjectionScale;
126
+ if (Array.isArray(materialUvScale) && materialUvScale.length >= 2) {
127
+ const referenceLength = Math.max(Number(standardMaterial.userData.mutracerUvReferenceLength) || 1, 0.000001);
128
+ const scaleX = Math.max(Number(materialUvScale[0]) || 0.000001, 0.000001);
129
+ const scaleY = Math.max(Number(materialUvScale[1]) || 0.000001, 0.000001);
130
+ material.uvProjectionScale = material.uvProjection === 'triplanar'
131
+ ? [scaleX / referenceLength, scaleY / referenceLength]
132
+ : material.uvProjection === 'cylindrical'
133
+ ? [scaleX, scaleY / referenceLength]
134
+ : [scaleX, scaleY];
135
+ }
136
+ material.map = convertTexture(standardMaterial.map, textureCache);
137
+ material.alphaMap = convertTexture(standardMaterial.alphaMap, textureCache);
138
+ material.alphaCutoff = Math.max(0, Number.isFinite(standardMaterial.alphaTest) ? standardMaterial.alphaTest : 0);
139
+ material.emissiveMap = convertTexture(standardMaterial.emissiveMap, textureCache);
140
+ material.normalMap = convertTexture(standardMaterial.normalMap, textureCache);
141
+ material.displacementMap = convertTexture(standardMaterial.displacementMap, textureCache);
142
+ const displacementScale = Number(standardMaterial.displacementScale);
143
+ material.displacementScale = Number.isFinite(displacementScale)
144
+ ? displacementScale
145
+ : material.displacementScale;
146
+ const displacementStepSize = Number(standardMaterial.userData.mutracerDisplacementStepSize);
147
+ if (Number.isFinite(displacementStepSize)) {
148
+ material.displacementStepSize = Math.max(0.000001, displacementStepSize);
149
+ }
150
+ const uvProjection = standardMaterial.userData
151
+ .mutracerDisplacementUvProjection;
152
+ if (uvProjection === 'triplanar' ||
153
+ uvProjection === 'spherical' ||
154
+ uvProjection === 'cylindrical' ||
155
+ uvProjection === 'none') {
156
+ material.displacementUvProjection = uvProjection;
157
+ }
158
+ const displacementUvProjectionScale = Number(standardMaterial.userData.mutracerDisplacementUvProjectionScale);
159
+ if (Number.isFinite(displacementUvProjectionScale)) {
160
+ material.displacementUvProjectionScale = Math.max(displacementUvProjectionScale, 0.000001);
161
+ }
162
+ if (standardMaterial.roughnessMap &&
163
+ standardMaterial.roughnessMap === standardMaterial.metalnessMap) {
164
+ material.metallicRoughnessMap = convertTexture(standardMaterial.roughnessMap, textureCache);
165
+ }
166
+ else {
167
+ material.roughnessMap = convertTexture(standardMaterial.roughnessMap, textureCache);
168
+ material.metalnessMap = convertTexture(standardMaterial.metalnessMap, textureCache);
169
+ }
170
+ const physicalMaterial = standardMaterial;
171
+ if (physicalMaterial.type === 'MeshPhysicalMaterial') {
172
+ material.transmissionWeight = physicalMaterial.transmission;
173
+ material.transmissionMap = convertTexture(physicalMaterial.transmissionMap, textureCache);
174
+ material.specularIor = physicalMaterial.ior;
175
+ material.specularWeight = physicalMaterial.specularIntensity;
176
+ if (physicalMaterial.specularColor) {
177
+ material.specularColor =
178
+ physicalMaterial.specularColor.toArray();
179
+ }
180
+ material.coatWeightMap = convertTexture(physicalMaterial.clearcoatMap, textureCache);
181
+ material.coatRoughnessMap = convertTexture(physicalMaterial.clearcoatRoughnessMap, textureCache);
182
+ material.coatNormalMap = convertTexture(physicalMaterial.clearcoatNormalMap, textureCache);
183
+ material.coatNormalScale = physicalMaterial.clearcoatNormalScale.toArray();
184
+ material.fuzzColorMap = convertTexture(physicalMaterial.sheenColorMap, textureCache);
185
+ material.fuzzRoughnessMap = convertTexture(physicalMaterial.sheenRoughnessMap, textureCache);
186
+ material.specularWeightMap = convertTexture(physicalMaterial.specularIntensityMap, textureCache);
187
+ material.specularColorMap = convertTexture(physicalMaterial.specularColorMap, textureCache);
188
+ material.coatWeight = physicalMaterial.clearcoat;
189
+ material.coatRoughness = physicalMaterial.clearcoatRoughness;
190
+ // MeshPhysicalMaterial's clearcoat BRDF uses the fixed dielectric F0
191
+ // for IOR 1.5. Match that in the OpenPBR path representation; explicit
192
+ // mutracerOpenPBR metadata below may provide a different coat IOR.
193
+ material.coatIor = 1.5;
194
+ // Three.js/glTF clearcoat does not model internal-reflection darkening.
195
+ material.coatDarkening = 0;
196
+ material.fuzzWeight = physicalMaterial.sheen;
197
+ material.fuzzRoughness = physicalMaterial.sheenRoughness;
198
+ if (physicalMaterial.sheenColor) {
199
+ material.fuzzColor = physicalMaterial.sheenColor.toArray();
200
+ }
201
+ if (physicalMaterial.attenuationColor) {
202
+ material.transmissionColor =
203
+ physicalMaterial.attenuationColor.toArray();
204
+ }
205
+ if (Number.isFinite(physicalMaterial.attenuationDistance)) {
206
+ material.transmissionDepth = Math.max(0, physicalMaterial.attenuationDistance);
207
+ }
208
+ }
209
+ const dispersion = Number(physicalMaterial.dispersion);
210
+ material.transmissionDispersionScale = Number.isFinite(dispersion)
211
+ ? Math.min(1, Math.max(0, dispersion))
212
+ : 0;
213
+ const realtimeIridescence = physicalMaterial;
214
+ material.thinFilmThickness = Math.min(20, Math.max(0, (realtimeIridescence.iridescenceThicknessRange?.[1] ?? 500) / 1000));
215
+ material.thinFilmWeight = Math.min(1, Math.max(0, realtimeIridescence.iridescence ?? 0));
216
+ material.thinFilmIor = Math.min(2.5, Math.max(1, realtimeIridescence.iridescenceIOR ?? 1.4));
217
+ const nativeThinFilmMap = standardMaterial.userData.mutracerThinFilmMap;
218
+ const thinFilmMap = standardMaterial.userData
219
+ .mutracerThinFilmMap ??
220
+ realtimeIridescence.iridescenceThicknessMap ??
221
+ undefined;
222
+ if (thinFilmMap) {
223
+ material.thinFilmMap = convertTexture(thinFilmMap, textureCache);
224
+ if (!nativeThinFilmMap) {
225
+ material.thinFilmThicknessMinimum = Math.min(20, Math.max(0, (realtimeIridescence.iridescenceThicknessRange?.[0] ?? 0) / 1000));
226
+ material.thinFilmMapChannel = 'g';
227
+ }
228
+ }
229
+ const anisotropy = Number(physicalMaterial.anisotropy);
230
+ material.specularRoughnessAnisotropy = Number.isFinite(anisotropy)
231
+ ? Math.min(1, Math.max(0, anisotropy))
232
+ : 0;
233
+ if (physicalMaterial.isMeshPhysicalMaterial) {
234
+ material.specularAnisotropyModel = 'gltf';
235
+ material.anisotropyMap = convertTexture(physicalMaterial.anisotropyMap, textureCache);
236
+ const rotation = Number(physicalMaterial.anisotropyRotation);
237
+ material.specularAnisotropyRotation = Number.isFinite(rotation) ? rotation : 0;
238
+ }
239
+ const sourceOpenPbr = standardMaterial.userData.mutracerOpenPBR;
240
+ const openPbr = sourceOpenPbr ? normalizeMaterialParams(sourceOpenPbr) : undefined;
241
+ const finite = (value, fallback, minimum = 0, maximum = 1) => {
242
+ const number = Number(value);
243
+ return Number.isFinite(number)
244
+ ? Math.min(maximum, Math.max(minimum, number))
245
+ : fallback;
246
+ };
247
+ const color = (value, fallback) => {
248
+ const components = value;
249
+ return components && components.length >= 3
250
+ ? [
251
+ finite(components[0], fallback[0]),
252
+ finite(components[1], fallback[1]),
253
+ finite(components[2], fallback[2])
254
+ ]
255
+ : fallback;
256
+ };
257
+ if (openPbr) {
258
+ if (openPbr.specularAnisotropyModel !== undefined) {
259
+ specularAnisotropyModelIndex(openPbr.specularAnisotropyModel);
260
+ material.specularAnisotropyModel = openPbr.specularAnisotropyModel;
261
+ }
262
+ if (openPbr.specularAnisotropy !== undefined && openPbr.specularAnisotropyModel !== 'gltf') {
263
+ material.specularAnisotropyModel = 'openpbr';
264
+ material.anisotropyMap = undefined;
265
+ material.specularAnisotropyRotation = 0;
266
+ }
267
+ // Only supported Texture inputs are accepted; arbitrary metadata objects
268
+ // must never enter the atlas as textures. Explicit null clears an import.
269
+ for (const name of ['coatWeightMap', 'coatRoughnessMap', 'fuzzColorMap',
270
+ 'fuzzRoughnessMap', 'specularWeightMap', 'specularColorMap', 'anisotropyMap', 'coatNormalMap']) {
271
+ const texture = openPbr[name];
272
+ if (texture === null)
273
+ material[name] = undefined;
274
+ else if (texture instanceof Texture)
275
+ material[name] = texture;
276
+ else if (texture && texture.isTexture &&
277
+ typeof texture.clone === 'function') {
278
+ material[name] = convertTexture(texture, textureCache);
279
+ }
280
+ }
281
+ material.specularAnisotropyRotation = finite(openPbr.specularAnisotropyRotation, material.specularAnisotropyRotation, -Infinity, Infinity);
282
+ material.coatAnisotropyRotation = finite(openPbr.coatAnisotropyRotation, material.coatAnisotropyRotation, -Infinity, Infinity);
283
+ const coatScale = openPbr.coatNormalScale;
284
+ if (coatScale && coatScale.length >= 2) {
285
+ material.coatNormalScale = [
286
+ finite(coatScale[0], material.coatNormalScale[0], -Infinity, Infinity),
287
+ finite(coatScale[1], material.coatNormalScale[1], -Infinity, Infinity)
288
+ ];
289
+ }
290
+ material.baseWeight = finite(openPbr.baseWeight, material.baseWeight);
291
+ material.baseDiffuseRoughness = finite(openPbr.baseDiffuseRoughness, material.baseDiffuseRoughness);
292
+ material.specularWeight = finite(openPbr.specularWeight, material.specularWeight);
293
+ material.specularColor = color(openPbr.specularColor, material.specularColor);
294
+ material.transmissionScatter = color(openPbr.transmissionScatter, material.transmissionScatter);
295
+ material.transmissionScatterAnisotropy = finite(openPbr.transmissionScatterAnisotropy, material.transmissionScatterAnisotropy, -0.95, 0.95);
296
+ material.transmissionDispersionScale = finite(openPbr.transmissionDispersionScale, material.transmissionDispersionScale);
297
+ material.transmissionDispersionAbbeNumber = finite(openPbr.transmissionDispersionAbbeNumber, material.transmissionDispersionAbbeNumber, 1, 100);
298
+ material.subsurfaceWeight = finite(openPbr.subsurfaceWeight, material.subsurfaceWeight);
299
+ material.subsurfaceColor = color(openPbr.subsurfaceColor, material.subsurfaceColor);
300
+ material.subsurfaceRadius = finite(openPbr.subsurfaceRadius, material.subsurfaceRadius, 0, Infinity);
301
+ material.subsurfaceRadiusScale = color(openPbr.subsurfaceRadiusScale, material.subsurfaceRadiusScale);
302
+ material.subsurfaceScatterAnisotropy = finite(openPbr.subsurfaceAnisotropy, material.subsurfaceAnisotropy, -0.95, 0.95);
303
+ material.coatWeight = finite(openPbr.coatWeight, material.coatWeight);
304
+ material.coatColor = color(openPbr.coatColor, material.coatColor);
305
+ material.coatRoughness = finite(openPbr.coatRoughness, material.coatRoughness);
306
+ material.coatRoughnessAnisotropy = finite(openPbr.coatAnisotropy, material.coatAnisotropy);
307
+ material.coatIor = finite(openPbr.coatIor, material.coatIor, 1, 2.5);
308
+ material.coatDarkening = finite(openPbr.coatDarkening, material.coatDarkening);
309
+ material.fuzzWeight = finite(openPbr.fuzzWeight, material.fuzzWeight);
310
+ material.fuzzColor = color(openPbr.fuzzColor, material.fuzzColor);
311
+ material.fuzzRoughness = finite(openPbr.fuzzRoughness, material.fuzzRoughness);
312
+ if ('thinWalled' in openPbr) {
313
+ material.geometryThinWalled = openPbr.thinWalled === true;
314
+ }
315
+ material.thinFilmWeight = finite(openPbr.thinFilmWeight, material.thinFilmWeight);
316
+ material.thinFilmThickness = finite(openPbr.thinFilmThickness, material.thinFilmThickness, 0, 20);
317
+ material.thinFilmThicknessMinimum = finite(openPbr.thinFilmThicknessMinimum, material.thinFilmThicknessMinimum, 0, 20);
318
+ if (openPbr.thinFilmMapChannel !== undefined) {
319
+ material.thinFilmMapChannel = ['r', 'g', 'b', 'a'][thinFilmMapChannelIndex(openPbr.thinFilmMapChannel)];
320
+ }
321
+ if (openPbr.thinFilmMap instanceof Texture)
322
+ material.thinFilmMap = openPbr.thinFilmMap;
323
+ else if (openPbr.thinFilmMap && openPbr.thinFilmMap.isTexture) {
324
+ material.thinFilmMap = convertTexture(openPbr.thinFilmMap, textureCache);
325
+ }
326
+ material.thinFilmIor = finite(openPbr.thinFilmIor, material.thinFilmIor, 1, 2.5);
327
+ }
328
+ material.geometryOpacity = standardMaterial.opacity;
329
+ // THREE.DoubleSide is the numeric enum value 2. Keep this module's Three.js
330
+ // import type-only while preserving the source material's culling semantics.
331
+ material.doubleSided = standardMaterial.side === 2;
332
+ if (openPbr) {
333
+ material.specularRoughnessAnisotropy = finite(openPbr.specularAnisotropy, material.specularRoughnessAnisotropy);
334
+ material.geometryOpacity = finite(openPbr.opacity, material.geometryOpacity);
335
+ }
336
+ const bevelSize = Number(standardMaterial.userData.mutracerBevelSize);
337
+ material.bevelSize = Number.isFinite(bevelSize) ? Math.max(0, bevelSize) : 0;
338
+ material.mapAlphaUsage =
339
+ standardMaterial.transparent ||
340
+ !!standardMaterial.alphaMap ||
341
+ standardMaterial.alphaTest > 0
342
+ ? "alpha"
343
+ : "opaque";
344
+ material.alphaMode = standardMaterial.alphaTest > 0
345
+ ? 'mask'
346
+ : standardMaterial.transparent ||
347
+ material.geometryOpacity < 1 ||
348
+ !!standardMaterial.alphaMap
349
+ ? 'blend'
350
+ : 'opaque';
351
+ return material;
352
+ }
353
+ function copyFloatAttribute(attribute, itemSize = attribute.itemSize) {
354
+ const result = new Float32Array(attribute.count * itemSize);
355
+ if (attribute.array instanceof Float32Array && !attribute.normalized) {
356
+ const interleaved = attribute;
357
+ if (!interleaved.isInterleavedBufferAttribute && itemSize === attribute.itemSize) {
358
+ result.set(attribute.array.subarray(0, result.length));
359
+ }
360
+ else {
361
+ const stride = interleaved.isInterleavedBufferAttribute
362
+ ? interleaved.data.stride : attribute.itemSize;
363
+ const offset = interleaved.isInterleavedBufferAttribute ? interleaved.offset : 0;
364
+ for (let index = 0; index < attribute.count; index++) {
365
+ const sourceOffset = index * stride + offset;
366
+ const targetOffset = index * itemSize;
367
+ for (let component = 0; component < itemSize; component++) {
368
+ result[targetOffset + component] = attribute.array[sourceOffset + component];
369
+ }
370
+ }
371
+ }
372
+ return result;
373
+ }
374
+ // Getters preserve normalized integer and Float16BufferAttribute decoding.
375
+ const getters = [
376
+ attribute.getX,
377
+ attribute.getY,
378
+ attribute.getZ,
379
+ attribute.getW
380
+ ];
381
+ for (let index = 0; index < attribute.count; index++) {
382
+ for (let component = 0; component < itemSize; component++) {
383
+ result[index * itemSize + component] = getters[component].call(attribute, index);
384
+ }
385
+ }
386
+ return result;
387
+ }
388
+ function convertGeometry(threeGeometry, drawRange) {
389
+ const positionAttrb = threeGeometry.getAttribute('position');
390
+ const normalAttrb = threeGeometry.getAttribute('normal');
391
+ const tangentAttrb = threeGeometry.getAttribute('tangent');
392
+ const uvAttrb = threeGeometry.getAttribute('uv');
393
+ const uv1Attrb = threeGeometry.getAttribute('uv1');
394
+ const indexAttrb = threeGeometry.getIndex();
395
+ const sourceCount = indexAttrb ? indexAttrb.array.length : positionAttrb.count;
396
+ // Match Array.slice range handling without expanding the complete index stream.
397
+ const clampOffset = (offset) => {
398
+ const integer = Math.trunc(offset) || 0;
399
+ return integer < 0 ? Math.max(sourceCount + integer, 0) : Math.min(integer, sourceCount);
400
+ };
401
+ const start = drawRange ? clampOffset(drawRange.start) : 0;
402
+ const end = drawRange ? clampOffset(drawRange.start + drawRange.count) : sourceCount;
403
+ let indexCount = Math.max(end - start, 0);
404
+ // WebGL's TRIANGLES draw mode ignores an incomplete final primitive. Keep
405
+ // path tracing on the same index stream so valid BufferGeometry with a
406
+ // dangling one or two elements cannot produce invalid BLAS input.
407
+ indexCount -= indexCount % 3;
408
+ if (indexCount === 0)
409
+ return null;
410
+ const indices = new Uint32Array(indexCount);
411
+ if (indexAttrb) {
412
+ indices.set(indexAttrb.array.subarray(start, start + indexCount));
413
+ }
414
+ else {
415
+ for (let index = 0; index < indexCount; index++)
416
+ indices[index] = start + index;
417
+ }
418
+ const geometry = new Geometry({
419
+ position: new Attribute(copyFloatAttribute(positionAttrb), positionAttrb.itemSize),
420
+ normal: normalAttrb &&
421
+ new Attribute(copyFloatAttribute(normalAttrb), normalAttrb.itemSize),
422
+ tangent: tangentAttrb && new Attribute(copyFloatAttribute(tangentAttrb, Math.min(4, tangentAttrb.itemSize)), Math.min(4, tangentAttrb.itemSize)),
423
+ uv: uvAttrb && new Attribute(copyFloatAttribute(uvAttrb), uvAttrb.itemSize),
424
+ uv1: uv1Attrb &&
425
+ new Attribute(copyFloatAttribute(uv1Attrb), uv1Attrb.itemSize),
426
+ indices: new Attribute(indices, 1)
427
+ });
428
+ if (!geometry.normal) {
429
+ generateVertexNormals(geometry);
430
+ }
431
+ updateBoundingBox(geometry);
432
+ return geometry;
433
+ }
434
+ function createConversionStore() {
435
+ return { updateId: 0, textures: new WeakMap(), materials: new WeakMap(), geometries: new WeakMap(),
436
+ materialHooks: new WeakMap(), lightHooks: new WeakMap(),
437
+ poseChanged: false, meshes: new WeakMap(), lights: new WeakMap(), deformedGeometries: new WeakMap(), deformations: new WeakMap(),
438
+ instanceMeshes: new WeakMap(), projectionVariants: new Map(), warned: new WeakSet() };
439
+ }
440
+ const geometryAttributeNames = ['position', 'normal', 'tangent', 'uv', 'uv1', 'index'];
441
+ function geometryState(geometry, deformation) {
442
+ const state = [];
443
+ for (let i = 0; i < geometryAttributeNames.length; i++) {
444
+ const name = geometryAttributeNames[i];
445
+ const attribute = name === 'index' ? geometry.index : geometry.getAttribute(name);
446
+ if (!attribute) {
447
+ state.push(undefined);
448
+ continue;
449
+ }
450
+ const interleaved = attribute;
451
+ const buffer = interleaved.isInterleavedBufferAttribute ? interleaved.data : attribute;
452
+ state.push(attribute, buffer, deformation && i < 3 ? undefined : buffer.version, buffer.array, attribute.count, attribute.itemSize, attribute.normalized, interleaved.offset, interleaved.data?.stride);
453
+ }
454
+ return state;
455
+ }
456
+ /** Compare cached fields directly; unchanged geometry creates no snapshot arrays. */
457
+ function geometryStateMatches(geometry, state, deformation) {
458
+ let field = 0;
459
+ for (let i = 0; i < geometryAttributeNames.length; i++) {
460
+ const name = geometryAttributeNames[i];
461
+ const attribute = name === 'index' ? geometry.index : geometry.getAttribute(name);
462
+ if (!attribute) {
463
+ if (state[field++] !== undefined)
464
+ return false;
465
+ continue;
466
+ }
467
+ const interleaved = attribute;
468
+ const buffer = interleaved.isInterleavedBufferAttribute ? interleaved.data : attribute;
469
+ if (state[field++] !== attribute || state[field++] !== buffer ||
470
+ !Object.is(state[field++], deformation && i < 3 ? undefined : buffer.version) ||
471
+ state[field++] !== buffer.array || !Object.is(state[field++], attribute.count) ||
472
+ !Object.is(state[field++], attribute.itemSize) || !Object.is(state[field++], attribute.normalized) ||
473
+ !Object.is(state[field++], interleaved.offset) || !Object.is(state[field++], interleaved.data?.stride))
474
+ return false;
475
+ }
476
+ return field === state.length;
477
+ }
478
+ function retainLight(store, source, value) {
479
+ const cached = store.lights.get(source);
480
+ if (!cached || cached.type !== value.type) {
481
+ store.lights.set(source, value);
482
+ return value;
483
+ }
484
+ // Matrix and color arrays are retained when unchanged; light identity always is.
485
+ for (const key of Object.keys(value)) {
486
+ const previous = cached[key];
487
+ const next = value[key];
488
+ if (Array.isArray(previous) && Array.isArray(next) && snapshotsEqual(previous, next))
489
+ continue;
490
+ cached[key] = next;
491
+ }
492
+ return cached;
493
+ }
494
+ /**
495
+ * Converts a Three.js scene into a MuTracer {@link Scene}: meshes with
496
+ * `MeshStandardMaterial` / `MeshPhysicalMaterial` (mapped to OpenPBR),
497
+ * directional, ambient, rect-area, point and spot lights, and the scene
498
+ * background / environment. Calls `scene.updateMatrixWorld()` and creates fresh objects on every call.
499
+ * CPU-evaluates skinning/morph targets and batches InstancedMesh instances
500
+ * with shared geometry, native colors and cached projection material variants. Unsupported batched
501
+ * or instanced deformation falls back to an ordinary mesh with a warning.
502
+ * For animation and editing, use {@link THREESync}.
503
+ *
504
+ * Renderer-specific material settings can be supplied through
505
+ * `material.userData`, e.g. `userData.mutracerShadowCatcher = true` or
506
+ * `userData.mutracerOpenPBR = { ... }` for OpenPBR inputs without a Three.js
507
+ * equivalent.
508
+ */
509
+ export function fromTHREEScene(scene, options = {}) {
510
+ return convertScene(scene, options, createConversionStore());
511
+ }
512
+ function convertScene(scene, options, store) {
513
+ const updateId = ++store.updateId;
514
+ const meshes = [];
515
+ const lights = [];
516
+ const textureCache = store.textures;
517
+ const convertedMaterials = new Set();
518
+ const baseHashes = new Map();
519
+ function refreshVariant(entry, base) {
520
+ let hash = baseHashes.get(base);
521
+ if (hash === undefined) {
522
+ hash = getMaterialHashKey(base);
523
+ baseHashes.set(base, hash);
524
+ }
525
+ if (entry.base === base && entry.hash === hash && materialParametersEqual(base, entry.parameters))
526
+ return;
527
+ for (const field of materialKeys)
528
+ entry.material[field] = base[field];
529
+ if (entry.autoUvProjection)
530
+ entry.material.uvProjection = 'triplanar';
531
+ if (entry.autoDisplacementUvProjection)
532
+ entry.material.displacementUvProjection = 'triplanar';
533
+ entry.parameters = snapshotMaterialParameters(base);
534
+ entry.hash = hash;
535
+ entry.base = base;
536
+ }
537
+ function materialVariant(source, base, autoUvProjection, autoDisplacementUvProjection) {
538
+ if (!autoUvProjection && !autoDisplacementUvProjection)
539
+ return base;
540
+ let variants = store.projectionVariants.get(source);
541
+ if (!variants) {
542
+ variants = new Map();
543
+ store.projectionVariants.set(source, variants);
544
+ }
545
+ const key = `${+autoUvProjection}:${+autoDisplacementUvProjection}`;
546
+ let variant = variants.get(key);
547
+ if (!variant) {
548
+ variant = { material: new OpenPBRMaterial(), parameters: [],
549
+ autoUvProjection, autoDisplacementUvProjection };
550
+ variants.set(key, variant);
551
+ }
552
+ refreshVariant(variant, base);
553
+ return variant.material;
554
+ }
555
+ function materialHook(source) {
556
+ if (!options.convertMaterial)
557
+ return undefined;
558
+ let entry = store.materialHooks.get(source);
559
+ if (!entry || entry.version !== source.version) {
560
+ entry = { version: source.version, value: options.convertMaterial(source) };
561
+ store.materialHooks.set(source, entry);
562
+ }
563
+ return entry.value;
564
+ }
565
+ function lightHook(source) {
566
+ if (!options.convertLight)
567
+ return undefined;
568
+ // Three.js Light has no built-in version; applications revise it through userData.
569
+ const revision = source.userData.mutracerVersion;
570
+ const version = typeof revision === 'number' ? revision : undefined;
571
+ let entry = store.lightHooks.get(source);
572
+ if (!entry || entry.version !== version) {
573
+ entry = { version, value: options.convertLight(source) };
574
+ store.lightHooks.set(source, entry);
575
+ }
576
+ return entry.value;
577
+ }
578
+ function resolveMaterial(source) {
579
+ const custom = materialHook(source);
580
+ if (custom !== undefined)
581
+ return custom;
582
+ const cached = store.materials.get(source);
583
+ if (convertedMaterials.has(source))
584
+ return cached.material;
585
+ const converted = convertMaterial(source, textureCache);
586
+ const hash = getMaterialHashKey(converted);
587
+ let material = converted;
588
+ if (cached) {
589
+ if (cached.hash !== hash) {
590
+ for (const key of materialKeys)
591
+ cached.material[key] = converted[key];
592
+ cached.hash = hash;
593
+ }
594
+ material = cached.material;
595
+ }
596
+ else
597
+ store.materials.set(source, { material, hash });
598
+ convertedMaterials.add(source);
599
+ return material;
600
+ }
601
+ function isMesh(node) {
602
+ return node.isMesh;
603
+ }
604
+ function isDirectionalLight(node) {
605
+ return node.isDirectionalLight;
606
+ }
607
+ function isAmbientLight(node) {
608
+ return node.isAmbientLight;
609
+ }
610
+ function isRectAreaLight(node) {
611
+ return node.isRectAreaLight;
612
+ }
613
+ function isPointLight(node) {
614
+ return node.type === 'PointLight';
615
+ }
616
+ function isSpotLight(node) {
617
+ return node.type === 'SpotLight';
618
+ }
619
+ scene.updateMatrixWorld(true);
620
+ scene.traverseVisible((child) => {
621
+ if (child.isLight) {
622
+ const custom = lightHook(child);
623
+ if (custom !== undefined) {
624
+ if (custom !== null)
625
+ lights.push(custom);
626
+ return;
627
+ }
628
+ }
629
+ if (isMesh(child)) {
630
+ if (child.userData.viewerEnvironment)
631
+ return;
632
+ // Viewer-only proxy geometry is already represented by its source mesh.
633
+ if (child.userData.viewerRealtimeDisplacement)
634
+ return;
635
+ const childMaterials = Array.isArray(child.material)
636
+ ? child.material
637
+ : [child.material];
638
+ // A null result rejects the source mesh, including all of its groups/instances.
639
+ if (childMaterials.some(material => materialHook(material) === null))
640
+ return;
641
+ if (!child.geometry) {
642
+ console.warn(child, 'must have a geometry property');
643
+ }
644
+ else if (childMaterials.some((material) => materialHook(material) === undefined &&
645
+ !material.isMeshStandardMaterial &&
646
+ !material.isMeshBasicMaterial &&
647
+ material.userData.mutracerShadowCatcher !== true)) {
648
+ console.warn(child, 'must use MeshStandardMaterial or MeshBasicMaterial in order to be rendered.');
649
+ }
650
+ else {
651
+ const instanced = child;
652
+ const unsupported = child.isBatchedMesh ||
653
+ instanced.isInstancedMesh && (!!instanced.morphTexture || child.isSkinnedMesh);
654
+ if (unsupported && !store.warned.has(child)) {
655
+ console.warn('MuTracer: BatchedMesh, instanced morph targets and skinned instancing are not supported; converting as an ordinary mesh.', child);
656
+ store.warned.add(child);
657
+ }
658
+ const expand = instanced.isInstancedMesh && !unsupported;
659
+ let deformation;
660
+ let deformed = false;
661
+ if (!unsupported && isDeformingMesh(child)) {
662
+ deformation = store.deformations.get(child);
663
+ if (!deformation?.matches(child.geometry)) {
664
+ deformation = new THREEDeformation(child.geometry);
665
+ store.deformations.set(child, deformation);
666
+ store.deformedGeometries.delete(child);
667
+ }
668
+ deformed = deformation.update(child);
669
+ store.poseChanged ||= deformed;
670
+ }
671
+ const threeMaterials = childMaterials;
672
+ const groups = threeMaterials.length > 1 && child.geometry.groups.length
673
+ ? child.geometry.groups
674
+ : [{ start: 0, count: Infinity, materialIndex: 0 }];
675
+ // Shared static geometry is checked once per update, before its groups.
676
+ // Deforming meshes keep independent entries for their evaluated geometry.
677
+ let entry = deformation ? store.deformedGeometries.get(child) : store.geometries.get(child.geometry);
678
+ if (!entry || entry.checkedAt !== updateId) {
679
+ if (!entry || !geometryStateMatches(child.geometry, entry.state, !!deformation)) {
680
+ entry = { state: geometryState(child.geometry, !!deformation), groups: new Map(), checkedAt: updateId };
681
+ if (deformation)
682
+ store.deformedGeometries.set(child, entry);
683
+ else
684
+ store.geometries.set(child.geometry, entry);
685
+ }
686
+ entry.checkedAt = updateId;
687
+ }
688
+ const geometryEntry = entry;
689
+ groups.forEach((group, groupIndex) => {
690
+ const count = Number.isFinite(group.count)
691
+ ? group.count
692
+ : (child.geometry.getIndex()?.count ??
693
+ child.geometry.getAttribute('position').count);
694
+ const geometryKey = `${group.start}:${count}`;
695
+ let geometry = geometryEntry.groups.get(geometryKey);
696
+ const newGeometry = !geometry;
697
+ if (!geometry) {
698
+ const converted = convertGeometry(child.geometry, { start: group.start, count });
699
+ if (!converted)
700
+ return;
701
+ geometry = converted;
702
+ geometryEntry.groups.set(geometryKey, geometry);
703
+ }
704
+ if (deformation && (deformed || newGeometry)) {
705
+ geometry.dynamic = true;
706
+ geometry.position.array.set(deformation.position);
707
+ if (deformation.normal)
708
+ geometry.normal.array.set(deformation.normal);
709
+ if (deformation.tangent && geometry.tangent)
710
+ geometry.tangent.array.set(deformation.tangent);
711
+ if (!child.geometry.getAttribute('tangent'))
712
+ updateDynamicTangents(geometry);
713
+ updateBoundingBox(geometry);
714
+ if (!newGeometry)
715
+ markDeformedGeometry(geometry);
716
+ }
717
+ const sourceMaterial = threeMaterials[group.materialIndex ?? 0];
718
+ let material = resolveMaterial(sourceMaterial);
719
+ const baseMaterial = material;
720
+ const autoUvProjection = !geometry.uv && baseMaterial.uvProjection === 'none' &&
721
+ !!(baseMaterial.map || baseMaterial.normalMap || baseMaterial.emissiveMap || baseMaterial.metallicRoughnessMap ||
722
+ baseMaterial.roughnessMap || baseMaterial.metalnessMap || baseMaterial.thinFilmMap ||
723
+ baseMaterial.coatWeightMap || baseMaterial.coatRoughnessMap || baseMaterial.fuzzColorMap ||
724
+ baseMaterial.fuzzRoughnessMap || baseMaterial.specularWeightMap || baseMaterial.specularColorMap || baseMaterial.anisotropyMap || baseMaterial.coatNormalMap);
725
+ const autoDisplacementUvProjection = !geometry.uv && !!baseMaterial.displacementMap &&
726
+ baseMaterial.displacementUvProjection === 'none';
727
+ const instanceCount = expand ? instanced.count : 1;
728
+ if (expand) {
729
+ let batchesByGroup = store.instanceMeshes.get(child);
730
+ if (!batchesByGroup) {
731
+ batchesByGroup = new Map();
732
+ store.instanceMeshes.set(child, batchesByGroup);
733
+ }
734
+ const variant = materialVariant(sourceMaterial, baseMaterial, autoUvProjection, autoDisplacementUvProjection);
735
+ let batch = batchesByGroup.get(groupIndex);
736
+ if (!batch) {
737
+ batch = new InstancedMesh(geometry, variant, { count: instanceCount });
738
+ batch.transform = child.matrixWorld.elements.slice();
739
+ batchesByGroup.set(groupIndex, batch);
740
+ }
741
+ batch.geometry = geometry;
742
+ if (batch.materials[0] !== variant)
743
+ batch.materials = [variant];
744
+ let changed = batch.count !== instanceCount;
745
+ if (batch.transforms.length < instanceCount * 16) {
746
+ batch.transforms = new Float32Array(instanceCount * 16);
747
+ changed = true;
748
+ }
749
+ // Grow colors before count validation in either notification method.
750
+ const sourceColors = instanced.instanceColor;
751
+ let colorsChanged = false;
752
+ if (sourceColors) {
753
+ if (!batch.colors || batch.colors.length < instanceCount * 3)
754
+ batch.colors = new Float32Array(instanceCount * 3);
755
+ for (let i = 0; i < instanceCount; i++) {
756
+ for (let k = 0; k < 3; k++) {
757
+ const value = Math.fround(k === 0 ? sourceColors.getX(i) : k === 1 ? sourceColors.getY(i) : sourceColors.getZ(i));
758
+ if (!Object.is(batch.colors[i * 3 + k], value)) {
759
+ batch.colors[i * 3 + k] = value;
760
+ colorsChanged = true;
761
+ }
762
+ }
763
+ }
764
+ }
765
+ else
766
+ batch.colors = undefined;
767
+ batch.count = instanceCount;
768
+ const matrices = instanced.instanceMatrix;
769
+ for (let i = 0; i < instanceCount; i++)
770
+ for (let k = 0; k < 16; k++) {
771
+ const value = Math.fround(matrices.array[i * matrices.itemSize + k]);
772
+ if (!Object.is(batch.transforms[i * 16 + k], value)) {
773
+ batch.transforms[i * 16 + k] = value;
774
+ changed = true;
775
+ }
776
+ }
777
+ for (let i = 0; i < 16; i++)
778
+ batch.transform[i] = child.matrixWorld.elements[i];
779
+ if (changed)
780
+ batch.markTransformsUpdated();
781
+ if (colorsChanged)
782
+ batch.markColorsUpdated();
783
+ batch.name = child.name || `Mesh ${meshes.length + 1}${groups.length > 1 ? `.${groupIndex + 1}` : ''}`;
784
+ if (instanceCount > 0) {
785
+ meshes.push(batch);
786
+ options.onMeshConverted?.(batch, child, group, groupIndex);
787
+ }
788
+ }
789
+ else {
790
+ material = materialVariant(sourceMaterial, baseMaterial, autoUvProjection, autoDisplacementUvProjection);
791
+ let meshGroups = store.meshes.get(child);
792
+ if (!meshGroups) {
793
+ meshGroups = new Map();
794
+ store.meshes.set(child, meshGroups);
795
+ }
796
+ let mesh = meshGroups.get(groupIndex);
797
+ if (!mesh) {
798
+ mesh = new Mesh(geometry, material);
799
+ mesh.transform = child.matrixWorld.elements.slice();
800
+ meshGroups.set(groupIndex, mesh);
801
+ }
802
+ mesh.geometry = geometry;
803
+ if (mesh.materials[0] !== material)
804
+ mesh.materials = [material];
805
+ mesh.name = child.name || `Mesh ${meshes.length + 1}${groups.length > 1 ? `.${groupIndex + 1}` : ''}`;
806
+ for (let i = 0; i < 16; i++)
807
+ mesh.transform[i] = child.matrixWorld.elements[i];
808
+ meshes.push(mesh);
809
+ options.onMeshConverted?.(mesh, child, group, groupIndex);
810
+ }
811
+ });
812
+ }
813
+ }
814
+ else if (isDirectionalLight(child)) {
815
+ const light = new DirectionalLight({ color: child.color.toArray(), intensity: child.intensity });
816
+ light.transform = Array.from(light.transform);
817
+ light.position = child.getWorldPosition(child.position.clone()).toArray();
818
+ light.lookAt(child.target.getWorldPosition(child.target.position.clone()).toArray());
819
+ lights.push(retainLight(store, child, light));
820
+ }
821
+ else if (isRectAreaLight(child)) {
822
+ const worldMatrix = child.matrixWorld.clone();
823
+ // Shear decomposition can return a non-unit quaternion. The size below
824
+ // carries scale; this approximated rectangle's sampling frame is rigid.
825
+ const worldRotation = child.getWorldQuaternion(child.quaternion.clone()).normalize();
826
+ const worldPosition = child.getWorldPosition(child.position.clone());
827
+ const elements = worldMatrix.elements;
828
+ const widthScale = Math.hypot(elements[0], elements[1], elements[2]);
829
+ const heightScale = Math.hypot(elements[4], elements[5], elements[6]);
830
+ const light = new RectLight({
831
+ size: [child.width * widthScale, child.height * heightScale],
832
+ color: child.color.toArray(),
833
+ intensity: child.intensity
834
+ });
835
+ worldMatrix.compose(worldPosition, worldRotation, child.scale.clone().set(1, 1, 1));
836
+ light.transform = worldMatrix.elements.slice();
837
+ lights.push(retainLight(store, child, light));
838
+ }
839
+ else if (isSpotLight(child)) {
840
+ const worldPosition = child.getWorldPosition(child.position.clone());
841
+ const worldTarget = child.target.getWorldPosition(child.target.position.clone());
842
+ const outerAngle = (child.angle * 180) / Math.PI;
843
+ const profile = child.userData.mutracerIesProfile;
844
+ if (profile != null && !(profile instanceof IESProfile)) {
845
+ throw new Error(`THREE.SpotLight "${child.name || '<unnamed>'}" has an invalid mutracerIesProfile`);
846
+ }
847
+ const light = new SpotLight({
848
+ color: child.color.toArray(),
849
+ intensity: child.intensity,
850
+ radius: child.userData.mutracerRadius ?? 0.01,
851
+ innerAngle: outerAngle * (1 - child.penumbra),
852
+ outerAngle,
853
+ iesProfile: profile
854
+ });
855
+ light.transform = Array.from(light.transform);
856
+ light.position = worldPosition.toArray();
857
+ light.lookAt(worldTarget.toArray());
858
+ const rotation = -(child.userData.mutracerIesRotation ?? 0) * Math.PI / 180;
859
+ if (rotation)
860
+ mat4.rotateZ(light.transform, light.transform, rotation);
861
+ lights.push(retainLight(store, child, light));
862
+ }
863
+ else if (isPointLight(child)) {
864
+ const world = child.matrixWorld.elements;
865
+ const position = [
866
+ world[12],
867
+ world[13],
868
+ world[14]
869
+ ];
870
+ lights.push(retainLight(store, child, Object.assign(new SphereLight({
871
+ color: child.color.toArray(),
872
+ intensity: child.intensity,
873
+ radius: child.userData.mutracerRadius ?? 0.25
874
+ }), { transform: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ...position, 1] })));
875
+ }
876
+ else if (isAmbientLight(child)) {
877
+ lights.push(retainLight(store, child, new AmbientLight({ color: child.color.toArray(), intensity: child.intensity })));
878
+ }
879
+ });
880
+ const threeEnvironment = scene.environment;
881
+ const environmentMap = convertDataTexture(threeEnvironment, textureCache);
882
+ const environmentLight = threeEnvironment && environmentMap
883
+ ? retainLight(store, threeEnvironment, new EnvironmentLight({ map: environmentMap }))
884
+ : undefined;
885
+ if (environmentLight)
886
+ lights.push(environmentLight);
887
+ const grounded = scene.userData.mutracerGroundedSkybox;
888
+ const groundedTexture = grounded && convertDataTexture(grounded.texture, textureCache);
889
+ const hideEnvironmentBackground = scene.userData.mutracerHiddenBackground === true;
890
+ let background = hideEnvironmentBackground
891
+ ? [0, 0, 0, 0]
892
+ : grounded && groundedTexture
893
+ ? {
894
+ type: 'GroundedSkybox',
895
+ map: groundedTexture,
896
+ height: grounded.height,
897
+ radius: grounded.radius,
898
+ groundHeight: grounded.groundHeight,
899
+ center: grounded.center
900
+ }
901
+ : scene.background
902
+ ? scene.background.isColor
903
+ ? [...scene.background.toArray(), 1]
904
+ : scene.background === scene.environment && environmentLight
905
+ ? environmentLight.map
906
+ : convertDataTexture(scene.background, textureCache)
907
+ : undefined;
908
+ const oldBackground = store.background;
909
+ if (Array.isArray(background) && Array.isArray(oldBackground) && snapshotsEqual(background, oldBackground)) {
910
+ background = oldBackground;
911
+ }
912
+ else if (background && oldBackground && !Array.isArray(background) && !Array.isArray(oldBackground)
913
+ && !(background instanceof Texture) && !(oldBackground instanceof Texture)) {
914
+ // Compare by values, ignoring the newly constructed wrapper's identity.
915
+ if (snapshotsEqual(snapshotFields(background).slice(1), snapshotFields(oldBackground).slice(1)))
916
+ background = oldBackground;
917
+ else {
918
+ Object.assign(oldBackground, background);
919
+ background = oldBackground;
920
+ }
921
+ }
922
+ store.background = background;
923
+ // Inspect the final converted meshes, including onMeshConverted overrides.
924
+ // Iterate across source materials so removed/hidden objects are pruned too.
925
+ const usedMaterials = new Set(meshes.flatMap(mesh => mesh.materials));
926
+ for (const [source, variants] of store.projectionVariants) {
927
+ for (const [key, variant] of variants)
928
+ if (!usedMaterials.has(variant.material))
929
+ variants.delete(key);
930
+ if (!variants.size)
931
+ store.projectionVariants.delete(source);
932
+ }
933
+ return {
934
+ background,
935
+ meshes,
936
+ lights
937
+ };
938
+ }
939
+ /** Inputs that can wake an idle OrbitControls instance, without inspecting its private inertia. */
940
+ function orbitControlsState(camera, controls) {
941
+ if (!camera || !controls.getPolarAngle || !controls.getAzimuthalAngle)
942
+ return;
943
+ camera.parent?.updateWorldMatrix(true, false);
944
+ const state = [camera, controls.update, camera.parent, ...camera.position.toArray(), ...camera.quaternion.toArray(),
945
+ ...camera.scale.toArray(), ...camera.up.toArray(), camera.zoom, ...(camera.parent?.matrixWorld.elements ?? [])];
946
+ for (const [key, value] of Object.entries(controls)) {
947
+ if (key.startsWith('_'))
948
+ continue;
949
+ const vector = value;
950
+ if (vector?.isVector3)
951
+ state.push(key, ...vector.toArray());
952
+ else if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'string')
953
+ state.push(key, value);
954
+ }
955
+ return state;
956
+ }
957
+ /**
958
+ * Keeps one MuTracer scene in sync with a Three.js scene, reusing unchanged objects.
959
+ * Skinning/morph targets run on the CPU with per-source-mesh dynamic geometry.
960
+ * InstancedMesh retains its prefix on count changes and shares geometry/BLAS;
961
+ * Instance colors use native batch storage; automatic UV-less projections
962
+ * share cached material variants per source material. Source edits refresh variants; unused variants
963
+ * are removed after each update.
964
+ */
965
+ export class THREESync extends Sync {
966
+ _options;
967
+ /** Retained converted scene; absent when no scene source was supplied. */
968
+ scene;
969
+ /** Retained converted camera; absent until the first camera update. */
970
+ _camera;
971
+ _store = createConversionStore();
972
+ _disposed = false;
973
+ _started = false;
974
+ _cameraState = [];
975
+ _lastUpdate;
976
+ _idleControlsState;
977
+ _start = () => { this._started = true; this._idleControlsState = undefined; this.setActive(true); };
978
+ _end = () => { this._started = false; };
979
+ /** Subscribes to controls without converting sources or modifying the engine. */
980
+ constructor(engine, _options = {}) {
981
+ super(engine);
982
+ this._options = _options;
983
+ if (_options.scene)
984
+ this.scene = { meshes: [], lights: [] };
985
+ _options.controls?.addEventListener('start', this._start);
986
+ _options.controls?.addEventListener('end', this._end);
987
+ }
988
+ /** Updates controls, world matrices, retained instances and camera before engine.update. */
989
+ update() {
990
+ if (this._disposed)
991
+ throw new Error('THREESync has been disposed');
992
+ const now = performance.now(), controls = this._options.controls, sourceCamera = this._options.camera;
993
+ const elapsed = this._lastUpdate === undefined ? 0 : Math.max(0, (now - this._lastUpdate) / 1000);
994
+ const dt = Math.min(.1, elapsed);
995
+ this._lastUpdate = now;
996
+ let moving = false, settled = false;
997
+ if (controls && this._options.updateControls !== false) {
998
+ const orbitInputs = orbitControlsState(sourceCamera, controls);
999
+ const idle = !this._started && !controls.autoRotate && orbitInputs && this._idleControlsState && snapshotsEqual(orbitInputs, this._idleControlsState);
1000
+ if (!idle) {
1001
+ this._idleControlsState = undefined;
1002
+ const position = sourceCamera?.position.clone(), rotation = sourceCamera?.quaternion.clone(), zoom = sourceCamera?.zoom;
1003
+ const target = controls.target?.clone(), damping = controls.dampingFactor;
1004
+ const frameDamping = controls.enableDamping && damping !== undefined && damping >= 0 && damping <= 1
1005
+ ? 1 - Math.pow(1 - damping, elapsed * 60) : undefined;
1006
+ if (frameDamping !== undefined)
1007
+ controls.dampingFactor = frameDamping;
1008
+ try {
1009
+ moving = !!controls.update(dt);
1010
+ }
1011
+ finally {
1012
+ if (frameDamping !== undefined)
1013
+ controls.dampingFactor = damping;
1014
+ }
1015
+ if (!this._started && !controls.autoRotate && controls.enableDamping && position && sourceCamera && controls.target) {
1016
+ const referenceScale = frameDamping ? damping / frameDamping : 1;
1017
+ const step = position.distanceTo(sourceCamera.position) * referenceScale;
1018
+ const zoomStep = Math.abs(Math.log(sourceCamera.zoom / zoom)) * referenceScale;
1019
+ const poseChanged = step > 0 || sourceCamera.zoom !== zoom || !!(orbitInputs && (!rotation.equals(sourceCamera.quaternion) || !target.equals(controls.target)));
1020
+ // End the remaining inertia once its 60 Hz movement is imperceptible.
1021
+ // update() can return false before that tail has actually stopped.
1022
+ if ((moving || poseChanged) && step < 5e-4 * sourceCamera.position.distanceTo(controls.target) && zoomStep < 5e-4) {
1023
+ controls.enableDamping = false;
1024
+ try {
1025
+ controls.update(0);
1026
+ }
1027
+ finally {
1028
+ controls.enableDamping = true;
1029
+ }
1030
+ moving = false;
1031
+ settled = true;
1032
+ }
1033
+ // Once stopped, no more spherical/cartesian round trips occur until
1034
+ // a gesture, source pose, parent transform or public control option changes.
1035
+ if (orbitInputs && (settled || (!moving && !poseChanged)))
1036
+ this._idleControlsState = orbitControlsState(sourceCamera, controls);
1037
+ }
1038
+ else if (orbitInputs && !this._started && !controls.autoRotate && !moving) {
1039
+ this._idleControlsState = orbitControlsState(sourceCamera, controls);
1040
+ }
1041
+ }
1042
+ }
1043
+ this._store.poseChanged = false;
1044
+ if (this._options.scene && this.scene) {
1045
+ const next = convertScene(this._options.scene, this._options, this._store);
1046
+ if (!snapshotsEqual(this.scene.meshes, next.meshes))
1047
+ this.scene.meshes = next.meshes;
1048
+ if (!snapshotsEqual(this.scene.lights, next.lights))
1049
+ this.scene.lights = next.lights;
1050
+ this.scene.background = next.background;
1051
+ this.engine.scene = this.scene;
1052
+ }
1053
+ let cameraChanged = false;
1054
+ if (sourceCamera) {
1055
+ sourceCamera.updateWorldMatrix(true, false);
1056
+ const next = fromTHREECamera(sourceCamera);
1057
+ const state = snapshotFields(next).slice(1);
1058
+ cameraChanged = this._cameraState.length > 0 && !snapshotsEqual(state, this._cameraState);
1059
+ this._cameraState = state;
1060
+ if (!this._camera)
1061
+ this._camera = next;
1062
+ else
1063
+ this._camera.copy(next);
1064
+ this.engine.camera = this._camera;
1065
+ }
1066
+ this.setActive(this._started || moving || this._store.poseChanged || (cameraChanged && !settled));
1067
+ }
1068
+ /** Removes control subscriptions and caches. The last converted objects remain usable. */
1069
+ dispose() {
1070
+ if (this._disposed)
1071
+ return;
1072
+ this._options.controls?.removeEventListener('start', this._start);
1073
+ this._options.controls?.removeEventListener('end', this._end);
1074
+ this._store = createConversionStore();
1075
+ this._idleControlsState = undefined;
1076
+ this._disposed = true;
1077
+ super.dispose();
1078
+ }
1079
+ }
1080
+ /**
1081
+ * Converts a Three.js perspective or orthographic camera. A perspective
1082
+ * camera's `focus` and film height (`filmGauge` and `aspect`) become
1083
+ * `focusDistance` and `sensorHeight`.
1084
+ */
1085
+ export function fromTHREECamera(threeCamera, options = {}) {
1086
+ const camera = threeCamera.fov
1087
+ ? new Camera({ projection: 'perspective', fov: threeCamera.fov, aspect: threeCamera.aspect, near: threeCamera.near, far: threeCamera.far })
1088
+ : new Camera({ projection: 'orthographic', left: threeCamera.left, right: threeCamera.right, bottom: threeCamera.bottom, top: threeCamera.top, near: threeCamera.near, far: threeCamera.far });
1089
+ threeCamera.updateWorldMatrix(true, false);
1090
+ camera.zoom = threeCamera.zoom;
1091
+ camera.transform =
1092
+ threeCamera.matrixWorld.elements.slice();
1093
+ const perspective = threeCamera;
1094
+ if (perspective.isPerspectiveCamera) {
1095
+ if (perspective.focus > 0)
1096
+ camera.focusDistance = perspective.focus;
1097
+ const filmHeight = perspective.getFilmHeight();
1098
+ if (filmHeight > 0)
1099
+ camera.sensorHeight = filmHeight;
1100
+ }
1101
+ if (options.fStop !== undefined)
1102
+ camera.fStop = options.fStop;
1103
+ if (options.focusDistance !== undefined) {
1104
+ camera.focusDistance = options.focusDistance;
1105
+ }
1106
+ if (options.metersPerUnit !== undefined) {
1107
+ camera.metersPerUnit = options.metersPerUnit;
1108
+ }
1109
+ return camera;
1110
+ }
1111
+ //# sourceMappingURL=fromTHREE.js.map