three-base 2.0.188 → 2.0.192
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/MeshBase.d.ts +23 -0
- package/MeshBase.js +47 -1
- package/MeshBase.ts +301 -257
- package/MktMesh/MktMesh.d.ts +36 -3
- package/MktMesh/MktMesh.js +72 -5
- package/MktMesh/MktMesh.ts +1437 -1368
- package/MktMesh/imagePlane.d.ts +4 -0
- package/MktMesh/imagePlane.js +8 -0
- package/MktMesh/imagePlane.ts +7 -0
- package/MktMesh/mktMappingShader.d.ts +5 -3
- package/MktMesh/mktMappingShader.js +7 -5
- package/MktMesh/mktMappingShader.ts +7 -5
- package/MktMesh/mktShader.d.ts +58 -54
- package/MktMesh/mktShader.js +61 -57
- package/MktMesh/mktShader.ts +68 -64
- package/MktMesh/modelSlot.d.ts +8 -0
- package/MktMesh/modelSlot.js +26 -2
- package/MktMesh/modelSlot.ts +26 -2
- package/MktMesh/panoTileStitcher.d.ts +8 -6
- package/MktMesh/panoTileStitcher.js +36 -25
- package/MktMesh/panoTileStitcher.ts +37 -26
- package/MktMesh/types.d.ts +2 -1
- package/MktMesh/types.ts +2 -1
- package/ThreeBase.d.ts +4 -1
- package/ThreeBase.js +51 -42
- package/ThreeBase.ts +51 -42
- package/instanced/InstancedMeshBase.js +3 -0
- package/instanced/InstancedMeshBase.ts +3 -0
- package/package.json +1 -1
package/ThreeBase.js
CHANGED
|
@@ -72,21 +72,23 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
72
72
|
// (纹理被欠采样时的拍频,必须靠提高实际采样率才能消除)。
|
|
73
73
|
// 1 = 关闭超采样(仅设备 pixelRatio);2 = 2 倍超采样(质量最高,片元开销 ×4,需强 GPU)。
|
|
74
74
|
renderScale = 1;
|
|
75
|
-
//
|
|
76
|
-
// effectiveRatio × resolution
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// ⚠️ 必须用 getter/setter
|
|
86
|
-
// 里按 effectiveRatio × resolution
|
|
75
|
+
// 超采样倍率(SSAA)**只作用于 baseRenderTarget**(2026-10-27 需求:「只有 baseRT 的超采样参数是 4,
|
|
76
|
+
// 其他的 RT 超采样参数是 1」):base 按 effectiveRatio × resolution 渲染,深度 / 法线 / 效果 mask /
|
|
77
|
+
// 屏幕合成一律按 effectiveRatio × auxResolution(= 1)渲染。
|
|
78
|
+
// ⚠️ 两条与「全链路同倍率」那版不同、看得见的后果:
|
|
79
|
+
// ① base(4×) → screen(1×) 那次拷贝是**降采样**(RT 不长 mipmap,线性滤波只取到 4 个纹素)
|
|
80
|
+
// ⇒ base 的超采样不会原样带到屏幕上,末端仍靠 FXAA 兜锯齿。
|
|
81
|
+
// ② 描边/发光/覆盖/磨砂的 mask 与 base 深度都从 4× 降到 1×,而它们要合成进 4× 的 base
|
|
82
|
+
// ⇒ 这些效果的边缘按 1× 精度放大,比同倍率那版软;UV 仍严格对齐(错位只发生在精度,不在位置)。
|
|
83
|
+
// 现行 resolution = 4(setter 夹的上限也是 4);上一档 1 出自 2026-10-21「有点卡,分辨率改成 1」。
|
|
84
|
+
// 历史:再早是 base / 深度 / 法线 / mask / 屏幕 **共用同一个 resolution**,2026-10-27 起拆成 base 与其余两档。
|
|
85
|
+
// ⚠️ 必须用 getter/setter,不能是普通字段:RT 尺寸只在 updateRenderTargetSizes()
|
|
86
|
+
// 里按 effectiveRatio × resolution(base)/ × auxResolution(其余)计算,而该方法过去只被 setSize()(容器尺寸变化)调用
|
|
87
87
|
// → 运行时改 resolution 不会重建任何 RT,画面毫无变化(表现为"调分辨率没感觉")。
|
|
88
88
|
// 故 setter 里改动倍率后立刻重建全部 RT。
|
|
89
89
|
_resolution = 4;
|
|
90
|
+
/** baseRenderTarget 之外**全部** RT 的倍率(深度 / 法线 / 各效果 mask / 屏幕合成);1 = 不超采样 */
|
|
91
|
+
auxResolution = 1;
|
|
90
92
|
get resolution() {
|
|
91
93
|
return this._resolution;
|
|
92
94
|
}
|
|
@@ -172,6 +174,9 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
172
174
|
}
|
|
173
175
|
const w = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this._resolution));
|
|
174
176
|
const h = Math.max(1, Math.round(this.size.y * this.effectiveRatio * this._resolution));
|
|
177
|
+
// 除 base 之外的 RT 走 auxResolution(= 1):屏幕合成目标不跟着 base 超采样
|
|
178
|
+
const aw = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this.auxResolution));
|
|
179
|
+
const ah = Math.max(1, Math.round(this.size.y * this.effectiveRatio * this.auxResolution));
|
|
175
180
|
const opts = {
|
|
176
181
|
minFilter: this._rtOptions.filter,
|
|
177
182
|
magFilter: this._rtOptions.filter,
|
|
@@ -184,23 +189,22 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
184
189
|
this.baseRenderTarget = new WebGLRenderTarget(w, h, { ...opts });
|
|
185
190
|
this.baseRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
|
|
186
191
|
this.screenRenderTarget.dispose();
|
|
187
|
-
this.screenRenderTarget = new WebGLRenderTarget(
|
|
192
|
+
this.screenRenderTarget = new WebGLRenderTarget(aw, ah, { ...opts });
|
|
188
193
|
this.screenRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
|
|
189
194
|
this.needRender = true;
|
|
190
195
|
}
|
|
191
|
-
// 效果 mask
|
|
192
|
-
//
|
|
193
|
-
//
|
|
196
|
+
// 效果 mask 像素比硬上限(历史旋钮,当前渲染链未再引用):避免高 dpr 屏(如 2×)上
|
|
197
|
+
// effectiveRatio×resolution 爆到 4×,让效果 mask RT(含辉光多次高斯迭代)填充量失控。
|
|
198
|
+
// 2026-10-27 起 mask/深度/法线/屏幕全部按 auxResolution(= 1)走,超采样只留在 base 一张。
|
|
194
199
|
effectMaxPixelRatio = 2;
|
|
195
|
-
//
|
|
196
|
-
// 辅助通道(深度/法线)分辨率系数。
|
|
200
|
+
// 辅助通道(深度/法线)与各效果 mask、屏幕合成的倍率见下方 auxResolution 字段(= 1,不超采样)。
|
|
197
201
|
// 关键:描边/发光/辉光/毛玻璃都拿 baseDepthTexture 做遮挡比对(deathTestShader 以全分辨率
|
|
198
202
|
// UV 采样半分辨率深度,并与全分辨率物体深度做硬阈值比较)。半分辨率深度(Nearest 滤波)被
|
|
199
203
|
// 放大采样后与锐利的物体深度在边缘逐像素翻转 discard,产生边缘摩尔纹/锯齿——这是这 4 个特效
|
|
200
|
-
//
|
|
201
|
-
// 法线仅 SSAO
|
|
202
|
-
// 之前为"不卡"
|
|
203
|
-
// 辅助通道(深度/法线)
|
|
204
|
+
// 共同的摩尔纹根因。故深度与 mask 必须同倍率(都取 auxResolution),彼此 1:1 采样才无放大错位。
|
|
205
|
+
// 法线仅 SSAO 使用(首页默认关闭、不渲染),无额外开销。
|
|
206
|
+
// 之前为"不卡"把深度单独降到 0.5 反而引入摩尔纹,已恢复为 1。
|
|
207
|
+
// 辅助通道(深度/法线)倍率 = auxResolution,与 base 的 resolution 分离(2026-10-27 需求)。
|
|
204
208
|
// 实际帧缓冲像素比 = min( max(devicePixelRatio, minDevicePixelRatio) * renderScale, maxPixelRatio )
|
|
205
209
|
get effectiveRatio() {
|
|
206
210
|
return Math.min(Math.max(window.devicePixelRatio, this.minDevicePixelRatio) * this.renderScale, this.maxPixelRatio);
|
|
@@ -490,7 +494,8 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
490
494
|
this.orthographicCamera.right = width / height;
|
|
491
495
|
this.renderer.setPixelRatio(Math.max(window.devicePixelRatio, this.minDevicePixelRatio)),
|
|
492
496
|
this.renderer.setSize(width, height);
|
|
493
|
-
//
|
|
497
|
+
// base 按 effectiveRatio × resolution、其余 RT 按 effectiveRatio × auxResolution 重建
|
|
498
|
+
// (容器尺寸变化与 resolution 变化共用)
|
|
494
499
|
this.updateRenderTargetSizes(width, height);
|
|
495
500
|
this.size.set(width, height);
|
|
496
501
|
setTimeout(() => {
|
|
@@ -501,7 +506,8 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
501
506
|
// this.renderer.render(this.scene, this.camera);
|
|
502
507
|
}
|
|
503
508
|
/**
|
|
504
|
-
* 按「容器尺寸 × effectiveRatio
|
|
509
|
+
* 按「容器尺寸 × effectiveRatio」重建所有渲染目标尺寸:base 再乘 resolution,
|
|
510
|
+
* 其余(深度 / 法线 / mask / 屏幕合成)再乘 auxResolution。
|
|
505
511
|
* 由 setSize()(容器尺寸变化)与 resolution setter(运行时调倍率)共用 ——
|
|
506
512
|
* 关键:resolution 是运行时可调的性能/质量旋钮,改完必须立刻重建 RT,
|
|
507
513
|
* 否则倍率变了而 RT 尺寸没变,画面毫无变化(历史坑:"调分辨率没感觉")。
|
|
@@ -510,17 +516,20 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
510
516
|
// 防御 0 尺寸:RT 不接受 0,否则 WebGL 报 framebuffer incomplete
|
|
511
517
|
const w = Math.max(1, Math.round(width * this.effectiveRatio * this._resolution));
|
|
512
518
|
const h = Math.max(1, Math.round(height * this.effectiveRatio * this._resolution));
|
|
513
|
-
|
|
519
|
+
const aw = Math.max(1, Math.round(width * this.effectiveRatio * this.auxResolution));
|
|
520
|
+
const ah = Math.max(1, Math.round(height * this.effectiveRatio * this.auxResolution));
|
|
521
|
+
// 主画面:只有这一张吃 resolution 超采样(纹理摩尔纹在此被根治)
|
|
514
522
|
this.baseRenderTarget.setSize(w, h);
|
|
515
|
-
//
|
|
523
|
+
// 深度/法线辅助通道:按 auxResolution(= 1)。与 base 之间**倍率不同但 UV 一致**,
|
|
524
|
+
// 遮挡判定读的是归一化 UV ⇒ 位置不错位,只是精度按 1× 走(2026-10-27 需求点名要的这一档)。
|
|
516
525
|
// 其 depthTexture(baseDepthTexture) 尺寸由 renderer 在 setRenderTarget 时
|
|
517
526
|
// 强制同步为 depthRenderTarget 尺寸,下面再手动对齐一次避免首帧抖动。
|
|
518
|
-
this.depthRenderTarget.setSize(
|
|
519
|
-
this.normalRenderTarget.setSize(
|
|
520
|
-
//
|
|
521
|
-
this.screenRenderTarget.setSize(
|
|
522
|
-
this.baseDepthTexture.image.width =
|
|
523
|
-
this.baseDepthTexture.image.height =
|
|
527
|
+
this.depthRenderTarget.setSize(aw, ah);
|
|
528
|
+
this.normalRenderTarget.setSize(aw, ah);
|
|
529
|
+
// 屏幕合成目标:同样按 auxResolution,与 base 之间的那次拷贝是降采样
|
|
530
|
+
this.screenRenderTarget.setSize(aw, ah);
|
|
531
|
+
this.baseDepthTexture.image.width = aw;
|
|
532
|
+
this.baseDepthTexture.image.height = ah;
|
|
524
533
|
// 立即渲染一帧,避免静态场景下改了倍率却停在旧画面
|
|
525
534
|
this.needRender = true;
|
|
526
535
|
}
|
|
@@ -900,10 +909,10 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
900
909
|
renderVisibleDepthPass(this.renderer, camera, this.scene, this.depthRenderTarget);
|
|
901
910
|
// 切回 baseRenderTarget,后处理 pass 需要把效果叠加到颜色渲染目标上
|
|
902
911
|
this.renderer.setRenderTarget(this.baseRenderTarget);
|
|
903
|
-
// 效果 mask 灰度图尺寸 = effectiveRatio ×
|
|
904
|
-
//
|
|
905
|
-
//
|
|
906
|
-
const dpr = this.effectiveRatio * this.
|
|
912
|
+
// 效果 mask 灰度图尺寸 = effectiveRatio × auxResolution(= 1),与 baseDepthTexture 同倍率;
|
|
913
|
+
// baseRenderTarget 是唯一的超采样档(resolution),故 mask/深度 → base 的合成是「1× 精度放大到 4×」。
|
|
914
|
+
// 位置靠归一化 UV 对齐,不会偏移;只是描边/发光/覆盖/磨砂的边缘精度按 1× 走(2026-10-27 需求)。
|
|
915
|
+
const dpr = this.effectiveRatio * this.auxResolution;
|
|
907
916
|
// SSAO 后处理(基于深度计算遮蔽,乘法叠加):数据准备 + 计算全在 ssao_pass 内部,
|
|
908
917
|
// 结果输出到「调用时绑定的渲染目标」。
|
|
909
918
|
// ⚠️ 顺序(2026-09-14 皇上旨):SSAO 必须排在对象级特效(描边/发光/bloom/覆盖/磨砂)之前——
|
|
@@ -914,18 +923,18 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
914
923
|
// 后处理特效渲染(描边,发光,颜色覆盖,bloom,磨砂玻璃):叠加到 baseRenderTarget(此时已含 SSAO)
|
|
915
924
|
this.scene.traverseVisible((child) => {
|
|
916
925
|
if (child instanceof Mesh || child instanceof Line || child instanceof Points) {
|
|
917
|
-
stroke_pass(this.renderer, camera, child, this.baseDepthTexture,
|
|
918
|
-
glow_pass(this.renderer, camera, child, this.baseDepthTexture,
|
|
919
|
-
bloom_pass(this.renderer, camera, child, this.baseRenderTarget, this.baseDepthTexture,
|
|
926
|
+
stroke_pass(this.renderer, camera, child, this.baseDepthTexture, dpr);
|
|
927
|
+
glow_pass(this.renderer, camera, child, this.baseDepthTexture, dpr);
|
|
928
|
+
bloom_pass(this.renderer, camera, child, this.baseRenderTarget, this.baseDepthTexture, dpr);
|
|
920
929
|
}
|
|
921
930
|
});
|
|
922
931
|
// 自定义描边对象(如 InstancedChild 的选择代理):不在 scene 内,单独在效果阶段描边。
|
|
923
932
|
// 代理用实例自身的 matrixWorld + 同款 geometry/material 重建,故其深度/灰度与真实实例严格对齐,
|
|
924
933
|
// 并复用同一张 baseDepthTexture 做遮挡判定(被其他物体挡住的部分不描边)。
|
|
925
934
|
for (const so of this._strokeObjects) {
|
|
926
|
-
stroke_pass(this.renderer, camera, so, this.baseDepthTexture,
|
|
927
|
-
glow_pass(this.renderer, camera, so, this.baseDepthTexture,
|
|
928
|
-
bloom_pass(this.renderer, camera, so, this.baseRenderTarget, this.baseDepthTexture,
|
|
935
|
+
stroke_pass(this.renderer, camera, so, this.baseDepthTexture, dpr);
|
|
936
|
+
glow_pass(this.renderer, camera, so, this.baseDepthTexture, dpr);
|
|
937
|
+
bloom_pass(this.renderer, camera, so, this.baseRenderTarget, this.baseDepthTexture, dpr);
|
|
929
938
|
}
|
|
930
939
|
// 把 base(含 SSAO)+描边/发光/bloom 合成结果拷到屏幕合成目标,后续 颜色叠加/磨砂玻璃
|
|
931
940
|
// 在此目标上叠加;最后统一跑一次 FXAA 终处理输出到屏幕,覆盖全部后处理的锯齿/摩尔纹。
|
package/ThreeBase.ts
CHANGED
|
@@ -113,22 +113,24 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
113
113
|
// (纹理被欠采样时的拍频,必须靠提高实际采样率才能消除)。
|
|
114
114
|
// 1 = 关闭超采样(仅设备 pixelRatio);2 = 2 倍超采样(质量最高,片元开销 ×4,需强 GPU)。
|
|
115
115
|
renderScale: number = 1;
|
|
116
|
-
//
|
|
117
|
-
// effectiveRatio × resolution
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
116
|
+
// 超采样倍率(SSAA)**只作用于 baseRenderTarget**(2026-10-27 需求:「只有 baseRT 的超采样参数是 4,
|
|
117
|
+
// 其他的 RT 超采样参数是 1」):base 按 effectiveRatio × resolution 渲染,深度 / 法线 / 效果 mask /
|
|
118
|
+
// 屏幕合成一律按 effectiveRatio × auxResolution(= 1)渲染。
|
|
119
|
+
// ⚠️ 两条与「全链路同倍率」那版不同、看得见的后果:
|
|
120
|
+
// ① base(4×) → screen(1×) 那次拷贝是**降采样**(RT 不长 mipmap,线性滤波只取到 4 个纹素)
|
|
121
|
+
// ⇒ base 的超采样不会原样带到屏幕上,末端仍靠 FXAA 兜锯齿。
|
|
122
|
+
// ② 描边/发光/覆盖/磨砂的 mask 与 base 深度都从 4× 降到 1×,而它们要合成进 4× 的 base
|
|
123
|
+
// ⇒ 这些效果的边缘按 1× 精度放大,比同倍率那版软;UV 仍严格对齐(错位只发生在精度,不在位置)。
|
|
124
|
+
// 现行 resolution = 4(setter 夹的上限也是 4);上一档 1 出自 2026-10-21「有点卡,分辨率改成 1」。
|
|
125
|
+
// 历史:再早是 base / 深度 / 法线 / mask / 屏幕 **共用同一个 resolution**,2026-10-27 起拆成 base 与其余两档。
|
|
126
126
|
|
|
127
|
-
// ⚠️ 必须用 getter/setter
|
|
128
|
-
// 里按 effectiveRatio × resolution
|
|
127
|
+
// ⚠️ 必须用 getter/setter,不能是普通字段:RT 尺寸只在 updateRenderTargetSizes()
|
|
128
|
+
// 里按 effectiveRatio × resolution(base)/ × auxResolution(其余)计算,而该方法过去只被 setSize()(容器尺寸变化)调用
|
|
129
129
|
// → 运行时改 resolution 不会重建任何 RT,画面毫无变化(表现为"调分辨率没感觉")。
|
|
130
130
|
// 故 setter 里改动倍率后立刻重建全部 RT。
|
|
131
131
|
private _resolution: number = 4;
|
|
132
|
+
/** baseRenderTarget 之外**全部** RT 的倍率(深度 / 法线 / 各效果 mask / 屏幕合成);1 = 不超采样 */
|
|
133
|
+
auxResolution: number = 1;
|
|
132
134
|
|
|
133
135
|
get resolution(): number {
|
|
134
136
|
return this._resolution;
|
|
@@ -232,6 +234,9 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
232
234
|
}
|
|
233
235
|
const w = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this._resolution));
|
|
234
236
|
const h = Math.max(1, Math.round(this.size.y * this.effectiveRatio * this._resolution));
|
|
237
|
+
// 除 base 之外的 RT 走 auxResolution(= 1):屏幕合成目标不跟着 base 超采样
|
|
238
|
+
const aw = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this.auxResolution));
|
|
239
|
+
const ah = Math.max(1, Math.round(this.size.y * this.effectiveRatio * this.auxResolution));
|
|
235
240
|
const opts = {
|
|
236
241
|
minFilter: this._rtOptions.filter,
|
|
237
242
|
magFilter: this._rtOptions.filter,
|
|
@@ -244,24 +249,23 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
244
249
|
this.baseRenderTarget = new WebGLRenderTarget(w, h, { ...opts });
|
|
245
250
|
this.baseRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
|
|
246
251
|
this.screenRenderTarget.dispose();
|
|
247
|
-
this.screenRenderTarget = new WebGLRenderTarget(
|
|
252
|
+
this.screenRenderTarget = new WebGLRenderTarget(aw, ah, { ...opts });
|
|
248
253
|
this.screenRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
|
|
249
254
|
this.needRender = true;
|
|
250
255
|
}
|
|
251
256
|
|
|
252
|
-
// 效果 mask
|
|
253
|
-
//
|
|
254
|
-
//
|
|
257
|
+
// 效果 mask 像素比硬上限(历史旋钮,当前渲染链未再引用):避免高 dpr 屏(如 2×)上
|
|
258
|
+
// effectiveRatio×resolution 爆到 4×,让效果 mask RT(含辉光多次高斯迭代)填充量失控。
|
|
259
|
+
// 2026-10-27 起 mask/深度/法线/屏幕全部按 auxResolution(= 1)走,超采样只留在 base 一张。
|
|
255
260
|
effectMaxPixelRatio: number = 2;
|
|
256
|
-
//
|
|
257
|
-
// 辅助通道(深度/法线)分辨率系数。
|
|
261
|
+
// 辅助通道(深度/法线)与各效果 mask、屏幕合成的倍率见下方 auxResolution 字段(= 1,不超采样)。
|
|
258
262
|
// 关键:描边/发光/辉光/毛玻璃都拿 baseDepthTexture 做遮挡比对(deathTestShader 以全分辨率
|
|
259
263
|
// UV 采样半分辨率深度,并与全分辨率物体深度做硬阈值比较)。半分辨率深度(Nearest 滤波)被
|
|
260
264
|
// 放大采样后与锐利的物体深度在边缘逐像素翻转 discard,产生边缘摩尔纹/锯齿——这是这 4 个特效
|
|
261
|
-
//
|
|
262
|
-
// 法线仅 SSAO
|
|
263
|
-
// 之前为"不卡"
|
|
264
|
-
// 辅助通道(深度/法线)
|
|
265
|
+
// 共同的摩尔纹根因。故深度与 mask 必须同倍率(都取 auxResolution),彼此 1:1 采样才无放大错位。
|
|
266
|
+
// 法线仅 SSAO 使用(首页默认关闭、不渲染),无额外开销。
|
|
267
|
+
// 之前为"不卡"把深度单独降到 0.5 反而引入摩尔纹,已恢复为 1。
|
|
268
|
+
// 辅助通道(深度/法线)倍率 = auxResolution,与 base 的 resolution 分离(2026-10-27 需求)。
|
|
265
269
|
// 实际帧缓冲像素比 = min( max(devicePixelRatio, minDevicePixelRatio) * renderScale, maxPixelRatio )
|
|
266
270
|
get effectiveRatio(): number {
|
|
267
271
|
return Math.min(Math.max(window.devicePixelRatio, this.minDevicePixelRatio) * this.renderScale, this.maxPixelRatio);
|
|
@@ -552,7 +556,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
552
556
|
this.orthographicCamera.right = width / height;
|
|
553
557
|
this.renderer.setPixelRatio(Math.max(window.devicePixelRatio, this.minDevicePixelRatio)),
|
|
554
558
|
this.renderer.setSize(width, height);
|
|
555
|
-
//
|
|
559
|
+
// base 按 effectiveRatio × resolution、其余 RT 按 effectiveRatio × auxResolution 重建
|
|
560
|
+
// (容器尺寸变化与 resolution 变化共用)
|
|
556
561
|
this.updateRenderTargetSizes(width, height);
|
|
557
562
|
this.size.set(width, height);
|
|
558
563
|
setTimeout(() => {
|
|
@@ -564,7 +569,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
564
569
|
}
|
|
565
570
|
|
|
566
571
|
/**
|
|
567
|
-
* 按「容器尺寸 × effectiveRatio
|
|
572
|
+
* 按「容器尺寸 × effectiveRatio」重建所有渲染目标尺寸:base 再乘 resolution,
|
|
573
|
+
* 其余(深度 / 法线 / mask / 屏幕合成)再乘 auxResolution。
|
|
568
574
|
* 由 setSize()(容器尺寸变化)与 resolution setter(运行时调倍率)共用 ——
|
|
569
575
|
* 关键:resolution 是运行时可调的性能/质量旋钮,改完必须立刻重建 RT,
|
|
570
576
|
* 否则倍率变了而 RT 尺寸没变,画面毫无变化(历史坑:"调分辨率没感觉")。
|
|
@@ -573,18 +579,21 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
573
579
|
// 防御 0 尺寸:RT 不接受 0,否则 WebGL 报 framebuffer incomplete
|
|
574
580
|
const w = Math.max(1, Math.round(width * this.effectiveRatio * this._resolution));
|
|
575
581
|
const h = Math.max(1, Math.round(height * this.effectiveRatio * this._resolution));
|
|
582
|
+
const aw = Math.max(1, Math.round(width * this.effectiveRatio * this.auxResolution));
|
|
583
|
+
const ah = Math.max(1, Math.round(height * this.effectiveRatio * this.auxResolution));
|
|
576
584
|
|
|
577
|
-
//
|
|
585
|
+
// 主画面:只有这一张吃 resolution 超采样(纹理摩尔纹在此被根治)
|
|
578
586
|
this.baseRenderTarget.setSize(w, h);
|
|
579
|
-
//
|
|
587
|
+
// 深度/法线辅助通道:按 auxResolution(= 1)。与 base 之间**倍率不同但 UV 一致**,
|
|
588
|
+
// 遮挡判定读的是归一化 UV ⇒ 位置不错位,只是精度按 1× 走(2026-10-27 需求点名要的这一档)。
|
|
580
589
|
// 其 depthTexture(baseDepthTexture) 尺寸由 renderer 在 setRenderTarget 时
|
|
581
590
|
// 强制同步为 depthRenderTarget 尺寸,下面再手动对齐一次避免首帧抖动。
|
|
582
|
-
this.depthRenderTarget.setSize(
|
|
583
|
-
this.normalRenderTarget.setSize(
|
|
584
|
-
//
|
|
585
|
-
this.screenRenderTarget.setSize(
|
|
586
|
-
this.baseDepthTexture.image.width =
|
|
587
|
-
this.baseDepthTexture.image.height =
|
|
591
|
+
this.depthRenderTarget.setSize(aw, ah);
|
|
592
|
+
this.normalRenderTarget.setSize(aw, ah);
|
|
593
|
+
// 屏幕合成目标:同样按 auxResolution,与 base 之间的那次拷贝是降采样
|
|
594
|
+
this.screenRenderTarget.setSize(aw, ah);
|
|
595
|
+
this.baseDepthTexture.image.width = aw;
|
|
596
|
+
this.baseDepthTexture.image.height = ah;
|
|
588
597
|
// 立即渲染一帧,避免静态场景下改了倍率却停在旧画面
|
|
589
598
|
this.needRender = true;
|
|
590
599
|
}
|
|
@@ -997,10 +1006,10 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
997
1006
|
renderVisibleDepthPass(this.renderer, camera, this.scene, this.depthRenderTarget);
|
|
998
1007
|
// 切回 baseRenderTarget,后处理 pass 需要把效果叠加到颜色渲染目标上
|
|
999
1008
|
this.renderer.setRenderTarget(this.baseRenderTarget);
|
|
1000
|
-
// 效果 mask 灰度图尺寸 = effectiveRatio ×
|
|
1001
|
-
//
|
|
1002
|
-
//
|
|
1003
|
-
const dpr = this.effectiveRatio * this.
|
|
1009
|
+
// 效果 mask 灰度图尺寸 = effectiveRatio × auxResolution(= 1),与 baseDepthTexture 同倍率;
|
|
1010
|
+
// baseRenderTarget 是唯一的超采样档(resolution),故 mask/深度 → base 的合成是「1× 精度放大到 4×」。
|
|
1011
|
+
// 位置靠归一化 UV 对齐,不会偏移;只是描边/发光/覆盖/磨砂的边缘精度按 1× 走(2026-10-27 需求)。
|
|
1012
|
+
const dpr = this.effectiveRatio * this.auxResolution;
|
|
1004
1013
|
// SSAO 后处理(基于深度计算遮蔽,乘法叠加):数据准备 + 计算全在 ssao_pass 内部,
|
|
1005
1014
|
// 结果输出到「调用时绑定的渲染目标」。
|
|
1006
1015
|
// ⚠️ 顺序(2026-09-14 皇上旨):SSAO 必须排在对象级特效(描边/发光/bloom/覆盖/磨砂)之前——
|
|
@@ -1011,18 +1020,18 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
|
|
|
1011
1020
|
// 后处理特效渲染(描边,发光,颜色覆盖,bloom,磨砂玻璃):叠加到 baseRenderTarget(此时已含 SSAO)
|
|
1012
1021
|
this.scene.traverseVisible((child: Object3D) => {
|
|
1013
1022
|
if (child instanceof Mesh || child instanceof Line || child instanceof Points) {
|
|
1014
|
-
stroke_pass(this.renderer, camera, child, this.baseDepthTexture,
|
|
1015
|
-
glow_pass(this.renderer, camera, child, this.baseDepthTexture,
|
|
1016
|
-
bloom_pass(this.renderer, camera, child, this.baseRenderTarget, this.baseDepthTexture,
|
|
1023
|
+
stroke_pass(this.renderer, camera, child, this.baseDepthTexture, dpr);
|
|
1024
|
+
glow_pass(this.renderer, camera, child, this.baseDepthTexture, dpr);
|
|
1025
|
+
bloom_pass(this.renderer, camera, child, this.baseRenderTarget, this.baseDepthTexture, dpr);
|
|
1017
1026
|
}
|
|
1018
1027
|
});
|
|
1019
1028
|
// 自定义描边对象(如 InstancedChild 的选择代理):不在 scene 内,单独在效果阶段描边。
|
|
1020
1029
|
// 代理用实例自身的 matrixWorld + 同款 geometry/material 重建,故其深度/灰度与真实实例严格对齐,
|
|
1021
1030
|
// 并复用同一张 baseDepthTexture 做遮挡判定(被其他物体挡住的部分不描边)。
|
|
1022
1031
|
for (const so of this._strokeObjects) {
|
|
1023
|
-
stroke_pass(this.renderer, camera, so, this.baseDepthTexture,
|
|
1024
|
-
glow_pass(this.renderer, camera, so, this.baseDepthTexture,
|
|
1025
|
-
bloom_pass(this.renderer, camera, so, this.baseRenderTarget, this.baseDepthTexture,
|
|
1032
|
+
stroke_pass(this.renderer, camera, so, this.baseDepthTexture, dpr);
|
|
1033
|
+
glow_pass(this.renderer, camera, so, this.baseDepthTexture, dpr);
|
|
1034
|
+
bloom_pass(this.renderer, camera, so, this.baseRenderTarget, this.baseDepthTexture, dpr);
|
|
1026
1035
|
}
|
|
1027
1036
|
// 把 base(含 SSAO)+描边/发光/bloom 合成结果拷到屏幕合成目标,后续 颜色叠加/磨砂玻璃
|
|
1028
1037
|
// 在此目标上叠加;最后统一跑一次 FXAA 终处理输出到屏幕,覆盖全部后处理的锯齿/摩尔纹。
|
|
@@ -122,6 +122,9 @@ export default class InstancedMeshBase extends MeshBase {
|
|
|
122
122
|
instanceCollect[uuid] = instancedMesh;
|
|
123
123
|
this.add(instancedMesh);
|
|
124
124
|
});
|
|
125
|
+
// ⭐ 2026-10-28「每个模型对象逐帧显示出来」:这一组 InstancedMesh 是**一个对象**的内容 ⇒ 一次放行
|
|
126
|
+
// (一帧一个对象,⛔ 不是一个对象里的几十块零件排几十帧,那会变成零件逐块拼装)
|
|
127
|
+
this.revealSoon(this.children.slice());
|
|
125
128
|
// 加载完成事件
|
|
126
129
|
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
127
130
|
this.loaded = true;
|
|
@@ -124,6 +124,9 @@ export default class InstancedMeshBase extends MeshBase {
|
|
|
124
124
|
instanceCollect[uuid] = instancedMesh;
|
|
125
125
|
this.add(instancedMesh);
|
|
126
126
|
});
|
|
127
|
+
// ⭐ 2026-10-28「每个模型对象逐帧显示出来」:这一组 InstancedMesh 是**一个对象**的内容 ⇒ 一次放行
|
|
128
|
+
// (一帧一个对象,⛔ 不是一个对象里的几十块零件排几十帧,那会变成零件逐块拼装)
|
|
129
|
+
this.revealSoon(this.children.slice());
|
|
127
130
|
// 加载完成事件
|
|
128
131
|
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
129
132
|
this.loaded = true;
|