three-base 2.0.187 → 2.0.190

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/ThreeBase.ts CHANGED
@@ -113,21 +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
- // 全局超采样/分辨率倍率(SSAA):base / 深度 / 法线 / 效果 mask / 屏幕合成 全部按
117
- // effectiveRatio × resolution 内部超采样渲染,终处理 FXAA 降采样输出到屏幕。
118
- // 全链路同倍率 → 各 RT 严格 1:1 对齐:几何锯齿、效果边缘锯齿、辉光漏光(深度 vs mask 错位)、
119
- // mask 合成 UV 缩放错位、SSAO 深度错位变黑 一并消除。
120
- // ⭐ 默认 1(原生分辨率):2026-10-21 皇上旨「有点卡,分辨率改成 1」。原默认 2 = 每维 2×、
121
- // 总像素 4×,全链路填充 ×4 且 35 张 RT 显存约 1.1 GB(1920×1080 画布)。降到 1 后填充与显存
122
- // 均降约 75%,几何硬边锯齿由终处理 FXAA 兜底。需要纹理摩尔纹治本时,面板上再调回 2。
123
- // 历史坑:baseRenderScale/auxRenderScale/effectRenderScale 三参各自为政,倍率不同步必错位,
124
- // 故统一为单参数 resolution 管全局。
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 与其余两档。
125
126
 
126
- // ⚠️ 必须用 getter/setter,不能是普通字段:所有 RT 尺寸只在 updateRenderTargetSizes()
127
- // 里按 effectiveRatio × resolution 计算,而该方法过去只被 setSize()(容器尺寸变化)调用
127
+ // ⚠️ 必须用 getter/setter,不能是普通字段:RT 尺寸只在 updateRenderTargetSizes()
128
+ // 里按 effectiveRatio × resolution(base)/ × auxResolution(其余)计算,而该方法过去只被 setSize()(容器尺寸变化)调用
128
129
  // → 运行时改 resolution 不会重建任何 RT,画面毫无变化(表现为"调分辨率没感觉")。
129
130
  // 故 setter 里改动倍率后立刻重建全部 RT。
130
- private _resolution: number = 1;
131
+ private _resolution: number = 4;
132
+ /** baseRenderTarget 之外**全部** RT 的倍率(深度 / 法线 / 各效果 mask / 屏幕合成);1 = 不超采样 */
133
+ auxResolution: number = 1;
131
134
 
132
135
  get resolution(): number {
133
136
  return this._resolution;
@@ -231,6 +234,9 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
231
234
  }
232
235
  const w = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this._resolution));
233
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));
234
240
  const opts = {
235
241
  minFilter: this._rtOptions.filter,
236
242
  magFilter: this._rtOptions.filter,
@@ -243,24 +249,23 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
243
249
  this.baseRenderTarget = new WebGLRenderTarget(w, h, { ...opts });
244
250
  this.baseRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
245
251
  this.screenRenderTarget.dispose();
246
- this.screenRenderTarget = new WebGLRenderTarget(w, h, { ...opts });
252
+ this.screenRenderTarget = new WebGLRenderTarget(aw, ah, { ...opts });
247
253
  this.screenRenderTarget.texture.colorSpace = this._rtOptions.colorSpace;
248
254
  this.needRender = true;
249
255
  }
250
256
 
251
- // 效果 mask 像素比硬上限:避免高 dpr 屏(如 2×)上 effectiveRatio×resolution 爆到 4×,
252
- // 让效果 mask RT(含辉光多次高斯迭代)填充量失控。经验值 2×:相对设备 dpr 输出足够平滑,
253
- // 且把"效果 mask 超采样"的填充量控制在场景同级的 2× 以内(原本 3× 在高 dpr 屏是"还是卡"的高嫌疑点)。
257
+ // 效果 mask 像素比硬上限(历史旋钮,当前渲染链未再引用):避免高 dpr 屏(如 2×)上
258
+ // effectiveRatio×resolution 爆到 4×,让效果 mask RT(含辉光多次高斯迭代)填充量失控。
259
+ // 2026-10-27 起 mask/深度/法线/屏幕全部按 auxResolution(= 1)走,超采样只留在 base 一张。
254
260
  effectMaxPixelRatio: number = 2;
