three-base 2.0.142 → 2.0.166
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.
- package/DirectionalLight.d.ts +6 -6
- package/DirectionalLight.js +68 -68
- package/EventMap.d.ts +103 -103
- package/EventMap.js +17 -17
- package/EventMesh.d.ts +18 -18
- package/EventMesh.js +59 -59
- package/ExtrudeMesh.d.ts +112 -112
- package/ExtrudeMesh.js +342 -342
- package/FPScontrol.d.ts +531 -511
- package/FPScontrol.js +1866 -1799
- package/FPScontrol.ts +1922 -1855
- package/Fire/Fire.d.ts +28 -28
- package/Fire/Fire.js +80 -80
- package/Fire/FireGeometry.d.ts +9 -9
- package/Fire/FireGeometry.js +40 -40
- package/Fire/FireMaterial.d.ts +28 -28
- package/Fire/FireMaterial.js +32 -32
- package/Fire/index.d.ts +2 -2
- package/Fire/index.js +2 -2
- package/GLTFDracoLoader.d.ts +71 -71
- package/GLTFDracoLoader.js +266 -266
- package/GLTFDracoLoader.ts +1 -1
- package/Grass/Grass.d.ts +8 -8
- package/Grass/Grass.js +38 -38
- package/Grass/index.d.ts +2 -2
- package/Grass/index.js +2 -2
- package/Ground1/Ground1.d.ts +10 -10
- package/Ground1/Ground1.js +71 -71
- package/Ground1/index.d.ts +1 -1
- package/Ground1/index.js +1 -1
- package/MeshBase.d.ts +36 -36
- package/MeshBase.js +251 -247
- package/MeshBase.ts +6 -2
- package/Mirror.d.ts +25 -25
- package/Mirror.js +143 -143
- package/MktMesh/MktMesh.d.ts +301 -291
- package/MktMesh/MktMesh.js +1064 -1045
- package/MktMesh/MktMesh.ts +32 -11
- package/MktMesh/assetUrl.d.ts +59 -35
- package/MktMesh/assetUrl.js +165 -69
- package/MktMesh/assetUrl.ts +164 -69
- package/MktMesh/mktMappingShader.d.ts +12 -12
- package/MktMesh/mktMappingShader.js +138 -138
- package/MktMesh/mktMappingShader.ts +139 -139
- package/MktMesh/mktShader.d.ts +263 -263
- package/MktMesh/mktShader.js +1236 -1236
- package/MktMesh/mktShader.ts +1344 -1344
- package/MktMesh/panoBitmapTexture.d.ts +25 -25
- package/MktMesh/panoBitmapTexture.js +52 -52
- package/MktMesh/panoBitmapTexture.ts +54 -54
- package/MktMesh/panoSlotBind.d.ts +29 -29
- package/MktMesh/panoSlotBind.js +106 -106
- package/MktMesh/panoSlotBind.ts +153 -153
- package/MktMesh/panoSlotRoster.d.ts +22 -22
- package/MktMesh/panoSlotRoster.js +169 -169
- package/MktMesh/panoSlotRoster.ts +168 -168
- package/MktMesh/panoTileStitcher.d.ts +119 -119
- package/MktMesh/panoTileStitcher.js +529 -529
- package/MktMesh/panoTileStitcher.ts +616 -616
- package/MktMesh/types.d.ts +75 -75
- package/MktMesh/types.js +1 -1
- package/MktMesh/wallCapTessellate.d.ts +33 -33
- package/MktMesh/wallCapTessellate.js +97 -97
- package/MktMesh/wallCapTessellate.ts +68 -68
- package/PipeMesh/PathGeometry.d.ts +44 -44
- package/PipeMesh/PathGeometry.js +307 -307
- package/PipeMesh/PathPoint.d.ts +17 -17
- package/PipeMesh/PathPoint.js +31 -31
- package/PipeMesh/PathPointList.d.ts +31 -31
- package/PipeMesh/PathPointList.js +209 -209
- package/PipeMesh/PathTubeGeometry.d.ts +25 -25
- package/PipeMesh/PathTubeGeometry.js +130 -130
- package/PipeMesh/PipeMesh.d.ts +25 -25
- package/PipeMesh/PipeMesh.js +63 -63
- package/PipeMesh/index.d.ts +1 -1
- package/PipeMesh/index.js +1 -1
- package/PlaneModal1/PlaneModal1.d.ts +34 -34
- package/PlaneModal1/PlaneModal1.js +109 -109
- package/PlaneModal1/index.d.ts +1 -1
- package/PlaneModal1/index.js +1 -1
- package/PlaneText.d.ts +27 -27
- package/PlaneText.js +35 -35
- package/PlaneWithHtml.d.ts +13 -13
- package/PlaneWithHtml.js +66 -64
- package/PlaneWithHtml.ts +3 -1
- package/PointLight/PointLight.d.ts +13 -13
- package/PointLight/PointLight.js +64 -64
- package/PointLight/index.d.ts +1 -1
- package/PointLight/index.js +1 -1
- package/Sky/Sky.d.ts +9 -9
- package/Sky/Sky.js +22 -22
- package/Sky/index.d.ts +1 -1
- package/Sky/index.js +1 -1
- package/SpotLight.d.ts +6 -6
- package/SpotLight.js +72 -72
- package/SpriteModal1/SpriteModal1.d.ts +33 -33
- package/SpriteModal1/SpriteModal1.js +116 -116
- package/SpriteModal1/index.d.ts +1 -1
- package/SpriteModal1/index.js +1 -1
- package/SpriteText.d.ts +46 -46
- package/SpriteText.js +176 -176
- package/SpriteText2.d.ts +48 -48
- package/SpriteText2.js +223 -223
- package/SpriteText3.d.ts +86 -86
- package/SpriteText3.js +517 -517
- package/SpriteText3.ts +599 -599
- package/SpriteWithHtml.d.ts +9 -9
- package/SpriteWithHtml.js +46 -44
- package/SpriteWithHtml.ts +3 -1
- package/Text3D/Text3D.d.ts +20 -20
- package/Text3D/Text3D.js +58 -58
- package/Text3D/fontController.d.ts +60 -60
- package/Text3D/fontController.js +166 -166
- package/Text3D/index.d.ts +1 -1
- package/Text3D/index.js +1 -1
- package/ThreeBase.d.ts +248 -248
- package/ThreeBase.js +1202 -1202
- package/ThreeBase.ts +1314 -1314
- package/ThreeMouse.d.ts +53 -54
- package/ThreeMouse.js +453 -453
- package/Transition.d.ts +45 -45
- package/Transition.js +209 -209
- package/Water/Water.d.ts +5 -5
- package/Water/Water.js +44 -44
- package/Water/index.d.ts +2 -2
- package/Water/index.js +2 -2
- package/WaterFlow/FloatingDuck.d.ts +88 -88
- package/WaterFlow/FloatingDuck.js +307 -307
- package/WaterFlow/FloatingDuck.ts +445 -445
- package/WaterFlow/GPUFluidSimulation.d.ts +56 -56
- package/WaterFlow/GPUFluidSimulation.js +781 -781
- package/WaterFlow/GPUFluidSimulation.ts +827 -827
- package/WaterFlow/ReservoirSystem.d.ts +106 -106
- package/WaterFlow/ReservoirSystem.js +611 -611
- package/WaterFlow/ReservoirSystem.ts +754 -754
- package/WaterFlow/SPHField.d.ts +35 -35
- package/WaterFlow/SPHField.js +203 -203
- package/WaterFlow/SPHField.ts +228 -228
- package/WaterFlow/ScreenSpaceFluidPass.d.ts +69 -69
- package/WaterFlow/ScreenSpaceFluidPass.js +728 -728
- package/WaterFlow/ScreenSpaceFluidPass.ts +789 -789
- package/WaterFlow/ShallowWaterSurface.d.ts +45 -45
- package/WaterFlow/ShallowWaterSurface.js +438 -438
- package/WaterFlow/ShallowWaterSurface.ts +510 -510
- package/WaterFlow/WaterFlow.d.ts +87 -87
- package/WaterFlow/WaterFlow.js +171 -171
- package/WaterFlow/WaterFlow.ts +219 -219
- package/WaterFlow/types.d.ts +161 -161
- package/WaterFlow/types.js +1 -1
- package/WaterFlow/types.ts +189 -189
- package/WaterFlow/waterFlowPass.d.ts +3 -3
- package/WaterFlow/waterFlowPass.js +20 -20
- package/WaterFlow/waterFlowPass.ts +40 -40
- package/collisionOBB.d.ts +42 -42
- package/collisionOBB.js +112 -112
- package/collisionOBB.ts +108 -108
- package/declare.d.ts +25 -25
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/instanced/InstancedBatch.d.ts +57 -57
- package/instanced/InstancedBatch.js +348 -348
- package/instanced/InstancedBatch.ts +406 -406
- package/instanced/InstancedChild.d.ts +174 -174
- package/instanced/InstancedChild.js +264 -264
- package/instanced/InstancedChild.ts +327 -327
- package/instanced/InstancedGroup.d.ts +43 -43
- package/instanced/InstancedGroup.js +126 -126
- package/instanced/InstancedGroup.ts +137 -137
- package/instanced/InstancedMeshBase.d.ts +38 -38
- package/instanced/InstancedMeshBase.js +282 -282
- package/instanced/InstancedTemplate.d.ts +46 -46
- package/instanced/InstancedTemplate.js +125 -125
- package/keyControls.d.ts +29 -30
- package/keyControls.js +101 -101
- package/lensflare/LensFlare.d.ts +39 -39
- package/lensflare/LensFlare.js +284 -284
- package/package.json +6 -1
- package/pass/bloom_pass.d.ts +2 -2
- package/pass/bloom_pass.js +174 -174
- package/pass/cover_pass.d.ts +2 -2
- package/pass/cover_pass.js +108 -108
- package/pass/debugDepthState.d.ts +20 -20
- package/pass/debugDepthState.js +9 -9
- package/pass/debugDepthState.ts +22 -22
- package/pass/depthTestBias.d.ts +12 -12
- package/pass/depthTestBias.js +12 -12
- package/pass/depthTestBias.ts +12 -12
- package/pass/effectUserData.d.ts +27 -27
- package/pass/effectUserData.js +1 -1
- package/pass/effectUserData.ts +46 -46
- package/pass/frosted_glass_pass.d.ts +2 -2
- package/pass/frosted_glass_pass.js +150 -150
- package/pass/fsQuad.d.ts +9 -9
- package/pass/fsQuad.js +28 -28
- package/pass/glow_pass.d.ts +2 -2
- package/pass/glow_pass.js +350 -350
- package/pass/screen_bloom_pass.d.ts +11 -11
- package/pass/screen_bloom_pass.js +136 -136
- package/pass/ssao_pass.d.ts +88 -88
- package/pass/ssao_pass.js +799 -799
- package/pass/ssao_pass.ts +918 -918
- package/pass/stroke_pass.d.ts +2 -2
- package/pass/stroke_pass.js +267 -267
- package/shaders/FXAAShaderMaterial.d.ts +3 -3
- package/shaders/FXAAShaderMaterial.js +20 -20
- package/shaders/baseDepthVisShader.d.ts +11 -11
- package/shaders/baseDepthVisShader.js +36 -36
- package/shaders/baseDepthVisShader.ts +36 -36
- package/shaders/baseTextureToRenderShader.d.ts +2 -2
- package/shaders/baseTextureToRenderShader.js +19 -19
- package/shaders/copyShader.d.ts +3 -3
- package/shaders/copyShader.js +13 -13
- package/shaders/debugDepthCompareShader.d.ts +14 -14
- package/shaders/debugDepthCompareShader.js +49 -49
- package/shaders/debugDepthCompareShader.ts +50 -50
- package/shaders/debugDepthJudgeShader.d.ts +18 -18
- package/shaders/debugDepthJudgeShader.js +52 -52
- package/shaders/debugDepthJudgeShader.ts +54 -54
- package/shaders/debugExcludedShader.d.ts +13 -13
- package/shaders/debugExcludedShader.js +46 -46
- package/shaders/debugExcludedShader.ts +48 -48
- package/spriteTextBg.d.ts +1 -1
- package/spriteTextBg.js +20 -20
- package/spriteTextBg.ts +20 -20
- package/threeLoader.d.ts +35 -35
- package/threeLoader.js +518 -518
- package/threeUtils.d.ts +71 -53
- package/threeUtils.js +363 -329
- package/threeUtils.ts +35 -0
- package/types.d.ts +2 -2
- package/types.js +6 -6
package/lensflare/LensFlare.js
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: xiaosihan
|
|
3
|
-
* @Date: 2026-08-14
|
|
4
|
-
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time: 2026-08-16
|
|
6
|
-
* @Description: 镜头光晕(Lens Flare)组件。
|
|
7
|
-
* 内联 fork 自 three r167 的 examples/jsm/objects/Lensflare.js(仅复用官方 LensflareElement 作为数据容器)。
|
|
8
|
-
* 正对强光源(太阳)时沿「光源→屏幕中心」连线生成一串彩色光环/鬼影,并做遮挡判断。
|
|
9
|
-
* 光晕素材为自定义 PNG(lensflare_custom.png,来自用户提供的「preview_png.png」),
|
|
10
|
-
* 靠 LensflareElement 的 color 叠加染色(默认橙色)。
|
|
11
|
-
* 每个实例用 TextureLoader 独立加载素材成独立纹理,故 dispose 时只释放自己的,互不影响。
|
|
12
|
-
* 布局:主光点(mainSize@0,最小) + 4 鬼影(100/140/180/220 @ 0.6/0.7/0.9/1,越靠近屏幕中心越大) + 光源背面 3 光斑(40/70/50 @ -0.2/-0.45/-0.7,小)。
|
|
13
|
-
*
|
|
14
|
-
* 【与官方源码的关键差异】去除了「光源超出屏幕范围(validArea.containsPoint)则整串不渲染」的 screen cull:
|
|
15
|
-
* 官方把"光源在屏幕内"作为主光点 + 全部鬼影的统一渲染前提,光源一出屏幕,整串光晕消失。
|
|
16
|
-
* 本项目改为「始终渲染鬼影串」——GPU 会自动裁剪超出屏幕的 quad,落进屏幕内的鬼影部分照常显示;
|
|
17
|
-
* 仅当光源在屏幕内(onScreen)时才做遮挡采样(occlusion),光源在屏幕外时越界采样无意义,
|
|
18
|
-
* 改用 occlusionForceVisible=1 强制可见(避免遮挡图采样越界得到全黑→鬼影被 vVisibility 乘成透明)。
|
|
19
|
-
* 相机背后(positionView.z>0)仍不显示——那是几何上光源在视线后方,光晕本无意义,不属于"超出屏幕"。
|
|
20
|
-
*/
|
|
21
|
-
import { AdditiveBlending, Box2, BufferGeometry, Color, FramebufferTexture, InterleavedBuffer, InterleavedBufferAttribute, Mesh, MeshBasicMaterial, RawShaderMaterial, Scene, UnsignedByteType, Vector2, Vector3, Vector4 } from "three";
|
|
22
|
-
import { LensflareElement } from "three/examples/jsm/objects/Lensflare.js";
|
|
23
|
-
import { TextureLoader } from "three";
|
|
24
|
-
import customPNG from "./lensflare_custom.png";
|
|
25
|
-
// 复用同一 loader,但 load() 每次返回独立 Texture 对象(加载同一 URL 也互不共享),dispose 安全
|
|
26
|
-
const textureLoader = new TextureLoader();
|
|
27
|
-
// 每个 LensFlare 实例有独立的 overlayScene(含 mesh2),
|
|
28
|
-
// 屏幕叠加阶段用 renderer.render(scene, camera) 而非 renderBufferDirect,
|
|
29
|
-
// 因为 renderBufferDirect 依赖 renderer.render 流程初始化的 currentRenderState,
|
|
30
|
-
// 而在 ThreeBase 终处理之后调用时 currentRenderState 已被清空,会 null.state 崩溃。
|
|
31
|
-
// 所有存活的 LensFlare 实例(构造时注册、dispose 时注销)。
|
|
32
|
-
// 渲染器每帧在屏幕输出后调用 flushLensflareOverlays() 统一叠加所有可见鬼影,
|
|
33
|
-
// 无需 ThreeBase 遍历场景或依赖 renderer 事件系统(避免 addEventListener 兼容问题)。
|
|
34
|
-
const lensflareInstances = new Set();
|
|
35
|
-
/**
|
|
36
|
-
* 屏幕叠加入口:渲染器在最终画面输出到屏幕后调用一次,
|
|
37
|
-
* 把所有本帧可见的 LensFlare 鬼影以加色混合叠加到当前屏幕帧缓冲。
|
|
38
|
-
* 仅当 renderer 当前渲染目标为屏幕(null)时生效;中间后处理 target 调用会被忽略。
|
|
39
|
-
* 不依赖具体渲染器类型(只要是 three WebGLRenderer),LensFlare 与 ThreeBase 零耦合。
|
|
40
|
-
*/
|
|
41
|
-
export function flushLensflareOverlays(renderer, camera) {
|
|
42
|
-
if (renderer.getRenderTarget() !== null)
|
|
43
|
-
return;
|
|
44
|
-
lensflareInstances.forEach((lf) => lf.renderScreenOverlay(renderer, camera));
|
|
45
|
-
}
|
|
46
|
-
/** 鬼影元素着色器:在官方 LensflareElement.Shader 基础上新增 occlusionForceVisible uniform,
|
|
47
|
-
* 当其为 1.0 时强制 vVisibility=1(光源在屏幕外、遮挡采样无意义时,让鬼影完全可见)。 */
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2026-08-14
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2026-08-16
|
|
6
|
+
* @Description: 镜头光晕(Lens Flare)组件。
|
|
7
|
+
* 内联 fork 自 three r167 的 examples/jsm/objects/Lensflare.js(仅复用官方 LensflareElement 作为数据容器)。
|
|
8
|
+
* 正对强光源(太阳)时沿「光源→屏幕中心」连线生成一串彩色光环/鬼影,并做遮挡判断。
|
|
9
|
+
* 光晕素材为自定义 PNG(lensflare_custom.png,来自用户提供的「preview_png.png」),
|
|
10
|
+
* 靠 LensflareElement 的 color 叠加染色(默认橙色)。
|
|
11
|
+
* 每个实例用 TextureLoader 独立加载素材成独立纹理,故 dispose 时只释放自己的,互不影响。
|
|
12
|
+
* 布局:主光点(mainSize@0,最小) + 4 鬼影(100/140/180/220 @ 0.6/0.7/0.9/1,越靠近屏幕中心越大) + 光源背面 3 光斑(40/70/50 @ -0.2/-0.45/-0.7,小)。
|
|
13
|
+
*
|
|
14
|
+
* 【与官方源码的关键差异】去除了「光源超出屏幕范围(validArea.containsPoint)则整串不渲染」的 screen cull:
|
|
15
|
+
* 官方把"光源在屏幕内"作为主光点 + 全部鬼影的统一渲染前提,光源一出屏幕,整串光晕消失。
|
|
16
|
+
* 本项目改为「始终渲染鬼影串」——GPU 会自动裁剪超出屏幕的 quad,落进屏幕内的鬼影部分照常显示;
|
|
17
|
+
* 仅当光源在屏幕内(onScreen)时才做遮挡采样(occlusion),光源在屏幕外时越界采样无意义,
|
|
18
|
+
* 改用 occlusionForceVisible=1 强制可见(避免遮挡图采样越界得到全黑→鬼影被 vVisibility 乘成透明)。
|
|
19
|
+
* 相机背后(positionView.z>0)仍不显示——那是几何上光源在视线后方,光晕本无意义,不属于"超出屏幕"。
|
|
20
|
+
*/
|
|
21
|
+
import { AdditiveBlending, Box2, BufferGeometry, Color, FramebufferTexture, InterleavedBuffer, InterleavedBufferAttribute, Mesh, MeshBasicMaterial, RawShaderMaterial, Scene, UnsignedByteType, Vector2, Vector3, Vector4 } from "three";
|
|
22
|
+
import { LensflareElement } from "three/examples/jsm/objects/Lensflare.js";
|
|
23
|
+
import { TextureLoader } from "three";
|
|
24
|
+
import customPNG from "./lensflare_custom.png";
|
|
25
|
+
// 复用同一 loader,但 load() 每次返回独立 Texture 对象(加载同一 URL 也互不共享),dispose 安全
|
|
26
|
+
const textureLoader = new TextureLoader();
|
|
27
|
+
// 每个 LensFlare 实例有独立的 overlayScene(含 mesh2),
|
|
28
|
+
// 屏幕叠加阶段用 renderer.render(scene, camera) 而非 renderBufferDirect,
|
|
29
|
+
// 因为 renderBufferDirect 依赖 renderer.render 流程初始化的 currentRenderState,
|
|
30
|
+
// 而在 ThreeBase 终处理之后调用时 currentRenderState 已被清空,会 null.state 崩溃。
|
|
31
|
+
// 所有存活的 LensFlare 实例(构造时注册、dispose 时注销)。
|
|
32
|
+
// 渲染器每帧在屏幕输出后调用 flushLensflareOverlays() 统一叠加所有可见鬼影,
|
|
33
|
+
// 无需 ThreeBase 遍历场景或依赖 renderer 事件系统(避免 addEventListener 兼容问题)。
|
|
34
|
+
const lensflareInstances = new Set();
|
|
35
|
+
/**
|
|
36
|
+
* 屏幕叠加入口:渲染器在最终画面输出到屏幕后调用一次,
|
|
37
|
+
* 把所有本帧可见的 LensFlare 鬼影以加色混合叠加到当前屏幕帧缓冲。
|
|
38
|
+
* 仅当 renderer 当前渲染目标为屏幕(null)时生效;中间后处理 target 调用会被忽略。
|
|
39
|
+
* 不依赖具体渲染器类型(只要是 three WebGLRenderer),LensFlare 与 ThreeBase 零耦合。
|
|
40
|
+
*/
|
|
41
|
+
export function flushLensflareOverlays(renderer, camera) {
|
|
42
|
+
if (renderer.getRenderTarget() !== null)
|
|
43
|
+
return;
|
|
44
|
+
lensflareInstances.forEach((lf) => lf.renderScreenOverlay(renderer, camera));
|
|
45
|
+
}
|
|
46
|
+
/** 鬼影元素着色器:在官方 LensflareElement.Shader 基础上新增 occlusionForceVisible uniform,
|
|
47
|
+
* 当其为 1.0 时强制 vVisibility=1(光源在屏幕外、遮挡采样无意义时,让鬼影完全可见)。 */
|
|
48
48
|
const LensflareElementVertexShader = /* glsl */ `
|
|
49
49
|
precision highp float;
|
|
50
50
|
|
|
@@ -86,7 +86,7 @@ const LensflareElementVertexShader = /* glsl */ `
|
|
|
86
86
|
gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );
|
|
87
87
|
|
|
88
88
|
}
|
|
89
|
-
`;
|
|
89
|
+
`;
|
|
90
90
|
const LensflareElementFragmentShader = /* glsl */ `
|
|
91
91
|
precision highp float;
|
|
92
92
|
|
|
@@ -104,39 +104,39 @@ const LensflareElementFragmentShader = /* glsl */ `
|
|
|
104
104
|
gl_FragColor.rgb *= color;
|
|
105
105
|
|
|
106
106
|
}
|
|
107
|
-
`;
|
|
108
|
-
/** 内联 fork 自 three r167 的 Lensflare 主类(去除了屏幕外整体 cull)。
|
|
109
|
-
* 仅在官方实现上做了两处改动:
|
|
110
|
-
* 1) 移除 `if ( validArea.containsPoint(...) )` 对鬼影渲染的整体包裹,改为始终渲染;
|
|
111
|
-
* 2) 新增 occlusionForceVisible uniform,光源在屏幕外时置 1 强制可见。 */
|
|
112
|
-
class BaseLensflare extends Mesh {
|
|
113
|
-
static Geometry;
|
|
114
|
-
isLensflare;
|
|
115
|
-
addElement;
|
|
116
|
-
dispose;
|
|
117
|
-
/** 屏幕叠加:由模块级 flushLensflareOverlays() 在渲染器输出屏幕后统一调用,把鬼影画到当前帧缓冲。 */
|
|
118
|
-
renderScreenOverlay;
|
|
119
|
-
constructor() {
|
|
120
|
-
super(BaseLensflare.Geometry, new MeshBasicMaterial({ opacity: 0, transparent: true }));
|
|
121
|
-
// 注册进全局实例表,供 flushLensflareOverlays 统一叠加(不依赖 renderer 事件系统,避免 addEventListener 兼容问题)
|
|
122
|
-
lensflareInstances.add(this);
|
|
123
|
-
this.isLensflare = true;
|
|
124
|
-
this.type = "Lensflare";
|
|
125
|
-
this.frustumCulled = false;
|
|
126
|
-
this.renderOrder = Infinity;
|
|
127
|
-
// -- 以下变量与官方保持一致(闭包局部,供 onBeforeRender 使用) --
|
|
128
|
-
const positionScreen = new Vector3();
|
|
129
|
-
const positionView = new Vector3();
|
|
130
|
-
const tempMap = new FramebufferTexture(16, 16);
|
|
131
|
-
const occlusionMap = new FramebufferTexture(16, 16);
|
|
132
|
-
let currentType = UnsignedByteType;
|
|
133
|
-
const geometry = BaseLensflare.Geometry;
|
|
134
|
-
// 遮挡采样:在光源像素处画一个洋红 quad,再把该处像素拷进 occlusionMap(被遮挡则非洋红→变暗)
|
|
135
|
-
const material1a = new RawShaderMaterial({
|
|
136
|
-
uniforms: {
|
|
137
|
-
scale: { value: null },
|
|
138
|
-
screenPosition: { value: null }
|
|
139
|
-
},
|
|
107
|
+
`;
|
|
108
|
+
/** 内联 fork 自 three r167 的 Lensflare 主类(去除了屏幕外整体 cull)。
|
|
109
|
+
* 仅在官方实现上做了两处改动:
|
|
110
|
+
* 1) 移除 `if ( validArea.containsPoint(...) )` 对鬼影渲染的整体包裹,改为始终渲染;
|
|
111
|
+
* 2) 新增 occlusionForceVisible uniform,光源在屏幕外时置 1 强制可见。 */
|
|
112
|
+
class BaseLensflare extends Mesh {
|
|
113
|
+
static Geometry;
|
|
114
|
+
isLensflare;
|
|
115
|
+
addElement;
|
|
116
|
+
dispose;
|
|
117
|
+
/** 屏幕叠加:由模块级 flushLensflareOverlays() 在渲染器输出屏幕后统一调用,把鬼影画到当前帧缓冲。 */
|
|
118
|
+
renderScreenOverlay;
|
|
119
|
+
constructor() {
|
|
120
|
+
super(BaseLensflare.Geometry, new MeshBasicMaterial({ opacity: 0, transparent: true }));
|
|
121
|
+
// 注册进全局实例表,供 flushLensflareOverlays 统一叠加(不依赖 renderer 事件系统,避免 addEventListener 兼容问题)
|
|
122
|
+
lensflareInstances.add(this);
|
|
123
|
+
this.isLensflare = true;
|
|
124
|
+
this.type = "Lensflare";
|
|
125
|
+
this.frustumCulled = false;
|
|
126
|
+
this.renderOrder = Infinity;
|
|
127
|
+
// -- 以下变量与官方保持一致(闭包局部,供 onBeforeRender 使用) --
|
|
128
|
+
const positionScreen = new Vector3();
|
|
129
|
+
const positionView = new Vector3();
|
|
130
|
+
const tempMap = new FramebufferTexture(16, 16);
|
|
131
|
+
const occlusionMap = new FramebufferTexture(16, 16);
|
|
132
|
+
let currentType = UnsignedByteType;
|
|
133
|
+
const geometry = BaseLensflare.Geometry;
|
|
134
|
+
// 遮挡采样:在光源像素处画一个洋红 quad,再把该处像素拷进 occlusionMap(被遮挡则非洋红→变暗)
|
|
135
|
+
const material1a = new RawShaderMaterial({
|
|
136
|
+
uniforms: {
|
|
137
|
+
scale: { value: null },
|
|
138
|
+
screenPosition: { value: null }
|
|
139
|
+
},
|
|
140
140
|
vertexShader: /* glsl */ `
|
|
141
141
|
precision highp float;
|
|
142
142
|
uniform vec3 screenPosition;
|
|
@@ -145,24 +145,24 @@ class BaseLensflare extends Mesh {
|
|
|
145
145
|
void main() {
|
|
146
146
|
gl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );
|
|
147
147
|
}
|
|
148
|
-
`,
|
|
148
|
+
`,
|
|
149
149
|
fragmentShader: /* glsl */ `
|
|
150
150
|
precision highp float;
|
|
151
151
|
void main() {
|
|
152
152
|
gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );
|
|
153
153
|
}
|
|
154
|
-
`,
|
|
155
|
-
depthTest: true,
|
|
156
|
-
depthWrite: false,
|
|
157
|
-
transparent: false
|
|
158
|
-
});
|
|
159
|
-
// 恢复:把采样前保存的背景(tempMap)画回,避免洋红 quad 残留在屏幕
|
|
160
|
-
const material1b = new RawShaderMaterial({
|
|
161
|
-
uniforms: {
|
|
162
|
-
map: { value: tempMap },
|
|
163
|
-
scale: { value: null },
|
|
164
|
-
screenPosition: { value: null }
|
|
165
|
-
},
|
|
154
|
+
`,
|
|
155
|
+
depthTest: true,
|
|
156
|
+
depthWrite: false,
|
|
157
|
+
transparent: false
|
|
158
|
+
});
|
|
159
|
+
// 恢复:把采样前保存的背景(tempMap)画回,避免洋红 quad 残留在屏幕
|
|
160
|
+
const material1b = new RawShaderMaterial({
|
|
161
|
+
uniforms: {
|
|
162
|
+
map: { value: tempMap },
|
|
163
|
+
scale: { value: null },
|
|
164
|
+
screenPosition: { value: null }
|
|
165
|
+
},
|
|
166
166
|
vertexShader: /* glsl */ `
|
|
167
167
|
precision highp float;
|
|
168
168
|
uniform vec3 screenPosition;
|
|
@@ -174,7 +174,7 @@ class BaseLensflare extends Mesh {
|
|
|
174
174
|
vUV = uv;
|
|
175
175
|
gl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );
|
|
176
176
|
}
|
|
177
|
-
`,
|
|
177
|
+
`,
|
|
178
178
|
fragmentShader: /* glsl */ `
|
|
179
179
|
precision highp float;
|
|
180
180
|
uniform sampler2D map;
|
|
@@ -182,192 +182,192 @@ class BaseLensflare extends Mesh {
|
|
|
182
182
|
void main() {
|
|
183
183
|
gl_FragColor = texture2D( map, vUV );
|
|
184
184
|
}
|
|
185
|
-
`,
|
|
186
|
-
depthTest: false,
|
|
187
|
-
depthWrite: false,
|
|
188
|
-
transparent: false
|
|
189
|
-
});
|
|
190
|
-
const elements = [];
|
|
191
|
-
// 鬼影元素材质(加色混合叠加到屏幕),含本项目新增的 occlusionForceVisible
|
|
192
|
-
const material2 = new RawShaderMaterial({
|
|
193
|
-
name: "LensflareElementShader",
|
|
194
|
-
uniforms: {
|
|
195
|
-
map: { value: null },
|
|
196
|
-
occlusionMap: { value: occlusionMap },
|
|
197
|
-
color: { value: new Color(0xffffff) },
|
|
198
|
-
scale: { value: new Vector2() },
|
|
199
|
-
screenPosition: { value: new Vector3() },
|
|
200
|
-
occlusionForceVisible: { value: 0.0 }
|
|
201
|
-
},
|
|
202
|
-
vertexShader: LensflareElementVertexShader,
|
|
203
|
-
fragmentShader: LensflareElementFragmentShader,
|
|
204
|
-
blending: AdditiveBlending,
|
|
205
|
-
transparent: true,
|
|
206
|
-
depthWrite: false
|
|
207
|
-
});
|
|
208
|
-
const mesh1 = new Mesh(geometry, material1a);
|
|
209
|
-
const mesh2 = new Mesh(geometry, material2);
|
|
210
|
-
// mesh2 用 screenPosition uniform 直接定位,不依赖真实 3D 位置;
|
|
211
|
-
// 关闭视锥剔除,避免 renderer.render 按 mesh2 世界坐标(默认原点)将其裁掉。
|
|
212
|
-
mesh2.frustumCulled = false;
|
|
213
|
-
// 独立的屏幕叠加场景:避免多实例共享场景导致 uniform 串扰,
|
|
214
|
-
// 同时保证 renderer.render 时内部 currentRenderState 被正确初始化。
|
|
215
|
-
const overlayScene = new Scene();
|
|
216
|
-
overlayScene.add(mesh2);
|
|
217
|
-
this.addElement = function (element) {
|
|
218
|
-
elements.push(element);
|
|
219
|
-
};
|
|
220
|
-
const scale = new Vector2();
|
|
221
|
-
const screenPositionPixels = new Vector2();
|
|
222
|
-
const validArea = new Box2();
|
|
223
|
-
const viewport = new Vector4();
|
|
224
|
-
// 本帧鬼影绘制所需的共享状态(onBeforeRender 计算、renderScreenOverlay 消费)
|
|
225
|
-
let frameCamera = null;
|
|
226
|
-
let frameVisible = false;
|
|
227
|
-
let frameForceVisible = 0.0;
|
|
228
|
-
let framePositionScreen = new Vector3();
|
|
229
|
-
let frameViewport = new Vector4();
|
|
230
|
-
// 屏幕叠加:由模块级 flushLensflareOverlays() 在渲染器输出屏幕后统一调用。
|
|
231
|
-
// 仅当本帧 onBeforeRender 计算出可见(光源在相机前方且在屏幕内/外但强制可见)时才画鬼影,
|
|
232
|
-
// 把鬼影串以加色混合叠加到当前屏幕帧缓冲(不污染任何中间后处理 target)。
|
|
233
|
-
// 必须用 renderer.render(scene, camera) 而不能用 renderBufferDirect:
|
|
234
|
-
// renderBufferDirect 依赖 renderer.render 流程建立的 currentRenderState,
|
|
235
|
-
// 终处理之后调用时 currentRenderState 已被清空,会出现 "null (reading 'state')" 崩溃。
|
|
236
|
-
this.renderScreenOverlay = function (renderer, camera) {
|
|
237
|
-
// 兜底:实例已从场景树移除(parent 为 null)时不绘制,
|
|
238
|
-
// 避免上层切页遗漏 dispose 时旧光晕残留在屏幕上。
|
|
239
|
-
if (!frameVisible || !frameCamera || this.parent === null)
|
|
240
|
-
return;
|
|
241
|
-
const vp = frameViewport;
|
|
242
|
-
const ps = framePositionScreen;
|
|
243
|
-
const vecX = -ps.x * 2;
|
|
244
|
-
const vecY = -ps.y * 2;
|
|
245
|
-
const sizeBbase = 1 / vp.w;
|
|
246
|
-
const invAspect2 = vp.w / vp.z;
|
|
247
|
-
for (let i = 0, l = elements.length; i < l; i++) {
|
|
248
|
-
const element = elements[i];
|
|
249
|
-
const u = material2.uniforms;
|
|
250
|
-
u.color.value.copy(element.color);
|
|
251
|
-
u.map.value = element.texture;
|
|
252
|
-
u.screenPosition.value.x = ps.x + vecX * element.distance;
|
|
253
|
-
u.screenPosition.value.y = ps.y + vecY * element.distance;
|
|
254
|
-
const sb = element.size * sizeBbase;
|
|
255
|
-
u.scale.value.set(sb * invAspect2, sb);
|
|
256
|
-
// 调试:强制鬼影完全可见,排除 occlusion/vVisibility 导致看不见的问题
|
|
257
|
-
u.occlusionForceVisible.value = 1.0;
|
|
258
|
-
material2.uniformsNeedUpdate = true;
|
|
259
|
-
renderer.render(overlayScene, frameCamera);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
this.onBeforeRender = function (renderer, _scene, camera) {
|
|
263
|
-
renderer.getCurrentViewport(viewport);
|
|
264
|
-
const renderTarget = renderer.getRenderTarget();
|
|
265
|
-
const type = renderTarget !== null ? renderTarget.texture.type : UnsignedByteType;
|
|
266
|
-
if (currentType !== type) {
|
|
267
|
-
tempMap.dispose();
|
|
268
|
-
occlusionMap.dispose();
|
|
269
|
-
// three 类型定义把 Texture.type 标为 readonly,但运行时可写(需匹配 renderTarget 纹理类型)
|
|
270
|
-
tempMap.type = type;
|
|
271
|
-
occlusionMap.type = type;
|
|
272
|
-
currentType = type;
|
|
273
|
-
}
|
|
274
|
-
const invAspect = viewport.w / viewport.z;
|
|
275
|
-
const halfViewportWidth = viewport.z / 2.0;
|
|
276
|
-
const halfViewportHeight = viewport.w / 2.0;
|
|
277
|
-
const sizeA = 16 / viewport.w;
|
|
278
|
-
scale.set(sizeA * invAspect, sizeA);
|
|
279
|
-
validArea.min.set(viewport.x, viewport.y);
|
|
280
|
-
validArea.max.set(viewport.x + (viewport.z - 16), viewport.y + (viewport.w - 16));
|
|
281
|
-
// 计算光源在相机视图/屏幕空间的位置
|
|
282
|
-
positionView.setFromMatrixPosition(this.matrixWorld);
|
|
283
|
-
positionView.applyMatrix4(camera.matrixWorldInverse);
|
|
284
|
-
if (positionView.z > 0) {
|
|
285
|
-
// 光源在相机背后:不显示(几何无意义,非"超出屏幕")
|
|
286
|
-
frameVisible = false;
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
positionScreen.copy(positionView).applyMatrix4(camera.projectionMatrix);
|
|
290
|
-
// 光源像素坐标(遮挡采样 16x16 纹理居中在光源像素位置的 -8 处)
|
|
291
|
-
screenPositionPixels.x = viewport.x + (positionScreen.x * halfViewportWidth) + halfViewportWidth - 8;
|
|
292
|
-
screenPositionPixels.y = viewport.y + (positionScreen.y * halfViewportHeight) + halfViewportHeight - 8;
|
|
293
|
-
const onScreen = validArea.containsPoint(screenPositionPixels);
|
|
294
|
-
let forceVisible = 0.0;
|
|
295
|
-
if (onScreen) {
|
|
296
|
-
// 仅当光源在屏幕内才做遮挡采样(采样区域落到视口外会越界/得到无效遮挡图)
|
|
297
|
-
renderer.copyFramebufferToTexture(tempMap, screenPositionPixels);
|
|
298
|
-
let uniforms = material1a.uniforms;
|
|
299
|
-
uniforms.scale.value = scale;
|
|
300
|
-
uniforms.screenPosition.value = positionScreen;
|
|
301
|
-
renderer.renderBufferDirect(camera, null, geometry, material1a, mesh1, null);
|
|
302
|
-
renderer.copyFramebufferToTexture(occlusionMap, screenPositionPixels);
|
|
303
|
-
uniforms = material1b.uniforms;
|
|
304
|
-
uniforms.scale.value = scale;
|
|
305
|
-
uniforms.screenPosition.value = positionScreen;
|
|
306
|
-
renderer.renderBufferDirect(camera, null, geometry, material1b, mesh1, null);
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
// 光源在屏幕外:遮挡采样越界无意义,强制鬼影可见(屏幕内的鬼影部分仍正常显示)
|
|
310
|
-
forceVisible = 1.0;
|
|
311
|
-
}
|
|
312
|
-
// 记录本帧状态,供 afterRender 在屏幕阶段绘制鬼影(已移除官方「光源在屏幕内才渲染」的整体 cull)。
|
|
313
|
-
// 超出屏幕的 quad 会在 afterRender 的 renderBufferDirect 时被 GPU 自动裁剪,落进屏幕内的鬼影照常显示。
|
|
314
|
-
frameCamera = camera;
|
|
315
|
-
frameVisible = true;
|
|
316
|
-
frameForceVisible = forceVisible;
|
|
317
|
-
framePositionScreen = positionScreen.clone();
|
|
318
|
-
frameViewport = viewport.clone();
|
|
319
|
-
};
|
|
320
|
-
this.dispose = function () {
|
|
321
|
-
lensflareInstances.delete(this);
|
|
322
|
-
material1a.dispose();
|
|
323
|
-
material1b.dispose();
|
|
324
|
-
material2.dispose();
|
|
325
|
-
tempMap.dispose();
|
|
326
|
-
occlusionMap.dispose();
|
|
327
|
-
for (let i = 0, l = elements.length; i < l; i++) {
|
|
328
|
-
elements[i].texture.dispose();
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
BaseLensflare.Geometry = (function () {
|
|
334
|
-
const geometry = new BufferGeometry();
|
|
335
|
-
const float32Array = new Float32Array([
|
|
336
|
-
-1, -1, 0, 0, 0,
|
|
337
|
-
1, -1, 0, 1, 0,
|
|
338
|
-
1, 1, 0, 1, 1,
|
|
339
|
-
-1, 1, 0, 0, 1
|
|
340
|
-
]);
|
|
341
|
-
const interleavedBuffer = new InterleavedBuffer(float32Array, 5);
|
|
342
|
-
geometry.setIndex([0, 1, 2, 0, 2, 3]);
|
|
343
|
-
geometry.setAttribute("position", new InterleavedBufferAttribute(interleavedBuffer, 3, 0, false));
|
|
344
|
-
geometry.setAttribute("uv", new InterleavedBufferAttribute(interleavedBuffer, 2, 3, false));
|
|
345
|
-
return geometry;
|
|
346
|
-
})();
|
|
347
|
-
/** 对外暴露的镜头光晕组件:fork 自 three 的 Lensflare,已去除「光源出屏幕整串消失」的限制。 */
|
|
348
|
-
export default class LensFlare extends BaseLensflare {
|
|
349
|
-
constructor(opts = {}) {
|
|
350
|
-
super();
|
|
351
|
-
const { color = "#ff9933", mainSize = 120, renderer } = opts;
|
|
352
|
-
if (renderer) {
|
|
353
|
-
this.ensureScreenOverlay(renderer);
|
|
354
|
-
}
|
|
355
|
-
const mainTex = textureLoader.load(customPNG);
|
|
356
|
-
// 主光点(光源正后方,尺寸最小,由 mainSize 控制;越小越不抢戏)
|
|
357
|
-
this.addElement(new LensflareElement(mainTex, mainSize, 0, new Color(color)));
|
|
358
|
-
// 正向鬼影:沿「光源→屏幕中心」连线分布,越靠近屏幕中心(distance 越大)尺寸越大
|
|
359
|
-
this.addElement(new LensflareElement(mainTex, 100, 0.6, new Color(color)));
|
|
360
|
-
this.addElement(new LensflareElement(mainTex, 140, 0.7, new Color(color)));
|
|
361
|
-
this.addElement(new LensflareElement(mainTex, 180, 0.9, new Color(color)));
|
|
362
|
-
this.addElement(new LensflareElement(mainTex, 220, 1, new Color(color)));
|
|
363
|
-
// 背面:光源后方,保持小尺寸
|
|
364
|
-
this.addElement(new LensflareElement(mainTex, 40, -0.2, new Color(color)));
|
|
365
|
-
this.addElement(new LensflareElement(mainTex, 70, -0.45, new Color(color)));
|
|
366
|
-
this.addElement(new LensflareElement(mainTex, 50, -0.7, new Color(color)));
|
|
367
|
-
}
|
|
368
|
-
/** 把光晕挂到某个光源(或任意 Object3D)上,使其出现在该对象的世界坐标处 */
|
|
369
|
-
attachTo(target) {
|
|
370
|
-
target.add(this);
|
|
371
|
-
return this;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
185
|
+
`,
|
|
186
|
+
depthTest: false,
|
|
187
|
+
depthWrite: false,
|
|
188
|
+
transparent: false
|
|
189
|
+
});
|
|
190
|
+
const elements = [];
|
|
191
|
+
// 鬼影元素材质(加色混合叠加到屏幕),含本项目新增的 occlusionForceVisible
|
|
192
|
+
const material2 = new RawShaderMaterial({
|
|
193
|
+
name: "LensflareElementShader",
|
|
194
|
+
uniforms: {
|
|
195
|
+
map: { value: null },
|
|
196
|
+
occlusionMap: { value: occlusionMap },
|
|
197
|
+
color: { value: new Color(0xffffff) },
|
|
198
|
+
scale: { value: new Vector2() },
|
|
199
|
+
screenPosition: { value: new Vector3() },
|
|
200
|
+
occlusionForceVisible: { value: 0.0 }
|
|
201
|
+
},
|
|
202
|
+
vertexShader: LensflareElementVertexShader,
|
|
203
|
+
fragmentShader: LensflareElementFragmentShader,
|
|
204
|
+
blending: AdditiveBlending,
|
|
205
|
+
transparent: true,
|
|
206
|
+
depthWrite: false
|
|
207
|
+
});
|
|
208
|
+
const mesh1 = new Mesh(geometry, material1a);
|
|
209
|
+
const mesh2 = new Mesh(geometry, material2);
|
|
210
|
+
// mesh2 用 screenPosition uniform 直接定位,不依赖真实 3D 位置;
|
|
211
|
+
// 关闭视锥剔除,避免 renderer.render 按 mesh2 世界坐标(默认原点)将其裁掉。
|
|
212
|
+
mesh2.frustumCulled = false;
|
|
213
|
+
// 独立的屏幕叠加场景:避免多实例共享场景导致 uniform 串扰,
|
|
214
|
+
// 同时保证 renderer.render 时内部 currentRenderState 被正确初始化。
|
|
215
|
+
const overlayScene = new Scene();
|
|
216
|
+
overlayScene.add(mesh2);
|
|
217
|
+
this.addElement = function (element) {
|
|
218
|
+
elements.push(element);
|
|
219
|
+
};
|
|
220
|
+
const scale = new Vector2();
|
|
221
|
+
const screenPositionPixels = new Vector2();
|
|
222
|
+
const validArea = new Box2();
|
|
223
|
+
const viewport = new Vector4();
|
|
224
|
+
// 本帧鬼影绘制所需的共享状态(onBeforeRender 计算、renderScreenOverlay 消费)
|
|
225
|
+
let frameCamera = null;
|
|
226
|
+
let frameVisible = false;
|
|
227
|
+
let frameForceVisible = 0.0;
|
|
228
|
+
let framePositionScreen = new Vector3();
|
|
229
|
+
let frameViewport = new Vector4();
|
|
230
|
+
// 屏幕叠加:由模块级 flushLensflareOverlays() 在渲染器输出屏幕后统一调用。
|
|
231
|
+
// 仅当本帧 onBeforeRender 计算出可见(光源在相机前方且在屏幕内/外但强制可见)时才画鬼影,
|
|
232
|
+
// 把鬼影串以加色混合叠加到当前屏幕帧缓冲(不污染任何中间后处理 target)。
|
|
233
|
+
// 必须用 renderer.render(scene, camera) 而不能用 renderBufferDirect:
|
|
234
|
+
// renderBufferDirect 依赖 renderer.render 流程建立的 currentRenderState,
|
|
235
|
+
// 终处理之后调用时 currentRenderState 已被清空,会出现 "null (reading 'state')" 崩溃。
|
|
236
|
+
this.renderScreenOverlay = function (renderer, camera) {
|
|
237
|
+
// 兜底:实例已从场景树移除(parent 为 null)时不绘制,
|
|
238
|
+
// 避免上层切页遗漏 dispose 时旧光晕残留在屏幕上。
|
|
239
|
+
if (!frameVisible || !frameCamera || this.parent === null)
|
|
240
|
+
return;
|
|
241
|
+
const vp = frameViewport;
|
|
242
|
+
const ps = framePositionScreen;
|
|
243
|
+
const vecX = -ps.x * 2;
|
|
244
|
+
const vecY = -ps.y * 2;
|
|
245
|
+
const sizeBbase = 1 / vp.w;
|
|
246
|
+
const invAspect2 = vp.w / vp.z;
|
|
247
|
+
for (let i = 0, l = elements.length; i < l; i++) {
|
|
248
|
+
const element = elements[i];
|
|
249
|
+
const u = material2.uniforms;
|
|
250
|
+
u.color.value.copy(element.color);
|
|
251
|
+
u.map.value = element.texture;
|
|
252
|
+
u.screenPosition.value.x = ps.x + vecX * element.distance;
|
|
253
|
+
u.screenPosition.value.y = ps.y + vecY * element.distance;
|
|
254
|
+
const sb = element.size * sizeBbase;
|
|
255
|
+
u.scale.value.set(sb * invAspect2, sb);
|
|
256
|
+
// 调试:强制鬼影完全可见,排除 occlusion/vVisibility 导致看不见的问题
|
|
257
|
+
u.occlusionForceVisible.value = 1.0;
|
|
258
|
+
material2.uniformsNeedUpdate = true;
|
|
259
|
+
renderer.render(overlayScene, frameCamera);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
this.onBeforeRender = function (renderer, _scene, camera) {
|
|
263
|
+
renderer.getCurrentViewport(viewport);
|
|
264
|
+
const renderTarget = renderer.getRenderTarget();
|
|
265
|
+
const type = renderTarget !== null ? renderTarget.texture.type : UnsignedByteType;
|
|
266
|
+
if (currentType !== type) {
|
|
267
|
+
tempMap.dispose();
|
|
268
|
+
occlusionMap.dispose();
|
|
269
|
+
// three 类型定义把 Texture.type 标为 readonly,但运行时可写(需匹配 renderTarget 纹理类型)
|
|
270
|
+
tempMap.type = type;
|
|
271
|
+
occlusionMap.type = type;
|
|
272
|
+
currentType = type;
|
|
273
|
+
}
|
|
274
|
+
const invAspect = viewport.w / viewport.z;
|
|
275
|
+
const halfViewportWidth = viewport.z / 2.0;
|
|
276
|
+
const halfViewportHeight = viewport.w / 2.0;
|
|
277
|
+
const sizeA = 16 / viewport.w;
|
|
278
|
+
scale.set(sizeA * invAspect, sizeA);
|
|
279
|
+
validArea.min.set(viewport.x, viewport.y);
|
|
280
|
+
validArea.max.set(viewport.x + (viewport.z - 16), viewport.y + (viewport.w - 16));
|
|
281
|
+
// 计算光源在相机视图/屏幕空间的位置
|
|
282
|
+
positionView.setFromMatrixPosition(this.matrixWorld);
|
|
283
|
+
positionView.applyMatrix4(camera.matrixWorldInverse);
|
|
284
|
+
if (positionView.z > 0) {
|
|
285
|
+
// 光源在相机背后:不显示(几何无意义,非"超出屏幕")
|
|
286
|
+
frameVisible = false;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
positionScreen.copy(positionView).applyMatrix4(camera.projectionMatrix);
|
|
290
|
+
// 光源像素坐标(遮挡采样 16x16 纹理居中在光源像素位置的 -8 处)
|
|
291
|
+
screenPositionPixels.x = viewport.x + (positionScreen.x * halfViewportWidth) + halfViewportWidth - 8;
|
|
292
|
+
screenPositionPixels.y = viewport.y + (positionScreen.y * halfViewportHeight) + halfViewportHeight - 8;
|
|
293
|
+
const onScreen = validArea.containsPoint(screenPositionPixels);
|
|
294
|
+
let forceVisible = 0.0;
|
|
295
|
+
if (onScreen) {
|
|
296
|
+
// 仅当光源在屏幕内才做遮挡采样(采样区域落到视口外会越界/得到无效遮挡图)
|
|
297
|
+
renderer.copyFramebufferToTexture(tempMap, screenPositionPixels);
|
|
298
|
+
let uniforms = material1a.uniforms;
|
|
299
|
+
uniforms.scale.value = scale;
|
|
300
|
+
uniforms.screenPosition.value = positionScreen;
|
|
301
|
+
renderer.renderBufferDirect(camera, null, geometry, material1a, mesh1, null);
|
|
302
|
+
renderer.copyFramebufferToTexture(occlusionMap, screenPositionPixels);
|
|
303
|
+
uniforms = material1b.uniforms;
|
|
304
|
+
uniforms.scale.value = scale;
|
|
305
|
+
uniforms.screenPosition.value = positionScreen;
|
|
306
|
+
renderer.renderBufferDirect(camera, null, geometry, material1b, mesh1, null);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
// 光源在屏幕外:遮挡采样越界无意义,强制鬼影可见(屏幕内的鬼影部分仍正常显示)
|
|
310
|
+
forceVisible = 1.0;
|
|
311
|
+
}
|
|
312
|
+
// 记录本帧状态,供 afterRender 在屏幕阶段绘制鬼影(已移除官方「光源在屏幕内才渲染」的整体 cull)。
|
|
313
|
+
// 超出屏幕的 quad 会在 afterRender 的 renderBufferDirect 时被 GPU 自动裁剪,落进屏幕内的鬼影照常显示。
|
|
314
|
+
frameCamera = camera;
|
|
315
|
+
frameVisible = true;
|
|
316
|
+
frameForceVisible = forceVisible;
|
|
317
|
+
framePositionScreen = positionScreen.clone();
|
|
318
|
+
frameViewport = viewport.clone();
|
|
319
|
+
};
|
|
320
|
+
this.dispose = function () {
|
|
321
|
+
lensflareInstances.delete(this);
|
|
322
|
+
material1a.dispose();
|
|
323
|
+
material1b.dispose();
|
|
324
|
+
material2.dispose();
|
|
325
|
+
tempMap.dispose();
|
|
326
|
+
occlusionMap.dispose();
|
|
327
|
+
for (let i = 0, l = elements.length; i < l; i++) {
|
|
328
|
+
elements[i].texture.dispose();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
BaseLensflare.Geometry = (function () {
|
|
334
|
+
const geometry = new BufferGeometry();
|
|
335
|
+
const float32Array = new Float32Array([
|
|
336
|
+
-1, -1, 0, 0, 0,
|
|
337
|
+
1, -1, 0, 1, 0,
|
|
338
|
+
1, 1, 0, 1, 1,
|
|
339
|
+
-1, 1, 0, 0, 1
|
|
340
|
+
]);
|
|
341
|
+
const interleavedBuffer = new InterleavedBuffer(float32Array, 5);
|
|
342
|
+
geometry.setIndex([0, 1, 2, 0, 2, 3]);
|
|
343
|
+
geometry.setAttribute("position", new InterleavedBufferAttribute(interleavedBuffer, 3, 0, false));
|
|
344
|
+
geometry.setAttribute("uv", new InterleavedBufferAttribute(interleavedBuffer, 2, 3, false));
|
|
345
|
+
return geometry;
|
|
346
|
+
})();
|
|
347
|
+
/** 对外暴露的镜头光晕组件:fork 自 three 的 Lensflare,已去除「光源出屏幕整串消失」的限制。 */
|
|
348
|
+
export default class LensFlare extends BaseLensflare {
|
|
349
|
+
constructor(opts = {}) {
|
|
350
|
+
super();
|
|
351
|
+
const { color = "#ff9933", mainSize = 120, renderer } = opts;
|
|
352
|
+
if (renderer) {
|
|
353
|
+
this.ensureScreenOverlay(renderer);
|
|
354
|
+
}
|
|
355
|
+
const mainTex = textureLoader.load(customPNG);
|
|
356
|
+
// 主光点(光源正后方,尺寸最小,由 mainSize 控制;越小越不抢戏)
|
|
357
|
+
this.addElement(new LensflareElement(mainTex, mainSize, 0, new Color(color)));
|
|
358
|
+
// 正向鬼影:沿「光源→屏幕中心」连线分布,越靠近屏幕中心(distance 越大)尺寸越大
|
|
359
|
+
this.addElement(new LensflareElement(mainTex, 100, 0.6, new Color(color)));
|
|
360
|
+
this.addElement(new LensflareElement(mainTex, 140, 0.7, new Color(color)));
|
|
361
|
+
this.addElement(new LensflareElement(mainTex, 180, 0.9, new Color(color)));
|
|
362
|
+
this.addElement(new LensflareElement(mainTex, 220, 1, new Color(color)));
|
|
363
|
+
// 背面:光源后方,保持小尺寸
|
|
364
|
+
this.addElement(new LensflareElement(mainTex, 40, -0.2, new Color(color)));
|
|
365
|
+
this.addElement(new LensflareElement(mainTex, 70, -0.45, new Color(color)));
|
|
366
|
+
this.addElement(new LensflareElement(mainTex, 50, -0.7, new Color(color)));
|
|
367
|
+
}
|
|
368
|
+
/** 把光晕挂到某个光源(或任意 Object3D)上,使其出现在该对象的世界坐标处 */
|
|
369
|
+
attachTo(target) {
|
|
370
|
+
target.add(this);
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "three-base",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.166",
|
|
4
4
|
"description": "A Three.js extension library providing common 3D components, animations, materials, and utilities",
|
|
5
5
|
"author": "xiaosihan",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"./Transition": "./Transition.js",
|
|
28
28
|
"./ThreeMouse": "./ThreeMouse.js",
|
|
29
29
|
"./MeshBase": "./MeshBase.js",
|
|
30
|
+
"./MktMesh": {
|
|
31
|
+
"types": "./MktMesh/MktMesh.d.ts",
|
|
32
|
+
"import": "./MktMesh/MktMesh.js",
|
|
33
|
+
"require": "./MktMesh/MktMesh.js"
|
|
34
|
+
},
|
|
30
35
|
"./InstancedMeshBase": "./instanced/InstancedMeshBase.js",
|
|
31
36
|
"./threeLoader": "./threeLoader.js",
|
|
32
37
|
"./threeUtils": "./threeUtils.js",
|
package/pass/bloom_pass.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { DepthTexture, WebGLRenderTarget, WebGLRenderer, Camera, Object3D } from "three";
|
|
2
|
-
export default function bloom_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseRenderTarget: WebGLRenderTarget, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
|
|
1
|
+
import { DepthTexture, WebGLRenderTarget, WebGLRenderer, Camera, Object3D } from "three";
|
|
2
|
+
export default function bloom_pass(renderer: WebGLRenderer, camera: Camera, object3d: Object3D, baseRenderTarget: WebGLRenderTarget, baseDepthTexture: DepthTexture, devicePixelRatio: number): void;
|