@unikia/upe-renderer 0.186.110 → 0.187.11

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 (506) hide show
  1. package/README.md +5 -7
  2. package/UPSTREAM.md +4 -4
  3. package/build/three.core.js +853 -277
  4. package/build/three.module.js +1098 -1280
  5. package/build/three.tsl.js +41938 -686
  6. package/build/three.webgpu.js +10604 -49055
  7. package/build/three.webgpu.nodes.js +9249 -5788
  8. package/examples/jsm/Addons.js +2 -0
  9. package/examples/jsm/animation/CCDIKSolver.js +17 -5
  10. package/examples/jsm/controls/FirstPersonControls.js +1 -1
  11. package/examples/jsm/controls/OrbitControls.js +27 -14
  12. package/examples/jsm/csm/CSMShader.js +74 -3
  13. package/examples/jsm/curves/CurveExtras.js +4 -4
  14. package/examples/jsm/curves/NURBSCurve.js +14 -0
  15. package/examples/jsm/exporters/EXRExporter.js +673 -16
  16. package/examples/jsm/exporters/GLTFExporter.js +4 -4
  17. package/examples/jsm/exporters/KTX2Exporter.js +1 -1
  18. package/examples/jsm/exporters/OBJExporter.js +48 -5
  19. package/examples/jsm/exporters/PLYExporter.js +22 -11
  20. package/examples/jsm/generators/CityGenerator.js +3 -2
  21. package/examples/jsm/generators/city/SkyscraperGenerator.js +63 -21
  22. package/examples/jsm/gpgpu/BitonicSort.js +30 -23
  23. package/examples/jsm/helpers/VertexTangentsHelper.js +1 -1
  24. package/examples/jsm/inspector/Extension.js +1 -1
  25. package/examples/jsm/inspector/Inspector.js +6 -46
  26. package/examples/jsm/inspector/RendererInspector.js +43 -8
  27. package/examples/jsm/inspector/Storage.js +49 -0
  28. package/examples/jsm/inspector/extensions/color-grading/ColorGrading.js +32 -27
  29. package/examples/jsm/inspector/tabs/Parameters.js +5 -1
  30. package/examples/jsm/inspector/tabs/Performance.js +22 -7
  31. package/examples/jsm/inspector/tabs/Settings.js +1 -1
  32. package/examples/jsm/inspector/tabs/Timeline.js +83 -7
  33. package/examples/jsm/inspector/tabs/Viewer.js +25 -10
  34. package/examples/jsm/inspector/ui/Profiler.js +1 -1
  35. package/examples/jsm/inspector/ui/Style.js +21 -53
  36. package/examples/jsm/inspector/ui/Values.js +28 -3
  37. package/examples/jsm/libs/fflate.module.js +83 -56
  38. package/examples/jsm/libs/mikktspace.README.md +27 -0
  39. package/examples/jsm/libs/mikktspace.module.js +721 -109
  40. package/examples/jsm/lighting/ClusteredLighting.js +100 -2
  41. package/examples/jsm/lighting/LightMapper.js +295 -0
  42. package/examples/jsm/lighting/LightProbeGrid.js +242 -139
  43. package/examples/jsm/lighting/LightProbeGridWebGL.js +30 -14
  44. package/examples/jsm/lighting/vxgi/VXGIConeTracer.js +54 -5
  45. package/examples/jsm/lighting/vxgi/VXGIIrradiance.js +43 -0
  46. package/examples/jsm/lighting/vxgi/VXGINode.js +13 -56
  47. package/examples/jsm/lighting/vxgi/VXGISceneCollector.js +316 -1
  48. package/examples/jsm/lighting/vxgi/VXGIVolume.js +69 -59
  49. package/examples/jsm/lights/SunLight.js +9 -4
  50. package/examples/jsm/lights/SunLightNode.js +3 -3
  51. package/examples/jsm/lines/LineMaterial.js +26 -10
  52. package/examples/jsm/loaders/3DMLoader.js +10 -1
  53. package/examples/jsm/loaders/3MFLoader.js +5 -1
  54. package/examples/jsm/loaders/AMFLoader.js +2 -0
  55. package/examples/jsm/loaders/BVHLoader.js +2 -0
  56. package/examples/jsm/loaders/ColladaLoader.js +8 -0
  57. package/examples/jsm/loaders/DDSLoader.js +1 -1
  58. package/examples/jsm/loaders/DRACOLoader.js +5 -1
  59. package/examples/jsm/loaders/EXRLoader.js +120 -104
  60. package/examples/jsm/loaders/FBXLoader.js +4 -0
  61. package/examples/jsm/loaders/FontLoader.js +2 -0
  62. package/examples/jsm/loaders/GCodeLoader.js +5 -9
  63. package/examples/jsm/loaders/GLTFLoader.js +112 -31
  64. package/examples/jsm/loaders/GaussianSplatPLYLoader.js +2 -0
  65. package/examples/jsm/loaders/HDRCubeTextureLoader.js +3 -0
  66. package/examples/jsm/loaders/IESLoader.js +46 -12
  67. package/examples/jsm/loaders/JXLLoader.js +159 -0
  68. package/examples/jsm/loaders/KMZLoader.js +6 -0
  69. package/examples/jsm/loaders/KSPLATLoader.js +2 -0
  70. package/examples/jsm/loaders/KTX2Loader.js +49 -4
  71. package/examples/jsm/loaders/KTXLoader.js +5 -3
  72. package/examples/jsm/loaders/LDrawLoader.js +15 -22
  73. package/examples/jsm/loaders/LUT3dlLoader.js +5 -1
  74. package/examples/jsm/loaders/LUTCubeLoader.js +6 -2
  75. package/examples/jsm/loaders/LUTImageLoader.js +2 -0
  76. package/examples/jsm/loaders/LWOLoader.js +6 -0
  77. package/examples/jsm/loaders/MD2Loader.js +2 -0
  78. package/examples/jsm/loaders/MDDLoader.js +4 -0
  79. package/examples/jsm/loaders/MTLLoader.js +8 -0
  80. package/examples/jsm/loaders/MaterialXLoader.js +57 -5
  81. package/examples/jsm/loaders/NRRDLoader.js +4 -2
  82. package/examples/jsm/loaders/OBJLoader.js +10 -4
  83. package/examples/jsm/loaders/PCDLoader.js +6 -2
  84. package/examples/jsm/loaders/PDBLoader.js +5 -3
  85. package/examples/jsm/loaders/PLYLoader.js +39 -15
  86. package/examples/jsm/loaders/PVRLoader.js +2 -2
  87. package/examples/jsm/loaders/SPLATLoader.js +2 -0
  88. package/examples/jsm/loaders/SPZLoader.js +2 -0
  89. package/examples/jsm/loaders/STLLoader.js +3 -1
  90. package/examples/jsm/loaders/SVGLoader.js +27 -49
  91. package/examples/jsm/loaders/TDSLoader.js +4 -0
  92. package/examples/jsm/loaders/TGALoader.js +6 -5
  93. package/examples/jsm/loaders/TTFLoader.js +2 -0
  94. package/examples/jsm/loaders/USDLoader.js +14 -0
  95. package/examples/jsm/loaders/UltraHDRLoader.js +2 -0
  96. package/examples/jsm/loaders/VOXLoader.js +3 -0
  97. package/examples/jsm/loaders/VRMLLoader.js +4 -0
  98. package/examples/jsm/loaders/VTKLoader.js +2 -0
  99. package/examples/jsm/loaders/XYZLoader.js +2 -0
  100. package/examples/jsm/loaders/collada/ColladaComposer.js +15 -8
  101. package/examples/jsm/loaders/materialx/MaterialXDocument.js +610 -138
  102. package/examples/jsm/loaders/materialx/MaterialXInterfaceValidation.js +12 -95
  103. package/examples/jsm/loaders/materialx/MaterialXLog.js +4 -0
  104. package/examples/jsm/loaders/materialx/MaterialXNodeDefs.js +99 -0
  105. package/examples/jsm/loaders/materialx/MaterialXNodeInterfaceRegistry.js +760 -1
  106. package/examples/jsm/loaders/materialx/MaterialXNodeLibrary.js +222 -372
  107. package/examples/jsm/loaders/materialx/MaterialXSurfaceMappings.js +163 -259
  108. package/examples/jsm/loaders/materialx/MaterialXUtils.js +25 -0
  109. package/examples/jsm/loaders/materialx/compile/MaterialXCompileRegistry.js +161 -159
  110. package/examples/jsm/loaders/usd/USDAParser.js +56 -47
  111. package/examples/jsm/loaders/usd/USDComposer.js +25 -30
  112. package/examples/jsm/math/ColorConverter.js +7 -3
  113. package/examples/jsm/math/Lut.js +2 -2
  114. package/examples/jsm/math/OBB.js +3 -3
  115. package/examples/jsm/math/Octree.js +20 -17
  116. package/examples/jsm/objects/GaussianSplat.js +5 -4
  117. package/examples/jsm/objects/Reflector.js +5 -0
  118. package/examples/jsm/objects/SkyMesh.js +14 -7
  119. package/examples/jsm/objects/Water2Mesh.js +2 -2
  120. package/examples/jsm/physics/RapierPhysics.js +2 -2
  121. package/examples/jsm/pipelines/MeshletDrawingPipeline.js +5571 -0
  122. package/examples/jsm/pipelines/VisibilityBufferDrawingPipeline.js +954 -0
  123. package/examples/jsm/postprocessing/BokehPass.js +1 -1
  124. package/examples/jsm/postprocessing/GTAOPass.js +26 -18
  125. package/examples/jsm/renderers/SVGRenderer.js +3 -2
  126. package/examples/jsm/shaders/GTAOShader.js +7 -4
  127. package/examples/jsm/shaders/PoissonDenoiseShader.js +1 -10
  128. package/examples/jsm/tsl/WebGLNodesHandler.js +21 -9
  129. package/examples/jsm/tsl/display/AfterImageNode.js +3 -3
  130. package/examples/jsm/tsl/display/BilateralBlurNode.js +3 -3
  131. package/examples/jsm/tsl/display/BloomNode.js +3 -3
  132. package/examples/jsm/tsl/display/ChromaticAberrationNode.js +8 -19
  133. package/examples/jsm/tsl/display/DenoiseNode.js +5 -5
  134. package/examples/jsm/tsl/display/DepthOfFieldNode.js +3 -3
  135. package/examples/jsm/tsl/display/DotScreenNode.js +3 -3
  136. package/examples/jsm/tsl/display/FSR1Node.js +3 -3
  137. package/examples/jsm/tsl/display/FXAANode.js +3 -10
  138. package/examples/jsm/tsl/display/FilmNode.js +3 -3
  139. package/examples/jsm/tsl/display/GTAONode.js +33 -25
  140. package/examples/jsm/tsl/display/GaussianBlurNode.js +3 -3
  141. package/examples/jsm/tsl/display/GodraysNode.js +5 -19
  142. package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +8 -4
  143. package/examples/jsm/tsl/display/LensflareNode.js +3 -3
  144. package/examples/jsm/tsl/display/Lut3DNode.js +3 -3
  145. package/examples/jsm/tsl/display/OITPassNode.js +0 -11
  146. package/examples/jsm/tsl/display/OutlineNode.js +107 -5
  147. package/examples/jsm/tsl/display/PixelationPassNode.js +85 -193
  148. package/examples/jsm/tsl/display/RGBShiftNode.js +3 -3
  149. package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +23 -126
  150. package/examples/jsm/tsl/display/SMAANode.js +3 -3
  151. package/examples/jsm/tsl/display/SSAONode.js +6 -20
  152. package/examples/jsm/tsl/display/SSGINode.js +36 -29
  153. package/examples/jsm/tsl/display/SSRNode.js +135 -63
  154. package/examples/jsm/tsl/display/SSSNode.js +6 -20
  155. package/examples/jsm/tsl/display/SharpenNode.js +3 -3
  156. package/examples/jsm/tsl/display/SobelOperatorNode.js +3 -3
  157. package/examples/jsm/tsl/display/TAAUNode.js +10 -42
  158. package/examples/jsm/tsl/display/TRAANode.js +11 -43
  159. package/examples/jsm/tsl/display/TemporalReprojectNode.js +42 -47
  160. package/examples/jsm/tsl/display/TransitionNode.js +3 -3
  161. package/examples/jsm/tsl/display/lensDirt.js +30 -0
  162. package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +482 -121
  163. package/examples/jsm/tsl/lighting/DynamicLightsNode.js +41 -140
  164. package/examples/jsm/tsl/lighting/LightProbeGridNode.js +72 -25
  165. package/examples/jsm/tsl/lighting/data/AmbientLightDataNode.js +6 -0
  166. package/examples/jsm/tsl/lighting/data/DirectionalLightDataNode.js +6 -0
  167. package/examples/jsm/tsl/lighting/data/HemisphereLightDataNode.js +6 -0
  168. package/examples/jsm/tsl/lighting/data/PointLightDataNode.js +6 -0
  169. package/examples/jsm/tsl/lighting/data/SpotLightDataNode.js +6 -0
  170. package/examples/jsm/tsl/shadows/TileShadowNode.js +102 -14
  171. package/examples/jsm/tsl/utils/Raymarching.js +1 -1
  172. package/examples/jsm/tsl/utils/SoftParticles.js +5 -12
  173. package/examples/jsm/tsl/utils/SpecularHelpers.js +47 -70
  174. package/examples/jsm/tsl/utils/TAAUtils.js +6 -17
  175. package/examples/jsm/utils/BufferGeometryUtils.js +110 -88
  176. package/examples/jsm/utils/MeshletGeometryUtils.js +417 -0
  177. package/examples/jsm/utils/SceneOptimizer.js +2 -1
  178. package/examples/jsm/utils/SceneUtils.js +1 -1
  179. package/examples/jsm/utils/unwrapUVs.js +865 -0
  180. package/examples/jsm/webxr/XREstimatedLight.js +11 -4
  181. package/package.json +3 -3
  182. package/src/Three.TSL.js +2 -683
  183. package/src/Three.WebGPU.Nodes.js +2 -1
  184. package/src/Three.WebGPU.js +2 -1
  185. package/src/animation/AnimationAction.js +1 -1
  186. package/src/animation/AnimationUtils.js +1 -3
  187. package/src/animation/KeyframeTrack.js +19 -0
  188. package/src/cameras/ArrayCamera.js +12 -0
  189. package/src/cameras/CubeCamera.js +3 -3
  190. package/src/constants.js +1 -9
  191. package/src/core/BufferAttribute.js +57 -21
  192. package/src/core/BufferGeometry.js +5 -13
  193. package/src/core/Clock.js +1 -1
  194. package/src/core/InterleavedBuffer.js +28 -18
  195. package/src/core/InterleavedBufferAttribute.js +54 -20
  196. package/src/core/Object3D.js +19 -9
  197. package/src/core/Raycaster.js +2 -0
  198. package/src/core/RenderTarget.js +11 -5
  199. package/src/core/UniformsGroup.js +7 -3
  200. package/src/extras/PMREMGenerator.js +392 -685
  201. package/src/extras/core/Curve.js +4 -0
  202. package/src/extras/core/CurvePath.js +13 -0
  203. package/src/extras/core/ShapePath.js +1 -1
  204. package/src/geometries/EdgesGeometry.js +12 -10
  205. package/src/geometries/LatheGeometry.js +2 -0
  206. package/src/helpers/PolarGridHelper.js +1 -1
  207. package/src/lights/Light.js +11 -0
  208. package/src/lights/LightProbe.js +2 -0
  209. package/src/lights/LightShadow.js +2 -0
  210. package/src/loaders/AnimationLoader.js +2 -0
  211. package/src/loaders/AudioLoader.js +2 -0
  212. package/src/loaders/BufferGeometryLoader.js +2 -0
  213. package/src/loaders/CompressedTextureLoader.js +2 -0
  214. package/src/loaders/CubeTextureLoader.js +2 -0
  215. package/src/loaders/DataTextureLoader.js +2 -0
  216. package/src/loaders/FileLoader.js +2 -0
  217. package/src/loaders/ImageBitmapLoader.js +3 -1
  218. package/src/loaders/ImageLoader.js +1 -0
  219. package/src/loaders/Loader.js +47 -0
  220. package/src/loaders/MaterialLoader.js +2 -0
  221. package/src/loaders/ObjectLoader.js +27 -8
  222. package/src/loaders/TextureLoader.js +5 -3
  223. package/src/loaders/nodes/NodeLoader.js +2 -0
  224. package/src/materials/Material.js +21 -2
  225. package/src/materials/MeshDepthMaterial.js +1 -1
  226. package/src/materials/MeshDistanceMaterial.js +1 -1
  227. package/src/materials/MeshLambertMaterial.js +1 -1
  228. package/src/materials/MeshMatcapMaterial.js +1 -1
  229. package/src/materials/MeshNormalMaterial.js +1 -1
  230. package/src/materials/MeshPhongMaterial.js +1 -1
  231. package/src/materials/MeshPhysicalMaterial.js +90 -11
  232. package/src/materials/MeshStandardMaterial.js +1 -1
  233. package/src/materials/MeshToonMaterial.js +1 -1
  234. package/src/materials/nodes/Line2NodeMaterial.js +32 -10
  235. package/src/materials/nodes/MeshLambertNodeMaterial.js +13 -0
  236. package/src/materials/nodes/MeshPhongNodeMaterial.js +13 -0
  237. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +40 -5
  238. package/src/materials/nodes/MeshToonNodeMaterial.js +13 -0
  239. package/src/materials/nodes/NodeMaterial.js +36 -16
  240. package/src/materials/nodes/NodeMaterialInstance.js +193 -0
  241. package/src/materials/nodes/NodeMaterials.js +1 -0
  242. package/src/materials/nodes/PointsNodeMaterial.js +1 -1
  243. package/src/materials/nodes/SpriteNodeMaterial.js +3 -3
  244. package/src/materials/nodes/manager/NodeMaterialObserver.js +191 -22
  245. package/src/math/Box3.js +2 -2
  246. package/src/math/Color.js +8 -8
  247. package/src/math/ColorManagement.js +2 -21
  248. package/src/math/FrustumArray.js +12 -0
  249. package/src/math/Interpolant.js +1 -1
  250. package/src/math/Line3.js +2 -4
  251. package/src/math/MathUtils.js +33 -46
  252. package/src/math/Matrix2.js +1 -1
  253. package/src/math/Matrix3.js +1 -1
  254. package/src/math/Matrix4.js +1 -1
  255. package/src/math/Triangle.js +2 -1
  256. package/src/math/Vector2.js +1 -1
  257. package/src/math/Vector3.js +1 -1
  258. package/src/math/Vector4.js +1 -1
  259. package/src/nodes/Nodes.js +1 -0
  260. package/src/nodes/TSL.js +2 -0
  261. package/src/nodes/accessors/Arrays.js +1 -1
  262. package/src/nodes/accessors/Batch.js +29 -23
  263. package/src/nodes/accessors/BufferAttributeNode.js +21 -1
  264. package/src/nodes/accessors/BuiltinNode.js +6 -0
  265. package/src/nodes/accessors/Camera.js +100 -93
  266. package/src/nodes/accessors/ClippingNode.js +17 -6
  267. package/src/nodes/accessors/CubeTextureNode.js +12 -24
  268. package/src/nodes/accessors/Instance.js +198 -160
  269. package/src/nodes/accessors/Lights.js +19 -6
  270. package/src/nodes/accessors/MaterialNode.js +33 -4
  271. package/src/nodes/accessors/Morph.js +81 -22
  272. package/src/nodes/accessors/Normal.js +0 -42
  273. package/src/nodes/accessors/Object3DNode.js +6 -0
  274. package/src/nodes/accessors/PointUVNode.js +6 -0
  275. package/src/nodes/accessors/ReferenceAttributeNode.js +279 -0
  276. package/src/nodes/accessors/ReferenceBaseNode.js +6 -0
  277. package/src/nodes/accessors/ReferenceNode.js +6 -0
  278. package/src/nodes/accessors/Skinning.js +57 -52
  279. package/src/nodes/accessors/StorageBufferNode.js +3 -12
  280. package/src/nodes/accessors/TextureBicubic.js +30 -27
  281. package/src/nodes/accessors/TextureNode.js +164 -78
  282. package/src/nodes/accessors/TextureSizeNode.js +6 -0
  283. package/src/nodes/accessors/UniformArrayNode.js +8 -15
  284. package/src/nodes/accessors/VelocityNode.js +13 -8
  285. package/src/nodes/code/CodeNode.js +6 -0
  286. package/src/nodes/code/ExpressionNode.js +6 -0
  287. package/src/nodes/code/FunctionCallNode.js +3 -3
  288. package/src/nodes/code/FunctionNode.js +15 -13
  289. package/src/nodes/core/ArrayNode.js +3 -3
  290. package/src/nodes/core/AssignNode.js +10 -9
  291. package/src/nodes/core/AttributeNode.js +39 -0
  292. package/src/nodes/core/BypassNode.js +6 -0
  293. package/src/nodes/core/ConstNode.js +31 -1
  294. package/src/nodes/core/ContextNode.js +11 -6
  295. package/src/nodes/core/IndexNode.js +6 -0
  296. package/src/nodes/core/InputNode.js +6 -0
  297. package/src/nodes/core/InspectorNode.js +17 -31
  298. package/src/nodes/core/IsolateNode.js +8 -0
  299. package/src/nodes/core/Node.js +367 -67
  300. package/src/nodes/core/NodeBuilder.js +664 -222
  301. package/src/nodes/core/NodeUtils.js +25 -0
  302. package/src/nodes/core/NodeVar.js +10 -1
  303. package/src/nodes/core/OutputStructNode.js +6 -0
  304. package/src/nodes/core/OverrideContextNode.js +38 -37
  305. package/src/nodes/core/PropertyNode.js +14 -0
  306. package/src/nodes/core/StackNode.js +33 -21
  307. package/src/nodes/core/StructNode.js +6 -0
  308. package/src/nodes/core/StructTypeNode.js +6 -0
  309. package/src/nodes/core/SubBuildNode.js +8 -0
  310. package/src/nodes/core/TempNode.js +10 -35
  311. package/src/nodes/core/UniformGroupNode.js +6 -0
  312. package/src/nodes/core/VarNode.js +43 -135
  313. package/src/nodes/core/VaryingNode.js +33 -2
  314. package/src/nodes/display/BlendModes.js +5 -40
  315. package/src/nodes/display/BumpMapNode.js +17 -7
  316. package/src/nodes/display/ColorAdjustment.js +22 -10
  317. package/src/nodes/display/ColorSpaceFunctions.js +2 -14
  318. package/src/nodes/display/ColorSpaceNode.js +3 -3
  319. package/src/nodes/display/FrontFacingNode.js +6 -0
  320. package/src/nodes/display/NormalMapNode.js +3 -3
  321. package/src/nodes/display/PassNode.js +75 -16
  322. package/src/nodes/display/RenderOutputNode.js +22 -5
  323. package/src/nodes/display/ScreenNode.js +6 -0
  324. package/src/nodes/display/ToneMappingFunctions.js +9 -51
  325. package/src/nodes/display/ToneMappingNode.js +3 -3
  326. package/src/nodes/display/ToonOutlinePassNode.js +66 -2
  327. package/src/nodes/display/ViewportDepthNode.js +34 -4
  328. package/src/nodes/functions/BSDF/BRDF_EON.js +65 -0
  329. package/src/nodes/functions/BSDF/BRDF_GGX.js +5 -3
  330. package/src/nodes/functions/BSDF/BRDF_Sheen.js +2 -16
  331. package/src/nodes/functions/BSDF/D_GGX.js +1 -8
  332. package/src/nodes/functions/BSDF/D_GGX_Anisotropic.js +7 -10
  333. package/src/nodes/functions/BSDF/LTC.js +20 -47
  334. package/src/nodes/functions/BSDF/Schlick_to_F0.js +1 -9
  335. package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +1 -9
  336. package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +10 -13
  337. package/src/nodes/functions/PhysicalLightingModel.js +84 -51
  338. package/src/nodes/functions/VolumetricLightingModel.js +1 -1
  339. package/src/nodes/functions/material/getAlphaHashThreshold.js +3 -9
  340. package/src/nodes/functions/material/getParallaxCorrectNormal.js +10 -11
  341. package/src/nodes/functions/material/getRoughness.js +3 -1
  342. package/src/nodes/geometry/RangeNode.js +52 -69
  343. package/src/nodes/gpgpu/AtomicFunctionNode.js +11 -6
  344. package/src/nodes/gpgpu/BarrierNode.js +6 -0
  345. package/src/nodes/gpgpu/ComputeBuiltinNode.js +6 -0
  346. package/src/nodes/gpgpu/ComputeNode.js +6 -0
  347. package/src/nodes/gpgpu/SubgroupFunctionNode.js +38 -29
  348. package/src/nodes/gpgpu/WorkgroupInfoNode.js +6 -0
  349. package/src/nodes/lighting/AnalyticLightNode.js +7 -14
  350. package/src/nodes/lighting/BasicEnvironmentNode.js +5 -1
  351. package/src/nodes/lighting/EnvironmentNode.js +58 -8
  352. package/src/nodes/lighting/IESSpotLightNode.js +19 -4
  353. package/src/nodes/lighting/LightProbeNode.js +2 -1
  354. package/src/nodes/lighting/LightUtils.js +2 -2
  355. package/src/nodes/lighting/LightingNode.js +6 -0
  356. package/src/nodes/lighting/LightsNode.js +26 -32
  357. package/src/nodes/lighting/PointShadowNode.js +92 -48
  358. package/src/nodes/lighting/ProjectorLightNode.js +1 -1
  359. package/src/nodes/lighting/RectAreaLightNode.js +13 -14
  360. package/src/nodes/lighting/ShadowBaseNode.js +9 -17
  361. package/src/nodes/lighting/ShadowFilterNode.js +26 -3
  362. package/src/nodes/lighting/ShadowNode.js +13 -11
  363. package/src/nodes/materialx/MaterialXColor.js +2 -14
  364. package/src/nodes/materialx/MaterialXColorTransform.js +1 -7
  365. package/src/nodes/materialx/MaterialXNodes.js +8 -11
  366. package/src/nodes/materialx/MaterialXNoise.js +195 -454
  367. package/src/nodes/math/BitcastNode.js +5 -5
  368. package/src/nodes/math/BitcountNode.js +18 -46
  369. package/src/nodes/math/ConditionalNode.js +92 -22
  370. package/src/nodes/math/Hash.js +1 -1
  371. package/src/nodes/math/MathNode.js +86 -64
  372. package/src/nodes/math/MathUtils.js +2 -2
  373. package/src/nodes/math/OperatorNode.js +42 -59
  374. package/src/nodes/math/PackFloatNode.js +9 -9
  375. package/src/nodes/math/Packed4x8IntegerNode.js +20 -52
  376. package/src/nodes/math/TriNoise3D.js +3 -23
  377. package/src/nodes/math/UnpackFloatNode.js +9 -9
  378. package/src/nodes/pmrem/PMREMNode.js +38 -75
  379. package/src/nodes/pmrem/PMREMUtils.js +108 -272
  380. package/src/nodes/procedural/Checker.js +1 -1
  381. package/src/nodes/tsl/TSLCore.js +199 -74
  382. package/src/nodes/utils/ArrayElementNode.js +19 -1
  383. package/src/nodes/utils/CubeMapNode.js +3 -3
  384. package/src/nodes/utils/DebugNode.js +2 -2
  385. package/src/nodes/utils/EventNode.js +6 -0
  386. package/src/nodes/utils/FlipNode.js +3 -3
  387. package/src/nodes/utils/FunctionOverloadingNode.js +7 -1
  388. package/src/nodes/utils/JoinNode.js +3 -3
  389. package/src/nodes/utils/LoopNode.js +14 -9
  390. package/src/nodes/utils/MemberNode.js +18 -0
  391. package/src/nodes/utils/PostProcessingUtils.js +20 -25
  392. package/src/nodes/utils/RTTNode.js +2 -0
  393. package/src/nodes/utils/ReflectorNode.js +24 -0
  394. package/src/nodes/utils/RotateNode.js +3 -3
  395. package/src/nodes/utils/SampleNode.js +6 -0
  396. package/src/nodes/utils/SetNode.js +3 -3
  397. package/src/nodes/utils/SplitNode.js +6 -0
  398. package/src/nodes/utils/UVUtils.js +2 -2
  399. package/src/objects/BatchedMesh.js +146 -15
  400. package/src/objects/InstancedMesh.js +12 -4
  401. package/src/objects/Line.js +20 -0
  402. package/src/objects/Mesh.js +8 -0
  403. package/src/objects/Points.js +20 -0
  404. package/src/objects/Skeleton.js +26 -0
  405. package/src/objects/SkinnedMesh.js +3 -3
  406. package/src/objects/Sprite.js +10 -0
  407. package/src/renderers/WebGLRenderer.js +104 -70
  408. package/src/renderers/common/Animation.js +5 -1
  409. package/src/renderers/common/Attributes.js +67 -57
  410. package/src/renderers/common/Backend.js +78 -3
  411. package/src/renderers/common/BindGroup.js +11 -0
  412. package/src/renderers/common/Binding.js +0 -11
  413. package/src/renderers/common/Bindings.js +116 -10
  414. package/src/renderers/common/Buffer.js +1 -1
  415. package/src/renderers/common/ClippingContext.js +12 -1
  416. package/src/renderers/common/ComputePipeline.js +17 -1
  417. package/src/renderers/common/DirectRenderPipeline.js +7 -3
  418. package/src/renderers/common/Geometries.js +170 -132
  419. package/src/renderers/common/Info.js +1 -1
  420. package/src/renderers/common/InspectorBase.js +5 -5
  421. package/src/renderers/common/Lighting.js +59 -0
  422. package/src/renderers/common/Pipelines.js +26 -12
  423. package/src/renderers/common/ProgrammableStage.js +1 -17
  424. package/src/renderers/common/RenderContext.js +21 -0
  425. package/src/renderers/common/RenderContexts.js +13 -4
  426. package/src/renderers/common/RenderObject.js +111 -35
  427. package/src/renderers/common/RenderObjects.js +37 -19
  428. package/src/renderers/common/Renderer.js +537 -295
  429. package/src/renderers/common/RendererUtils.js +15 -0
  430. package/src/renderers/common/StandardDrawingPipeline.js +343 -0
  431. package/src/renderers/common/Storage3DTexture.js +11 -0
  432. package/src/renderers/common/StorageArrayTexture.js +10 -0
  433. package/src/renderers/common/StorageTexture.js +0 -9
  434. package/src/renderers/common/Textures.js +144 -37
  435. package/src/renderers/common/UniformsGroup.js +19 -0
  436. package/src/renderers/common/XRManager.js +10 -91
  437. package/src/renderers/common/extras/PMREMGenerator.js +298 -576
  438. package/src/renderers/common/nodes/NodeBuilderState.js +7 -5
  439. package/src/renderers/common/nodes/NodeLibrary.js +11 -35
  440. package/src/renderers/common/nodes/NodeManager.js +80 -31
  441. package/src/renderers/common/nodes/NodeSampledTexture.js +14 -0
  442. package/src/renderers/common/nodes/NodeSampler.js +14 -0
  443. package/src/renderers/common/nodes/NodeStorageBuffer.js +1 -1
  444. package/src/renderers/common/nodes/NodeUniformBuffer.js +1 -14
  445. package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +13 -4
  446. package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +8 -8
  447. package/src/renderers/shaders/ShaderChunk/lightprobes_pars_fragment.glsl.js +23 -11
  448. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +21 -2
  449. package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +1 -1
  450. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +18 -2
  451. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +104 -7
  452. package/src/renderers/shaders/ShaderChunk/morphcolor_vertex.glsl.js +11 -2
  453. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +36 -20
  454. package/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js +5 -0
  455. package/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js +6 -0
  456. package/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js +5 -0
  457. package/src/renderers/shaders/ShaderChunk.js +0 -2
  458. package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +4 -18
  459. package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +0 -1
  460. package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +0 -1
  461. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +8 -1
  462. package/src/renderers/shaders/ShaderLib.js +3 -0
  463. package/src/renderers/shaders/UniformsLib.js +4 -5
  464. package/src/renderers/webgl/WebGLBackground.js +3 -3
  465. package/src/renderers/webgl/WebGLBindingStates.js +4 -2
  466. package/src/renderers/webgl/WebGLCapabilities.js +7 -1
  467. package/src/renderers/webgl/WebGLEnvironments.js +2 -2
  468. package/src/renderers/webgl/WebGLGeometries.js +42 -14
  469. package/src/renderers/webgl/WebGLMaterials.js +15 -2
  470. package/src/renderers/webgl/WebGLOutput.js +37 -1
  471. package/src/renderers/webgl/WebGLProgram.js +13 -54
  472. package/src/renderers/webgl/WebGLPrograms.js +22 -8
  473. package/src/renderers/webgl/WebGLRenderStates.js +11 -8
  474. package/src/renderers/webgl/WebGLShadowMap.js +6 -4
  475. package/src/renderers/webgl/WebGLState.js +10 -6
  476. package/src/renderers/webgl/WebGLTextures.js +129 -77
  477. package/src/renderers/webgl/WebGLUniforms.js +44 -6
  478. package/src/renderers/webgl/WebGLUniformsGroups.js +75 -69
  479. package/src/renderers/webgl-fallback/WebGLBackend.js +206 -278
  480. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +154 -20
  481. package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +45 -42
  482. package/src/renderers/webgl-fallback/utils/WebGLState.js +29 -4
  483. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +129 -49
  484. package/src/renderers/webgl-fallback/utils/WebGLVertexArrayUtils.js +346 -0
  485. package/src/renderers/webgpu/WebGPUBackend.js +140 -82
  486. package/src/renderers/webgpu/WebGPURenderer.js +1 -1
  487. package/src/renderers/webgpu/nodes/BasicNodeLibrary.js +10 -10
  488. package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +10 -10
  489. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +135 -60
  490. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +128 -55
  491. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +1 -1
  492. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +15 -12
  493. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +55 -19
  494. package/src/renderers/webgpu/utils/WebGPUUtils.js +20 -3
  495. package/src/renderers/webxr/WebXRController.js +3 -3
  496. package/src/renderers/webxr/WebXRManager.js +5 -90
  497. package/src/scenes/Scene.js +4 -4
  498. package/src/textures/CompressedTexture.js +2 -2
  499. package/src/textures/DepthTexture.js +2 -2
  500. package/src/textures/FramebufferTexture.js +11 -0
  501. package/src/textures/Texture.js +29 -1
  502. package/src/textures/TextureSource.js +1 -1
  503. package/src/upe.js +1 -1
  504. package/src/utils.js +4 -4
  505. package/examples/jsm/libs/surfaceNet.js +0 -201
  506. package/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +0 -186