255
- // 超采样倍率已统一为上方 resolution 字段(base / 深度 / 法线 / mask / 屏幕全部取它)。
256
- // 辅助通道(深度/法线)分辨率系数。
261
+ // 辅助通道(深度/法线)与各效果 mask、屏幕合成的倍率见下方 auxResolution 字段(= 1,不超采样)。
257
262
  // 关键:描边/发光/辉光/毛玻璃都拿 baseDepthTexture 做遮挡比对(deathTestShader 以全分辨率
258
263
  // UV 采样半分辨率深度,并与全分辨率物体深度做硬阈值比较)。半分辨率深度(Nearest 滤波)被
259
264
  // 放大采样后与锐利的物体深度在边缘逐像素翻转 discard,产生边缘摩尔纹/锯齿——这是这 4 个特效
260
- // 共同的摩尔纹根因。故深度必须与 mask 同分辨率(全分辨率),1:1 采样才无放大错位。
261
- // 法线仅 SSAO 使用(首页默认关闭、不渲染),全分辨率无额外开销。
262
- // 之前为"不卡"降到 0.5 反而引入摩尔纹,已恢复为 1。
263
- // 辅助通道(深度/法线)倍率已并入 resolution,不再单独设 auxRenderScale。
265
+ // 共同的摩尔纹根因。故深度与 mask 必须同倍率(都取 auxResolution),彼此 1:1 采样才无放大错位。
266
+ // 法线仅 SSAO 使用(首页默认关闭、不渲染),无额外开销。
267
+ // 之前为"不卡"把深度单独降到 0.5 反而引入摩尔纹,已恢复为 1。
268
+ // 辅助通道(深度/法线)倍率 = auxResolution,与 base 的 resolution 分离(2026-10-27 需求)。
264
269
  // 实际帧缓冲像素比 = min( max(devicePixelRatio, minDevicePixelRatio) * renderScale, maxPixelRatio )
