three-base 2.0.197 → 2.0.199
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/MktMesh/MktMesh.d.ts +52 -8
- package/MktMesh/MktMesh.js +104 -13
- package/MktMesh/MktMesh.ts +106 -14
- package/MktMesh/imagePlane.d.ts +14 -0
- package/MktMesh/imagePlane.js +79 -3
- package/MktMesh/imagePlane.ts +79 -2
- package/MktMesh/mktResManager.d.ts +77 -0
- package/MktMesh/mktResManager.js +89 -0
- package/MktMesh/mktResManager.ts +130 -0
- package/MktMesh/modelSlot.d.ts +2 -0
- package/MktMesh/modelSlot.js +12 -0
- package/MktMesh/modelSlot.ts +12 -0
- package/ThreeBase.js +1 -10
- package/ThreeBase.ts +1 -9
- package/package.json +1 -1
- package/pass/debugDepthState.d.ts +4 -8
- package/pass/debugDepthState.js +0 -4
- package/pass/debugDepthState.ts +4 -10
- package/pass/stroke_pass.js +8 -90
- package/pass/stroke_pass.ts +8 -94
package/MktMesh/modelSlot.ts
CHANGED
|
@@ -42,6 +42,11 @@ import threeLoader from "../threeLoader";
|
|
|
42
42
|
import threeUtils from "../threeUtils";
|
|
43
43
|
import BoxLine2 from "./boxLine2";
|
|
44
44
|
|
|
45
|
+
/** glb 地址 → 文件名(日志唯一口径:去掉查询串取最后一段;⛔ 别在打印点各写一份 split) */
|
|
46
|
+
export function glbFileName(url: string): string {
|
|
47
|
+
return url.split("?")[0].split("/").pop() || url;
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
/** 模型槽的持久化数据(进 exportData / importData / 预览 loadData) */
|
|
46
51
|
export interface ModelSlotData {
|
|
47
52
|
name?: string;
|
|
@@ -219,6 +224,9 @@ export class ModelSlot extends Group {
|
|
|
219
224
|
this._loaded = true;
|
|
220
225
|
return true;
|
|
221
226
|
}
|
|
227
|
+
// 用户 2026-11-04「日志少打印点吧」⇒ 这一颗的取回入口⛔ 不出声:整层重建一次几十颗,逐颗一行会刷屏。
|
|
228
|
+
// 文件名改由两个批次入口各打一条 —— 单颗动作(上传/复制/换地址)在下面的 `setModelUrl`,
|
|
229
|
+
// 整层重建在 `MktMesh.setModels`(那边一条列全)⇒ 一颗不落,但一拍一条。
|
|
222
230
|
// 取回失败(404 / 解析报错都从这一档走):`threeLoader.loadModel` 是会 reject 的,⚠️ 必须当「落定在占位方块」处理
|
|
223
231
|
// —— 整层重建时这一颗是压着不亮的,不落定就永远隐形(旧写法里它至少还露得出占位方块)。
|
|
224
232
|
let obj: Object3D | undefined;
|
|
@@ -263,6 +271,10 @@ export class ModelSlot extends Group {
|
|
|
263
271
|
* @returns 是否真的挂上了(地址无效/载入失败/这次结果已作废 ⇒ false;空地址 = 退回占位,返回 true)
|
|
264
272
|
*/
|
|
265
273
|
async setModelUrl(url: string): Promise<boolean> {
|
|
274
|
+
// 用户 2026-11-04「日志少打印点吧」⇒ 逐颗一行从 `loadModel` 挪到这里:这一路一次动作只动一/几颗
|
|
275
|
+
// (上传 .glb、复制模型、换同名 glb),一条就是他能对上号的那一颗;整层重建那几十颗由
|
|
276
|
+
// `MktMesh.setModels` 攒成一条 ⇒ 文件名仍「一颗不落」,行数从 N 降到 1。空地址 = 退回占位,不打。
|
|
277
|
+
if (url) console.log(`[MktMesh] 加载 glb「${this.name}」:${glbFileName(url)}`);
|
|
266
278
|
if (!(await this.loadModel(url))) return false;
|
|
267
279
|
if (this._staged) this.mountStaged();
|
|
268
280
|
return true;
|
package/ThreeBase.js
CHANGED
|
@@ -971,10 +971,8 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
971
971
|
// compare → R=全局 base 深度,G=最近一次 glow/stroke 选区的 select 深度。两路任一全白即该侧写入失败。
|
|
972
972
|
// judge → R=base 原始深度、G=select 原始深度、B=判定结果(1=判为被遮挡应 discard)。
|
|
973
973
|
// strokeSelect → 【描边步骤 1】选区本体深度(selectDepthTexture),白色=空背景、灰=物体本体。
|
|
974
|
-
// strokeSelectBlur → 【描边步骤 5.5】描边外扩后的选区深度(selectDepthBlurTextureTarget),
|
|
975
|
-
// 物体轮廓比本体档更胖一圈即外扩生效。
|
|
976
974
|
// 通用控制台入口(任意页面可用,优先级高于面板属性):
|
|
977
|
-
// `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge" | "strokeSelect"
|
|
975
|
+
// `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge" | "strokeSelect"`,
|
|
978
976
|
// 设回 "none" 恢复。
|
|
979
977
|
const dbgWin = window.__TB_DEBUG_DEPTH;
|
|
980
978
|
const dbgMode = window.__BASE_DEPTH_VIS
|
|
@@ -1011,13 +1009,6 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
1011
1009
|
debugDepthState.lastSelectDepth ?? this.baseDepthTexture;
|
|
1012
1010
|
fsQuad.render(this.renderer, baseDepthVisShader);
|
|
1013
1011
|
}
|
|
1014
|
-
else if (dbgMode === "strokeSelectBlur") {
|
|
1015
|
-
// 描边步骤 5.5:外扩后的选区深度(RGBA8 目标,对数深度存在 .r 通道)。
|
|
1016
|
-
// 与本体档对比看:外扩生效时物体轮廓会「胖一圈」,被遮挡的外扩环则被判 discard 后不参与。
|
|
1017
|
-
baseDepthVisShader.uniforms.tDepth.value =
|
|
1018
|
-
debugDepthState.lastSelectBlurDepth ?? this.baseDepthTexture;
|
|
1019
|
-
fsQuad.render(this.renderer, baseDepthVisShader);
|
|
1020
|
-
}
|
|
1021
1012
|
flushLensflareOverlays(this.renderer, camera);
|
|
1022
1013
|
return;
|
|
1023
1014
|
}
|
package/ThreeBase.ts
CHANGED
|
@@ -1071,10 +1071,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
1071
1071
|
// compare → R=全局 base 深度,G=最近一次 glow/stroke 选区的 select 深度。两路任一全白即该侧写入失败。
|
|
1072
1072
|
// judge → R=base 原始深度、G=select 原始深度、B=判定结果(1=判为被遮挡应 discard)。
|
|
1073
1073
|
// strokeSelect → 【描边步骤 1】选区本体深度(selectDepthTexture),白色=空背景、灰=物体本体。
|
|
1074
|
-
// strokeSelectBlur → 【描边步骤 5.5】描边外扩后的选区深度(selectDepthBlurTextureTarget),
|
|
1075
|
-
// 物体轮廓比本体档更胖一圈即外扩生效。
|
|
1076
1074
|
// 通用控制台入口(任意页面可用,优先级高于面板属性):
|
|
1077
|
-
// `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge" | "strokeSelect"
|
|
1075
|
+
// `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge" | "strokeSelect"`,
|
|
1078
1076
|
// 设回 "none" 恢复。
|
|
1079
1077
|
const dbgWin = (window as unknown as { __TB_DEBUG_DEPTH?: DebugDepthMode }).__TB_DEBUG_DEPTH;
|
|
1080
1078
|
const dbgMode = (window as unknown as { __BASE_DEPTH_VIS?: boolean }).__BASE_DEPTH_VIS
|
|
@@ -1106,12 +1104,6 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
1106
1104
|
baseDepthVisShader.uniforms.tDepth.value =
|
|
1107
1105
|
debugDepthState.lastSelectDepth ?? this.baseDepthTexture;
|
|
1108
1106
|
fsQuad.render(this.renderer, baseDepthVisShader);
|
|
1109
|
-
} else if (dbgMode === "strokeSelectBlur") {
|
|
1110
|
-
// 描边步骤 5.5:外扩后的选区深度(RGBA8 目标,对数深度存在 .r 通道)。
|
|
1111
|
-
// 与本体档对比看:外扩生效时物体轮廓会「胖一圈」,被遮挡的外扩环则被判 discard 后不参与。
|
|
1112
|
-
baseDepthVisShader.uniforms.tDepth.value =
|
|
1113
|
-
debugDepthState.lastSelectBlurDepth ?? this.baseDepthTexture;
|
|
1114
|
-
fsQuad.render(this.renderer, baseDepthVisShader);
|
|
1115
1107
|
}
|
|
1116
1108
|
flushLensflareOverlays(this.renderer, camera);
|
|
1117
1109
|
return;
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DepthTexture
|
|
1
|
+
import type { DepthTexture } from "three";
|
|
2
2
|
/**
|
|
3
3
|
* 深度调试预览模式(面板按钮与控制台 `window.__TB_DEBUG_DEPTH` 共用同一枚举):
|
|
4
4
|
* - "none" :正常渲染(默认)
|
|
@@ -7,22 +7,18 @@ import type { DepthTexture, Texture } from "three";
|
|
|
7
7
|
* - "compare" :R=base 深度、G=选区 select 深度(对数反解后归一化)
|
|
8
8
|
* - "judge" :R=base 原始深度、G=select 原始深度、B=判定结果(1=判为被遮挡应 discard)
|
|
9
9
|
* - "strokeSelect" :【描边步骤 1】选区本体深度(selectDepthTexture,mask 那趟光栅化顺带写入)
|
|
10
|
-
* - "strokeSelectBlur":【描边步骤 5.5】描边外扩后的选区深度(selectDepthBlurTextureTarget,
|
|
11
|
-
* RGBA8 的 R 通道存对数深度,外扩环取邻域最近深度)
|
|
12
10
|
* ⚠️ 2026-10-18 皇上旨「所有的对象都要进入到深度图里面了,不需要用参数过滤掉了」⇒ 原 "excluded"
|
|
13
11
|
* 档(把被排除的面叠红)连同 ssao_pass 的排除判据整条删除,已无「写不进深度图的面」可标。
|
|
12
|
+
* ⚠️ 2026-11-04 描边回到年初口径 ⇒ 原 "strokeSelectBlur" 档(步骤 5.5 外扩后的选区深度)连同
|
|
13
|
+
* 那条 min-blur 整条删除,管线里已无「外扩深度」可供显示。
|
|
14
14
|
*/
|
|
15
|
-
export type DebugDepthMode = "none" | "global" | "ao" | "compare" | "judge" | "strokeSelect"
|
|
15
|
+
export type DebugDepthMode = "none" | "global" | "ao" | "compare" | "judge" | "strokeSelect";
|
|
16
16
|
/**
|
|
17
17
|
* 调试用全局状态:记录最近一次 glow_pass / stroke_pass 渲染的「选区自身深度图」(selectDepth)。
|
|
18
18
|
* 供 ThreeBase 渲染末尾的「辉光深度比对」调试视图读取(R=全局 base 深度,G=选区 select 深度),
|
|
19
19
|
* 让用户一眼看出到底是「全局 base 深度没写进」还是「选区自身深度没写进」。
|
|
20
20
|
* 由各 pass 在渲染完 selectDepth 后写入;每帧会被最后一个被处理的可见对象覆盖(调试够用)。
|
|
21
|
-
*
|
|
22
|
-
* lastSelectBlurDepth:描边专属(步骤 5.5 外扩后的选区深度)。它是 RGBA8 目标(不是 DepthTexture),
|
|
23
|
-
* 深度值存在 .r 通道里 —— 可视化时同样取 .r 即可。glow/cover/frosted 没有这一步,故只有 stroke_pass 写。
|
|
24
21
|
*/
|
|
25
22
|
export declare const debugDepthState: {
|
|
26
23
|
lastSelectDepth: DepthTexture | null;
|
|
27
|
-
lastSelectBlurDepth: Texture | null;
|
|
28
24
|
};
|
package/pass/debugDepthState.js
CHANGED
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
* 供 ThreeBase 渲染末尾的「辉光深度比对」调试视图读取(R=全局 base 深度,G=选区 select 深度),
|
|
4
4
|
* 让用户一眼看出到底是「全局 base 深度没写进」还是「选区自身深度没写进」。
|
|
5
5
|
* 由各 pass 在渲染完 selectDepth 后写入;每帧会被最后一个被处理的可见对象覆盖(调试够用)。
|
|
6
|
-
*
|
|
7
|
-
* lastSelectBlurDepth:描边专属(步骤 5.5 外扩后的选区深度)。它是 RGBA8 目标(不是 DepthTexture),
|
|
8
|
-
* 深度值存在 .r 通道里 —— 可视化时同样取 .r 即可。glow/cover/frosted 没有这一步,故只有 stroke_pass 写。
|
|
9
6
|
*/
|
|
10
7
|
export const debugDepthState = {
|
|
11
8
|
lastSelectDepth: null,
|
|
12
|
-
lastSelectBlurDepth: null,
|
|
13
9
|
};
|
package/pass/debugDepthState.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DepthTexture
|
|
1
|
+
import type { DepthTexture } from "three";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 深度调试预览模式(面板按钮与控制台 `window.__TB_DEBUG_DEPTH` 共用同一枚举):
|
|
@@ -8,10 +8,10 @@ import type { DepthTexture, Texture } from "three";
|
|
|
8
8
|
* - "compare" :R=base 深度、G=选区 select 深度(对数反解后归一化)
|
|
9
9
|
* - "judge" :R=base 原始深度、G=select 原始深度、B=判定结果(1=判为被遮挡应 discard)
|
|
10
10
|
* - "strokeSelect" :【描边步骤 1】选区本体深度(selectDepthTexture,mask 那趟光栅化顺带写入)
|
|
11
|
-
* - "strokeSelectBlur":【描边步骤 5.5】描边外扩后的选区深度(selectDepthBlurTextureTarget,
|
|
12
|
-
* RGBA8 的 R 通道存对数深度,外扩环取邻域最近深度)
|
|
13
11
|
* ⚠️ 2026-10-18 皇上旨「所有的对象都要进入到深度图里面了,不需要用参数过滤掉了」⇒ 原 "excluded"
|
|
14
12
|
* 档(把被排除的面叠红)连同 ssao_pass 的排除判据整条删除,已无「写不进深度图的面」可标。
|
|
13
|
+
* ⚠️ 2026-11-04 描边回到年初口径 ⇒ 原 "strokeSelectBlur" 档(步骤 5.5 外扩后的选区深度)连同
|
|
14
|
+
* 那条 min-blur 整条删除,管线里已无「外扩深度」可供显示。
|
|
15
15
|
*/
|
|
16
16
|
export type DebugDepthMode =
|
|
17
17
|
| "none"
|
|
@@ -19,22 +19,16 @@ export type DebugDepthMode =
|
|
|
19
19
|
| "ao"
|
|
20
20
|
| "compare"
|
|
21
21
|
| "judge"
|
|
22
|
-
| "strokeSelect"
|
|
23
|
-
| "strokeSelectBlur";
|
|
22
|
+
| "strokeSelect";
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* 调试用全局状态:记录最近一次 glow_pass / stroke_pass 渲染的「选区自身深度图」(selectDepth)。
|
|
27
26
|
* 供 ThreeBase 渲染末尾的「辉光深度比对」调试视图读取(R=全局 base 深度,G=选区 select 深度),
|
|
28
27
|
* 让用户一眼看出到底是「全局 base 深度没写进」还是「选区自身深度没写进」。
|
|
29
28
|
* 由各 pass 在渲染完 selectDepth 后写入;每帧会被最后一个被处理的可见对象覆盖(调试够用)。
|
|
30
|
-
*
|
|
31
|
-
* lastSelectBlurDepth:描边专属(步骤 5.5 外扩后的选区深度)。它是 RGBA8 目标(不是 DepthTexture),
|
|
32
|
-
* 深度值存在 .r 通道里 —— 可视化时同样取 .r 即可。glow/cover/frosted 没有这一步,故只有 stroke_pass 写。
|
|
33
29
|
*/
|
|
34
30
|
export const debugDepthState: {
|
|
35
31
|
lastSelectDepth: DepthTexture | null;
|
|
36
|
-
lastSelectBlurDepth: Texture | null;
|
|
37
32
|
} = {
|
|
38
33
|
lastSelectDepth: null,
|
|
39
|
-
lastSelectBlurDepth: null,
|
|
40
34
|
};
|
package/pass/stroke_pass.js
CHANGED
|
@@ -38,12 +38,6 @@ const selectDepthTestTextureTarget = new WebGLRenderTarget(1024, 1024, {
|
|
|
38
38
|
});
|
|
39
39
|
const blur1TextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
40
40
|
const blur2TextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
41
|
-
// 外扩深度临时/结果目标:depthMinBlurShader 把本体深度图随描边一起外扩,
|
|
42
|
-
// 外扩区取邻域最近深度(忽略背景 1.0),使外扩区 selD<1.0,depthTest 才能正确判遮挡(不漏光)。
|
|
43
|
-
const selectDepthBlurTmpTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
44
|
-
const selectDepthBlurTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
45
|
-
// 外扩描边经深度测试后的结果(步骤 5.6):独立 target,避免回写 blur1 触发历史回归 bug
|
|
46
|
-
const blurDepthTestTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
47
41
|
const size = new Vector2();
|
|
48
42
|
const depthTestShader = new ShaderMaterial({
|
|
49
43
|
uniforms: {
|
|
@@ -383,52 +377,6 @@ const strokeShader = new RawShaderMaterial({
|
|
|
383
377
|
depthWrite: false,
|
|
384
378
|
transparent: true
|
|
385
379
|
});
|
|
386
|
-
// 深度 min-blur(最近深度,忽略背景 1.0):随描边一起把深度图向外扩,
|
|
387
|
-
// 外扩区 selD = 物体最近深度(<1.0) 而非清屏 1.0,depthTest 在外扩区才能正确判遮挡(不漏光),
|
|
388
|
-
// 同时本体区仍靠 depthTestShader 的 EPSILON 容差防自遮挡闪烁(无缝)。separable(direction 控制 H/V)。
|
|
389
|
-
const depthMinBlurShader = new ShaderMaterial({
|
|
390
|
-
uniforms: {
|
|
391
|
-
tDepth: { value: null },
|
|
392
|
-
resolution: { value: new Vector2(1 / 512, 1 / 512) },
|
|
393
|
-
radius: { value: 1.0 },
|
|
394
|
-
direction: { value: new Vector2(1, 0) },
|
|
395
|
-
},
|
|
396
|
-
vertexShader: `
|
|
397
|
-
${ShaderChunk.common}
|
|
398
|
-
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
399
|
-
varying vec2 vUv;
|
|
400
|
-
void main() {
|
|
401
|
-
vUv = uv;
|
|
402
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
403
|
-
${ShaderChunk.logdepthbuf_vertex}
|
|
404
|
-
}
|
|
405
|
-
`,
|
|
406
|
-
fragmentShader: `
|
|
407
|
-
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
408
|
-
uniform sampler2D tDepth;
|
|
409
|
-
uniform vec2 resolution;
|
|
410
|
-
uniform float radius;
|
|
411
|
-
uniform vec2 direction;
|
|
412
|
-
varying vec2 vUv;
|
|
413
|
-
void main() {
|
|
414
|
-
float minD = 1.0;
|
|
415
|
-
for (int i = -10; i <= 10; i++) {
|
|
416
|
-
float x = float(i);
|
|
417
|
-
vec2 off = direction * (x * radius * resolution);
|
|
418
|
-
float d = texture2D(tDepth, vUv + off).r;
|
|
419
|
-
if (d < 0.9999) {
|
|
420
|
-
minD = min(minD, d);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
gl_FragColor = vec4(minD, 0.0, 0.0, 1.0);
|
|
424
|
-
${ShaderChunk.logdepthbuf_fragment}
|
|
425
|
-
}
|
|
426
|
-
`,
|
|
427
|
-
blending: NoBlending,
|
|
428
|
-
depthTest: false,
|
|
429
|
-
depthWrite: false,
|
|
430
|
-
transparent: true,
|
|
431
|
-
});
|
|
432
380
|
const filterSelectShader = new RawShaderMaterial({
|
|
433
381
|
uniforms: {
|
|
434
382
|
selectTexture: { value: null },
|
|
@@ -508,9 +456,6 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
508
456
|
selectDepthTestTextureTarget.setSize(size.x, size.y);
|
|
509
457
|
blur1TextureTarget.setSize(size.x, size.y);
|
|
510
458
|
blur2TextureTarget.setSize(size.x, size.y);
|
|
511
|
-
selectDepthBlurTmpTextureTarget.setSize(size.x, size.y);
|
|
512
|
-
selectDepthBlurTextureTarget.setSize(size.x, size.y);
|
|
513
|
-
blurDepthTestTextureTarget.setSize(size.x, size.y);
|
|
514
459
|
// 1. 渲染物体本体 mask(灰度)。⭐ 本体深度由同一趟光栅化顺带写进 selectDepthTexture
|
|
515
460
|
// (挂在 selectTextureTarget 的 depth attachment 上)—— 原先这里还有第 2 趟「只渲深度」,
|
|
516
461
|
// 同材质/同相机/同几何 ⇒ 深度逐位相同,纯重复遍历,2026-10-11 皇上旨简化时删除。
|
|
@@ -532,7 +477,8 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
532
477
|
depthTestShader.uniforms.cameraFar.value = camera.far;
|
|
533
478
|
depthTestShader.uniforms.uDebugVis.value = (window.__STROKE_DEPTH_VIS) ? 1.0 : 0.0;
|
|
534
479
|
fsQuad.render(renderer, depthTestShader);
|
|
535
|
-
// 4.
|
|
480
|
+
// 4. 从「深度测试后的本体描边」开始外扩(外扩的源头是本体判过的结果,被挡掉的本体不会再长出描边;
|
|
481
|
+
// 但外扩出来那圈像素本身不再判深度 ⇒ 贴着遮挡物时会压到遮挡物前面,见步骤 6 的代价点名),
|
|
536
482
|
// 描边粗细由 stroke_width 控制的迭代次数决定。
|
|
537
483
|
strokeShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
538
484
|
FXAAShaderMaterial.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
@@ -557,42 +503,14 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
557
503
|
renderer.setRenderTarget(blur1TextureTarget);
|
|
558
504
|
FXAAShaderMaterial.uniforms.tDiffuse.value = blur2TextureTarget.texture;
|
|
559
505
|
fsQuad.render(renderer, FXAAShaderMaterial);
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
depthMinBlurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
566
|
-
depthMinBlurShader.uniforms.radius.value = Math.max(1, stroke_width);
|
|
567
|
-
// H:直接采 DepthTexture(selectDepthTexture),其 .r 即对数深度
|
|
568
|
-
depthMinBlurShader.uniforms.direction.value.set(1, 0);
|
|
569
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthTexture;
|
|
570
|
-
renderer.setRenderTarget(selectDepthBlurTmpTextureTarget);
|
|
571
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
572
|
-
// V
|
|
573
|
-
depthMinBlurShader.uniforms.direction.value.set(0, 1);
|
|
574
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthBlurTmpTextureTarget.texture;
|
|
575
|
-
renderer.setRenderTarget(selectDepthBlurTextureTarget);
|
|
576
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
577
|
-
// 调试:记录「外扩后的选区深度」,供面板「深度图(分步)」的步骤 5.5 档读取。
|
|
578
|
-
// 它是 RGBA8 目标、对数深度存在 .r 里(与 DepthTexture 取 .r 的读法一致)。
|
|
579
|
-
debugDepthState.lastSelectBlurDepth = selectDepthBlurTextureTarget.texture;
|
|
580
|
-
// 5.6 对外扩后的描边判遮挡:被更近几何挡住的外扩环像素 discard。
|
|
581
|
-
// ⚠️ 输出到独立 target,绝不回写 blur1(历史回归 bug:blur1 被 depthTest 结果覆盖
|
|
582
|
-
// 会导致步骤 6 相减归零、描边全不显示)。
|
|
583
|
-
renderer.setRenderTarget(blurDepthTestTextureTarget);
|
|
584
|
-
renderer.clear();
|
|
585
|
-
depthTestShader.uniforms.map.value = blur1TextureTarget.texture;
|
|
586
|
-
depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
|
|
587
|
-
depthTestShader.uniforms.selectDepth.value = selectDepthBlurTextureTarget.texture;
|
|
588
|
-
depthTestShader.uniforms.cameraFar.value = camera.far;
|
|
589
|
-
depthTestShader.uniforms.uDebugVis.value = 0.0;
|
|
590
|
-
fsQuad.render(renderer, depthTestShader);
|
|
591
|
-
// 6. 合成:最终外扩描边(blurDepthTest,已判遮挡) 减去 深度测试后的本体描边
|
|
592
|
-
// = 仅保留描边外扩环;本体被减掉。filterSelectShader 用 NormalBlending 叠到场景上。
|
|
506
|
+
// 6. 合成:FXAA 后的外扩描边(blur1) 减去 深度测试后的本体 = 仅保留描边外扩环;本体被减掉。
|
|
507
|
+
// ⚠️ 2026-11-04 决定回到「年初口径」:原先这里有 5.5(本体深度随描边一起 separable min-blur 外扩)
|
|
508
|
+
// 与 5.6(用外扩后的深度再判一次遮挡)两趟,作用是外扩环也参与遮挡判定 ⇒ 物体被挡住时描边不漏光。
|
|
509
|
+
// 撤掉换来的是每个描边对象每帧全屏绘制 10 趟降 7 趟(min-blur 那两趟是 ±10 共 21 次采样/像素,最贵);
|
|
510
|
+
// 代价点名:只有本体参与判遮挡,外扩环不参与 ⇒ 物体贴着遮挡物边缘时,一圈描边会压在遮挡物前面。
|
|
593
511
|
renderer.setRenderTarget(originRenderTarget);
|
|
594
512
|
filterSelectShader.uniforms.selectTexture.value = selectDepthTestTextureTarget.texture;
|
|
595
|
-
filterSelectShader.uniforms.blurTexture.value =
|
|
513
|
+
filterSelectShader.uniforms.blurTexture.value = blur1TextureTarget.texture;
|
|
596
514
|
filterSelectShader.blending = NormalBlending;
|
|
597
515
|
fsQuad.render(renderer, filterSelectShader);
|
|
598
516
|
}
|
package/pass/stroke_pass.ts
CHANGED
|
@@ -44,12 +44,6 @@ const selectDepthTestTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(10
|
|
|
44
44
|
const blur1TextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
45
45
|
|
|
46
46
|
const blur2TextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
47
|
-
// 外扩深度临时/结果目标:depthMinBlurShader 把本体深度图随描边一起外扩,
|
|
48
|
-
// 外扩区取邻域最近深度(忽略背景 1.0),使外扩区 selD<1.0,depthTest 才能正确判遮挡(不漏光)。
|
|
49
|
-
const selectDepthBlurTmpTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
50
|
-
const selectDepthBlurTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
51
|
-
// 外扩描边经深度测试后的结果(步骤 5.6):独立 target,避免回写 blur1 触发历史回归 bug
|
|
52
|
-
const blurDepthTestTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
53
47
|
|
|
54
48
|
const size: Vector2 = new Vector2();
|
|
55
49
|
|
|
@@ -394,53 +388,6 @@ const strokeShader: RawShaderMaterial = new RawShaderMaterial({
|
|
|
394
388
|
transparent: true
|
|
395
389
|
});
|
|
396
390
|
|
|
397
|
-
// 深度 min-blur(最近深度,忽略背景 1.0):随描边一起把深度图向外扩,
|
|
398
|
-
// 外扩区 selD = 物体最近深度(<1.0) 而非清屏 1.0,depthTest 在外扩区才能正确判遮挡(不漏光),
|
|
399
|
-
// 同时本体区仍靠 depthTestShader 的 EPSILON 容差防自遮挡闪烁(无缝)。separable(direction 控制 H/V)。
|
|
400
|
-
const depthMinBlurShader: ShaderMaterial = new ShaderMaterial({
|
|
401
|
-
uniforms: {
|
|
402
|
-
tDepth: { value: null },
|
|
403
|
-
resolution: { value: new Vector2(1 / 512, 1 / 512) },
|
|
404
|
-
radius: { value: 1.0 },
|
|
405
|
-
direction: { value: new Vector2(1, 0) },
|
|
406
|
-
},
|
|
407
|
-
vertexShader: `
|
|
408
|
-
${ShaderChunk.common}
|
|
409
|
-
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
410
|
-
varying vec2 vUv;
|
|
411
|
-
void main() {
|
|
412
|
-
vUv = uv;
|
|
413
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
414
|
-
${ShaderChunk.logdepthbuf_vertex}
|
|
415
|
-
}
|
|
416
|
-
`,
|
|
417
|
-
fragmentShader: `
|
|
418
|
-
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
419
|
-
uniform sampler2D tDepth;
|
|
420
|
-
uniform vec2 resolution;
|
|
421
|
-
uniform float radius;
|
|
422
|
-
uniform vec2 direction;
|
|
423
|
-
varying vec2 vUv;
|
|
424
|
-
void main() {
|
|
425
|
-
float minD = 1.0;
|
|
426
|
-
for (int i = -10; i <= 10; i++) {
|
|
427
|
-
float x = float(i);
|
|
428
|
-
vec2 off = direction * (x * radius * resolution);
|
|
429
|
-
float d = texture2D(tDepth, vUv + off).r;
|
|
430
|
-
if (d < 0.9999) {
|
|
431
|
-
minD = min(minD, d);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
gl_FragColor = vec4(minD, 0.0, 0.0, 1.0);
|
|
435
|
-
${ShaderChunk.logdepthbuf_fragment}
|
|
436
|
-
}
|
|
437
|
-
`,
|
|
438
|
-
blending: NoBlending,
|
|
439
|
-
depthTest: false,
|
|
440
|
-
depthWrite: false,
|
|
441
|
-
transparent: true,
|
|
442
|
-
});
|
|
443
|
-
|
|
444
391
|
const filterSelectShader: RawShaderMaterial = new RawShaderMaterial({
|
|
445
392
|
uniforms: {
|
|
446
393
|
selectTexture: { value: null },
|
|
@@ -536,9 +483,6 @@ export default function stroke_pass(
|
|
|
536
483
|
selectDepthTestTextureTarget.setSize(size.x, size.y);
|
|
537
484
|
blur1TextureTarget.setSize(size.x, size.y);
|
|
538
485
|
blur2TextureTarget.setSize(size.x, size.y);
|
|
539
|
-
selectDepthBlurTmpTextureTarget.setSize(size.x, size.y);
|
|
540
|
-
selectDepthBlurTextureTarget.setSize(size.x, size.y);
|
|
541
|
-
blurDepthTestTextureTarget.setSize(size.x, size.y);
|
|
542
486
|
|
|
543
487
|
// 1. 渲染物体本体 mask(灰度)。⭐ 本体深度由同一趟光栅化顺带写进 selectDepthTexture
|
|
544
488
|
// (挂在 selectTextureTarget 的 depth attachment 上)—— 原先这里还有第 2 趟「只渲深度」,
|
|
@@ -563,7 +507,8 @@ export default function stroke_pass(
|
|
|
563
507
|
depthTestShader.uniforms.uDebugVis.value = ((window as unknown as { __STROKE_DEPTH_VIS?: boolean }).__STROKE_DEPTH_VIS) ? 1.0 : 0.0;
|
|
564
508
|
fsQuad.render(renderer, depthTestShader);
|
|
565
509
|
|
|
566
|
-
// 4.
|
|
510
|
+
// 4. 从「深度测试后的本体描边」开始外扩(外扩的源头是本体判过的结果,被挡掉的本体不会再长出描边;
|
|
511
|
+
// 但外扩出来那圈像素本身不再判深度 ⇒ 贴着遮挡物时会压到遮挡物前面,见步骤 6 的代价点名),
|
|
567
512
|
// 描边粗细由 stroke_width 控制的迭代次数决定。
|
|
568
513
|
strokeShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
569
514
|
FXAAShaderMaterial.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
@@ -590,45 +535,14 @@ export default function stroke_pass(
|
|
|
590
535
|
FXAAShaderMaterial.uniforms.tDiffuse.value = blur2TextureTarget.texture;
|
|
591
536
|
fsQuad.render(renderer, FXAAShaderMaterial);
|
|
592
537
|
|
|
593
|
-
//
|
|
594
|
-
//
|
|
595
|
-
//
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
depthMinBlurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
599
|
-
depthMinBlurShader.uniforms.radius.value = Math.max(1, stroke_width);
|
|
600
|
-
// H:直接采 DepthTexture(selectDepthTexture),其 .r 即对数深度
|
|
601
|
-
depthMinBlurShader.uniforms.direction.value.set(1, 0);
|
|
602
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthTexture;
|
|
603
|
-
renderer.setRenderTarget(selectDepthBlurTmpTextureTarget);
|
|
604
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
605
|
-
// V
|
|
606
|
-
depthMinBlurShader.uniforms.direction.value.set(0, 1);
|
|
607
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthBlurTmpTextureTarget.texture;
|
|
608
|
-
renderer.setRenderTarget(selectDepthBlurTextureTarget);
|
|
609
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
610
|
-
|
|
611
|
-
// 调试:记录「外扩后的选区深度」,供面板「深度图(分步)」的步骤 5.5 档读取。
|
|
612
|
-
// 它是 RGBA8 目标、对数深度存在 .r 里(与 DepthTexture 取 .r 的读法一致)。
|
|
613
|
-
debugDepthState.lastSelectBlurDepth = selectDepthBlurTextureTarget.texture;
|
|
614
|
-
|
|
615
|
-
// 5.6 对外扩后的描边判遮挡:被更近几何挡住的外扩环像素 discard。
|
|
616
|
-
// ⚠️ 输出到独立 target,绝不回写 blur1(历史回归 bug:blur1 被 depthTest 结果覆盖
|
|
617
|
-
// 会导致步骤 6 相减归零、描边全不显示)。
|
|
618
|
-
renderer.setRenderTarget(blurDepthTestTextureTarget);
|
|
619
|
-
renderer.clear();
|
|
620
|
-
depthTestShader.uniforms.map.value = blur1TextureTarget.texture;
|
|
621
|
-
depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
|
|
622
|
-
depthTestShader.uniforms.selectDepth.value = selectDepthBlurTextureTarget.texture;
|
|
623
|
-
depthTestShader.uniforms.cameraFar.value = (camera as PerspectiveCamera).far;
|
|
624
|
-
depthTestShader.uniforms.uDebugVis.value = 0.0;
|
|
625
|
-
fsQuad.render(renderer, depthTestShader);
|
|
626
|
-
|
|
627
|
-
// 6. 合成:最终外扩描边(blurDepthTest,已判遮挡) 减去 深度测试后的本体描边
|
|
628
|
-
// = 仅保留描边外扩环;本体被减掉。filterSelectShader 用 NormalBlending 叠到场景上。
|
|
538
|
+
// 6. 合成:FXAA 后的外扩描边(blur1) 减去 深度测试后的本体 = 仅保留描边外扩环;本体被减掉。
|
|
539
|
+
// ⚠️ 2026-11-04 决定回到「年初口径」:原先这里有 5.5(本体深度随描边一起 separable min-blur 外扩)
|
|
540
|
+
// 与 5.6(用外扩后的深度再判一次遮挡)两趟,作用是外扩环也参与遮挡判定 ⇒ 物体被挡住时描边不漏光。
|
|
541
|
+
// 撤掉换来的是每个描边对象每帧全屏绘制 10 趟降 7 趟(min-blur 那两趟是 ±10 共 21 次采样/像素,最贵);
|
|
542
|
+
// 代价点名:只有本体参与判遮挡,外扩环不参与 ⇒ 物体贴着遮挡物边缘时,一圈描边会压在遮挡物前面。
|
|
629
543
|
renderer.setRenderTarget(originRenderTarget);
|
|
630
544
|
filterSelectShader.uniforms.selectTexture.value = selectDepthTestTextureTarget.texture;
|
|
631
|
-
filterSelectShader.uniforms.blurTexture.value =
|
|
545
|
+
filterSelectShader.uniforms.blurTexture.value = blur1TextureTarget.texture;
|
|
632
546
|
filterSelectShader.blending = NormalBlending;
|
|
633
547
|
fsQuad.render(renderer, filterSelectShader);
|
|
634
548
|
}
|