@@ -1,66 +1,54 @@
1
1
  import {
2
2
  CubeReflectionMapping,
3
3
  CubeRefractionMapping,
4
- CubeUVReflectionMapping,
5
- LinearFilter,
6
- NoToneMapping,
4
+ LinearMipmapLinearFilter,
7
5
  NoBlending,
8
- RGBAFormat,
9
6
  HalfFloatType,
10
7
  BackSide,
11
8
  LinearSRGBColorSpace
12
9
  } from '../constants.js';
13
10
 
14
- import { BufferAttribute } from '../core/BufferAttribute.js';
15
- import { BufferGeometry } from '../core/BufferGeometry.js';
16
11
  import { Mesh } from '../objects/Mesh.js';
17
- import { OrthographicCamera } from '../cameras/OrthographicCamera.js';
18
- import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';
12
+ import { BoxGeometry } from '../geometries/BoxGeometry.js';
13
+ import { CubeCamera } from '../cameras/CubeCamera.js';
19
14
  import { ShaderMaterial } from '../materials/ShaderMaterial.js';
20
- import { Vector3 } from '../math/Vector3.js';
21
15
  import { Color } from '../math/Color.js';
22
- import { WebGLRenderTarget } from '../renderers/WebGLRenderTarget.js';
23
- import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js';
24
- import { BoxGeometry } from '../geometries/BoxGeometry.js';
16
+ import { floorPowerOfTwo } from '../math/MathUtils.js';
17
+ import { Vector3 } from '../math/Vector3.js';
18
+ import { ShaderChunk } from '../renderers/shaders/ShaderChunk.js';
19
+ import { WebGLCubeRenderTarget } from '../renderers/WebGLCubeRenderTarget.js';
25
20
 
