@aura3d/rendering 1.4.0 → 1.4.2

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 (308) hide show
  1. package/package.json +38 -4
  2. package/AGENTS.md +0 -46
  3. package/src/ArchitecturalLightingFixtures.ts +0 -241
  4. package/src/ArchitecturalMaterialCatalog.ts +0 -130
  5. package/src/ArchitecturalMeasurementFixtures.ts +0 -155
  6. package/src/BRDFLut.ts +0 -47
  7. package/src/CameraFraming.ts +0 -200
  8. package/src/CanonicalSceneFixtures.ts +0 -95
  9. package/src/CascadedShadowMaps.ts +0 -449
  10. package/src/ColorManagement.ts +0 -127
  11. package/src/CullingFixtures.ts +0 -280
  12. package/src/DecalGeometry.ts +0 -26
  13. package/src/DepthPass.ts +0 -110
  14. package/src/EnvironmentBackgroundPass.ts +0 -194
  15. package/src/EnvironmentBackgroundResources.ts +0 -309
  16. package/src/EnvironmentLighting.ts +0 -96
  17. package/src/EnvironmentMapResources.ts +0 -1026
  18. package/src/EnvironmentPipeline.ts +0 -69
  19. package/src/EnvironmentPlatform.ts +0 -1306
  20. package/src/EnvironmentPreset.ts +0 -155
  21. package/src/Exposure.ts +0 -66
  22. package/src/ExternalParityRenderPreset.ts +0 -725
  23. package/src/ForwardPass.ts +0 -1668
  24. package/src/FrameVisualMetrics.ts +0 -301
  25. package/src/Geometry.ts +0 -461
  26. package/src/GeometryPrimitives.ts +0 -2
  27. package/src/HDRRenderPipeline.ts +0 -94
  28. package/src/IBL.ts +0 -86
  29. package/src/IndexBuffer.ts +0 -57
  30. package/src/InstancedPBRMaterial.ts +0 -186
  31. package/src/InstancedUnlitMaterial.ts +0 -60
  32. package/src/Instancing.ts +0 -19
  33. package/src/LightCollector.ts +0 -82
  34. package/src/LightUniforms.ts +0 -47
  35. package/src/LightingDebug.ts +0 -80
  36. package/src/LightingDefaults.ts +0 -79
  37. package/src/LightingRig.ts +0 -301
  38. package/src/LineGeometry.ts +0 -2
  39. package/src/Material.ts +0 -209
  40. package/src/MaterialBinding.ts +0 -131
  41. package/src/MaterialInstance.ts +0 -59
  42. package/src/MaterialPresets.ts +0 -272
  43. package/src/MorphTarget.ts +0 -124
  44. package/src/MorphTargetPlan.ts +0 -178
  45. package/src/MorphUnlitMaterial.ts +0 -60
  46. package/src/NormalMappedPBRMaterial.ts +0 -188
  47. package/src/OceanFixtures.ts +0 -318
  48. package/src/PBRLightingDefaults.ts +0 -12
  49. package/src/PBRMaterial.ts +0 -442
  50. package/src/PMREM.ts +0 -53
  51. package/src/PbrReference.ts +0 -681
  52. package/src/PostProcessPass.ts +0 -2507
  53. package/src/ProceduralTextureFixtures.ts +0 -393
  54. package/src/ProductTurntableFixtures.ts +0 -815
  55. package/src/Raycaster.ts +0 -21
  56. package/src/ReflectionProbe.ts +0 -13
  57. package/src/ReflectionSurfaces.ts +0 -219
  58. package/src/RenderBackend.ts +0 -43
  59. package/src/RenderDebugViews.ts +0 -138
  60. package/src/RenderDevice.ts +0 -836
  61. package/src/RenderGraph.ts +0 -194
  62. package/src/RenderPass.ts +0 -27
  63. package/src/RenderPipeline.ts +0 -101
  64. package/src/RenderQueue.ts +0 -12
  65. package/src/RenderState.ts +0 -12
  66. package/src/Renderer.ts +0 -2631
  67. package/src/RendererDebugOverlay.ts +0 -80
  68. package/src/RendererFeatureGates.ts +0 -150
  69. package/src/RendererPostprocessPlan.ts +0 -279
  70. package/src/RendererTiming.ts +0 -251
  71. package/src/RendererVisualPipelineReport.ts +0 -836
  72. package/src/ResourceLifecycle.ts +0 -21
  73. package/src/Sampler.ts +0 -37
  74. package/src/SceneOptimization.ts +0 -518
  75. package/src/ShaderChunks.ts +0 -393
  76. package/src/ShaderLibrary.ts +0 -2766
  77. package/src/ShaderModule.ts +0 -36
  78. package/src/ShaderPreprocessor.ts +0 -260
  79. package/src/ShaderReflection.ts +0 -201
  80. package/src/ShadowMap.ts +0 -237
  81. package/src/ShadowPass.ts +0 -198
  82. package/src/ShadowProjection.ts +0 -115
  83. package/src/SkinnedLitMaterial.ts +0 -397
  84. package/src/SkinnedUnlitMaterial.ts +0 -63
  85. package/src/SkinningBounds.ts +0 -131
  86. package/src/SpaceEnvironmentFixtures.ts +0 -200
  87. package/src/SpriteGeometry.ts +0 -21
  88. package/src/StereoCameraRig.ts +0 -127
  89. package/src/StereoEffects.ts +0 -274
  90. package/src/TerrainFixtures.ts +0 -180
  91. package/src/Texture.ts +0 -307
  92. package/src/TextureBinding.ts +0 -91
  93. package/src/TexturedPBRMaterial.ts +0 -1112
  94. package/src/TexturedUnlitMaterial.ts +0 -67
  95. package/src/ToneMapping.ts +0 -105
  96. package/src/UniformBinder.ts +0 -16
  97. package/src/UniformLayout.ts +0 -129
  98. package/src/UnlitMaterial.ts +0 -75
  99. package/src/VegetationFixtures.ts +0 -314
  100. package/src/VertexBuffer.ts +0 -120
  101. package/src/VertexFormat.ts +0 -171
  102. package/src/VoxelWorldFixtures.ts +0 -280
  103. package/src/WeatherFixtures.ts +0 -223
  104. package/src/WebGL2Device.ts +0 -2280
  105. package/src/WebGL2StateCache.ts +0 -330
  106. package/src/WebGPUDevice.ts +0 -2877
  107. package/src/WebGPURenderToTextureProof.ts +0 -139
  108. package/src/advanced-runtime/AdvancedRenderer.ts +0 -73
  109. package/src/advanced-runtime/index.ts +0 -9
  110. package/src/animation/AnimationMaterialStyle.ts +0 -32
  111. package/src/animation/AnimationRenderPreset.ts +0 -45
  112. package/src/animation/AnimationToonMaterial.ts +0 -387
  113. package/src/animation/AnimationVisualQuality.ts +0 -71
  114. package/src/animation/applyAnimationRenderPreset.ts +0 -180
  115. package/src/animation/index.ts +0 -5
  116. package/src/cinematic/BloomPass.ts +0 -26
  117. package/src/cinematic/CinematicDepthComposition.ts +0 -30
  118. package/src/cinematic/CinematicEvidence.ts +0 -123
  119. package/src/cinematic/CinematicLightingRig.ts +0 -144
  120. package/src/cinematic/CinematicMaterialPresets.ts +0 -130
  121. package/src/cinematic/CinematicPostProcess.ts +0 -83
  122. package/src/cinematic/DepthHazePass.ts +0 -30
  123. package/src/cinematic/EmissivePracticalLightSystem.ts +0 -45
  124. package/src/cinematic/FilmGrainPass.ts +0 -24
  125. package/src/cinematic/FogVolumeSystem.ts +0 -30
  126. package/src/cinematic/GlowCardSystem.ts +0 -44
  127. package/src/cinematic/RainParticleSystem.ts +0 -151
  128. package/src/cinematic/VignettePass.ts +0 -25
  129. package/src/cinematic/WetReflectionApproximation.ts +0 -27
  130. package/src/cinematic/index.ts +0 -14
  131. package/src/effects/CollisionModule.ts +0 -64
  132. package/src/effects/ColorModule.ts +0 -60
  133. package/src/effects/ForceModule.ts +0 -25
  134. package/src/effects/GPUParticleBackend.ts +0 -569
  135. package/src/effects/Particle.ts +0 -108
  136. package/src/effects/ParticleDiagnostics.ts +0 -224
  137. package/src/effects/ParticleEffectPresets.ts +0 -147
  138. package/src/effects/ParticleEmitter.ts +0 -326
  139. package/src/effects/ParticleModule.ts +0 -26
  140. package/src/effects/ParticleRenderPass.ts +0 -117
  141. package/src/effects/ParticleRenderer.ts +0 -132
  142. package/src/effects/ParticleSystem.ts +0 -333
  143. package/src/effects/SizeModule.ts +0 -56
  144. package/src/effects/TrailModule.ts +0 -72
  145. package/src/effects/VelocityModule.ts +0 -75
  146. package/src/effects/index.ts +0 -15
  147. package/src/index.ts +0 -925
  148. package/src/materials/AlphaSorting.ts +0 -30
  149. package/src/materials/MaterialExtensions.ts +0 -42
  150. package/src/materials/PhysicalMaterial.ts +0 -133
  151. package/src/materials/TransmissionPass.ts +0 -51
  152. package/src/performance/BVH.ts +0 -18
  153. package/src/performance/Batcher.ts +0 -2
  154. package/src/performance/FrustumCuller.ts +0 -9
  155. package/src/performance/LOD.ts +0 -20
  156. package/src/performance/Octree.ts +0 -10
  157. package/src/performance/RenderItemSorting.ts +0 -170
  158. package/src/performance/RendererStats.ts +0 -43
  159. package/src/performance/ResourceBudget.ts +0 -44
  160. package/src/postprocess/BloomPass.ts +0 -28
  161. package/src/postprocess/CinematicDiagnostics.ts +0 -642
  162. package/src/postprocess/ColorGradingPass.ts +0 -24
  163. package/src/postprocess/DepthOfFieldPass.ts +0 -12
  164. package/src/postprocess/EffectComposer.ts +0 -349
  165. package/src/postprocess/SSAOPass.ts +0 -20
  166. package/src/postprocess/index.ts +0 -34
  167. package/src/production-runtime/AnimationControlsPipeline.ts +0 -77
  168. package/src/production-runtime/PBRHDRPipeline.ts +0 -381
  169. package/src/production-runtime/ProductionEffectsPipeline.ts +0 -85
  170. package/src/production-runtime/ProductionRendererTypes.ts +0 -136
  171. package/src/production-runtime/ProductionRuntimeRenderer.ts +0 -172
  172. package/src/production-runtime/ProductionWebGL2Renderer.ts +0 -313
  173. package/src/production-runtime/ProductionWebGPURenderer.ts +0 -396
  174. package/src/production-runtime/TransmissionBackdropCapture.ts +0 -130
  175. package/src/production-runtime/animation/MorphTargetRenderer.ts +0 -2
  176. package/src/production-runtime/animation/SkinningRenderer.ts +0 -2
  177. package/src/production-runtime/backends/RendererBackend.ts +0 -17
  178. package/src/production-runtime/backends/WebGL2RendererBackend.ts +0 -30
  179. package/src/production-runtime/backends/WebGPURendererBackend.ts +0 -24
  180. package/src/production-runtime/backends/webgl2/WebGL2Buffer.ts +0 -2
  181. package/src/production-runtime/backends/webgl2/WebGL2Capabilities.ts +0 -2
  182. package/src/production-runtime/backends/webgl2/WebGL2RenderTarget.ts +0 -2
  183. package/src/production-runtime/backends/webgl2/WebGL2Shader.ts +0 -2
  184. package/src/production-runtime/backends/webgl2/WebGL2StateCache.ts +0 -1
  185. package/src/production-runtime/backends/webgl2/WebGL2Texture.ts +0 -2
  186. package/src/production-runtime/backends/webgpu/WebGPUBuffer.ts +0 -2
  187. package/src/production-runtime/backends/webgpu/WebGPUCapabilities.ts +0 -2
  188. package/src/production-runtime/backends/webgpu/WebGPURenderTarget.ts +0 -2
  189. package/src/production-runtime/backends/webgpu/WebGPUShader.ts +0 -2
  190. package/src/production-runtime/backends/webgpu/WebGPUTexture.ts +0 -2
  191. package/src/production-runtime/color/ColorManagement.ts +0 -3
  192. package/src/production-runtime/color/ToneMapping.ts +0 -7
  193. package/src/production-runtime/diagnostics/FrameCapture.ts +0 -2
  194. package/src/production-runtime/diagnostics/GPUCapabilities.ts +0 -2
  195. package/src/production-runtime/diagnostics/RendererStats.ts +0 -2
  196. package/src/production-runtime/environment/EnvironmentMap.ts +0 -1
  197. package/src/production-runtime/environment/HDRLoader.ts +0 -57
  198. package/src/production-runtime/environment/PMREMGenerator.ts +0 -713
  199. package/src/production-runtime/framegraph/FrameGraph.ts +0 -18
  200. package/src/production-runtime/framegraph/RenderPass.ts +0 -15
  201. package/src/production-runtime/geometry/ProjectedDecalGeometry.ts +0 -439
  202. package/src/production-runtime/index.ts +0 -127
  203. package/src/production-runtime/lights/LightManager.ts +0 -7
  204. package/src/production-runtime/lights/ShadowMapRenderer.ts +0 -5
  205. package/src/production-runtime/materials/GLTFMaterialAdapter.ts +0 -6
  206. package/src/production-runtime/materials/GLTFPBRMaterialAdapter.ts +0 -2
  207. package/src/production-runtime/materials/MaterialCompiler.ts +0 -7
  208. package/src/production-runtime/materials/MaterialTextureBindings.ts +0 -5
  209. package/src/production-runtime/materials/PBRMaterial.ts +0 -2
  210. package/src/production-runtime/materials/PBRShaderFeatures.ts +0 -2
  211. package/src/production-runtime/passes/ContactShadowPass.ts +0 -184
  212. package/src/production-runtime/passes/DepthPrepass.ts +0 -7
  213. package/src/production-runtime/passes/OpaquePass.ts +0 -7
  214. package/src/production-runtime/passes/ShadowPass.ts +0 -7
  215. package/src/production-runtime/passes/SkyboxPass.ts +0 -7
  216. package/src/production-runtime/passes/ToneMappingPass.ts +0 -7
  217. package/src/production-runtime/passes/TransparentPass.ts +0 -7
  218. package/src/production-runtime/postprocess/BloomPass.ts +0 -51
  219. package/src/production-runtime/postprocess/ColorGradingPass.ts +0 -49
  220. package/src/production-runtime/postprocess/DOFPass.ts +0 -47
  221. package/src/production-runtime/postprocess/FXAAPass.ts +0 -53
  222. package/src/production-runtime/postprocess/ProductionEffectComposer.ts +0 -78
  223. package/src/production-runtime/postprocess/ProductionPostProcessTypes.ts +0 -174
  224. package/src/production-runtime/postprocess/SSAOPass.ts +0 -45
  225. package/src/production-runtime/resources/GPUBuffer.ts +0 -2
  226. package/src/production-runtime/resources/GPUTexture.ts +0 -2
  227. package/src/production-runtime/resources/RenderTarget.ts +0 -3
  228. package/src/production-runtime/resources/ResourceCache.ts +0 -7
  229. package/src/production-runtime/scene/Camera.ts +0 -1
  230. package/src/production-runtime/scene/Lights.ts +0 -2
  231. package/src/production-runtime/scene/RenderableMesh.ts +0 -2
  232. package/src/production-runtime/scene/RenderablePrimitive.ts +0 -1
  233. package/src/production-runtime/scene/RenderableScene.ts +0 -4
  234. package/src/production-runtime/shaders/ShaderProgramLibrary.ts +0 -7
  235. package/src/production-runtime/shaders/chunks/brdf.glsl +0 -2
  236. package/src/production-runtime/shaders/chunks/ibl.glsl +0 -3
  237. package/src/production-runtime/shaders/chunks/pbr.frag.glsl +0 -47
  238. package/src/production-runtime/shaders/chunks/pbr.vert.glsl +0 -8
  239. package/src/production-runtime/shaders/chunks/shadows.glsl +0 -2
  240. package/src/production-runtime/shaders/wgsl/pbr.wgsl +0 -3
  241. package/src/production-runtime/shaders/wgsl/postprocess.wgsl +0 -2
  242. package/src/production-runtime/shaders/wgsl/skybox.wgsl +0 -2
  243. package/src/shaders/depth.frag.glsl +0 -5
  244. package/src/shaders/depth.vert.glsl +0 -8
  245. package/src/shaders/pbr-direct.frag.glsl +0 -687
  246. package/src/shaders/pbr-direct.vert.glsl +0 -18
  247. package/src/shaders/unlit.frag.glsl +0 -18
  248. package/src/shaders/unlit.vert.glsl +0 -13
  249. package/src/shadows/CascadedShadowPipeline.ts +0 -53
  250. package/src/shadows/ContactShadows.ts +0 -106
  251. package/src/shadows/ShadowDebugViews.ts +0 -46
  252. package/src/threejs-compatibility/InstancingSystem.ts +0 -17
  253. package/src/threejs-compatibility/LightingSystem.ts +0 -22
  254. package/src/threejs-compatibility/MaterialSystem.ts +0 -9
  255. package/src/threejs-compatibility/RenderTargetSystem.ts +0 -35
  256. package/src/threejs-compatibility/RendererDiagnostics.ts +0 -61
  257. package/src/threejs-compatibility/SceneRenderer.ts +0 -34
  258. package/src/threejs-compatibility/ShadowSystem.ts +0 -19
  259. package/src/threejs-compatibility/TextureSystem.ts +0 -19
  260. package/src/threejs-compatibility/ThreeCompatRenderer.ts +0 -90
  261. package/src/threejs-compatibility/TransparencySystem.ts +0 -19
  262. package/src/threejs-compatibility/index.ts +0 -29
  263. package/src/threejs-compatibility/performance/BVH.ts +0 -14
  264. package/src/threejs-compatibility/performance/FrustumCulling.ts +0 -10
  265. package/src/threejs-compatibility/performance/Instancing.ts +0 -4
  266. package/src/threejs-compatibility/performance/LODSystem.ts +0 -16
  267. package/src/threejs-compatibility/performance/OcclusionCulling.ts +0 -6
  268. package/src/threejs-compatibility/performance/RaycastAcceleration.ts +0 -12
  269. package/src/threejs-compatibility/performance/RendererProfiler.ts +0 -19
  270. package/src/threejs-compatibility/performance/TextureStreaming.ts +0 -4
  271. package/src/threejs-compatibility/performance/index.ts +0 -12
  272. package/src/threejs-compatibility/postprocess/BloomPass.ts +0 -16
  273. package/src/threejs-compatibility/postprocess/ColorGradingPass.ts +0 -16
  274. package/src/threejs-compatibility/postprocess/DepthOfFieldPass.ts +0 -21
  275. package/src/threejs-compatibility/postprocess/EffectComposer.ts +0 -14
  276. package/src/threejs-compatibility/postprocess/FXAAPass.ts +0 -15
  277. package/src/threejs-compatibility/postprocess/MotionBlurPass.ts +0 -20
  278. package/src/threejs-compatibility/postprocess/OutlinePass.ts +0 -21
  279. package/src/threejs-compatibility/postprocess/PostProcessTypes.ts +0 -169
  280. package/src/threejs-compatibility/postprocess/RenderPass.ts +0 -9
  281. package/src/threejs-compatibility/postprocess/SMAAPass.ts +0 -15
  282. package/src/threejs-compatibility/postprocess/SSAOPass.ts +0 -21
  283. package/src/threejs-compatibility/postprocess/ShaderPass.ts +0 -7
  284. package/src/threejs-compatibility/postprocess/TAAPass.ts +0 -15
  285. package/src/threejs-compatibility/postprocess/VignettePass.ts +0 -16
  286. package/src/threejs-compatibility/postprocess/index.ts +0 -15
  287. package/src/threejs-compatibility/shaders/NodeMaterial.ts +0 -21
  288. package/src/threejs-compatibility/shaders/RawShaderMaterial.ts +0 -6
  289. package/src/threejs-compatibility/shaders/ShaderDiagnostics.ts +0 -17
  290. package/src/threejs-compatibility/shaders/ShaderMaterial.ts +0 -18
  291. package/src/threejs-compatibility/shaders/ThreeCompatShaderChunks.ts +0 -6
  292. package/src/threejs-compatibility/shaders/Uniforms.ts +0 -18
  293. package/src/threejs-compatibility/shaders/index.ts +0 -9
  294. package/src/threejs-compatibility/vfx/GPUPointCloud.ts +0 -7
  295. package/src/threejs-compatibility/vfx/LineRenderer.ts +0 -13
  296. package/src/threejs-compatibility/vfx/ParticleSystem.ts +0 -23
  297. package/src/threejs-compatibility/vfx/SpriteSystem.ts +0 -14
  298. package/src/threejs-compatibility/vfx/TrailRenderer.ts +0 -8
  299. package/src/threejs-compatibility/vfx/VFXDiagnostics.ts +0 -23
  300. package/src/threejs-compatibility/vfx/index.ts +0 -9
  301. package/src/threejs-example-parity/index.ts +0 -205
  302. package/src/webgpu/WebGPUBuffer.ts +0 -1
  303. package/src/webgpu/WebGPUCompute.ts +0 -2
  304. package/src/webgpu/WebGPUPipelineCache.ts +0 -15
  305. package/src/webgpu/WebGPUPostProcess.ts +0 -2
  306. package/src/webgpu/WebGPUTexture.ts +0 -2
  307. package/tsconfig.json +0 -26
  308. package/vitest.config.ts +0 -20
