three-base 2.0.168 → 2.0.172
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/FPScontrol.d.ts +41 -7
- package/FPScontrol.js +232 -155
- package/FPScontrol.ts +129 -55
- package/Ground1/Ground1.js +6 -6
- package/Ground1/Ground1.ts +6 -6
- package/MktMesh/MktMesh.d.ts +5 -1
- package/MktMesh/MktMesh.js +20 -7
- package/MktMesh/MktMesh.ts +20 -7
- package/MktMesh/panoSlotBind.js +18 -2
- package/MktMesh/panoSlotBind.ts +18 -1
- package/MktMesh/panoTileStitcher.d.ts +35 -7
- package/MktMesh/panoTileStitcher.js +71 -11
- package/MktMesh/panoTileStitcher.ts +73 -12
- package/MktMesh/types.d.ts +5 -1
- package/MktMesh/types.ts +5 -1
- package/ThreeBase.d.ts +2 -11
- package/ThreeBase.js +14 -26
- package/ThreeBase.ts +14 -26
- package/WaterFlow/WaterFlow.d.ts +1 -1
- package/WaterFlow/WaterFlow.js +1 -1
- package/WaterFlow/WaterFlow.ts +1 -1
- package/package.json +1 -1
- package/pass/bloom_pass.js +7 -14
- package/pass/bloom_pass.ts +7 -16
- package/pass/cover_pass.js +7 -15
- package/pass/cover_pass.ts +7 -17
- package/pass/debugDepthState.d.ts +2 -2
- package/pass/debugDepthState.ts +2 -2
- package/pass/glow_pass.js +8 -16
- package/pass/glow_pass.ts +8 -18
- package/pass/ssao_pass.d.ts +13 -44
- package/pass/ssao_pass.js +60 -78
- package/pass/ssao_pass.ts +74 -88
- package/pass/stroke_pass.js +10 -16
- package/pass/stroke_pass.ts +10 -18
- package/shaders/baseDepthVisShader.d.ts +1 -1
- package/shaders/baseDepthVisShader.js +1 -1
- package/shaders/baseDepthVisShader.ts +1 -1
- package/shaders/debugDepthCompareShader.d.ts +1 -1
- package/shaders/debugDepthCompareShader.js +1 -1
- package/shaders/debugDepthCompareShader.ts +1 -1
- package/shaders/debugExcludedShader.d.ts +6 -4
- package/shaders/debugExcludedShader.js +6 -4
- package/shaders/debugExcludedShader.ts +6 -4
package/pass/ssao_pass.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Color, DataTexture, DoubleSide, LinearFilter, MeshBasicMaterial, NoBlending, RGBAFormat, RawShaderMaterial, RepeatWrapping, Vector2, Vector3, WebGLRenderTarget, Matrix4, MultiplyBlending, PerspectiveCamera, OrthographicCamera } from "three";
|
|
2
2
|
import fsQuad from "./fsQuad";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* 判断是否为「可透视的半透明表面」——这类表面不该在世界空间 AO 里充当实体。
|
|
5
5
|
* 让它进入深度/法线图,被它遮挡的区域会发黑,成因分两种:
|
|
6
6
|
* a) transparent:true + opacity<1(毛玻璃、透明装饰):深度图与法线图都落在半透明表面上,
|
|
7
7
|
* GTAO 在其表面算自遮蔽(褶皱、紧贴其它几何的窄缝)→ 这份 AO 被乘到「透过它看到的
|
|
@@ -9,67 +9,50 @@ import fsQuad from "./fsQuad";
|
|
|
9
9
|
* b) transparent:true + depthWrite:false(霓虹灯管、光晕、叠加面):深度图保留身后几何(远),
|
|
10
10
|
* 但法线 pass 用 overrideMaterial(MeshNormalMaterial 默认 depthWrite:true)会强行把它的
|
|
11
11
|
* 法线写进去(近)→ 深度与法线指的不是同一个点 → GTAO 几乎必然算错发黑。
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* 故 AO 那一趟统一隐藏这些面:该像素的法线即身后不透明几何,AO 由真实可见几何决定;
|
|
13
|
+
* 身后是背景时深度为 1.0,shader 守卫直接判「无遮蔽」(=1),不会发黑。
|
|
14
14
|
*
|
|
15
15
|
* 判据只看 material.transparent 本身,不再依赖 opacity / depthWrite(2026-08-30 修正):
|
|
16
16
|
* 大量半透明是自定义 ShaderMaterial,alpha 由 shader 算出来,而材质的 opacity 仍是默认 1、
|
|
17
|
-
* depthWrite 仍是 true ——
|
|
18
|
-
*
|
|
17
|
+
* depthWrite 仍是 true —— 典型如聚光灯光斑、effectMaterial1,靠材质属性完全读不出来,
|
|
18
|
+
* 会被漏判并继续污染 AO。
|
|
19
19
|
* 代价:Mirror 这类「标了 transparent 但 shader 实际输出 alpha=1.0」的实心反射面会被误排除,
|
|
20
20
|
* 故 Mirror 在构造函数里显式标记 userData.aoOpaque = true 保留(见各 Mirror 实现)。
|
|
21
21
|
* 其余特例同样可用 userData.aoTransparent=true 强制排除 / userData.aoOpaque=true 强制保留。
|
|
22
22
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* - false
|
|
25
|
-
*
|
|
23
|
+
* @param excludeTransparent 两道 pass 的唯一差别,取值就是它名字的含义:
|
|
24
|
+
* - false(可见深度 / 描边/辉光/毛玻璃/覆盖色遮挡判定):透明面**当实体**参与遮挡。
|
|
25
|
+
* ⚠️ 关键(2026-09-06 回归根因):three-base 大量面(玻璃、特效载体、alpha 贴图实体、
|
|
26
|
+
* 半透明墙)都标了 transparent:true;若在此排除,它们就不再遮挡身后特效,所有依赖
|
|
27
|
+
* baseDepthTexture 的深度测试全部失效、一律显示在前面。
|
|
28
|
+
* - true(AO 深度 + 法线):透明面排除,避免 GTAO 在其上算错发黑。
|
|
29
|
+
* ⚠️ 2026-10-11 起此参数原名 includeFloor(地板特例已整条拆除,见文件头),别再当"地板开关"读。
|
|
26
30
|
*/
|
|
27
|
-
|
|
28
|
-
* 可见深度图的运行时开关:**标了 `userData.aoFloor` 的地板是否参与遮挡判定**。
|
|
29
|
-
*
|
|
30
|
-
* 默认 false = 保持原设计(可透视地板:透过地板看到的物体照常显示,不被地板挡住)。
|
|
31
|
-
* 置 true 后,地板会写进 baseDepthTexture,于是**被地板挡住的描边/辉光/毛玻璃/覆盖色会被正确遮挡**。
|
|
32
|
-
* 面板「深度调试 → 地板参与遮挡」可一键切换,用于排查"挡不住"是不是地板(如 Ground1)造成的。
|
|
33
|
-
*
|
|
34
|
-
* 只影响 aoFloor 地板这一类;transparent 面的处理不受影响(见 isSeeThroughSurface)。
|
|
35
|
-
*/
|
|
36
|
-
export const visibleDepthOptions = { includeFloor: false };
|
|
37
|
-
const isSeeThroughSurface = (obj, includeFloor = false) => {
|
|
31
|
+
const isSeeThroughSurface = (obj, excludeTransparent = false) => {
|
|
38
32
|
const o = obj;
|
|
39
33
|
const userData = o.userData;
|
|
40
34
|
if (userData && userData.aoOpaque === true)
|
|
41
35
|
return false;
|
|
42
36
|
if (userData && userData.aoTransparent === true)
|
|
43
37
|
return true;
|
|
44
|
-
// 地板类半透明:可见深度(includeFloor=false,描边/辉光/毛玻璃/覆盖色遮挡判定用)里排除
|
|
45
|
-
// → 可透视,透过地板看到的物体照常显示;AO 深度(includeFloor=true)里保留 → 接触 AO。
|
|
46
|
-
// ⚠️ 例外:visibleDepthOptions.includeFloor=true 时,可见深度里也保留地板 → 地板能挡住特效。
|
|
47
|
-
if (userData && userData.aoFloor === true) {
|
|
48
|
-
return includeFloor ? false : !visibleDepthOptions.includeFloor;
|
|
49
|
-
}
|
|
50
38
|
const mat = o.material;
|
|
51
39
|
if (!mat)
|
|
52
40
|
return false;
|
|
53
41
|
const list = Array.isArray(mat) ? mat : [mat];
|
|
54
42
|
const transparent = list.some((m) => m !== null && m.transparent === true);
|
|
55
|
-
|
|
56
|
-
// transparent 但实为实心/不透明"的面当作实体参与遮挡——three-base 大量面(玻璃、特效载体、
|
|
57
|
-
// alpha 贴图实体、半透明墙)都标了 transparent:true;若在此排除,它们就不再遮挡身后特效,
|
|
58
|
-
// 所有依赖 baseDepthTexture 的深度测试(描边/辉光/毛玻璃/覆盖色)全部失效、一律显示在前面。
|
|
59
|
-
// 仅 AO 深度(includeFloor=true)需要排除透明面,避免 GTAO 在半透明面上算错发黑(保留原 AO 修复)。
|
|
60
|
-
return includeFloor && transparent;
|
|
43
|
+
return excludeTransparent && transparent;
|
|
61
44
|
};
|
|
62
|
-
const isNonSurface = (obj,
|
|
45
|
+
const isNonSurface = (obj, excludeTransparent = false) => {
|
|
63
46
|
const o = obj;
|
|
64
47
|
if (o.isSprite === true || o.isLine === true || o.isLine2 === true || o.isLineSegments2 === true || o.isPoints === true) {
|
|
65
48
|
return true;
|
|
66
49
|
}
|
|
67
|
-
return isSeeThroughSurface(obj,
|
|
50
|
+
return isSeeThroughSurface(obj, excludeTransparent);
|
|
68
51
|
};
|
|
69
|
-
const hideNonSurface = (scene,
|
|
52
|
+
const hideNonSurface = (scene, excludeTransparent = false) => {
|
|
70
53
|
const list = [];
|
|
71
54
|
scene.traverse((obj) => {
|
|
72
|
-
if (isNonSurface(obj,
|
|
55
|
+
if (isNonSurface(obj, excludeTransparent)) {
|
|
73
56
|
list.push({ obj, prev: obj.visible });
|
|
74
57
|
obj.visible = false;
|
|
75
58
|
}
|
|
@@ -80,18 +63,21 @@ const restoreVisibility = (list) => {
|
|
|
80
63
|
list.forEach(({ obj, prev }) => (obj.visible = prev));
|
|
81
64
|
};
|
|
82
65
|
/**
|
|
83
|
-
*
|
|
84
|
-
* depthRenderTarget.depthTexture 即 baseDepthTexture
|
|
66
|
+
* 可见深度 pass:固定排除非实体表面后,用**各物体自身的材质**把场景深度渲染到 depthRenderTarget。
|
|
67
|
+
* depthRenderTarget.depthTexture 即 baseDepthTexture,供描边 / 发光 / 覆盖 / 磨砂的遮挡判定,
|
|
68
|
+
* 也是 SSAO 合成时「真实可见表面」的参考。
|
|
85
69
|
* 排除的非实体对象(sprite/线条/点)在深度图保留 clear 深度(1.0=远),与背景一致;排除的
|
|
86
70
|
* 半透明对象则保留其身后不透明几何的深度(身后无几何时同样为 1.0)。均不影响颜色通道渲染。
|
|
71
|
+
* ⚠️ 名字里的 ao 已不适用(2026-10-11 改名自 renderAoDepthPass):它产出的是**可见深度**,
|
|
72
|
+
* AO 自己的深度挂在法线 pass 上(见 renderAoNormalPass),两者只差 excludeTransparent 一个开关。
|
|
87
73
|
*/
|
|
88
|
-
export function
|
|
89
|
-
const hidden = hideNonSurface(scene,
|
|
74
|
+
export function renderVisibleDepthPass(renderer, camera, scene, depthRenderTarget, excludeTransparent = false) {
|
|
75
|
+
const hidden = hideNonSurface(scene, excludeTransparent);
|
|
90
76
|
// ⚠️ 深度预通道铁律:必须让所有「未被排除」的可见表面都写入深度,深度图才有真实的几何遮挡信息。
|
|
91
77
|
// 透明材质(特效载体、半透明墙、alpha 贴图实体等)大多 transparent:true 且 depthWrite:false,
|
|
92
78
|
// 若不强转,它们不会写进 baseDepthTexture → 深度图只剩不透明几何 → 描边/辉光/毛玻璃/覆盖色
|
|
93
79
|
// 依赖 baseDepthTexture 的遮挡判定全部失效、一律显示在前(即本次回归根因)。
|
|
94
|
-
//
|
|
80
|
+
// 被显式标记的面(userData.aoTransparent)已在 hideNonSurface 中隐藏,
|
|
95
81
|
// 此处根本不会触及,故不影响 see-through 设计;其余透明面强制写深度 = 作为实体参与遮挡,符合预期。
|
|
96
82
|
const depthWriteRestore = [];
|
|
97
83
|
scene.traverse((obj) => {
|
|
@@ -118,16 +104,16 @@ export function renderAoDepthPass(renderer, camera, scene, depthRenderTarget, in
|
|
|
118
104
|
/**
|
|
119
105
|
* 调试用:把「被排除出可见深度图」的表面单独渲成红色 mask。
|
|
120
106
|
*
|
|
121
|
-
* 这些面在
|
|
107
|
+
* 这些面在 renderVisibleDepthPass 里被 hideNonSurface 隐藏,因此**不会写进 baseDepthTexture**,
|
|
122
108
|
* 也就永远挡不住描边/辉光/毛玻璃/覆盖色 —— 这正是"深度测试看起来失效"最常见的成因
|
|
123
|
-
* (用户以为是 bug,其实是该面被设计成可透视:sprite/线条/点、userData.aoTransparent
|
|
124
|
-
*
|
|
109
|
+
* (用户以为是 bug,其实是该面被设计成可透视:sprite/线条/点、userData.aoTransparent)。
|
|
110
|
+
* ⚠️ 地板不在此列:2026-10-11 起 Ground1 是实心不透明面,正常写进可见深度图。
|
|
125
111
|
* 面板「深度调试 → 排除面标记」叠加显示:灰=能挡住的真实遮挡面,红=被排除、挡不住任何东西。
|
|
126
112
|
*
|
|
127
113
|
* 只渲染 Mesh:sprite / Line2 / Points 在 MeshBasicMaterial override 下渲染异常(见文件头注释),
|
|
128
114
|
* 且它们数量少、用户关心的遮挡体基本都是 Mesh,故跳过。
|
|
129
115
|
*/
|
|
130
|
-
export function renderExcludedMaskPass(renderer, camera, scene, maskRenderTarget,
|
|
116
|
+
export function renderExcludedMaskPass(renderer, camera, scene, maskRenderTarget, excludeTransparent = false) {
|
|
131
117
|
const maskMaterial = new MeshBasicMaterial({
|
|
132
118
|
color: 0xff0000,
|
|
133
119
|
depthTest: false,
|
|
@@ -139,7 +125,7 @@ export function renderExcludedMaskPass(renderer, camera, scene, maskRenderTarget
|
|
|
139
125
|
const isMesh = obj.isMesh === true;
|
|
140
126
|
prevVisible.push({ obj, prev: obj.visible });
|
|
141
127
|
// 只显示「被排除的 Mesh」:其余一律隐藏,得到纯黑底 + 红面的 mask
|
|
142
|
-
obj.visible = isMesh && isNonSurface(obj,
|
|
128
|
+
obj.visible = isMesh && isNonSurface(obj, excludeTransparent);
|
|
143
129
|
});
|
|
144
130
|
const prevOverride = scene.overrideMaterial;
|
|
145
131
|
const prevTarget = renderer.getRenderTarget();
|
|
@@ -161,25 +147,16 @@ export function renderExcludedMaskPass(renderer, camera, scene, maskRenderTarget
|
|
|
161
147
|
* override 将视图空间法线渲染到 normalRenderTarget,供 GTAO 风格 SSAO 使用。
|
|
162
148
|
* 排除对象在法线图保留中性灰清屏色 → unpackRGBToNormal(0.5,0.5,0.5)=(0,0,0) →
|
|
163
149
|
* SSAO 退化法线守卫判"无遮蔽"(=1),避免精灵弹窗被 AO 乘黑。清屏色用后即还原。
|
|
150
|
+
* 深度白拿:normalRenderTarget 挂着 aoDepthTexture 作 depth attachment,这一趟的深度由光栅器
|
|
151
|
+
* 顺带写入 → 就是 AO 用的深度,无需再单独渲一遍(2026-09-14)。
|
|
164
152
|
*/
|
|
165
|
-
export function renderAoNormalPass(renderer, camera, scene, normalRenderTarget, normalMaterial,
|
|
166
|
-
const hidden = hideNonSurface(scene,
|
|
167
|
-
// ⚠️
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const mesh = obj;
|
|
173
|
-
if (!mesh.isMesh || !mesh.material)
|
|
174
|
-
return;
|
|
175
|
-
const list = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
176
|
-
list.forEach((m) => {
|
|
177
|
-
if (m && m.depthWrite === false) {
|
|
178
|
-
depthWriteRestore.push({ mat: m, val: false });
|
|
179
|
-
m.depthWrite = true;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
153
|
+
export function renderAoNormalPass(renderer, camera, scene, normalRenderTarget, normalMaterial, excludeTransparent = false) {
|
|
154
|
+
const hidden = hideNonSurface(scene, excludeTransparent);
|
|
155
|
+
// ⚠️ 2026-10-11 删掉了这里原有的「强制 depthWrite=true」整段遍历:scene.overrideMaterial 生效后,
|
|
156
|
+
// three 用的是 **override 材质**的渲染状态(WebGLRenderer.renderObjects:
|
|
157
|
+
// `material = overrideMaterial === null ? renderItem.material : overrideMaterial`,setDepthState 吃它),
|
|
158
|
+
// 物体自己材质的 depthWrite 根本读不到 ⇒ 那段是空转。需要强转的是用自身材质渲染的
|
|
159
|
+
// renderVisibleDepthPass(那边保留)。
|
|
183
160
|
const prevRenderTarget = renderer.getRenderTarget();
|
|
184
161
|
const prevClearColor = new Color();
|
|
185
162
|
renderer.getClearColor(prevClearColor);
|
|
@@ -191,7 +168,6 @@ export function renderAoNormalPass(renderer, camera, scene, normalRenderTarget,
|
|
|
191
168
|
renderer.render(scene, camera);
|
|
192
169
|
scene.overrideMaterial = null;
|
|
193
170
|
restoreVisibility(hidden);
|
|
194
|
-
depthWriteRestore.forEach(({ mat, val }) => { mat.depthWrite = val; });
|
|
195
171
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
196
172
|
renderer.setRenderTarget(prevRenderTarget);
|
|
197
173
|
}
|
|
@@ -658,9 +634,9 @@ const outputShader = new RawShaderMaterial({
|
|
|
658
634
|
ssaoTexture: { value: null },
|
|
659
635
|
ssaoStrength: { value: 1.0 },
|
|
660
636
|
debug: { value: 0.0 },
|
|
661
|
-
//
|
|
637
|
+
// 可见深度(用自身材质渲染,含地板)= baseDepthTexture:代表"真实可见表面"的深度。
|
|
662
638
|
tColorDepth: { value: null },
|
|
663
|
-
// AO
|
|
639
|
+
// AO 深度(= normalRenderTarget.depthTexture,法线 pass 顺带写入)。
|
|
664
640
|
tAoDepth: { value: null },
|
|
665
641
|
},
|
|
666
642
|
vertexShader: `
|
|
@@ -687,10 +663,13 @@ const outputShader = new RawShaderMaterial({
|
|
|
687
663
|
void main() {
|
|
688
664
|
float ssao = texture2D(ssaoTexture, vUv).r;
|
|
689
665
|
|
|
690
|
-
// 复合守卫:对数深度越小越近。若"
|
|
691
|
-
//
|
|
692
|
-
//
|
|
693
|
-
//
|
|
666
|
+
// 复合守卫:对数深度越小越近。若"AO 深度"比"可见深度"更近,说明该像素上法线趟
|
|
667
|
+
// (override 材质:DoubleSide、不做物体自己的 alpha discard)记到一个**屏幕上根本不可见**的面
|
|
668
|
+
// —— 典型如树叶抠图的空隙、单面墙的背面。此时深度与法线指的不是人眼看到的那个点,
|
|
669
|
+
// GTAO 算出的 AO 不可信 → 视为无遮蔽(=1)。
|
|
670
|
+
// ⚠️ 2026-10-11:本守卫原本主要防「可透视地板挡住身后实体」,那条特例已随地板进深度图而作废,
|
|
671
|
+
// 现在它守的是上面这类 override/自身材质两套渲染结果的错位,别当死代码删。
|
|
672
|
+
// 仅在最终合成时生效;debug 模式直接看 GTAO 原始 AO 图,便于排查。
|
|
694
673
|
float dColor = texture2D(tColorDepth, vUv).r;
|
|
695
674
|
float dAo = texture2D(tAoDepth, vUv).r;
|
|
696
675
|
if (debug < 0.5 && dAo < dColor - 0.0001) {
|
|
@@ -722,16 +701,19 @@ export default function ssao_pass(renderer, camera, scene, depthRenderTarget, no
|
|
|
722
701
|
// 故 AO 直接乘进 base,描边/发光/覆盖/磨砂都叠在 AO 之上不被压暗;末尾统一 FXAA 输出到屏幕,
|
|
723
702
|
// 覆盖 SSAO 自身的硬边。改动调用顺序时,本 pass 无需修改(输出到"绑定的那个目标"即可)。
|
|
724
703
|
const originRenderTarget = renderer.getRenderTarget();
|
|
725
|
-
// 法线 pass
|
|
704
|
+
// 法线 pass(excludeTransparent=true):隐式透明面不参与 AO,免得 GTAO 在其上算自遮蔽把
|
|
705
|
+
// 身后实体乘黑;地板/其它不透明面照常保留 —— 接触 AO 需要地板的视图空间法线。
|
|
726
706
|
// ⭐ 深度白拿(2026-09-14 优化):normalRenderTarget 挂着 aoDepthTexture 作 depth attachment,
|
|
727
|
-
// 这一次渲染的深度由光栅器顺带写入 →
|
|
728
|
-
// (原先法线 pass
|
|
707
|
+
// 这一次渲染的深度由光栅器顺带写入 → 直接就是 AO 深度,**不再单独渲一遍深度 pass**。
|
|
708
|
+
// (原先法线 pass 之后还要再渲一遍「AO 深度」——它与法线 pass 的排除集完全相同,
|
|
729
709
|
// 属于重复遍历全场景,2026-09-14 已删。)
|
|
730
|
-
//
|
|
710
|
+
// ⚠️ 这一趟的深度是 override 材质写的(DoubleSide、不做物体自己的 alpha discard),
|
|
711
|
+
// 所以只能给 AO 用;特效遮挡吃的是下面那张「用自身材质渲染」的可见深度。
|
|
731
712
|
renderAoNormalPass(renderer, camera, scene, normalRenderTarget, normalMaterial, true);
|
|
732
|
-
//
|
|
713
|
+
// 可见深度(用各物体自身材质渲染,含地板)= baseDepthTexture:描边/辉光/毛玻璃/覆盖色的遮挡参考,
|
|
714
|
+
// 也是复合守卫里「真实可见表面」的参考。
|
|
733
715
|
const colorDepthTexture = depthRenderTarget.depthTexture;
|
|
734
|
-
// AO
|
|
716
|
+
// AO 深度:GTAO 与去噪采样它(与上面的法线同一次光栅化,深度-法线永远同源)。
|
|
735
717
|
const aoDepthTexture = normalRenderTarget.depthTexture;
|
|
736
718
|
const normalTexture = normalRenderTarget.texture;
|
|
737
719
|
renderer.getSize(size);
|
|
@@ -796,8 +778,8 @@ export default function ssao_pass(renderer, camera, scene, depthRenderTarget, no
|
|
|
796
778
|
fsQuad.render(renderer, poissonDenoiseShader);
|
|
797
779
|
renderer.setRenderTarget(originRenderTarget);
|
|
798
780
|
outputShader.uniforms.ssaoTexture.value = blurTextureTarget.texture;
|
|
799
|
-
//
|
|
800
|
-
//
|
|
781
|
+
// 复合守卫:可见深度(自身材质渲染)与 AO 深度(override 渲染)两图比对,
|
|
782
|
+
// AO 侧更近 = 那像素记到屏幕上不可见的面(抠图空隙/单面墙背面)→ 作废该像素 AO(见 outputShader 注释)。
|
|
801
783
|
outputShader.uniforms.tColorDepth.value = colorDepthTexture;
|
|
802
784
|
outputShader.uniforms.tAoDepth.value = aoDepthTexture;
|
|
803
785
|
// 叠加强度:finalOcclusion = mix(1.0, ao, strength),0 = 完全不叠加 AO,1 = 原始强度,>1 外插加深。
|
package/pass/ssao_pass.ts
CHANGED
|
@@ -13,14 +13,18 @@ import fsQuad from "./fsQuad";
|
|
|
13
13
|
// 2) 可透视的半透明表面(详见 isSeeThroughSurface):会让「被它遮挡的区域」发黑。
|
|
14
14
|
// 故在深度/法线 pass 前临时隐藏,pass 后恢复(记录 prev visible 避免误改用户隐藏的 UI)。
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
16
|
+
// ⭐ 2026-10-11 皇上旨「物体的深度都要进深度图」:原先地板(Ground1 标 userData.aoFloor)被
|
|
17
|
+
// 特例从可见深度图里排除 —— 那是因为它当年是「径向 alpha 淡出的半透明地板」,透过去看到的实体
|
|
18
|
+
// 不该被它挡住。但 2026-09-20 二旨早已把 Ground1 改成 transparent:false 的实心深灰地板,那条例外
|
|
19
|
+
// 的理由随之作废(判据还走在 material.transparent 之前,读不出来),故整条拆除:
|
|
20
|
+
// 现在地板在两张图里都是实体 —— 可见深度图(特效遮挡判定)与 AO 深度图都有它,
|
|
21
|
+
// 被地板挡住的描边/辉光/覆盖色/磨砂会被正确裁掉(=皇上要的行为)。
|
|
22
|
+
// 两张图仍然都存在,但差别只剩「材质标了 transparent 的面」,且各自都是必须的,不能合并:
|
|
23
|
+
// - 可见深度(renderVisibleDepthPass,用各物体**自身材质**渲染):透明面当实体(否则 2026-09-06
|
|
24
|
+
// 那类「所有深度测试一律显示在前面」的回归复发);自身材质渲染 ⇒ 单面墙只记正面、
|
|
25
|
+
// alpha 抠图(树叶、带 discard 的自定义 shader)只记真正可见的像素 —— 特效遮挡必须吃这份保真度。
|
|
26
|
+
// - AO 深度(normalRenderTarget 的 depth attachment,法线 pass 顺带白拿):隐式透明面被排除,
|
|
27
|
+
// 免得 GTAO 在半透明面上算自遮蔽把身后实体乘黑;法线必须由片元着色器写,这一趟省不掉。
|
|
24
28
|
// 用 isSprite / isLine / isLine2 / isLineSegments2 / isPoints 属性判断而非 instanceof:
|
|
25
29
|
// 避免 three 子类场景下 instanceof 命中不到(如 SpriteText 等自定义 sprite 子类、
|
|
26
30
|
// Line2 继承自 Mesh 非 Line)。
|
|
@@ -29,7 +33,7 @@ import fsQuad from "./fsQuad";
|
|
|
29
33
|
type HiddenEntry = { obj: Object3D; prev: boolean };
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
|
-
*
|
|
36
|
+
* 判断是否为「可透视的半透明表面」——这类表面不该在世界空间 AO 里充当实体。
|
|
33
37
|
* 让它进入深度/法线图,被它遮挡的区域会发黑,成因分两种:
|
|
34
38
|
* a) transparent:true + opacity<1(毛玻璃、透明装饰):深度图与法线图都落在半透明表面上,
|
|
35
39
|
* GTAO 在其表面算自遮蔽(褶皱、紧贴其它几何的窄缝)→ 这份 AO 被乘到「透过它看到的
|
|
@@ -37,67 +41,49 @@ type HiddenEntry = { obj: Object3D; prev: boolean };
|
|
|
37
41
|
* b) transparent:true + depthWrite:false(霓虹灯管、光晕、叠加面):深度图保留身后几何(远),
|
|
38
42
|
* 但法线 pass 用 overrideMaterial(MeshNormalMaterial 默认 depthWrite:true)会强行把它的
|
|
39
43
|
* 法线写进去(近)→ 深度与法线指的不是同一个点 → GTAO 几乎必然算错发黑。
|
|
40
|
-
*
|
|
41
|
-
*
|
|
44
|
+
* 故 AO 那一趟统一隐藏这些面:该像素的法线即身后不透明几何,AO 由真实可见几何决定;
|
|
45
|
+
* 身后是背景时深度为 1.0,shader 守卫直接判「无遮蔽」(=1),不会发黑。
|
|
42
46
|
*
|
|
43
47
|
* 判据只看 material.transparent 本身,不再依赖 opacity / depthWrite(2026-08-30 修正):
|
|
44
48
|
* 大量半透明是自定义 ShaderMaterial,alpha 由 shader 算出来,而材质的 opacity 仍是默认 1、
|
|
45
|
-
* depthWrite 仍是 true ——
|
|
46
|
-
*
|
|
49
|
+
* depthWrite 仍是 true —— 典型如聚光灯光斑、effectMaterial1,靠材质属性完全读不出来,
|
|
50
|
+
* 会被漏判并继续污染 AO。
|
|
47
51
|
* 代价:Mirror 这类「标了 transparent 但 shader 实际输出 alpha=1.0」的实心反射面会被误排除,
|
|
48
52
|
* 故 Mirror 在构造函数里显式标记 userData.aoOpaque = true 保留(见各 Mirror 实现)。
|
|
49
53
|
* 其余特例同样可用 userData.aoTransparent=true 强制排除 / userData.aoOpaque=true 强制保留。
|
|
50
54
|
*
|
|
51
|
-
* @param
|
|
52
|
-
* - false
|
|
53
|
-
*
|
|
55
|
+
* @param excludeTransparent 两道 pass 的唯一差别,取值就是它名字的含义:
|
|
56
|
+
* - false(可见深度 / 描边/辉光/毛玻璃/覆盖色遮挡判定):透明面**当实体**参与遮挡。
|
|
57
|
+
* ⚠️ 关键(2026-09-06 回归根因):three-base 大量面(玻璃、特效载体、alpha 贴图实体、
|
|
58
|
+
* 半透明墙)都标了 transparent:true;若在此排除,它们就不再遮挡身后特效,所有依赖
|
|
59
|
+
* baseDepthTexture 的深度测试全部失效、一律显示在前面。
|
|
60
|
+
* - true(AO 深度 + 法线):透明面排除,避免 GTAO 在其上算错发黑。
|
|
61
|
+
* ⚠️ 2026-10-11 起此参数原名 includeFloor(地板特例已整条拆除,见文件头),别再当"地板开关"读。
|
|
54
62
|
*/
|
|
55
|
-
|
|
56
|
-
* 可见深度图的运行时开关:**标了 `userData.aoFloor` 的地板是否参与遮挡判定**。
|
|
57
|
-
*
|
|
58
|
-
* 默认 false = 保持原设计(可透视地板:透过地板看到的物体照常显示,不被地板挡住)。
|
|
59
|
-
* 置 true 后,地板会写进 baseDepthTexture,于是**被地板挡住的描边/辉光/毛玻璃/覆盖色会被正确遮挡**。
|
|
60
|
-
* 面板「深度调试 → 地板参与遮挡」可一键切换,用于排查"挡不住"是不是地板(如 Ground1)造成的。
|
|
61
|
-
*
|
|
62
|
-
* 只影响 aoFloor 地板这一类;transparent 面的处理不受影响(见 isSeeThroughSurface)。
|
|
63
|
-
*/
|
|
64
|
-
export const visibleDepthOptions: { includeFloor: boolean } = { includeFloor: false };
|
|
65
|
-
|
|
66
|
-
const isSeeThroughSurface = (obj: Object3D, includeFloor = false): boolean => {
|
|
63
|
+
const isSeeThroughSurface = (obj: Object3D, excludeTransparent = false): boolean => {
|
|
67
64
|
const o = obj as Object3D & { material?: Material | Material[] };
|
|
68
|
-
const userData = o.userData as { aoTransparent?: boolean; aoOpaque?: boolean
|
|
65
|
+
const userData = o.userData as { aoTransparent?: boolean; aoOpaque?: boolean } | undefined;
|
|
69
66
|
if (userData && userData.aoOpaque === true) return false;
|
|
70
67
|
if (userData && userData.aoTransparent === true) return true;
|
|
71
|
-
// 地板类半透明:可见深度(includeFloor=false,描边/辉光/毛玻璃/覆盖色遮挡判定用)里排除
|
|
72
|
-
// → 可透视,透过地板看到的物体照常显示;AO 深度(includeFloor=true)里保留 → 接触 AO。
|
|
73
|
-
// ⚠️ 例外:visibleDepthOptions.includeFloor=true 时,可见深度里也保留地板 → 地板能挡住特效。
|
|
74
|
-
if (userData && userData.aoFloor === true) {
|
|
75
|
-
return includeFloor ? false : !visibleDepthOptions.includeFloor;
|
|
76
|
-
}
|
|
77
68
|
const mat = o.material;
|
|
78
69
|
if (!mat) return false;
|
|
79
70
|
const list: Material[] = Array.isArray(mat) ? mat : [mat];
|
|
80
71
|
const transparent = list.some((m) => m !== null && m.transparent === true);
|
|
81
|
-
|
|
82
|
-
// transparent 但实为实心/不透明"的面当作实体参与遮挡——three-base 大量面(玻璃、特效载体、
|
|
83
|
-
// alpha 贴图实体、半透明墙)都标了 transparent:true;若在此排除,它们就不再遮挡身后特效,
|
|
84
|
-
// 所有依赖 baseDepthTexture 的深度测试(描边/辉光/毛玻璃/覆盖色)全部失效、一律显示在前面。
|
|
85
|
-
// 仅 AO 深度(includeFloor=true)需要排除透明面,避免 GTAO 在半透明面上算错发黑(保留原 AO 修复)。
|
|
86
|
-
return includeFloor && transparent;
|
|
72
|
+
return excludeTransparent && transparent;
|
|
87
73
|
};
|
|
88
74
|
|
|
89
|
-
const isNonSurface = (obj: Object3D,
|
|
75
|
+
const isNonSurface = (obj: Object3D, excludeTransparent = false): boolean => {
|
|
90
76
|
const o = obj as { isSprite?: boolean; isLine?: boolean; isLine2?: boolean; isLineSegments2?: boolean; isPoints?: boolean };
|
|
91
77
|
if (o.isSprite === true || o.isLine === true || o.isLine2 === true || o.isLineSegments2 === true || o.isPoints === true) {
|
|
92
78
|
return true;
|
|
93
79
|
}
|
|
94
|
-
return isSeeThroughSurface(obj,
|
|
80
|
+
return isSeeThroughSurface(obj, excludeTransparent);
|
|
95
81
|
};
|
|
96
82
|
|
|
97
|
-
const hideNonSurface = (scene: Object3D,
|
|
83
|
+
const hideNonSurface = (scene: Object3D, excludeTransparent = false): HiddenEntry[] => {
|
|
98
84
|
const list: HiddenEntry[] = [];
|
|
99
85
|
scene.traverse((obj: Object3D) => {
|
|
100
|
-
if (isNonSurface(obj,
|
|
86
|
+
if (isNonSurface(obj, excludeTransparent)) {
|
|
101
87
|
list.push({ obj, prev: obj.visible });
|
|
102
88
|
obj.visible = false;
|
|
103
89
|
}
|
|
@@ -110,24 +96,27 @@ const restoreVisibility = (list: HiddenEntry[]): void => {
|
|
|
110
96
|
};
|
|
111
97
|
|
|
112
98
|
/**
|
|
113
|
-
*
|
|
114
|
-
* depthRenderTarget.depthTexture 即 baseDepthTexture
|
|
99
|
+
* 可见深度 pass:固定排除非实体表面后,用**各物体自身的材质**把场景深度渲染到 depthRenderTarget。
|
|
100
|
+
* depthRenderTarget.depthTexture 即 baseDepthTexture,供描边 / 发光 / 覆盖 / 磨砂的遮挡判定,
|
|
101
|
+
* 也是 SSAO 合成时「真实可见表面」的参考。
|
|
115
102
|
* 排除的非实体对象(sprite/线条/点)在深度图保留 clear 深度(1.0=远),与背景一致;排除的
|
|
116
103
|
* 半透明对象则保留其身后不透明几何的深度(身后无几何时同样为 1.0)。均不影响颜色通道渲染。
|
|
104
|
+
* ⚠️ 名字里的 ao 已不适用(2026-10-11 改名自 renderAoDepthPass):它产出的是**可见深度**,
|
|
105
|
+
* AO 自己的深度挂在法线 pass 上(见 renderAoNormalPass),两者只差 excludeTransparent 一个开关。
|
|
117
106
|
*/
|
|
118
|
-
export function
|
|
107
|
+
export function renderVisibleDepthPass(
|
|
119
108
|
renderer: WebGLRenderer,
|
|
120
109
|
camera: Camera,
|
|
121
110
|
scene: Scene,
|
|
122
111
|
depthRenderTarget: WebGLRenderTarget,
|
|
123
|
-
|
|
112
|
+
excludeTransparent = false
|
|
124
113
|
): void {
|
|
125
|
-
const hidden = hideNonSurface(scene,
|
|
114
|
+
const hidden = hideNonSurface(scene, excludeTransparent);
|
|
126
115
|
// ⚠️ 深度预通道铁律:必须让所有「未被排除」的可见表面都写入深度,深度图才有真实的几何遮挡信息。
|
|
127
116
|
// 透明材质(特效载体、半透明墙、alpha 贴图实体等)大多 transparent:true 且 depthWrite:false,
|
|
128
117
|
// 若不强转,它们不会写进 baseDepthTexture → 深度图只剩不透明几何 → 描边/辉光/毛玻璃/覆盖色
|
|
129
118
|
// 依赖 baseDepthTexture 的遮挡判定全部失效、一律显示在前(即本次回归根因)。
|
|
130
|
-
//
|
|
119
|
+
// 被显式标记的面(userData.aoTransparent)已在 hideNonSurface 中隐藏,
|
|
131
120
|
// 此处根本不会触及,故不影响 see-through 设计;其余透明面强制写深度 = 作为实体参与遮挡,符合预期。
|
|
132
121
|
const depthWriteRestore: { mat: Material; val: boolean }[] = [];
|
|
133
122
|
scene.traverse((obj: Object3D) => {
|
|
@@ -154,10 +143,10 @@ export function renderAoDepthPass(
|
|
|
154
143
|
/**
|
|
155
144
|
* 调试用:把「被排除出可见深度图」的表面单独渲成红色 mask。
|
|
156
145
|
*
|
|
157
|
-
* 这些面在
|
|
146
|
+
* 这些面在 renderVisibleDepthPass 里被 hideNonSurface 隐藏,因此**不会写进 baseDepthTexture**,
|
|
158
147
|
* 也就永远挡不住描边/辉光/毛玻璃/覆盖色 —— 这正是"深度测试看起来失效"最常见的成因
|
|
159
|
-
* (用户以为是 bug,其实是该面被设计成可透视:sprite/线条/点、userData.aoTransparent
|
|
160
|
-
*
|
|
148
|
+
* (用户以为是 bug,其实是该面被设计成可透视:sprite/线条/点、userData.aoTransparent)。
|
|
149
|
+
* ⚠️ 地板不在此列:2026-10-11 起 Ground1 是实心不透明面,正常写进可见深度图。
|
|
161
150
|
* 面板「深度调试 → 排除面标记」叠加显示:灰=能挡住的真实遮挡面,红=被排除、挡不住任何东西。
|
|
162
151
|
*
|
|
163
152
|
* 只渲染 Mesh:sprite / Line2 / Points 在 MeshBasicMaterial override 下渲染异常(见文件头注释),
|
|
@@ -168,7 +157,7 @@ export function renderExcludedMaskPass(
|
|
|
168
157
|
camera: Camera,
|
|
169
158
|
scene: Scene,
|
|
170
159
|
maskRenderTarget: WebGLRenderTarget,
|
|
171
|
-
|
|
160
|
+
excludeTransparent = false
|
|
172
161
|
): void {
|
|
173
162
|
const maskMaterial = new MeshBasicMaterial({
|
|
174
163
|
color: 0xff0000,
|
|
@@ -181,7 +170,7 @@ export function renderExcludedMaskPass(
|
|
|
181
170
|
const isMesh = (obj as Object3D & { isMesh?: boolean }).isMesh === true;
|
|
182
171
|
prevVisible.push({ obj, prev: obj.visible });
|
|
183
172
|
// 只显示「被排除的 Mesh」:其余一律隐藏,得到纯黑底 + 红面的 mask
|
|
184
|
-
obj.visible = isMesh && isNonSurface(obj,
|
|
173
|
+
obj.visible = isMesh && isNonSurface(obj, excludeTransparent);
|
|
185
174
|
});
|
|
186
175
|
|
|
187
176
|
const prevOverride = scene.overrideMaterial;
|
|
@@ -207,6 +196,8 @@ export function renderExcludedMaskPass(
|
|
|
207
196
|
* override 将视图空间法线渲染到 normalRenderTarget,供 GTAO 风格 SSAO 使用。
|
|
208
197
|
* 排除对象在法线图保留中性灰清屏色 → unpackRGBToNormal(0.5,0.5,0.5)=(0,0,0) →
|
|
209
198
|
* SSAO 退化法线守卫判"无遮蔽"(=1),避免精灵弹窗被 AO 乘黑。清屏色用后即还原。
|
|
199
|
+
* 深度白拿:normalRenderTarget 挂着 aoDepthTexture 作 depth attachment,这一趟的深度由光栅器
|
|
200
|
+
* 顺带写入 → 就是 AO 用的深度,无需再单独渲一遍(2026-09-14)。
|
|
210
201
|
*/
|
|
211
202
|
export function renderAoNormalPass(
|
|
212
203
|
renderer: WebGLRenderer,
|
|
@@ -214,24 +205,14 @@ export function renderAoNormalPass(
|
|
|
214
205
|
scene: Scene,
|
|
215
206
|
normalRenderTarget: WebGLRenderTarget,
|
|
216
207
|
normalMaterial: MeshNormalMaterial,
|
|
217
|
-
|
|
208
|
+
excludeTransparent = false
|
|
218
209
|
): void {
|
|
219
|
-
const hidden = hideNonSurface(scene,
|
|
220
|
-
// ⚠️
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const mesh = obj as Object3D & { isMesh?: boolean; material?: Material | Material[] };
|
|
226
|
-
if (!mesh.isMesh || !mesh.material) return;
|
|
227
|
-
const list = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
228
|
-
list.forEach((m) => {
|
|
229
|
-
if (m && (m as Material).depthWrite === false) {
|
|
230
|
-
depthWriteRestore.push({ mat: m as Material, val: false });
|
|
231
|
-
(m as Material).depthWrite = true;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
});
|
|
210
|
+
const hidden = hideNonSurface(scene, excludeTransparent);
|
|
211
|
+
// ⚠️ 2026-10-11 删掉了这里原有的「强制 depthWrite=true」整段遍历:scene.overrideMaterial 生效后,
|
|
212
|
+
// three 用的是 **override 材质**的渲染状态(WebGLRenderer.renderObjects:
|
|
213
|
+
// `material = overrideMaterial === null ? renderItem.material : overrideMaterial`,setDepthState 吃它),
|
|
214
|
+
// 物体自己材质的 depthWrite 根本读不到 ⇒ 那段是空转。需要强转的是用自身材质渲染的
|
|
215
|
+
// renderVisibleDepthPass(那边保留)。
|
|
235
216
|
const prevRenderTarget = renderer.getRenderTarget();
|
|
236
217
|
const prevClearColor = new Color();
|
|
237
218
|
renderer.getClearColor(prevClearColor);
|
|
@@ -243,7 +224,6 @@ export function renderAoNormalPass(
|
|
|
243
224
|
renderer.render(scene, camera);
|
|
244
225
|
scene.overrideMaterial = null;
|
|
245
226
|
restoreVisibility(hidden);
|
|
246
|
-
depthWriteRestore.forEach(({ mat, val }) => { mat.depthWrite = val; });
|
|
247
227
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
248
228
|
renderer.setRenderTarget(prevRenderTarget);
|
|
249
229
|
}
|
|
@@ -721,9 +701,9 @@ const outputShader: RawShaderMaterial = new RawShaderMaterial({
|
|
|
721
701
|
ssaoTexture: { value: null },
|
|
722
702
|
ssaoStrength: { value: 1.0 },
|
|
723
703
|
debug: { value: 0.0 },
|
|
724
|
-
//
|
|
704
|
+
// 可见深度(用自身材质渲染,含地板)= baseDepthTexture:代表"真实可见表面"的深度。
|
|
725
705
|
tColorDepth: { value: null as DepthTexture | null },
|
|
726
|
-
// AO
|
|
706
|
+
// AO 深度(= normalRenderTarget.depthTexture,法线 pass 顺带写入)。
|
|
727
707
|
tAoDepth: { value: null as DepthTexture | null },
|
|
728
708
|
},
|
|
729
709
|
vertexShader: `
|
|
@@ -750,10 +730,13 @@ const outputShader: RawShaderMaterial = new RawShaderMaterial({
|
|
|
750
730
|
void main() {
|
|
751
731
|
float ssao = texture2D(ssaoTexture, vUv).r;
|
|
752
732
|
|
|
753
|
-
// 复合守卫:对数深度越小越近。若"
|
|
754
|
-
//
|
|
755
|
-
//
|
|
756
|
-
//
|
|
733
|
+
// 复合守卫:对数深度越小越近。若"AO 深度"比"可见深度"更近,说明该像素上法线趟
|
|
734
|
+
// (override 材质:DoubleSide、不做物体自己的 alpha discard)记到一个**屏幕上根本不可见**的面
|
|
735
|
+
// —— 典型如树叶抠图的空隙、单面墙的背面。此时深度与法线指的不是人眼看到的那个点,
|
|
736
|
+
// GTAO 算出的 AO 不可信 → 视为无遮蔽(=1)。
|
|
737
|
+
// ⚠️ 2026-10-11:本守卫原本主要防「可透视地板挡住身后实体」,那条特例已随地板进深度图而作废,
|
|
738
|
+
// 现在它守的是上面这类 override/自身材质两套渲染结果的错位,别当死代码删。
|
|
739
|
+
// 仅在最终合成时生效;debug 模式直接看 GTAO 原始 AO 图,便于排查。
|
|
757
740
|
float dColor = texture2D(tColorDepth, vUv).r;
|
|
758
741
|
float dAo = texture2D(tAoDepth, vUv).r;
|
|
759
742
|
if (debug < 0.5 && dAo < dColor - 0.0001) {
|
|
@@ -821,17 +804,20 @@ export default function ssao_pass(
|
|
|
821
804
|
// 覆盖 SSAO 自身的硬边。改动调用顺序时,本 pass 无需修改(输出到"绑定的那个目标"即可)。
|
|
822
805
|
const originRenderTarget = renderer.getRenderTarget();
|
|
823
806
|
|
|
824
|
-
// 法线 pass
|
|
807
|
+
// 法线 pass(excludeTransparent=true):隐式透明面不参与 AO,免得 GTAO 在其上算自遮蔽把
|
|
808
|
+
// 身后实体乘黑;地板/其它不透明面照常保留 —— 接触 AO 需要地板的视图空间法线。
|
|
825
809
|
// ⭐ 深度白拿(2026-09-14 优化):normalRenderTarget 挂着 aoDepthTexture 作 depth attachment,
|
|
826
|
-
// 这一次渲染的深度由光栅器顺带写入 →
|
|
827
|
-
// (原先法线 pass
|
|
810
|
+
// 这一次渲染的深度由光栅器顺带写入 → 直接就是 AO 深度,**不再单独渲一遍深度 pass**。
|
|
811
|
+
// (原先法线 pass 之后还要再渲一遍「AO 深度」——它与法线 pass 的排除集完全相同,
|
|
828
812
|
// 属于重复遍历全场景,2026-09-14 已删。)
|
|
829
|
-
//
|
|
813
|
+
// ⚠️ 这一趟的深度是 override 材质写的(DoubleSide、不做物体自己的 alpha discard),
|
|
814
|
+
// 所以只能给 AO 用;特效遮挡吃的是下面那张「用自身材质渲染」的可见深度。
|
|
830
815
|
renderAoNormalPass(renderer, camera, scene, normalRenderTarget, normalMaterial, true);
|
|
831
816
|
|
|
832
|
-
//
|
|
817
|
+
// 可见深度(用各物体自身材质渲染,含地板)= baseDepthTexture:描边/辉光/毛玻璃/覆盖色的遮挡参考,
|
|
818
|
+
// 也是复合守卫里「真实可见表面」的参考。
|
|
833
819
|
const colorDepthTexture = depthRenderTarget.depthTexture as DepthTexture;
|
|
834
|
-
// AO
|
|
820
|
+
// AO 深度:GTAO 与去噪采样它(与上面的法线同一次光栅化,深度-法线永远同源)。
|
|
835
821
|
const aoDepthTexture = normalRenderTarget.depthTexture as DepthTexture;
|
|
836
822
|
const normalTexture = normalRenderTarget.texture;
|
|
837
823
|
|
|
@@ -906,8 +892,8 @@ export default function ssao_pass(
|
|
|
906
892
|
|
|
907
893
|
renderer.setRenderTarget(originRenderTarget);
|
|
908
894
|
outputShader.uniforms.ssaoTexture.value = blurTextureTarget.texture;
|
|
909
|
-
//
|
|
910
|
-
//
|
|
895
|
+
// 复合守卫:可见深度(自身材质渲染)与 AO 深度(override 渲染)两图比对,
|
|
896
|
+
// AO 侧更近 = 那像素记到屏幕上不可见的面(抠图空隙/单面墙背面)→ 作废该像素 AO(见 outputShader 注释)。
|
|
911
897
|
outputShader.uniforms.tColorDepth.value = colorDepthTexture;
|
|
912
898
|
outputShader.uniforms.tAoDepth.value = aoDepthTexture;
|
|
913
899
|
// 叠加强度:finalOcclusion = mix(1.0, ao, strength),0 = 完全不叠加 AO,1 = 原始强度,>1 外插加深。
|