26
- const LOD_MIN = 4;
21
+ // Smaller inputs are upsampled so that every PMREM has enough mip levels.
22
+ const MIN_SIZE = 256;
27
23
 
28
- // The number of extra mips.
29
- // Used for scene blur in fromScene() method.
30
- const EXTRA_LODS = 6;
24
+ // Log2 of the face size of the roughest mip level. Smaller faces can't
25
+ // represent the diffuse irradiance that is stored in this level.
26
+ const LOD_MIN = 3;
31
27
 
32
- // The number of spiral samples per blur pass.
33
- // Used for scene blur in fromScene() method.
28
+ // Spiral samples per pass of the initial fromScene() blur.
34
29
  const BLUR_SAMPLES = 20;
35
30
 
36
- // GGX VNDF importance sampling configuration
31
+ // GGX VNDF samples for the sharp mip levels.
37
32
  const GGX_SAMPLES = 256;
38
33
 
39
- const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
40
- const _clearColor = /*@__PURE__*/ new Color();
41
- let _oldTarget = null;
42
- let _oldActiveCubeFace = 0;
43
- let _oldActiveMipmapLevel = 0;
44
- let _oldXrEnabled = false;
34
+ // Integrate a small source mip for the rough levels to avoid sampling noise.
35
+ const INTEGRATION_SIZE = 16;
36
+ const INTEGRATION_LEVELS = 3;
45
37
 