@@ -1,713 +0,0 @@
1
- import type { LinearHdrEnvironmentMapSource } from "../../EnvironmentMapResources";
2
-
3
- export type PMREMCubeFace = "px" | "nx" | "py" | "ny" | "pz" | "nz";
4
-
5
- export interface PMREMLevel {
6
- readonly mip: number;
7
- readonly roughness: number;
8
- readonly faceSize: number;
9
- }
10
-
11
- export interface CubemapPMREMFace {
12
- readonly face: PMREMCubeFace;
13
- readonly width: number;
14
- readonly height: number;
15
- readonly data: Uint16Array;
16
- }
17
-
18
- export interface CubemapPMREMLevel extends PMREMLevel {
19
- readonly faces: readonly CubemapPMREMFace[];
20
- }
21
-
22
- export interface CubemapPMREMResources {
23
- readonly faceSize: number;
24
- readonly mipCount: number;
25
- readonly levels: readonly CubemapPMREMLevel[];
26
- readonly diagnostics: {
27
- readonly faceCount: 6;
28
- readonly sourceProjection: "equirectangular-to-cubemap";
29
- readonly filterModel: "ggx-importance-sampled-cubemap-prefilter";
30
- readonly shaderSampling: "webgl2-sampler-cube";
31
- readonly totalByteLength: number;
32
- readonly maxLinearValue: number;
33
- };
34
- }
35
-
36
- export interface CubemapPMREMAudit {
37
- readonly parity: "bounded-pmrem-audit-not-threejs-parity";
38
- readonly completeMipPyramid: boolean;
39
- readonly faceCount: number;
40
- readonly mipCount: number;
41
- readonly baseFaceSize: number;
42
- readonly totalByteLength: number;
43
- readonly maxEdgeMeanDelta: number;
44
- readonly luminanceVarianceByMip: readonly number[];
45
- readonly roughnessVarianceNonIncreasing: boolean;
46
- readonly roughestVarianceReduced: boolean;
47
- }
48
-
49
- export interface CubemapPMREMShaderContract {
50
- readonly sampling: "webgl2-sampler-cube";
51
- readonly mipSelection: "roughness-scaled-textureLod";
52
- readonly splitSumBRDF: true;
53
- readonly bindableTextureDimension: "cube";
54
- readonly requiredUniforms: readonly string[];
55
- readonly materialVariantCoverage: readonly string[];
56
- readonly faceCompleteness: boolean;
57
- readonly mipCount: number;
58
- readonly baseFaceSize: number;
59
- readonly lodRange: readonly [number, number];
60
- readonly fallback2DEnvironmentSpecularDisabled: true;
61
- }
62
-
63
- export interface CubemapPMREMOptions {
64
- readonly faceSize?: number;
65
- readonly mipCount?: number;
66
- readonly sampleCount?: number;
67
- }
68
-
69
- export interface PMREMTransmissionProbeOptions {
70
- readonly position: readonly [number, number, number];
71
- readonly normal: readonly [number, number, number];
72
- readonly viewDirection: readonly [number, number, number];
73
- readonly ior?: number;
74
- readonly roughness?: number;
75
- readonly thickness?: number;
76
- readonly attenuationDistance?: number;
77
- readonly attenuationColor?: readonly [number, number, number];
78
- readonly environmentBoxMin?: readonly [number, number, number];
79
- readonly environmentBoxMax?: readonly [number, number, number];
80
- readonly maxBounces?: number;
81
- readonly mipCount?: number;
82
- }
83
-
84
- export interface PMREMTransmissionProbeBounce {
85
- readonly bounce: number;
86
- readonly direction: readonly [number, number, number];
87
- readonly hitPosition: readonly [number, number, number];
88
- readonly hitNormal: readonly [number, number, number];
89
- readonly travelDistance: number;
90
- readonly lod: number;
91
- readonly attenuation: readonly [number, number, number];
92
- readonly causticEnergy: number;
93
- }
94
-
95
- export interface PMREMTransmissionProbe {
96
- readonly projection: "box-parallax-corrected-cubemap";
97
- readonly refractionModel: "ior-refract-with-reflection-fallback";
98
- readonly multiBounce: boolean;
99
- readonly bounces: readonly PMREMTransmissionProbeBounce[];
100
- readonly totalTravelDistance: number;
101
- readonly averageAttenuation: readonly [number, number, number];
102
- readonly causticEnergy: number;
103
- readonly recommendedLod: number;
104
- }
105
-
106
- const CUBE_FACES: readonly PMREMCubeFace[] = ["px", "nx", "py", "ny", "pz", "nz"];
107
-
108
- export function generatePMREMLevels(faceSize = 256, mipCount = 9): readonly PMREMLevel[] {
109
- validatePositiveInteger(faceSize, "PMREM faceSize");
110
- validatePositiveInteger(mipCount, "PMREM mipCount");
111
- return Array.from({ length: mipCount }, (_, mip) => ({
112
- mip,
113
- roughness: mip / Math.max(1, mipCount - 1),
114
- faceSize: Math.max(1, faceSize >> mip)
115
- }));
116
- }
117
-
118
- export function generateCubemapPMREMResources(
119
- source: LinearHdrEnvironmentMapSource,
120
- options: CubemapPMREMOptions = {}
121
- ): CubemapPMREMResources {
122
- validateHdrSource(source);
123
- const faceSize = options.faceSize ?? 128;
124
- const mipCount = options.mipCount ?? Math.max(1, Math.floor(Math.log2(faceSize)) + 1);
125
- const sampleCount = options.sampleCount ?? 32;
126
- validatePositiveInteger(faceSize, "Cubemap PMREM faceSize");
127
- validatePositiveInteger(mipCount, "Cubemap PMREM mipCount");
128
- validatePositiveInteger(sampleCount, "Cubemap PMREM sampleCount");
129
-
130
- const averageRadiance = sourceAverageRadiance(source);
131
- const levels = generatePMREMLevels(faceSize, mipCount).map((level) => ({
132
- ...level,
133
- faces: CUBE_FACES.map((face) => projectPrefilteredFace(source, face, level.faceSize, level.roughness, sampleCount, averageRadiance))
134
- }));
135
- const totalByteLength = levels.reduce((total, level) => total + level.faces.reduce((faceTotal, face) => faceTotal + face.data.byteLength, 0), 0);
136
- return {
137
- faceSize,
138
- mipCount,
139
- levels,
140
- diagnostics: {
141
- faceCount: 6,
142
- sourceProjection: "equirectangular-to-cubemap",
143
- filterModel: "ggx-importance-sampled-cubemap-prefilter",
144
- shaderSampling: "webgl2-sampler-cube",
145
- totalByteLength,
146
- maxLinearValue: maxLinearValue(source.data)
147
- }
148
- };
149
- }
150
-
151
- export function auditCubemapPMREMResources(resources: CubemapPMREMResources): CubemapPMREMAudit {
152
- const expectedLevels = generatePMREMLevels(resources.faceSize, resources.mipCount);
153
- const completeMipPyramid = expectedLevels.every((expected) => {
154
- const level = resources.levels.find((candidate) => candidate.mip === expected.mip);
155
- return Boolean(level)
156
- && level!.faceSize === expected.faceSize
157
- && level!.faces.length === 6
158
- && CUBE_FACES.every((face) => {
159
- const faceData = level!.faces.find((candidate) => candidate.face === face);
160
- return Boolean(faceData)
161
- && faceData!.width === expected.faceSize
162
- && faceData!.height === expected.faceSize
163
- && faceData!.data.length === expected.faceSize * expected.faceSize * 4;
164
- });
165
- });
166
- const luminanceVarianceByMip = resources.levels.map((level) => levelLuminanceVariance(level));
167
- const roughnessVarianceNonIncreasing = luminanceVarianceByMip.every((variance, index) => {
168
- if (index === 0) return true;
169
- return variance <= (luminanceVarianceByMip[index - 1] ?? variance) + 0.0001;
170
- });
171
- const roughestVarianceReduced = (luminanceVarianceByMip.at(-1) ?? 0) < (luminanceVarianceByMip[0] ?? 0);
172
- return {
173
- parity: "bounded-pmrem-audit-not-threejs-parity",
174
- completeMipPyramid,
175
- faceCount: CUBE_FACES.length,
176
- mipCount: resources.levels.length,
177
- baseFaceSize: resources.faceSize,
178
- totalByteLength: resources.diagnostics.totalByteLength,
179
- maxEdgeMeanDelta: maxEdgeMeanDelta(resources.levels[0]),
180
- luminanceVarianceByMip,
181
- roughnessVarianceNonIncreasing,
182
- roughestVarianceReduced
183
- };
184
- }
185
-
186
- export function createCubemapPMREMShaderContract(resources: CubemapPMREMResources): CubemapPMREMShaderContract {
187
- const audit = auditCubemapPMREMResources(resources);
188
- return {
189
- sampling: "webgl2-sampler-cube",
190
- mipSelection: "roughness-scaled-textureLod",
191
- splitSumBRDF: true,
192
- bindableTextureDimension: "cube",
193
- requiredUniforms: [
194
- "u_environmentCubeMapTexture",
195
- "u_environmentCubeMapTextureEnabled",
196
- "u_environmentMapTextureMipCount",
197
- "u_environmentBrdfLutTexture",
198
- "u_environmentBrdfLutEnabled"
199
- ],
200
- materialVariantCoverage: [
201
- "PBRMaterial",
202
- "TexturedPBRMaterial",
203
- "SkinnedLitMaterial",
204
- "NormalMappedPBRMaterial",
205
- "InstancedPBRMaterial"
206
- ],
207
- faceCompleteness: audit.completeMipPyramid,
208
- mipCount: resources.mipCount,
209
- baseFaceSize: resources.faceSize,
210
- lodRange: [0, Math.max(0, resources.mipCount - 1)],
211
- fallback2DEnvironmentSpecularDisabled: true
212
- };
213
- }
214
-
215
- export function createPMREMTransmissionProbe(options: PMREMTransmissionProbeOptions): PMREMTransmissionProbe {
216
- const position = finiteVec3(options.position, "PMREM transmission probe position");
217
- const normal = normalize(finiteVec3(options.normal, "PMREM transmission probe normal"));
218
- const viewDirection = normalize(finiteVec3(options.viewDirection, "PMREM transmission probe viewDirection"));
219
- const ior = finitePositive(options.ior ?? 1.5, "PMREM transmission probe ior");
220
- const roughness = clampFinite(options.roughness ?? 0, 0, 1, "PMREM transmission probe roughness");
221
- const thickness = Math.max(0, finiteNumber(options.thickness ?? 0, "PMREM transmission probe thickness"));
222
- const attenuationDistance = finitePositive(options.attenuationDistance ?? 1_000_000, "PMREM transmission probe attenuationDistance");
223
- const attenuationColor = finiteColor(options.attenuationColor ?? [1, 1, 1], "PMREM transmission probe attenuationColor");
224
- const boxMin = finiteVec3(options.environmentBoxMin ?? [-1, -1, -1], "PMREM transmission probe environmentBoxMin");
225
- const boxMax = finiteVec3(options.environmentBoxMax ?? [1, 1, 1], "PMREM transmission probe environmentBoxMax");
226
- validateBox(boxMin, boxMax);
227
- const maxBounces = clampInteger(options.maxBounces ?? 2, 1, 4, "PMREM transmission probe maxBounces");
228
- const mipCount = clampInteger(options.mipCount ?? 9, 1, 16, "PMREM transmission probe mipCount");
229
- let origin = clampPointToBox(position, boxMin, boxMax);
230
- let direction = refract(scale(normalize(viewDirection), -1), normal, 1 / ior);
231
- if (length(direction) <= 1e-6) {
232
- direction = reflect(scale(normalize(viewDirection), -1), normal);
233
- }
234
- direction = normalize(direction);
235
- const bounces: PMREMTransmissionProbeBounce[] = [];
236
- let totalTravelDistance = 0;
237
- let attenuationProduct: readonly [number, number, number] = [1, 1, 1];
238
- let causticEnergy = 0;
239
-
240
- for (let bounce = 0; bounce < maxBounces; bounce += 1) {
241
- const hit = intersectBox(origin, direction, boxMin, boxMax);
242
- if (!hit) break;
243
- const travelDistance = hit.distance;
244
- totalTravelDistance += travelDistance;
245
- const volumeTravel = thickness <= 0 ? 0 : (thickness * (bounce + 1) + travelDistance * 0.08) / attenuationDistance;
246
- const attenuation: readonly [number, number, number] = [
247
- attenuationProduct[0] * attenuationColor[0] ** volumeTravel,
248
- attenuationProduct[1] * attenuationColor[1] ** volumeTravel,
249
- attenuationProduct[2] * attenuationColor[2] ** volumeTravel
250
- ];
251
- attenuationProduct = attenuation;
252
- const lod = clamp((roughness + bounce * 0.08 + Math.min(0.24, travelDistance * 0.015)) * (mipCount - 1), 0, mipCount - 1);
253
- const bounceCaustic = (1 - roughness) ** 2 * average3(attenuation) / (1 + travelDistance * 0.35) / (bounce + 1);
254
- causticEnergy += bounceCaustic;
255
- bounces.push({
256
- bounce,
257
- direction,
258
- hitPosition: hit.position,
259
- hitNormal: hit.normal,
260
- travelDistance,
261
- lod,
262
- attenuation,
263
- causticEnergy: bounceCaustic
264
- });
265
- origin = add(hit.position, scale(hit.normal, -0.001));
266
- direction = normalize(reflect(direction, hit.normal));
267
- }
268
-
269
- const recommendedLod = bounces.length === 0 ? roughness * (mipCount - 1) : bounces.reduce((total, bounce) => total + bounce.lod, 0) / bounces.length;
270
- return {
271
- projection: "box-parallax-corrected-cubemap",
272
- refractionModel: "ior-refract-with-reflection-fallback",
273
- multiBounce: bounces.length > 1,
274
- bounces,
275
- totalTravelDistance,
276
- averageAttenuation: attenuationProduct,
277
- causticEnergy,
278
- recommendedLod
279
- };
280
- }
281
-
282
- function projectPrefilteredFace(
283
- source: LinearHdrEnvironmentMapSource,
284
- face: PMREMCubeFace,
285
- faceSize: number,
286
- roughness: number,
287
- sampleCount: number,
288
- averageRadiance: readonly [number, number, number]
289
- ): CubemapPMREMFace {
290
- const data = new Uint16Array(faceSize * faceSize * 4);
291
- for (let y = 0; y < faceSize; y += 1) {
292
- const v = ((y + 0.5) / faceSize) * 2 - 1;
293
- for (let x = 0; x < faceSize; x += 1) {
294
- const u = ((x + 0.5) / faceSize) * 2 - 1;
295
- const direction = normalize(faceDirection(face, u, v));
296
- const color = samplePrefilteredDirection(source, direction, roughness, sampleCount, averageRadiance);
297
- const offset = (y * faceSize + x) * 4;
298
- data[offset] = numberToHalfFloat(color[0]);
299
- data[offset + 1] = numberToHalfFloat(color[1]);
300
- data[offset + 2] = numberToHalfFloat(color[2]);
301
- data[offset + 3] = numberToHalfFloat(1);
302
- }
303
- }
304
- return { face, width: faceSize, height: faceSize, data };
305
- }
306
-
307
- function samplePrefilteredDirection(
308
- source: LinearHdrEnvironmentMapSource,
309
- direction: readonly [number, number, number],
310
- roughness: number,
311
- sampleCount: number,
312
- averageRadiance: readonly [number, number, number]
313
- ): readonly [number, number, number] {
314
- if (roughness <= 0.0001 || sampleCount <= 1) {
315
- return sampleEquirect(source, direction);
316
- }
317
- const normal = normalize(direction);
318
- const view = normal;
319
- let red = 0;
320
- let green = 0;
321
- let blue = 0;
322
- let weightTotal = 0;
323
- for (let sample = 0; sample < sampleCount; sample += 1) {
324
- const halfVector = importanceSampleGGX(
325
- [(sample + 0.5) / sampleCount, radicalInverseVdc(sample)],
326
- normal,
327
- roughness
328
- );
329
- const viewDotHalf = Math.max(0, dot(view, halfVector));
330
- const light = normalize([
331
- 2 * viewDotHalf * halfVector[0] - view[0],
332
- 2 * viewDotHalf * halfVector[1] - view[1],
333
- 2 * viewDotHalf * halfVector[2] - view[2]
334
- ]);
335
- const weight = Math.max(0, dot(normal, light));
336
- if (weight <= 0) continue;
337
- const color = sampleEquirect(source, light);
338
- red += color[0] * weight;
339
- green += color[1] * weight;
340
- blue += color[2] * weight;
341
- weightTotal += weight;
342
- }
343
- if (weightTotal <= 0) return averageRadiance;
344
- const filtered: readonly [number, number, number] = [red / weightTotal, green / weightTotal, blue / weightTotal];
345
- const wideLobeBlend = Math.min(0.82, roughness ** 4 * 0.82);
346
- return [
347
- filtered[0] * (1 - wideLobeBlend) + averageRadiance[0] * wideLobeBlend,
348
- filtered[1] * (1 - wideLobeBlend) + averageRadiance[1] * wideLobeBlend,
349
- filtered[2] * (1 - wideLobeBlend) + averageRadiance[2] * wideLobeBlend
350
- ];
351
- }
352
-
353
- function importanceSampleGGX(
354
- xi: readonly [number, number],
355
- normal: readonly [number, number, number],
356
- roughness: number
357
- ): readonly [number, number, number] {
358
- const alpha = Math.max(0.001, roughness * roughness);
359
- const alphaSquared = alpha * alpha;
360
- const phi = 2 * Math.PI * xi[0];
361
- const cosTheta = Math.sqrt((1 - xi[1]) / Math.max(0.000001, 1 + (alphaSquared - 1) * xi[1]));
362
- const sinTheta = Math.sqrt(Math.max(0, 1 - cosTheta * cosTheta));
363
- const tangent = Math.abs(normal[1]) < 0.95
364
- ? normalize(cross([0, 1, 0], normal))
365
- : normalize(cross([1, 0, 0], normal));
366
- const bitangent = normalize(cross(normal, tangent));
367
- return normalize([
368
- tangent[0] * Math.cos(phi) * sinTheta + bitangent[0] * Math.sin(phi) * sinTheta + normal[0] * cosTheta,
369
- tangent[1] * Math.cos(phi) * sinTheta + bitangent[1] * Math.sin(phi) * sinTheta + normal[1] * cosTheta,
370
- tangent[2] * Math.cos(phi) * sinTheta + bitangent[2] * Math.sin(phi) * sinTheta + normal[2] * cosTheta
371
- ]);
372
- }
373
-
374
- function radicalInverseVdc(bits: number): number {
375
- let value = bits >>> 0;
376
- value = (value << 16) | (value >>> 16);
377
- value = ((value & 0x55555555) << 1) | ((value & 0xaaaaaaaa) >>> 1);
378
- value = ((value & 0x33333333) << 2) | ((value & 0xcccccccc) >>> 2);
379
- value = ((value & 0x0f0f0f0f) << 4) | ((value & 0xf0f0f0f0) >>> 4);
380
- value = ((value & 0x00ff00ff) << 8) | ((value & 0xff00ff00) >>> 8);
381
- return value * 2.3283064365386963e-10;
382
- }
383
-
384
- function sampleEquirect(
385
- source: LinearHdrEnvironmentMapSource,
386
- direction: readonly [number, number, number]
387
- ): readonly [number, number, number] {
388
- const u = 0.5 + Math.atan2(direction[2], direction[0]) / (Math.PI * 2);
389
- const v = 0.5 - Math.asin(clamp(direction[1], -1, 1)) / Math.PI;
390
- const sampleX = u * source.width - 0.5;
391
- const sampleY = v * source.height - 0.5;
392
- const x0 = Math.floor(sampleX);
393
- const y0 = Math.floor(sampleY);
394
- const x1 = x0 + 1;
395
- const y1 = y0 + 1;
396
- const tx = sampleX - x0;
397
- const ty = sampleY - y0;
398
- const topLeft = sampleEquirectTexel(source, x0, y0);
399
- const topRight = sampleEquirectTexel(source, x1, y0);
400
- const bottomLeft = sampleEquirectTexel(source, x0, y1);
401
- const bottomRight = sampleEquirectTexel(source, x1, y1);
402
- const top = mixRgb(topLeft, topRight, tx);
403
- const bottom = mixRgb(bottomLeft, bottomRight, tx);
404
- return mixRgb(top, bottom, ty);
405
- }
406
-
407
- function sampleEquirectTexel(
408
- source: LinearHdrEnvironmentMapSource,
409
- x: number,
410
- y: number
411
- ): readonly [number, number, number] {
412
- const pixelX = wrap(x, source.width);
413
- const pixelY = clamp(y, 0, source.height - 1);
414
- const offset = (pixelY * source.width + pixelX) * 4;
415
- return [
416
- Math.max(0, source.data[offset] ?? 0),
417
- Math.max(0, source.data[offset + 1] ?? 0),
418
- Math.max(0, source.data[offset + 2] ?? 0)
419
- ];
420
- }
421
-
422
- function mixRgb(
423
- a: readonly [number, number, number],
424
- b: readonly [number, number, number],
425
- t: number
426
- ): readonly [number, number, number] {
427
- return [
428
- a[0] + (b[0] - a[0]) * t,
429
- a[1] + (b[1] - a[1]) * t,
430
- a[2] + (b[2] - a[2]) * t
431
- ];
432
- }
433
-
434
- function sourceAverageRadiance(source: LinearHdrEnvironmentMapSource): readonly [number, number, number] {
435
- let red = 0;
436
- let green = 0;
437
- let blue = 0;
438
- let count = 0;
439
- for (let offset = 0; offset < source.data.length; offset += 4) {
440
- red += Math.max(0, source.data[offset] ?? 0);
441
- green += Math.max(0, source.data[offset + 1] ?? 0);
442
- blue += Math.max(0, source.data[offset + 2] ?? 0);
443
- count += 1;
444
- }
445
- return [red / Math.max(1, count), green / Math.max(1, count), blue / Math.max(1, count)];
446
- }
447
-
448
- function faceDirection(face: PMREMCubeFace, u: number, v: number): readonly [number, number, number] {
449
- switch (face) {
450
- case "px": return [1, -v, -u];
451
- case "nx": return [-1, -v, u];
452
- case "py": return [u, 1, v];
453
- case "ny": return [u, -1, -v];
454
- case "pz": return [u, -v, 1];
455
- case "nz": return [-u, -v, -1];
456
- }
457
- }
458
-
459
- function normalize(value: readonly [number, number, number]): readonly [number, number, number] {
460
- const length = Math.hypot(value[0], value[1], value[2]);
461
- if (!Number.isFinite(length) || length <= 0) return [0, 1, 0];
462
- return [value[0] / length, value[1] / length, value[2] / length];
463
- }
464
-
465
- function cross(a: readonly [number, number, number], b: readonly [number, number, number]): readonly [number, number, number] {
466
- return [
467
- a[1] * b[2] - a[2] * b[1],
468
- a[2] * b[0] - a[0] * b[2],
469
- a[0] * b[1] - a[1] * b[0]
470
- ];
471
- }
472
-
473
- function dot(a: readonly [number, number, number], b: readonly [number, number, number]): number {
474
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
475
- }
476
-
477
- function wrap(value: number, size: number): number {
478
- return ((value % size) + size) % size;
479
- }
480
-
481
- function clamp(value: number, min: number, max: number): number {
482
- return Math.min(max, Math.max(min, value));
483
- }
484
-
485
- function maxLinearValue(data: Float32Array | readonly number[]): number {
486
- let max = 0;
487
- for (let offset = 0; offset < data.length; offset += 4) {
488
- max = Math.max(max, data[offset] ?? 0, data[offset + 1] ?? 0, data[offset + 2] ?? 0);
489
- }
490
- return max;
491
- }
492
-
493
- function maxEdgeMeanDelta(level: CubemapPMREMLevel | undefined): number {
494
- if (!level) return 0;
495
- const edges = level.faces.flatMap((face) => [
496
- edgeMean(face, "top"),
497
- edgeMean(face, "right"),
498
- edgeMean(face, "bottom"),
499
- edgeMean(face, "left")
500
- ]);
501
- let maxDelta = 0;
502
- for (let a = 0; a < edges.length; a += 1) {
503
- for (let b = a + 1; b < edges.length; b += 1) {
504
- maxDelta = Math.max(maxDelta, colorDistance(edges[a]!, edges[b]!));
505
- }
506
- }
507
- return Number(maxDelta.toFixed(6));
508
- }
509
-
510
- function edgeMean(face: CubemapPMREMFace, edge: "top" | "right" | "bottom" | "left"): readonly [number, number, number] {
511
- let red = 0;
512
- let green = 0;
513
- let blue = 0;
514
- let count = 0;
515
- const size = face.width;
516
- for (let i = 0; i < size; i += 1) {
517
- const x = edge === "left" ? 0 : edge === "right" ? size - 1 : i;
518
- const y = edge === "top" ? 0 : edge === "bottom" ? size - 1 : i;
519
- const offset = (y * size + x) * 4;
520
- red += halfFloatToNumber(face.data[offset] ?? 0);
521
- green += halfFloatToNumber(face.data[offset + 1] ?? 0);
522
- blue += halfFloatToNumber(face.data[offset + 2] ?? 0);
523
- count += 1;
524
- }
525
- return [red / count, green / count, blue / count];
526
- }
527
-
528
- function levelLuminanceVariance(level: CubemapPMREMLevel): number {
529
- const values: number[] = [];
530
- for (const face of level.faces) {
531
- for (let offset = 0; offset < face.data.length; offset += 4) {
532
- values.push(
533
- halfFloatToNumber(face.data[offset] ?? 0) * 0.2126
534
- + halfFloatToNumber(face.data[offset + 1] ?? 0) * 0.7152
535
- + halfFloatToNumber(face.data[offset + 2] ?? 0) * 0.0722
536
- );
537
- }
538
- }
539
- const mean = values.reduce((total, value) => total + value, 0) / Math.max(1, values.length);
540
- const variance = values.reduce((total, value) => total + (value - mean) ** 2, 0) / Math.max(1, values.length);
541
- return Number(variance.toFixed(6));
542
- }
543
-
544
- function colorDistance(a: readonly [number, number, number], b: readonly [number, number, number]): number {
545
- return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
546
- }
547
-
548
- function halfFloatToNumber(bits: number): number {
549
- const sign = bits & 0x8000 ? -1 : 1;
550
- const exponent = (bits >>> 10) & 0x1f;
551
- const fraction = bits & 0x03ff;
552
- if (exponent === 0) return sign * 2 ** -14 * (fraction / 1024);
553
- if (exponent === 0x1f) return fraction === 0 ? sign * Infinity : Number.NaN;
554
- return sign * 2 ** (exponent - 15) * (1 + fraction / 1024);
555
- }
556
-
557
- function validateHdrSource(source: LinearHdrEnvironmentMapSource): void {
558
- validatePositiveInteger(source.width, "Cubemap PMREM source width");
559
- validatePositiveInteger(source.height, "Cubemap PMREM source height");
560
- if (source.data.length !== source.width * source.height * 4) {
561
- throw new RangeError("Cubemap PMREM source data must contain width * height * 4 linear RGBA values");
562
- }
563
- }
564
-
565
- function validatePositiveInteger(value: number, label: string): void {
566
- if (!Number.isInteger(value) || value <= 0) {
567
- throw new RangeError(`${label} must be a positive integer`);
568
- }
569
- }
570
-
571
- function finiteVec3(value: readonly [number, number, number], label: string): readonly [number, number, number] {
572
- if (value.length !== 3 || value.some((component) => !Number.isFinite(component))) {
573
- throw new RangeError(`${label} must contain three finite numbers`);
574
- }
575
- return [value[0], value[1], value[2]];
576
- }
577
-
578
- function finiteColor(value: readonly [number, number, number], label: string): readonly [number, number, number] {
579
- const color = finiteVec3(value, label);
580
- if (color.some((component) => component < 0 || component > 1)) {
581
- throw new RangeError(`${label} must be in the [0, 1] range`);
582
- }
583
- return color;
584
- }
585
-
586
- function finiteNumber(value: number, label: string): number {
587
- if (!Number.isFinite(value)) {
588
- throw new RangeError(`${label} must be finite`);
589
- }
590
- return value;
591
- }
592
-
593
- function finitePositive(value: number, label: string): number {
594
- if (!Number.isFinite(value) || value <= 0) {
595
- throw new RangeError(`${label} must be a positive finite number`);
596
- }
597
- return value;
598
- }
599
-
600
- function clampFinite(value: number, min: number, max: number, label: string): number {
601
- return clamp(finiteNumber(value, label), min, max);
602
- }
603
-
604
- function clampInteger(value: number, min: number, max: number, label: string): number {
605
- if (!Number.isInteger(value)) {
606
- throw new RangeError(`${label} must be an integer`);
607
- }
608
- return Math.max(min, Math.min(max, value));
609
- }
610
-
611
- function validateBox(min: readonly [number, number, number], max: readonly [number, number, number]): void {
612
- if (min.some((component, index) => component >= max[index]!)) {
613
- throw new RangeError("PMREM transmission probe environment box min values must be lower than max values");
614
- }
615
- }
616
-
617
- function clampPointToBox(point: readonly [number, number, number], min: readonly [number, number, number], max: readonly [number, number, number]): readonly [number, number, number] {
618
- return [
619
- clamp(point[0], min[0] + 0.0001, max[0] - 0.0001),
620
- clamp(point[1], min[1] + 0.0001, max[1] - 0.0001),
621
- clamp(point[2], min[2] + 0.0001, max[2] - 0.0001)
622
- ];
623
- }
624
-
625
- function intersectBox(
626
- origin: readonly [number, number, number],
627
- direction: readonly [number, number, number],
628
- min: readonly [number, number, number],
629
- max: readonly [number, number, number]
630
- ): { readonly position: readonly [number, number, number]; readonly normal: readonly [number, number, number]; readonly distance: number } | undefined {
631
- let bestDistance = Number.POSITIVE_INFINITY;
632
- let bestNormal: readonly [number, number, number] | undefined;
633
- for (let axis = 0; axis < 3; axis += 1) {
634
- const component = direction[axis]!;
635
- if (Math.abs(component) <= 1e-8) continue;
636
- const plane = component > 0 ? max[axis]! : min[axis]!;
637
- const distance = (plane - origin[axis]!) / component;
638
- if (distance <= 1e-6 || distance >= bestDistance) continue;
639
- const hit: readonly [number, number, number] = [
640
- origin[0] + direction[0] * distance,
641
- origin[1] + direction[1] * distance,
642
- origin[2] + direction[2] * distance
643
- ];
644
- if (
645
- hit[0] < min[0] - 1e-5 || hit[0] > max[0] + 1e-5 ||
646
- hit[1] < min[1] - 1e-5 || hit[1] > max[1] + 1e-5 ||
647
- hit[2] < min[2] - 1e-5 || hit[2] > max[2] + 1e-5
648
- ) {
649
- continue;
650
- }
651
- bestDistance = distance;
652
- bestNormal = axis === 0
653
- ? [component > 0 ? 1 : -1, 0, 0]
654
- : axis === 1
655
- ? [0, component > 0 ? 1 : -1, 0]
656
- : [0, 0, component > 0 ? 1 : -1];
657
- }
658
- if (!bestNormal || !Number.isFinite(bestDistance)) return undefined;
659
- return {
660
- position: [
661
- origin[0] + direction[0] * bestDistance,
662
- origin[1] + direction[1] * bestDistance,
663
- origin[2] + direction[2] * bestDistance
664
- ],
665
- normal: bestNormal,
666
- distance: bestDistance
667
- };
668
- }
669
-
670
- function length(vector: readonly [number, number, number]): number {
671
- return Math.hypot(vector[0], vector[1], vector[2]);
672
- }
673
-
674
- function scale(vector: readonly [number, number, number], scalar: number): readonly [number, number, number] {
675
- return [vector[0] * scalar, vector[1] * scalar, vector[2] * scalar];
676
- }
677
-
678
- function reflect(vector: readonly [number, number, number], normal: readonly [number, number, number]): readonly [number, number, number] {
679
- return subtract(vector, scale(normal, 2 * dot(vector, normal)));
680
- }
681
-
682
- function refract(vector: readonly [number, number, number], normal: readonly [number, number, number], eta: number): readonly [number, number, number] {
683
- const cosi = clamp(dot(scale(vector, -1), normal), -1, 1);
684
- const k = 1 - eta * eta * (1 - cosi * cosi);
685
- if (k < 0) return [0, 0, 0];
686
- return add(scale(vector, eta), scale(normal, eta * cosi - Math.sqrt(k)));
687
- }
688
-
689
- function add(left: readonly [number, number, number], right: readonly [number, number, number]): readonly [number, number, number] {
690
- return [left[0] + right[0], left[1] + right[1], left[2] + right[2]];
691
- }
692
-
693
- function subtract(left: readonly [number, number, number], right: readonly [number, number, number]): readonly [number, number, number] {
694
- return [left[0] - right[0], left[1] - right[1], left[2] - right[2]];
695
- }
696
-
697
- function average3(value: readonly [number, number, number]): number {
698
- return (value[0] + value[1] + value[2]) / 3;
699
- }
700
-
701
- function numberToHalfFloat(value: number): number {
702
- const clamped = Math.max(0, value);
703
- if (Number.isNaN(clamped)) return 0x7e00;
704
- if (clamped === Infinity) return 0x7c00;
705
- if (clamped >= 65504) return 0x7bff;
706
- if (clamped === 0) return 0;
707
- if (clamped < 2 ** -14) {
708
- return Math.round(clamped / 2 ** -24);
709
- }
710
- const exponent = Math.floor(Math.log2(clamped));
711
- const mantissa = Math.round((clamped / 2 ** exponent - 1) * 1024);
712
- return ((exponent + 15) << 10) | (mantissa & 0x03ff);
713
- }