265
270
  get effectiveRatio(): number {
266
271
  return Math.min(Math.max(window.devicePixelRatio, this.minDevicePixelRatio) * this.renderScale, this.maxPixelRatio);
@@ -551,7 +556,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
551
556
  this.orthographicCamera.right = width / height;
552
557
  this.renderer.setPixelRatio(Math.max(window.devicePixelRatio, this.minDevicePixelRatio)),
553
558
  this.renderer.setSize(width, height);
554
- // 所有 RT 尺寸按 effectiveRatio × resolution 重建(容器尺寸变化与 resolution 变化共用)
559
+ // base 按 effectiveRatio × resolution、其余 RT 按 effectiveRatio × auxResolution 重建
560
+ // (容器尺寸变化与 resolution 变化共用)
555
561
  this.updateRenderTargetSizes(width, height);
556
562
  this.size.set(width, height);
557
563
  setTimeout(() => {
@@ -563,7 +569,8 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
563
569
  }
564
570
 
565
571
  /**
566
- * 按「容器尺寸 × effectiveRatio × resolution」重建所有渲染目标尺寸。
572
+ * 按「容器尺寸 × effectiveRatio」重建所有渲染目标尺寸:base 再乘 resolution,
573
+ * 其余(深度 / 法线 / mask / 屏幕合成)再乘 auxResolution。
567
574
  * 由 setSize()(容器尺寸变化)与 resolution setter(运行时调倍率)共用 ——
568
575
  * 关键:resolution 是运行时可调的性能/质量旋钮,改完必须立刻重建 RT,
569
576
  * 否则倍率变了而 RT 尺寸没变,画面毫无变化(历史坑:"调分辨率没感觉")。
@@ -572,18 +579,21 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
572
579
  // 防御 0 尺寸:RT 不接受 0,否则 WebGL 报 framebuffer incomplete
573
580
  const w = Math.max(1, Math.round(width * this.effectiveRatio * this._resolution));
574
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));
575
584
 
576
- // 主画面:超采样渲染,纹理摩尔纹在此被根治
585
+ // 主画面:只有这一张吃 resolution 超采样(纹理摩尔纹在此被根治)
577
586
  this.baseRenderTarget.setSize(w, h);
578
- // 深度/法线辅助通道:与 base 同倍率,保证 depthTest 1:1 无漏光、SSAO 深度不黑。
587
+ // 深度/法线辅助通道:按 auxResolution(= 1)。与 base 之间**倍率不同但 UV 一致**,
588
+ // 遮挡判定读的是归一化 UV ⇒ 位置不错位,只是精度按 1× 走(2026-10-27 需求点名要的这一档)。
579
589
  // 其 depthTexture(baseDepthTexture) 尺寸由 renderer 在 setRenderTarget 时
580
590
  // 强制同步为 depthRenderTarget 尺寸,下面再手动对齐一次避免首帧抖动。
581
- this.depthRenderTarget.setSize(w, h);
582
- this.normalRenderTarget.setSize(w, h);
583
- // 屏幕合成目标:同样跟随 resolution,全链路 1:1 对齐
584
- this.screenRenderTarget.setSize(w, h);
585
- this.baseDepthTexture.image.width = w;
586
- this.baseDepthTexture.image.height = h;
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;
587
597
  // 立即渲染一帧,避免静态场景下改了倍率却停在旧画面
588
598
  this.needRender = true;
589
599
  }
@@ -996,10 +1006,10 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
996
1006
  renderVisibleDepthPass(this.renderer, camera, this.scene, this.depthRenderTarget);
997
1007
  // 切回 baseRenderTarget,后处理 pass 需要把效果叠加到颜色渲染目标上
998
1008
  this.renderer.setRenderTarget(this.baseRenderTarget);
999
- // 效果 mask 灰度图尺寸 = effectiveRatio × resolution,与 baseRenderTarget / baseDepthTexture 同倍率,
1000
- // 全链路 1:1 对齐(mask 跟随 resolution,深度也跟随 resolution,辉光漏光/mask 合成 UV 错位均消除)。
1001
- // 几何/效果边缘抗锯齿由「baseRenderTarget/screenRenderTarget 超采样(resolution) + 终处理 FXAA 降采样」承担。
1002
- const dpr = this.effectiveRatio * this.resolution;
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;
1003
1013
  // SSAO 后处理(基于深度计算遮蔽,乘法叠加):数据准备 + 计算全在 ssao_pass 内部,
1004
1014
  // 结果输出到「调用时绑定的渲染目标」。
1005
1015
  // ⚠️ 顺序(2026-09-14 皇上旨):SSAO 必须排在对象级特效(描边/发光/bloom/覆盖/磨砂)之前——
@@ -1010,18 +1020,18 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
1010
1020
  // 后处理特效渲染(描边,发光,颜色覆盖,bloom,磨砂玻璃):叠加到 baseRenderTarget(此时已含 SSAO)
1011
1021
  this.scene.traverseVisible((child: Object3D) => {
1012
1022
  if (child instanceof Mesh || child instanceof Line || child instanceof Points) {
1013
- stroke_pass(this.renderer, camera, child, this.baseDepthTexture, this.effectiveRatio * this.resolution);
1014
- glow_pass(this.renderer, camera, child, this.baseDepthTexture, this.effectiveRatio * this.resolution);
1015
- bloom_pass(this.renderer, camera, child, this.baseRenderTarget, this.baseDepthTexture, this.effectiveRatio * this.resolution);
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);
1016
1026
  }
1017
1027
  });
1018
1028
  // 自定义描边对象(如 InstancedChild 的选择代理):不在 scene 内,单独在效果阶段描边。
1019
1029
  // 代理用实例自身的 matrixWorld + 同款 geometry/material 重建,故其深度/灰度与真实实例严格对齐,
1020
1030
  // 并复用同一张 baseDepthTexture 做遮挡判定(被其他物体挡住的部分不描边)。
1021
1031
  for (const so of this._strokeObjects) {
1022
- stroke_pass(this.renderer, camera, so, this.baseDepthTexture, this.effectiveRatio * this.resolution);
1023
- glow_pass(this.renderer, camera, so, this.baseDepthTexture, this.effectiveRatio * this.resolution);
1024
- bloom_pass(this.renderer, camera, so, this.baseRenderTarget, this.baseDepthTexture, this.effectiveRatio * this.resolution);
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);
1025
1035
  }
1026
1036
  // 把 base(含 SSAO)+描边/发光/bloom 合成结果拷到屏幕合成目标,后续 颜色叠加/磨砂玻璃
1027
1037
  // 在此目标上叠加;最后统一跑一次 FXAA 终处理输出到屏幕,覆盖全部后处理的锯齿/摩尔纹。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.187",
3
+ "version": "2.0.190",
4
4
  "description": "A Three.js extension library providing common 3D components, animations, materials, and utilities",
5
5
  "author": "xiaosihan",
6
6
  "publishConfig": {