46
38
  const _origin = /*@__PURE__*/ new Vector3();
47
- const _direction = /*@__PURE__*/ new Vector3();
39
+ const _clearColor = /*@__PURE__*/ new Color();
48
40
 
49
41
  /**
50
- * This class generates a Prefiltered, Mipmapped Radiance Environment Map
51
- * (PMREM) from a cubeMap environment texture. This allows different levels of
52
- * blur to be quickly accessed based on material roughness. It is packed into a
53
- * special CubeUV format that allows us to perform custom interpolation so that
54
- * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
55
- * chain, it only goes down to the LOD_MIN level (above), and then creates extra
56
- * even more filtered 'mips' at the same LOD_MIN resolution, associated with
57
- * higher roughness levels. In this way we maintain resolution to smoothly
58
- * interpolate diffuse lighting while limiting sampling computation.
42
+ * Generates a Prefiltered, Mipmapped Radiance Environment Map (PMREM) for
43
+ * image-based lighting. The result is a cube render target whose mip levels
44
+ * store GGX-filtered radiance at increasing roughness, from a mirror at level 0
45
+ * to roughness 1. See {@link PMREMGenerator.lodToRoughness} for the mapping.
59
46
  *
60
- * The prefiltering uses GGX VNDF (Visible Normal Distribution Function)
61
- * importance sampling based on "Sampling the GGX Distribution of Visible Normals"
62
- * (Heitz, 2018) to generate environment maps that accurately match the GGX BRDF
63
- * used in material rendering for physically-based image-based lighting.
47
+ * Filtering assumes the view direction equals the surface normal. Sharp levels
48
+ * use GGX visible normal sampling (Heitz, 2018), while rough levels integrate a
49
+ * lower-resolution source cubemap.
50
+ *
51
+ * @see {@link https://jcgt.org/published/0007/04/01/ | Sampling the GGX Distribution of Visible Normals}
64
52
  */
65
53
  class PMREMGenerator {
66
54
 
@@ -72,37 +60,34 @@ class PMREMGenerator {
72
60
  constructor( renderer ) {
73
61
 
74
62
  this._renderer = renderer;
75
- this._pingPongRenderTarget = null;
76
63
 
77
- this._lodMax = 0;
78
64
  this._cubeSize = 0;
79
- this._sizeLods = [];
80
- this._lodMeshes = [];
65
+ this._sourceTarget = null;
81
66
 
82
- this._backgroundBox = null;
67
+ this._cubeCamera = new CubeCamera( 1, 10, null );
68
+ this._boxMesh = new Mesh( new BoxGeometry( 5, 5, 5 ), null );
83
69
 
84
70
  this._cubemapMaterial = null;
85
71
  this._equirectMaterial = null;
86
72
 
87
73
  this._blurMaterial = null;
88
74
  this._ggxMaterial = null;
75
+ this._integrationMaterial = null;
89
76
 
90
77
  }
91
78
 
92
79
  /**
93
- * Generates a PMREM from a supplied Scene, which can be faster than using an
94
- * image if networking bandwidth is low. Optional sigma specifies a blur radius
95
- * in radians to be applied to the scene before PMREM generation. Optional near
96
- * and far planes ensure the scene is rendered in its entirety.
80
+ * Generates a PMREM from a scene, optionally applying a Gaussian blur before
81
+ * GGX filtering.
97
82
  *
98
83
  * @param {Scene} scene - The scene to be captured.
99
84
  * @param {number} [sigma=0] - The blur radius in radians.
100
85
  * @param {number} [near=0.1] - The near plane distance.
101
86
  * @param {number} [far=100] - The far plane distance.
102
87
  * @param {Object} [options={}] - The configuration options.
103
- * @param {number} [options.size=256] - The texture size of the PMREM.
88
+ * @param {number} [options.size=256] - The texture size of the PMREM, rounded down to a power of two and at least 256.
104
89
  * @param {Vector3} [options.position=origin] - The position of the internal cube camera that renders the scene.
105
- * @return {WebGLRenderTarget} The resulting PMREM.
90
+ * @return {WebGLCubeRenderTarget} The resulting PMREM.
106
91
  */
107
92
  fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) {
108
93
 
@@ -111,42 +96,66 @@ class PMREMGenerator {
111
96
  position = _origin,
112
97
  } = options;
113
98
 
114
- _oldTarget = this._renderer.getRenderTarget();
115
- _oldActiveCubeFace = this._renderer.getActiveCubeFace();
116
- _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
117
- _oldXrEnabled = this._renderer.xr.enabled;
118
-
119
- this._renderer.xr.enabled = false;
99
+ const renderer = this._renderer;
120
100
 
121
101
  this._setSize( size );
122
102
 
123
- const cubeUVRenderTarget = this._allocateTargets();
124
- cubeUVRenderTarget.depthBuffer = true;
103
+ const pmremTarget = this._allocateTarget();
104
+ const sourceTarget = this._getSourceTarget( true );
105
+
106
+ if ( sigma > 0 ) {
107
+
108
+ sourceTarget.texture.mipmapsAutoUpdate = false;
109
+
110
+ }
111
+
112
+ // Clear every captured face, independent of the application's clear settings.
125
113
 
126
- this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position );
114
+ const autoClear = renderer.autoClear;
115
+ const autoClearColor = renderer.autoClearColor;
116
+ const autoClearDepth = renderer.autoClearDepth;
117
+ const autoClearStencil = renderer.autoClearStencil;
118
+ const background = scene.background;
119
+
120
+ renderer.autoClear = true;
121
+ renderer.autoClearColor = true;
122
+ renderer.autoClearDepth = true;
123
+ renderer.autoClearStencil = true;
124
+
125
+ if ( background === null ) scene.background = renderer.getClearColor( _clearColor );
126
+
127
+ const cubeCamera = new CubeCamera( near, far, sourceTarget );
128
+ cubeCamera.position.copy( position );
129
+ cubeCamera.update( renderer, scene );
130
+
131
+ renderer.autoClear = autoClear;
132
+ renderer.autoClearColor = autoClearColor;
133
+ renderer.autoClearDepth = autoClearDepth;
134
+ renderer.autoClearStencil = autoClearStencil;
135
+
136
+ scene.background = background;
127
137
 
128
138
  if ( sigma > 0 ) {
129
139
 
130
- this._blur( cubeUVRenderTarget, 0, 0, sigma );
140
+ sourceTarget.texture.mipmapsAutoUpdate = true;
141
+ this._blur( pmremTarget, sigma );
131
142
 
132
143
  }
133
144
 
134
- this._applyPMREM( cubeUVRenderTarget );
135
- this._cleanup( cubeUVRenderTarget );
145
+ this._applyPMREM( pmremTarget );
136
146
 
137
- return cubeUVRenderTarget;
147
+ return pmremTarget;
138
148
 
139
149
  }
140
150
 
141
151
  /**
142
- * Generates a PMREM from an equirectangular texture, which can be either LDR
143
- * or HDR. The ideal input image size is 1k (1024 x 512), as this matches best
144
- * with the 256 x 256 cubemap output. The minimum supported input image size
145
- * is 64 x 32.
152
+ * Generates a PMREM from an LDR or HDR equirectangular texture. The cube face
153
+ * size is one quarter of the image width, rounded down to a power of two and
154
+ * at least 256.
146
155
  *
147
156
  * @param {Texture} equirectangular - The equirectangular texture to be converted.
148
- * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
149
- * @return {WebGLRenderTarget} The resulting PMREM.
157
+ * @param {?WebGLCubeRenderTarget} [renderTarget=null] - The render target to use.
158
+ * @return {WebGLCubeRenderTarget} The resulting PMREM.
150
159
  */
151
160
  fromEquirectangular( equirectangular, renderTarget = null ) {
152
161
 
@@ -155,14 +164,12 @@ class PMREMGenerator {
155
164
  }
156
165
 
157
166
  /**
158
- * Generates a PMREM from an cubemap texture, which can be either LDR
159
- * or HDR. The ideal input cube size is 256 x 256, as this matches best
160
- * with the 256 x 256 cubemap output. The minimum supported input cube
161
- * size is 16 x 16 per face.
167
+ * Generates a PMREM from an LDR or HDR cubemap. The cube face size matches
168
+ * the input, rounded down to a power of two and at least 256.
162
169
  *
163
170
  * @param {Texture} cubemap - The cubemap texture to be converted.
164
- * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
165
- * @return {WebGLRenderTarget} The resulting PMREM.
171
+ * @param {?WebGLCubeRenderTarget} [renderTarget=null] - The render target to use.
172
+ * @return {WebGLCubeRenderTarget} The resulting PMREM.
166
173
  */
167
174
  fromCubemap( cubemap, renderTarget = null ) {
168
175
 
@@ -201,57 +208,42 @@ class PMREMGenerator {
201
208
  }
202
209
 
203
210
  /**
204
- * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
205
- * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
206
- * one of them will cause any others to also become unusable.
211
+ * Disposes of the PMREMGenerator's internal memory. The PMREMs it returned
212
+ * belong to the caller and are not disposed.
207
213
  */
208
214
  dispose() {
209
215
 
210
- this._dispose();
216
+ if ( this._sourceTarget !== null ) this._sourceTarget.dispose();
211
217
 
212
218
  if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
213
219
  if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
214
-
215
- if ( this._backgroundBox !== null ) {
216
-
217
- this._backgroundBox.geometry.dispose();
218
- this._backgroundBox.material.dispose();
219
-
220
- }
221
-
222
- }
223
-
224
- // private interface
225
-
226
- _setSize( cubeSize ) {
227
-
228
- this._lodMax = Math.floor( Math.log2( cubeSize ) );
229
- this._cubeSize = Math.pow( 2, this._lodMax );
230
-
231
- }
232
-
233
- _dispose() {
234
-
235
220
  if ( this._blurMaterial !== null ) this._blurMaterial.dispose();
236
221
  if ( this._ggxMaterial !== null ) this._ggxMaterial.dispose();
222
+ if ( this._integrationMaterial !== null ) this._integrationMaterial.dispose();
237
223
 
238
- if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();
224
+ this._boxMesh.geometry.dispose();
239
225
 
240
- for ( let i = 0; i < this._lodMeshes.length; i ++ ) {
226
+ }
241
227
 
242
- this._lodMeshes[ i ].geometry.dispose();
228
+ /**
229
+ * Returns the roughness a mip level of a PMREM has been prefiltered for.
230
+ * The inverse mapping is used by the renderers when sampling a PMREM.
231
+ *
232
+ * @param {number} lod - The mip level.
233
+ * @param {number} maxLod - The last mip level of the PMREM.
234
+ * @return {number} The roughness.
235
+ */
236
+ static lodToRoughness( lod, maxLod ) {
243
237
 
244
- }
238
+ return maxLod > 0 ? 1 - Math.sqrt( 1 - lod / maxLod ) : 0;
245
239
 
246
240
  }
247
241
 
248
- _cleanup( outputTarget ) {
242
+ // private interface
249
243
 
250
- this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
251
- this._renderer.xr.enabled = _oldXrEnabled;
244
+ _setSize( cubeSize ) {
252
245
 
253
- outputTarget.scissorTest = false;
254
- _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
246
+ this._cubeSize = Math.max( MIN_SIZE, floorPowerOfTwo( cubeSize ) );
255
247
 
256
248
  }
257
249
 
@@ -259,7 +251,7 @@ class PMREMGenerator {
259
251
 
260
252
  if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
261
253
 
262
- this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
254
+ this._setSize( texture.image.length === 0 ? MIN_SIZE : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
263
255
 
264
256
  } else { // Equirectangular
265
257
 
@@ -267,187 +259,97 @@ class PMREMGenerator {
267
259
 
268
260
  }
269
261
 
270
- _oldTarget = this._renderer.getRenderTarget();
271
- _oldActiveCubeFace = this._renderer.getActiveCubeFace();
272
- _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
273
- _oldXrEnabled = this._renderer.xr.enabled;
274
-
275
- this._renderer.xr.enabled = false;
262
+ const pmremTarget = renderTarget || this._allocateTarget();
276
263
 
277
- const cubeUVRenderTarget = renderTarget || this._allocateTargets();
278
- this._textureToCubeUV( texture, cubeUVRenderTarget );
279
- this._applyPMREM( cubeUVRenderTarget );
280
- this._cleanup( cubeUVRenderTarget );
264
+ this._textureToCubemap( texture );
265
+ this._applyPMREM( pmremTarget );
281
266
 
282
- return cubeUVRenderTarget;
267
+ return pmremTarget;
283
268
 
284
269
  }
285
270
 
286
- _allocateTargets() {
287
-
288
- const width = 3 * Math.max( this._cubeSize, 16 * 7 );
289
- const height = 4 * this._cubeSize;
290
-
291
- const params = {
292
- magFilter: LinearFilter,
293
- minFilter: LinearFilter,
294
- generateMipmaps: false,
295
- type: HalfFloatType,
296
- format: RGBAFormat,
297
- colorSpace: LinearSRGBColorSpace,
298
- depthBuffer: false
299
- };
271
+ _allocateTarget() {
300
272
 
301
- const cubeUVRenderTarget = _createRenderTarget( width, height, params );
302
-
303
- if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {
304
-
305
- if ( this._pingPongRenderTarget !== null ) {
273
+ const size = this._cubeSize;
306
274
 
307
- this._dispose();
275
+ const pmremTarget = _createRenderTarget( size, false, false );
308
276
 
309
- }
277
+ // Allocate only the prefiltered mip levels without automatic mipmap generation.
310
278
 
311
- this._pingPongRenderTarget = _createRenderTarget( width, height, params );
279
+ const maxLod = Math.log2( size ) - LOD_MIN;
312
280
 
313
- const { _lodMax } = this;
314
- ( { lodMeshes: this._lodMeshes, sizeLods: this._sizeLods } = _createPlanes( _lodMax ) );
281
+ for ( let lod = 0; lod <= maxLod; lod ++ ) {
315
282
 
316
- this._blurMaterial = _getBlurShader( _lodMax, width, height );
317
- this._ggxMaterial = _getGGXShader( _lodMax, width, height );
283
+ pmremTarget.texture.mipmaps.push( { width: size >> lod, height: size >> lod } );
318
284
 
319
285
  }
320
286
 
321
- return cubeUVRenderTarget;
287
+ pmremTarget.texture.name = 'PMREM';
288
+ pmremTarget.texture.isPMREMTexture = true;
322
289
 
323
- }
324
-
325
- _compileMaterial( material ) {
326
-
327
- const mesh = new Mesh( new BufferGeometry(), material );
328
- this._renderer.compile( mesh, _flatCamera );
290
+ return pmremTarget;
329
291
 
330
292
  }
331
293
 
332
- _sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ) {
333
-
334
- const fov = 90;
335
- const aspect = 1;
336
- const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
337
- const upSign = [ 1, - 1, 1, 1, 1, 1 ];
338
- const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
339
- const renderer = this._renderer;
340
-
341
- const originalAutoClear = renderer.autoClear;
342
- const toneMapping = renderer.toneMapping;
343
- renderer.getClearColor( _clearColor );
294
+ _getSourceTarget( depthBuffer = false ) {
344
295
 
345
- renderer.toneMapping = NoToneMapping;
346
- renderer.autoClear = false;
347
-
348
- // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812
349
- const reversedDepthBuffer = renderer.state.buffers.depth.getReversed();
350
-
351
- if ( reversedDepthBuffer ) {
352
-
353
- renderer.setRenderTarget( cubeUVRenderTarget );
354
- renderer.clearDepth();
355
- renderer.setRenderTarget( null );
356
-
357
- }
358
-
359
- if ( this._backgroundBox === null ) {
360
-
361
- this._backgroundBox = new Mesh(
362
- new BoxGeometry(),
363
- new MeshBasicMaterial( {
364
- name: 'PMREM.Background',
365
- side: BackSide,
366
- depthWrite: false,
367
- depthTest: false,
368
- } )
369
- );
370
-
371
- }
372
-
373
- const backgroundBox = this._backgroundBox;
374
- const backgroundMaterial = backgroundBox.material;
375
-
376
- let useSolidColor = false;
377
-
378
- const background = scene.background;
379
-
380
- if ( background ) {
381
-
382
- if ( background.isColor ) {
383
-
384
- backgroundMaterial.color.copy( background );
385
- scene.background = null;
386
- useSolidColor = true;
296
+ const size = this._cubeSize;
297
+ const sourceTarget = this._sourceTarget;
387
298
 
388
- }
299
+ if ( sourceTarget === null || sourceTarget.width !== size || ( depthBuffer && sourceTarget.depthBuffer === false ) ) {
389
300
 
390
- } else {
301
+ if ( sourceTarget !== null ) sourceTarget.dispose();
391
302
 
392
- backgroundMaterial.color.copy( _clearColor );
393
- useSolidColor = true;
303
+ this._sourceTarget = _createRenderTarget( size, true, depthBuffer );
394
304
 
395
305
  }
396
306
 
397
- for ( let i = 0; i < 6; i ++ ) {
398
-
399
- const col = i % 3;
400
-
401
- if ( col === 0 ) {
402
-
403
- cubeCamera.up.set( 0, upSign[ i ], 0 );
404
- cubeCamera.position.set( position.x, position.y, position.z );
405
- cubeCamera.lookAt( position.x + forwardSign[ i ], position.y, position.z );
406
-
407
- } else if ( col === 1 ) {
408
-
409
- cubeCamera.up.set( 0, 0, upSign[ i ] );
410
- cubeCamera.position.set( position.x, position.y, position.z );
411
- cubeCamera.lookAt( position.x, position.y + forwardSign[ i ], position.z );
307
+ return this._sourceTarget;
412
308
 
309
+ }
413
310
 
414
- } else {
311
+ _compileMaterial( material ) {
415
312
 
416
- cubeCamera.up.set( 0, upSign[ i ], 0 );
417
- cubeCamera.position.set( position.x, position.y, position.z );
418
- cubeCamera.lookAt( position.x, position.y, position.z + forwardSign[ i ] );
313
+ this._boxMesh.material = material;
314
+ this._renderer.compile( this._boxMesh, this._cubeCamera.children[ 0 ] );
419
315
 
420
- }
316
+ }
421
317
 
422
- const size = this._cubeSize;
318
+ /**
319
+ * Renders the box mesh with the given material into all six faces of a cube render target.
320
+ *
321
+ * @private
322
+ * @param {WebGLCubeRenderTarget} target - The render target.
323
+ * @param {number} lod - The mip level to render into.
324
+ * @param {ShaderMaterial} material - The material.
325
+ */
326
+ _renderCube( target, lod, material ) {
423
327
 
424
- _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );
328
+ const boxMesh = this._boxMesh;
329
+ const cubeCamera = this._cubeCamera;
425
330
 
426
- renderer.setRenderTarget( cubeUVRenderTarget );
331
+ boxMesh.material = material;
427
332
 
428
- if ( useSolidColor ) {
333
+ cubeCamera.renderTarget = target;
334
+ cubeCamera.activeMipmapLevel = lod;
429
335
 
430
- renderer.render( backgroundBox, cubeCamera );
336
+ // WebGLRenderer uses the target viewport without scaling it to the active mip.
431
337
 
432
- }
338
+ const size = target.width >> lod;
433
339
 
434
- renderer.render( scene, cubeCamera );
340
+ target.viewport.set( 0, 0, size, size );
435
341
 
436
- }
342
+ cubeCamera.update( this._renderer, boxMesh );
437
343
 
438
- renderer.toneMapping = toneMapping;
439
- renderer.autoClear = originalAutoClear;
440
- scene.background = background;
344
+ target.viewport.set( 0, 0, target.width, target.height );
441
345
 
442
346
  }
443
347
 
444
- _textureToCubeUV( texture, cubeUVRenderTarget ) {
445
-
446
- const renderer = this._renderer;
348
+ _textureToCubemap( texture ) {
447
349
 
448
- const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
350
+ let material;
449
351
 
450
- if ( isCubeTexture ) {
352
+ if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
451
353
 
452
354
  if ( this._cubemapMaterial === null ) {
453
355
 
@@ -455,7 +357,8 @@ class PMREMGenerator {
455
357
 
456
358
  }
457
359
 
458
- this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
360
+ material = this._cubemapMaterial;
361
+ material.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
459
362
 
460
363
  } else {
461
364
 
@@ -465,598 +368,402 @@ class PMREMGenerator {
465
368
 
466
369
  }
467
370
 
468
- }
469
-
470
- const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
471
-
472
- const mesh = this._lodMeshes[ 0 ];
473
- mesh.material = material;
474
-
475
- const uniforms = material.uniforms;
476
-
477
- uniforms[ 'envMap' ].value = texture;
371
+ material = this._equirectMaterial;
478
372
 
479
- const size = this._cubeSize;
373
+ }
480
374
 
481
- _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
375
+ material.uniforms.envMap.value = texture;
482
376
 
483
- renderer.setRenderTarget( cubeUVRenderTarget );
484
- renderer.render( mesh, _flatCamera );
377
+ this._renderCube( this._getSourceTarget(), 0, material );
485
378
 
486
379
  }
487
380
 
488
- _applyPMREM( cubeUVRenderTarget ) {
489
-
490
- const renderer = this._renderer;
491
- const autoClear = renderer.autoClear;
492
- renderer.autoClear = false;
493
-
494
- const n = this._lodMeshes.length;
381
+ /**
382
+ * Prefilters the source cubemap into the mip levels of the PMREM. The sharp levels
383
+ * integrate the GGX lobe of their roughness with VNDF importance sampling, reading the
384
+ * mip level of the source that matches the solid angle of each sample. The rough
385
+ * levels weight every texel of a small source mip with the GGX lobe instead.
386
+ *
387
+ * @private
388
+ * @param {WebGLCubeRenderTarget} pmremTarget - The PMREM.
389
+ */
390
+ _applyPMREM( pmremTarget ) {
495
391
 
496
- // Use GGX VNDF importance sampling
497
- for ( let i = 1; i < n; i ++ ) {
392
+ if ( this._ggxMaterial === null ) {
498
393
 
499
- this._applyGGXFilter( cubeUVRenderTarget, i - 1, i );
394
+ this._ggxMaterial = _getGGXMaterial();
395
+ this._integrationMaterial = _getIntegrationMaterial();
500
396
 
501
397
  }
502
398
 
503
- renderer.autoClear = autoClear;
399
+ const size = this._cubeSize;
400
+ const maxLod = pmremTarget.texture.mipmaps.length - 1;
504
401
 
505
- }
402
+ const ggxUniforms = this._ggxMaterial.uniforms;
403
+ ggxUniforms.envMap.value = this._sourceTarget.texture;
506
404
 
507
- /**
508
- * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map.
509
- * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the
510
- * GGX BRDF for physically-based rendering. Reads from the previous LOD level and
511
- * applies incremental roughness filtering to avoid over-blurring.
512
- *
513
- * @private
514
- * @param {WebGLRenderTarget} cubeUVRenderTarget
515
- * @param {number} lodIn - Source LOD level to read from
516
- * @param {number} lodOut - Target LOD level to write to
517
- */
518
- _applyGGXFilter( cubeUVRenderTarget, lodIn, lodOut ) {
405
+ const integrationUniforms = this._integrationMaterial.uniforms;
406
+ integrationUniforms.envMap.value = this._sourceTarget.texture;
407
+ integrationUniforms.sourceLod.value = Math.log2( size / INTEGRATION_SIZE );
519
408
 
520
- const renderer = this._renderer;
521
- const pingPongRenderTarget = this._pingPongRenderTarget;
409
+ for ( let lod = 0; lod <= maxLod; lod ++ ) {
522
410
 
523
- const ggxMaterial = this._ggxMaterial;
524
- const ggxMesh = this._lodMeshes[ lodOut ];
525
- ggxMesh.material = ggxMaterial;
411
+ const roughness = PMREMGenerator.lodToRoughness( lod, maxLod );
526
412
 
527
- const ggxUniforms = ggxMaterial.uniforms;
413
+ if ( lod > maxLod - INTEGRATION_LEVELS ) {
528
414
 
529
- // Calculate incremental roughness between LOD levels
530
- const targetRoughness = lodOut / ( this._lodMeshes.length - 1 );
531
- const sourceRoughness = lodIn / ( this._lodMeshes.length - 1 );
532
- const incrementalRoughness = Math.sqrt( targetRoughness * targetRoughness - sourceRoughness * sourceRoughness );
415
+ integrationUniforms.roughness.value = roughness;
533
416
 
534
- // Apply blur strength mapping for better quality across the roughness range
535
- const blurStrength = targetRoughness * 1.25;
536
- const adjustedRoughness = incrementalRoughness * blurStrength;
417
+ this._renderCube( pmremTarget, lod, this._integrationMaterial );
537
418
 
538
- // Calculate viewport position based on output LOD level
539
- const { _lodMax } = this;
540
- const outputSize = this._sizeLods[ lodOut ];
541
- const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
542
- const y = 4 * ( this._cubeSize - outputSize );
419
+ } else {
420
+
421
+ // For V = N, pdf( L ) = D( H ) / 4. Match the source texel solid angle to
422
+ // 1 / ( GGX_SAMPLES * pdf ), with a half-mip bias to reduce sampling noise.
423
+ // The shader supplies log2 of the GGX denominator.
424
+ const lodBias = roughness > 0 ? Math.log2( size ) + 0.5 * Math.log2( 6 / ( GGX_SAMPLES * Math.pow( roughness, 4 ) ) ) + 0.5 : 0;
543
425
 
544
- // Read from previous LOD with incremental roughness
545
- ggxUniforms[ 'envMap' ].value = cubeUVRenderTarget.texture;
546
- ggxUniforms[ 'roughness' ].value = adjustedRoughness;
547
- ggxUniforms[ 'mipInt' ].value = _lodMax - lodIn; // Sample from input LOD
426
+ ggxUniforms.roughness.value = roughness;
427
+ ggxUniforms.lodBias.value = lodBias;
548
428
 
549
- _setViewport( pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize );
550
- renderer.setRenderTarget( pingPongRenderTarget );
551
- renderer.render( ggxMesh, _flatCamera );
429
+ this._renderCube( pmremTarget, lod, this._ggxMaterial );
552
430
 
553
- // Copy from pingPong back to cubeUV (simple direct copy)
554
- ggxUniforms[ 'envMap' ].value = pingPongRenderTarget.texture;
555
- ggxUniforms[ 'roughness' ].value = 0.0; // Direct copy
556
- ggxUniforms[ 'mipInt' ].value = _lodMax - lodOut; // Read from the level we just wrote
431
+ }
557
432
 
558
- _setViewport( cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize );
559
- renderer.setRenderTarget( cubeUVRenderTarget );
560
- renderer.render( ggxMesh, _flatCamera );
433
+ }
561
434
 
562
435
  }
563
436
 
564
437
  /**
565
- * This is a two-pass Gaussian blur for a cubemap. Each pass importance-samples
566
- * the Gaussian along a spiral kernel (Golden Angle), which distributes samples
567
- * isotropically on the sphere (no pole artifacts).
568
- *
569
- * Used for initial scene blur in fromScene() method when sigma > 0.
438
+ * Applies the initial fromScene() blur in two passes using a golden-angle
439
+ * spiral kernel. Level 0 of the PMREM serves as the intermediate target.
570
440
  *
571
441
  * @private
572
- * @param {WebGLRenderTarget} cubeUVRenderTarget
573
- * @param {number} lodIn
574
- * @param {number} lodOut
575
- * @param {number} sigma
442
+ * @param {WebGLCubeRenderTarget} pmremTarget - The PMREM.
443
+ * @param {number} sigma - The blur radius in radians.
576
444
  */
577
- _blur( cubeUVRenderTarget, lodIn, lodOut, sigma ) {
578
-
579
- const pingPongRenderTarget = this._pingPongRenderTarget;
445
+ _blur( pmremTarget, sigma ) {
580
446
 
581
- // Two passes of sigma / sqrt( 2 ) compose to a blur of sigma while squaring
582
- // the effective sample count. Sigmas beyond PI are visually indistinguishable
583
- // from a uniform blur, so clamp to keep the shader math finite.
584
- const blurSigma = Math.min( sigma, Math.PI ) / Math.SQRT2;
447
+ if ( this._blurMaterial === null ) {
585
448
 
586
- this._blurPass( cubeUVRenderTarget, pingPongRenderTarget, lodIn, lodOut, blurSigma );
587
- this._blurPass( pingPongRenderTarget, cubeUVRenderTarget, lodOut, lodOut, blurSigma );
588
-
589
- }
449
+ this._blurMaterial = _getBlurMaterial();
590
450
 
591
- _blurPass( targetIn, targetOut, lodIn, lodOut, sigmaRadians ) {
592
-
593
- const renderer = this._renderer;
594
- const blurMaterial = this._blurMaterial;
451
+ }
595
452
 
596
- const blurMesh = this._lodMeshes[ lodOut ];
597
- blurMesh.material = blurMaterial;
453
+ const material = this._blurMaterial;
454
+ const uniforms = material.uniforms;
598
455
 
599
- const blurUniforms = blurMaterial.uniforms;
456
+ const sourceTarget = this._sourceTarget;
600
457
 
601
- blurUniforms[ 'envMap' ].value = targetIn.texture;
602
- blurUniforms[ 'sigma' ].value = sigmaRadians;
603
- blurUniforms[ 'mipInt' ].value = this._lodMax - lodIn;
458
+ // Split the blur variance between two passes. Clamp sigma to the sphere's
459
+ // maximum angular distance.
460
+ uniforms.sigma.value = Math.min( sigma, Math.PI ) / Math.SQRT2;
604
461
 
605
- const outputSize = this._sizeLods[ lodOut ];
606
- const x = 3 * outputSize * ( lodOut > this._lodMax - LOD_MIN ? lodOut - this._lodMax + LOD_MIN : 0 );
607
- const y = 4 * ( this._cubeSize - outputSize );
462
+ uniforms.envMap.value = sourceTarget.texture;
463
+ this._renderCube( pmremTarget, 0, material );
608
464
 
609
- _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
610
- renderer.setRenderTarget( targetOut );
611
- renderer.render( blurMesh, _flatCamera );
465
+ uniforms.envMap.value = pmremTarget.texture;
466
+ this._renderCube( sourceTarget, 0, material );
612
467
 
613
468
  }
614
469
 
615
470
  }
616
471
 
472
+ function _createRenderTarget( size, generateMipmaps, depthBuffer ) {
617
473
 
474
+ return new WebGLCubeRenderTarget( size, {
475
+ minFilter: LinearMipmapLinearFilter,
476
+ generateMipmaps: generateMipmaps,
477
+ type: HalfFloatType,
478
+ colorSpace: LinearSRGBColorSpace,
479
+ depthBuffer: depthBuffer
480
+ } );
618
481
 
619
- function _createPlanes( lodMax ) {
620
-
621
- const sizeLods = [];
622
- const lodMeshes = [];
623
-
624
- let lod = lodMax;
625
-
626
- const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LODS;
627
-
628
- for ( let i = 0; i < totalLods; i ++ ) {
629
-
630
- const sizeLod = Math.pow( 2, lod );
631
- sizeLods.push( sizeLod );
632
-
633
- // UVs overshoot the face by one texel to bake the CubeUV border into the directions.
634
- const texelSize = 1.0 / ( sizeLod - 2 );
635
- const min = - texelSize;
636
- const max = 1 + texelSize;
637
- const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
638
-
639
- const cubeFaces = 6;
640
- const vertices = 6;
641
- const positionSize = 3;
642
-
643
- const position = new Float32Array( positionSize * vertices * cubeFaces );
644
- const outputDirection = new Float32Array( positionSize * vertices * cubeFaces );
645
-
646
- for ( let face = 0; face < cubeFaces; face ++ ) {
647
-
648
- const x = ( face % 3 ) * 2 / 3 - 1;
649
- const y = face > 2 ? 0 : - 1;
650
- const coordinates = [
651
- x, y, 0,
652
- x + 2 / 3, y, 0,
653
- x + 2 / 3, y + 1, 0,
654
- x, y, 0,
655
- x + 2 / 3, y + 1, 0,
656
- x, y + 1, 0
657
- ];
658
- position.set( coordinates, positionSize * vertices * face );
659
-
660
- for ( let vertex = 0; vertex < vertices; vertex ++ ) {
482
+ }
661
483
 
662
- const u = uv1[ vertex * 2 ] * 2 - 1;
663
- const v = uv1[ vertex * 2 + 1 ] * 2 - 1;
484
+ function _getMaterial( name, uniforms, fragmentShader ) {
664
485
 
665
- // RH coordinate system; PMREM face-indexing convention
666
- if ( face === 0 ) {
486
+ return new ShaderMaterial( {
667
487
 
668
- _direction.set( 1, v, u ); // pos x
488
+ name: name,
669
489
 
670
- } else if ( face === 1 ) {
490
+ uniforms: uniforms,
671
491
 
672
- _direction.set( - u, 1, - v ); // pos y
492
+ vertexShader: ShaderChunk.cube_vert,
493
+ fragmentShader: fragmentShader,
673
494
 
674
- } else if ( face === 2 ) {
495
+ side: BackSide,
496
+ blending: NoBlending,
497
+ depthTest: false,
498
+ depthWrite: false
675
499
 
676
- _direction.set( - u, v, 1 ); // pos z
500
+ } );
677
501
 
678
- } else if ( face === 3 ) {
502
+ }
679
503
 
680
- _direction.set( - 1, v, - u ); // neg x
504
+ function _getGGXMaterial() {
681
505
 
682
- } else if ( face === 4 ) {
506
+ return _getMaterial( 'PMREMGGXConvolution', {
507
+ 'envMap': { value: null },
508
+ 'roughness': { value: 0 },
509
+ 'lodBias': { value: 0 }
510
+ }, /* glsl */`
683
511
 
684
- _direction.set( - u, - 1, v ); // neg y
512
+ #define GGX_SAMPLES ${ GGX_SAMPLES }u
685
513
 
686
- } else {
514
+ varying vec3 vWorldDirection;
687
515
 
688
- _direction.set( u, v, - 1 ); // neg z
516
+ uniform samplerCube envMap;
517
+ uniform float roughness;
518
+ uniform float lodBias;
689
519
 
690
- }
520
+ #include <common>
691
521
 
692
- _direction.toArray( outputDirection, ( face * vertices + vertex ) * positionSize );
522
+ // Van der Corput radical inverse
523
+ float radicalInverse_VdC( uint bits ) {
693
524
 
694
- }
525
+ bits = ( bits << 16u ) | ( bits >> 16u );
526
+ bits = ( ( bits & 0x55555555u ) << 1u ) | ( ( bits & 0xAAAAAAAAu ) >> 1u );
527
+ bits = ( ( bits & 0x33333333u ) << 2u ) | ( ( bits & 0xCCCCCCCCu ) >> 2u );
528
+ bits = ( ( bits & 0x0F0F0F0Fu ) << 4u ) | ( ( bits & 0xF0F0F0F0u ) >> 4u );
529
+ bits = ( ( bits & 0x00FF00FFu ) << 8u ) | ( ( bits & 0xFF00FF00u ) >> 8u );
530
+ return float( bits ) * 2.3283064365386963e-10; // / 0x100000000
695
531
 
696
532
  }
697
533
 
698
- const planes = new BufferGeometry();
699
- planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
700
- planes.setAttribute( 'outputDirection', new BufferAttribute( outputDirection, positionSize ) );
701
- lodMeshes.push( new Mesh( planes, null ) );
702
-
703
- if ( lod > LOD_MIN ) {
534
+ // Hammersley sequence
535
+ vec2 hammersley( uint i, uint N ) {
704
536
 
705
- lod --;
537
+ return vec2( float( i ) / float( N ), radicalInverse_VdC( i ) );
706
538
 
707
539
  }
708
540
 
709
- }
710
-
711
- return { lodMeshes, sizeLods };
712
-
713
- }
714
-
715
- function _createRenderTarget( width, height, params ) {
716
-
717
- const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );
718
- cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
719
- cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
720
- cubeUVRenderTarget.scissorTest = true;
721
- return cubeUVRenderTarget;
722
-
723
- }
724
-
725
- function _setViewport( target, x, y, width, height ) {
726
-
727
- target.viewport.set( x, y, width, height );
728
- target.scissor.set( x, y, width, height );
729
-
730
- }
731
-
732
- function _getGGXShader( lodMax, width, height ) {
733
-
734
- const shaderMaterial = new ShaderMaterial( {
735
-
736
- name: 'PMREMGGXConvolution',
737
-
738
- defines: {
739
- 'GGX_SAMPLES': GGX_SAMPLES,
740
- 'CUBEUV_TEXEL_WIDTH': 1.0 / width,
741
- 'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
742
- 'CUBEUV_MAX_MIP': `${lodMax}.0`,
743
- },
744
-
745
- uniforms: {
746
- 'envMap': { value: null },
747
- 'roughness': { value: 0.0 },
748
- 'mipInt': { value: 0 }
749
- },
750
-
751
- vertexShader: _getCommonVertexShader(),
752
-
753
- fragmentShader: /* glsl */`
754
-
755
- precision highp float;
756
- precision highp int;
757
-
758
- varying vec3 vOutputDirection;
759
-
760
- uniform sampler2D envMap;
761
- uniform float roughness;
762
- uniform float mipInt;
763
-
764
- #define ENVMAP_TYPE_CUBE_UV
765
- #include <cube_uv_reflection_fragment>
541
+ void main() {
766
542
 
767
- #define PI 3.14159265359
543
+ vec3 N = normalize( vWorldDirection );
768
544
 
769
- // Van der Corput radical inverse
770
- float radicalInverse_VdC(uint bits) {
771
- bits = (bits << 16u) | (bits >> 16u);
772
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
773
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
774
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
775
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
776
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
777
- }
545
+ // For very low roughness, just sample the environment directly
546
+ if ( roughness < 0.001 ) {
778
547
 
779
- // Hammersley sequence
780
- vec2 hammersley(uint i, uint N) {
781
- return vec2(float(i) / float(N), radicalInverse_VdC(i));
782
- }
548
+ gl_FragColor = vec4( textureLod( envMap, N, 0.0 ).rgb, 1.0 );
549
+ return;
783
550
 
784
- // GGX VNDF importance sampling (Eric Heitz 2018)
785
- // "Sampling the GGX Distribution of Visible Normals"
786
- // https://jcgt.org/published/0007/04/01/
787
- vec3 importanceSampleGGX_VNDF(vec2 Xi, vec3 V, float roughness) {
788
- float alpha = roughness * roughness;
789
-
790
- // Section 4.1: Orthonormal basis
791
- vec3 T1 = vec3(1.0, 0.0, 0.0);
792
- vec3 T2 = cross(V, T1);
793
-
794
- // Section 4.2: Parameterization of projected area
795
- float r = sqrt(Xi.x);
796
- float phi = 2.0 * PI * Xi.y;
797
- float t1 = r * cos(phi);
798
- float t2 = r * sin(phi);
799
- float s = 0.5 * (1.0 + V.z);
800
- t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
801
-
802
- // Section 4.3: Reprojection onto hemisphere
803
- vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * V;
804
-
805
- // Section 3.4: Transform back to ellipsoid configuration
806
- return normalize(vec3(alpha * Nh.x, alpha * Nh.y, max(0.0, Nh.z)));
807
551
  }
808
552
 
809
- void main() {
810
- vec3 N = normalize(vOutputDirection);
811
- vec3 V = N; // Assume view direction equals normal for pre-filtering
553
+ float alpha = roughness * roughness;
554
+ float alpha2 = alpha * alpha;
812
555
 
813
- vec3 prefilteredColor = vec3(0.0);
814
- float totalWeight = 0.0;
556
+ // Tangent space basis for VNDF sampling
557
+ vec3 up = abs( N.z ) < 0.999 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 1.0, 0.0, 0.0 );
558
+ vec3 tangent = normalize( cross( up, N ) );
559
+ vec3 bitangent = cross( N, tangent );
815
560
 
816
- // For very low roughness, just sample the environment directly
817
- if (roughness < 0.001) {
818
- gl_FragColor = vec4(bilinearCubeUV(envMap, N, mipInt), 1.0);
819
- return;
820
- }
561
+ vec3 prefilteredColor = vec3( 0.0 );
562
+ float totalWeight = 0.0;
821
563
 
822
- // Tangent space basis for VNDF sampling
823
- vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
824
- vec3 tangent = normalize(cross(up, N));
825
- vec3 bitangent = cross(N, tangent);
564
+ for ( uint i = 0u; i < GGX_SAMPLES; i ++ ) {
826
565
 
827
- for(uint i = 0u; i < uint(GGX_SAMPLES); i++) {
828
- vec2 Xi = hammersley(i, uint(GGX_SAMPLES));
566
+ vec2 Xi = hammersley( i, GGX_SAMPLES );
829
567
 
830
- // For PMREM, V = N, so in tangent space V is always (0, 0, 1)
831
- vec3 H_tangent = importanceSampleGGX_VNDF(Xi, vec3(0.0, 0.0, 1.0), roughness);
568
+ // With V = N, sample the reflected direction directly.
569
+ float invQ = 1.0 / ( 1.0 - Xi.x + alpha2 * Xi.x );
570
+ float NdotL = ( 1.0 - Xi.x - alpha2 * Xi.x ) * invQ;
832
571
 
833
- // Transform H back to world space
834
- vec3 H = normalize(tangent * H_tangent.x + bitangent * H_tangent.y + N * H_tangent.z);
835
- vec3 L = normalize(2.0 * dot(V, H) * H - V);
572
+ if ( NdotL > 0.0 ) {
836
573
 
837
- float NdotL = max(dot(N, L), 0.0);
574
+ float phi = 2.0 * PI * Xi.y;
575
+ float sinTheta = 2.0 * alpha * sqrt( Xi.x * ( 1.0 - Xi.x ) ) * invQ;
576
+ vec3 L = N * NdotL + ( tangent * cos( phi ) + bitangent * sin( phi ) ) * sinTheta;
838
577
 
839
- if(NdotL > 0.0) {
840
- // Sample environment at fixed mip level
841
- // VNDF importance sampling handles the distribution filtering
842
- vec3 sampleColor = bilinearCubeUV(envMap, L, mipInt);
578
+ // Match the source mip to the sample's solid angle. The terms
579
+ // independent of the sample are precomputed in lodBias.
580
+ float d = alpha2 * invQ;
581
+ float lod = max( log2( d ) + lodBias, 0.0 );
843
582
 
844
- // Weight by NdotL for the split-sum approximation
845
- // VNDF PDF naturally accounts for the visible microfacet distribution
846
- prefilteredColor += sampleColor * NdotL;
847
- totalWeight += NdotL;
848
- }
849
- }
583
+ // Weight by NdotL for the split-sum approximation
584
+ prefilteredColor += textureLod( envMap, L, lod ).rgb * NdotL;
585
+ totalWeight += NdotL;
850
586
 
851
- if (totalWeight > 0.0) {
852
- prefilteredColor = prefilteredColor / totalWeight;
853
587
  }
854
588
 
855
- gl_FragColor = vec4(prefilteredColor, 1.0);
856
589
  }
857
- `,
858
590
 
859
- blending: NoBlending,
860
- depthTest: false,
861
- depthWrite: false
591
+ gl_FragColor = vec4( prefilteredColor / totalWeight, 1.0 );
862
592
 
863
- } );
864
-
865
- return shaderMaterial;
593
+ }
594
+ ` );
866
595
 
867
596
  }
868
597
 
869
- function _getBlurShader( lodMax, width, height ) {
870
-
871
- const shaderMaterial = new ShaderMaterial( {
598
+ function _getIntegrationMaterial() {
872
599
 
873
- name: 'SphericalGaussianBlur',
600
+ return _getMaterial( 'PMREMGGXIntegration', {
601
+ 'envMap': { value: null },
602
+ 'roughness': { value: 0 },
603
+ 'sourceLod': { value: 0 },
604
+ 'sourceSize': { value: INTEGRATION_SIZE } // a uniform so the loops aren't unrolled
605
+ }, /* glsl */`
874
606
 
875
- defines: {
876
- 'SAMPLES': BLUR_SAMPLES,
877
- 'CUBEUV_TEXEL_WIDTH': 1.0 / width,
878
- 'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
879
- 'CUBEUV_MAX_MIP': `${lodMax}.0`,
880
- },
607
+ varying vec3 vWorldDirection;
881
608
 
882
- uniforms: {
883
- 'envMap': { value: null },
884
- 'sigma': { value: 0 },
885
- 'mipInt': { value: 0 },
886
- },
609
+ uniform samplerCube envMap;
610
+ uniform float roughness;
611
+ uniform float sourceLod;
612
+ uniform int sourceSize;
887
613
 
888
- vertexShader: _getCommonVertexShader(),
889
-
890
- fragmentShader: /* glsl */`
891
-
892
- precision highp float;
893
- precision highp int;
894
-
895
- varying vec3 vOutputDirection;
896
-
897
- uniform sampler2D envMap;
898
- uniform float sigma;
899
- uniform float mipInt;
900
-
901
- #define ENVMAP_TYPE_CUBE_UV
902
- #include <cube_uv_reflection_fragment>
903
-
904
- #define PI 3.14159265359
905
- #define GOLDEN_ANGLE 2.39996322973
614
+ void main() {
906
615
 
907
- void main() {
616
+ vec3 N = normalize( vWorldDirection );
908
617
 
909
- if ( sigma == 0.0 ) {
618
+ float alpha = roughness * roughness;
619
+ float alpha2 = alpha * alpha;
910
620
 
911
- gl_FragColor = vec4( bilinearCubeUV( envMap, vOutputDirection, mipInt ), 1.0 );
912
- return;
621
+ float texelSize = 2.0 / float( sourceSize );
913
622
 
914
- }
623
+ vec3 prefilteredColor = vec3( 0.0 );
624
+ float totalWeight = 0.0;
915
625
 
916
- vec3 outputDirection = normalize( vOutputDirection );
626
+ // Pair opposite texels: only the one in N's hemisphere contributes.
627
+ for ( int face = 0; face < 3; face ++ ) {
917
628
 
918
- vec3 up = abs( outputDirection.z ) < 0.999 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 1.0, 0.0, 0.0 );
919
- vec3 tangent = normalize( cross( up, outputDirection ) );
920
- vec3 bitangent = cross( outputDirection, tangent );
629
+ for ( int y = 0; y < sourceSize; y ++ ) {
921
630
 
922
- // Truncate the kernel at three standard deviations or at the antipode.
923
- float thetaMax = min( 3.0 * sigma, PI );
924
- float truncation = 1.0 - exp( - 0.5 * thetaMax * thetaMax / ( sigma * sigma ) );
631
+ for ( int x = 0; x < sourceSize; x ++ ) {
925
632
 
926
- vec3 accumColor = vec3( 0.0 );
927
- float accumWeight = 0.0;
633
+ vec2 uv = ( vec2( x, y ) + 0.5 ) * texelSize - 1.0;
634
+ vec3 texelDirection = face == 0 ? vec3( 1.0, uv ) : ( face == 1 ? vec3( uv.x, 1.0, uv.y ) : vec3( uv, 1.0 ) );
928
635
 
929
- for ( int i = 0; i < SAMPLES; i ++ ) {
636
+ float invDistance = inversesqrt( 1.0 + dot( uv, uv ) );
637
+ float NdotL = dot( N, texelDirection );
638
+ texelDirection *= NdotL < 0.0 ? - 1.0 : 1.0;
639
+ NdotL = abs( NdotL ) * invDistance;
930
640
 
931
- // Stratified inverse-CDF sampling of the Gaussian, placed on a golden-angle spiral.
932
- float stratum = ( float( i ) + 0.5 ) / float( SAMPLES );
933
- float theta = sigma * sqrt( - 2.0 * log( 1.0 - stratum * truncation ) );
934
- float phi = float( i ) * GOLDEN_ANGLE;
641
+ // With V = N, NdotH squared is ( 1 + NdotL ) / 2. Common factors
642
+ // in the GGX distribution and texel solid angle cancel when normalized.
643
+ float d = 1.0 + alpha2 + ( alpha2 - 1.0 ) * NdotL;
644
+ float weight = NdotL * invDistance * invDistance * invDistance / ( d * d );
935
645
 
936
- vec3 offset = cos( phi ) * tangent + sin( phi ) * bitangent;
937
- vec3 sampleDirection = cos( theta ) * outputDirection + sin( theta ) * offset;
646
+ prefilteredColor += textureLod( envMap, texelDirection, sourceLod ).rgb * weight;
647
+ totalWeight += weight;
938
648
 
939
- // Correct the planar sample density to solid angle.
940
- float weight = sin( theta ) / theta;
941
-
942
- accumColor += weight * bilinearCubeUV( envMap, sampleDirection, mipInt );
943
- accumWeight += weight;
649
+ }
944
650
 
945
651
  }
946
652
 
947
- gl_FragColor = vec4( accumColor / accumWeight, 1.0 );
948
-
949
653
  }
950
- `,
951
654
 
952
- blending: NoBlending,
953
- depthTest: false,
954
- depthWrite: false
655
+ gl_FragColor = vec4( prefilteredColor / totalWeight, 1.0 );
955
656
 
956
- } );
957
-
958
- return shaderMaterial;
657
+ }
658
+ ` );
959
659
 
960
660
  }
961
661
 
962
- function _getEquirectMaterial() {
662
+ function _getBlurMaterial() {
963
663
 
964
- return new ShaderMaterial( {
664
+ return _getMaterial( 'PMREMSphericalGaussianBlur', {
665
+ 'envMap': { value: null },
666
+ 'sigma': { value: 0 }
667
+ }, /* glsl */`
965
668
 
966
- name: 'EquirectangularToCubeUV',
669
+ #define SAMPLES ${ BLUR_SAMPLES }
670
+ #define GOLDEN_ANGLE 2.39996322973
967
671
 
968
- uniforms: {
969
- 'envMap': { value: null }
970
- },
672
+ varying vec3 vWorldDirection;
971
673
 
972
- vertexShader: _getCommonVertexShader(),
674
+ uniform samplerCube envMap;
675
+ uniform float sigma;
973
676
 
974
- fragmentShader: /* glsl */`
677
+ #include <common>
975
678
 
976
- precision mediump float;
977
- precision mediump int;
679
+ void main() {
978
680
 
979
- varying vec3 vOutputDirection;
681
+ vec3 outputDirection = normalize( vWorldDirection );
980
682
 
981
- uniform sampler2D envMap;
683
+ vec3 up = abs( outputDirection.z ) < 0.999 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 1.0, 0.0, 0.0 );
684
+ vec3 tangent = normalize( cross( up, outputDirection ) );
685
+ vec3 bitangent = cross( outputDirection, tangent );
982
686
 
983
- #include <common>
687
+ // Truncate the kernel at three standard deviations or at the antipode.
688
+ float thetaMax = min( 3.0 * sigma, PI );
689
+ float truncation = 1.0 - exp( - 0.5 * thetaMax * thetaMax / ( sigma * sigma ) );
984
690
 
985
- void main() {
691
+ vec3 accumColor = vec3( 0.0 );
692
+ float accumWeight = 0.0;
986
693
 
987
- vec3 outputDirection = normalize( vOutputDirection );
988
- vec2 uv = equirectUv( outputDirection );
694
+ for ( int i = 0; i < SAMPLES; i ++ ) {
989
695
 
990
- gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );
696
+ // Stratified inverse-CDF sampling of the Gaussian, placed on a golden-angle spiral.
697
+ float stratum = ( float( i ) + 0.5 ) / float( SAMPLES );
698
+ float theta = sigma * sqrt( - 2.0 * log( 1.0 - stratum * truncation ) );
699
+ float phi = float( i ) * GOLDEN_ANGLE;
991
700
 
992
- }
993
- `,
701
+ vec3 offset = cos( phi ) * tangent + sin( phi ) * bitangent;
702
+ vec3 sampleDirection = cos( theta ) * outputDirection + sin( theta ) * offset;
994
703
 
995
- blending: NoBlending,
996
- depthTest: false,
997
- depthWrite: false
998
-
999
- } );
704
+ // Correct the planar sample density to solid angle.
705
+ float weight = sin( theta ) / theta;
1000
706
 
1001
- }
707
+ accumColor += weight * textureLod( envMap, sampleDirection, 0.0 ).rgb;
708
+ accumWeight += weight;
1002
709
 
1003
- function _getCubemapMaterial() {
1004
-
1005
- return new ShaderMaterial( {
1006
-
1007
- name: 'CubemapToCubeUV',
710
+ }
1008
711
 
1009
- uniforms: {
1010
- 'envMap': { value: null },
1011
- 'flipEnvMap': { value: - 1 }
1012
- },
712
+ gl_FragColor = vec4( accumColor / accumWeight, 1.0 );
1013
713
 
1014
- vertexShader: _getCommonVertexShader(),
714
+ }
715
+ ` );
1015
716
 
1016
- fragmentShader: /* glsl */`
717
+ }
1017
718
 
1018
- precision mediump float;
1019
- precision mediump int;
719
+ function _getEquirectMaterial() {
1020
720
 
1021
- uniform float flipEnvMap;
721
+ return _getMaterial( 'PMREMEquirectangularToCubemap', {
722
+ 'envMap': { value: null }
723
+ }, /* glsl */`
1022
724
 
1023
- varying vec3 vOutputDirection;
725
+ varying vec3 vWorldDirection;
1024
726
 
1025
- uniform samplerCube envMap;
727
+ uniform sampler2D envMap;
1026
728
 
1027
- void main() {
729
+ #include <common>
1028
730
 
1029
- gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );
731
+ void main() {
1030
732
 
1031
- }
1032
- `,
733
+ // Average four subpixel samples to preserve small, bright features.
734
+ vec3 direction = normalize( vWorldDirection );
735
+ vec3 dx = dFdx( direction ) * 0.25;
736
+ vec3 dy = dFdy( direction ) * 0.25;
1033
737
 
1034
- blending: NoBlending,
1035
- depthTest: false,
1036
- depthWrite: false
738
+ vec3 color = textureLod( envMap, equirectUv( normalize( direction - dx - dy ) ), 0.0 ).rgb;
739
+ color += textureLod( envMap, equirectUv( normalize( direction + dx - dy ) ), 0.0 ).rgb;
740
+ color += textureLod( envMap, equirectUv( normalize( direction - dx + dy ) ), 0.0 ).rgb;
741
+ color += textureLod( envMap, equirectUv( normalize( direction + dx + dy ) ), 0.0 ).rgb;
742
+ gl_FragColor = vec4( color * 0.25, 1.0 );
1037
743
 
1038
- } );
744
+ }
745
+ ` );
1039
746
 
1040
747
  }
1041
748
 
1042
- function _getCommonVertexShader() {
1043
-
1044
- return /* glsl */`
749
+ function _getCubemapMaterial() {
1045
750
 
1046
- precision mediump float;
1047
- precision mediump int;
751
+ return _getMaterial( 'PMREMCubemapToCubemap', {
752
+ 'envMap': { value: null },
753
+ 'flipEnvMap': { value: - 1 }
754
+ }, /* glsl */`
1048
755
 
1049
- attribute vec3 outputDirection;
756
+ varying vec3 vWorldDirection;
1050
757
 
1051
- varying vec3 vOutputDirection;
758
+ uniform samplerCube envMap;
759
+ uniform float flipEnvMap;
1052
760
 
1053
761
  void main() {
1054
762
 
1055
- vOutputDirection = outputDirection;
1056
- gl_Position = vec4( position, 1.0 );
763
+ gl_FragColor = vec4( textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ).rgb, 1.0 );
1057
764
 
1058
765
  }
1059
- `;
766
+ ` );
1060
767
 
1061
768
  }
1062
769