three-base 2.0.166 → 2.0.168
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.js +2 -1
- package/MktMesh/MktMesh.ts +2 -1
- package/MktMesh/mktMappingShader.d.ts +9 -0
- package/MktMesh/mktMappingShader.js +10 -1
- package/MktMesh/mktMappingShader.ts +11 -1
- package/MktMesh/mktShader.d.ts +73 -31
- package/MktMesh/mktShader.js +10 -409
- package/MktMesh/mktShader.ts +10 -424
- package/package.json +1 -1
package/MktMesh/MktMesh.js
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
* 同一时刻只激活名册 0 号槽(中心)那一个纹理(全局共享单激活方案)。
|
|
25
25
|
*/
|
|
26
26
|
import { BufferGeometry, BackSide, Float32BufferAttribute, Matrix4, Mesh, Shape, ShapeGeometry, SRGBColorSpace, Vector3, } from "three";
|
|
27
|
-
import { createPlaceholderTexture,
|
|
27
|
+
import { createPlaceholderTexture, isPanoTexMode, mktPanoTiledFlag, mktPanoTexUrls, isRtStitchKey, rtStitchKeyParts, RT_STITCH_KEY_PREFIX, RT_STITCH_SLOT_COUNT } from "./mktShader";
|
|
28
|
+
import { MKT_PANO_MAX_SLOTS } from "./mktMappingShader";
|
|
28
29
|
import { createMktFloorMappingShaderMaterial } from "./mktMappingShader";
|
|
29
30
|
// ⭐ 皇上旨 2026-10-06:拼合 = shader 逐格画进 WebGLRenderTarget,**一份实现**(canvas 2D 那一份连同
|
|
30
31
|
// `?panoStitch=canvas` 开关整条删除)
|
package/MktMesh/MktMesh.ts
CHANGED
|
@@ -41,7 +41,8 @@ import {
|
|
|
41
41
|
Vector3,
|
|
42
42
|
} from "three";
|
|
43
43
|
import type { WebGLRenderer } from "three";
|
|
44
|
-
import { createPlaceholderTexture,
|
|
44
|
+
import { createPlaceholderTexture, isPanoTexMode, mktPanoTiledFlag, mktPanoTexUrls, isRtStitchKey, rtStitchKeyParts, RT_STITCH_KEY_PREFIX, RT_STITCH_SLOT_COUNT, type PanoTexMode } from "./mktShader";
|
|
45
|
+
import { MKT_PANO_MAX_SLOTS } from "./mktMappingShader";
|
|
45
46
|
import { createMktFloorMappingShaderMaterial } from "./mktMappingShader";
|
|
46
47
|
// ⭐ 皇上旨 2026-10-06:拼合 = shader 逐格画进 WebGLRenderTarget,**一份实现**(canvas 2D 那一份连同
|
|
47
48
|
// `?panoStitch=canvas` 开关整条删除)
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { ShaderMaterial } from "three";
|
|
2
|
+
/**
|
|
3
|
+
* ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
|
|
4
|
+
* (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
5
|
+
* (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
|
|
6
|
+
*
|
|
7
|
+
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
8
|
+
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
9
|
+
*/
|
|
10
|
+
export declare const MKT_PANO_MAX_SLOTS = 8;
|
|
2
11
|
/**
|
|
3
12
|
* 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
4
13
|
* 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
|
|
@@ -6,7 +6,16 @@
|
|
|
6
6
|
* 与 blend / selected 共用同一份 floorVertexShader 与同一套采样口径(改采样两处同改)。
|
|
7
7
|
*/
|
|
8
8
|
import { BackSide, Matrix4, ShaderMaterial, Vector3 } from "three";
|
|
9
|
-
import { createPlaceholderTexture, floorVertexShader,
|
|
9
|
+
import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } from "./mktShader";
|
|
10
|
+
/**
|
|
11
|
+
* ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
|
|
12
|
+
* (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
13
|
+
* (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
|
|
14
|
+
*
|
|
15
|
+
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
16
|
+
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
17
|
+
*/
|
|
18
|
+
export const MKT_PANO_MAX_SLOTS = 8;
|
|
10
19
|
/**
|
|
11
20
|
* 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
12
21
|
* 按三角面 aPanoIndex 在 panoIndices 槽里找对应全景纹理 —— **不看距离、不看夹角**(blend 那套打分/归约整段没有)。
|
|
@@ -6,7 +6,17 @@
|
|
|
6
6
|
* 与 blend / selected 共用同一份 floorVertexShader 与同一套采样口径(改采样两处同改)。
|
|
7
7
|
*/
|
|
8
8
|
import { BackSide, Matrix4, ShaderMaterial, Vector3 } from "three";
|
|
9
|
-
import { createPlaceholderTexture, floorVertexShader,
|
|
9
|
+
import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } from "./mktShader";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
|
|
13
|
+
* (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
14
|
+
* (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
|
|
15
|
+
*
|
|
16
|
+
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
17
|
+
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
18
|
+
*/
|
|
19
|
+
export const MKT_PANO_MAX_SLOTS = 8;
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
22
|
* 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
|
package/MktMesh/mktShader.d.ts
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
import { DataTexture, Matrix4, ShaderMaterial } from "three";
|
|
2
|
+
/** ⭐ 2026-10-09 随blend 材质搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
3
|
+
export declare const TILE_DEBUG_GLSL: string;
|
|
2
4
|
/** 诊断配色是否开启(应用层据此把全景点标记染成同色板,两边对得上) */
|
|
3
5
|
export declare const MKT_PANO_TINT_ON: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* 🔬 诊断色的**叠加强度**(0~1):`mix(原画面色, 染色, 本值)`。1 = 整块换成色相(09-25 初版,墙上只剩明暗,
|
|
8
|
+
* 照片本身看不清);皇上旨 2026-09-26 晚「叠加的颜色比例少一点」⇒ 取 **0.5**:色相仍是主色、一眼分得出归属,
|
|
9
|
+
* 但底下那张全景图的明暗与颜色能同时读出来。两份材质(融合 / 单全景)**共用这一个值**。
|
|
10
|
+
*/
|
|
11
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质搬去编辑器,故改为导出。 */
|
|
12
|
+
export declare const PANO_TINT_MIX = 0.5;
|
|
13
|
+
/**
|
|
14
|
+
* 🔬 **距离明暗诊断图**(皇上旨 2026-09-26 晚「你计一下每个点距离最近的一个全景点的距离, 然后距离越小颜色就是白色,
|
|
15
|
+
* 越远颜色就是黑色」)。
|
|
16
|
+
*
|
|
17
|
+
* 用法:分两条路,**各自独立**,谁也不靠谁:
|
|
18
|
+
* · **编辑器(MktMeshEdit)= 建材质时显式传 `panoDist: mktPanoDistEditorOn()`** ⇒ 默认关、地址里写 `panoDist=1` 才开
|
|
19
|
+
* (皇上旨 2026-09-27 晚「把颜色换成纹理,全景的纹理」—— 灰阶诊断让位给真投影,诊断图按需开)。
|
|
20
|
+
* · **库侧(发布页 / 预览弹窗)= 不传 ⇒ 读 URL 的 `PANO_DIST_ON`,默认关** ⇒ 正常渲染路径零影响。
|
|
21
|
+
* 开了之后片元算完最终颜色,按**这面这点到「它实际用的那张全景」的投影中心的水平距离**涂明暗:
|
|
22
|
+
* **贴到球脚下 = 白,远到房间最远角 = 黑**。
|
|
23
|
+
* 与归属配色的分工:`panoTint` 回答「这块归哪个球」(分家线),`panoDist` 回答「这点离自己的球到底有多远」——
|
|
24
|
+
* 后者能把「整墙一个色」那面墙上的**连续渐变**照出来,距离判据是不是真在起作用一眼可辨(恒白/恒黑才是坏的)。
|
|
25
|
+
* ⚠️ 距离口径与取图那条**同一个**:水平(xz)距离、候选 = 存活槽、门优先兜底不限门 ⇒ 白色区域就是那一张覆盖到的地方。
|
|
26
|
+
* ⚠️ 黑端(多远算全黑)= 应用层每次喂的 `uPanoDistMax`,取**墙体上最远处到自己最近景点的那段水平距离**
|
|
27
|
+
* (`_panoDistRange()`,皇上那间约 12m)⇒「黑」就是这间房可能出现的最大距离,跨面可比(不是每面各自归一化)。
|
|
28
|
+
* ⛔ 别拿地板尺寸当尺子:默认地板盘 `FLOOR_SIZE_DEFAULT = 80`(远超房间),对角线 113m 会把整面墙的灰阶压平
|
|
29
|
+
* (09-26 实测横扫三个点亮度 222/223/224,等于没有渐变)。
|
|
30
|
+
* ⚠️ 明暗曲线 = **线性**(`1 − d/D`,皇上旨 2026-09-27「要,改成线性渐变」)。09-26 那版 `pow(…, 2.2)` 的动机是
|
|
31
|
+
* 「着色器里是线性色,不补感知伽马会中间偏亮」—— 代价实测更糟:6m 处灰阶只剩 0.22 ⇒ 渐变几乎全压在景点脚下,
|
|
32
|
+
* 他数不出圆。线性后同一点 0.50 中灰,整间房的远近一眼读得出。
|
|
33
|
+
* ⚠️ 强度**不沿用** `PANO_TINT_MIX` 而是自己的 `PANO_DIST_MIX = 1`(整块换成灰阶):皇上要的是「近=白、远=黑」这张**距离图**本身,
|
|
34
|
+
* 09-26 实测按 0.5 混 ⇒ 一面墙横扫过去只有 135→151(19 级)的差别,肉眼仍是「一片灰」;归属配色那条 0.5 的旨意针对的是
|
|
35
|
+
* 「色叠加把照片盖住了」,与本图无关(要看照片本来颜色就把 `?panoDist` 关掉)。
|
|
36
|
+
* ⚠️ 两道诊断**同时开**时本图后上色 ⇒ 明暗图盖住色相(要同时看归属与距离请分开截两张)。
|
|
37
|
+
* ⚠️ 开关口径历经三版:① 初版「默认关、URL `?panoDist=1` 才开」⇒ 皇上第二天地址栏里只剩 `panoTint=1`,
|
|
38
|
+
* 看到的又是实拍照片,误判「代码被改回去了」(09-26 实测线上包里 panoDist 一段俱在,纯为开关没跟上)。
|
|
39
|
+
* ② 皇上同日晚旨「继续改成 距离越近越白、越远越黑的模式」⇒ 改成**编辑器这一页默认开**:写法是在 renderer
|
|
40
|
+
* 模块顶层调 `mktPanoDistEditorDefaultOn()` 翻全局开关。09-26 实测线上打印当场暴露它是**半张图**:
|
|
41
|
+
* 「墙 / 地板 / 家具三份材质的片元着色器不是同一份」—— 立方体那份是 `static material = create…()`,
|
|
42
|
+
* 在**模块求值期**就建好了,永远早于任何应用层模块体里的语句 ⇒ 墙/地板黑了白了,立方体仍是实拍。
|
|
43
|
+
* ③ 现行(本次定论):**开关不再靠语句先后**,而是建材质时把这一份材质要不要这张图**显式说清楚**
|
|
44
|
+
* (融合工厂的 `panoDist` 选项)。⇒ 编辑器三处建材质点同传一个纯函数,预览/发布页不传 ⇒ 天然关。
|
|
45
|
+
* ④ 09-27 晚皇上旨「把颜色换成纹理,全景的纹理」⇒ 编辑器这一页翻回**默认关**(`mktPanoDistEditorOn()`
|
|
46
|
+
* = `panoDebugOn("panoDist")`),灰阶诊断按需 `?panoDist=1` 再看。口径机制不变,只翻默认值。
|
|
47
|
+
* ⛔ 不许再回到「模块顶层翻全局变量」那一路:那份 GLSL 是建材质时一次性拼出来的,谁先谁后取决于 import 顺序,
|
|
48
|
+
* 改一次 import 就悄悄漏一面(且 `统一性检查` 会当场报不是同一份源码)。
|
|
49
|
+
*/
|
|
50
|
+
/** ⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 本常量改为导出:
|
|
51
|
+
* 编辑器那份 `mktMeshFloorBlendShader.ts` 要用它当默认值。库内的映射材质仍照常用。 */
|
|
52
|
+
export declare const PANO_DIST_ON: boolean;
|
|
4
53
|
/**
|
|
5
54
|
* 🔬 **编辑器这一页**该不该有近白远黑图:**默认关**(皇上旨 2026-09-27 晚「把颜色换成纹理,全景的纹理」——
|
|
6
55
|
* 灰阶诊断盖住了真投影,默认让位给全景纹理;要看诊断图 URL 显式写 `panoDist=1`,`#` 前后都认)。
|
|
@@ -9,6 +58,16 @@ export declare const MKT_PANO_TINT_ON: boolean;
|
|
|
9
58
|
* ⚠️ URL 解析只留库侧这一处(与 `panoDebugOn` 同族口径),⛔ 应用层不许再各解一遍。
|
|
10
59
|
*/
|
|
11
60
|
export declare function mktPanoDistEditorOn(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* 🔬 距离明暗图的「求最近景点」那一段 —— **真循环**版(皇上旨 2026-09-27 晚「那就更不对了,我一开始的需求就是
|
|
63
|
+
* 把 4 个全景点的坐标传给 shader,按最近取用」+ 看过代码后点头要这版)。
|
|
64
|
+
* 语义与他原话逐字对齐:每个像素遍历 `uPanoPoints[0..N-1]`,只留最小水平距离。
|
|
65
|
+
* ⚠️ 09-27 晚起取图与明暗图**同把尺**(皇上「取用距离最近的那个全景点的瓦片纹理」定版):取图那条的夹角门
|
|
66
|
+
* 已整链删除 ⇒ 两边都是「纯水平距离最近」,圆与图永远一致。⛔ 本函数只动颜色,不动取图。
|
|
67
|
+
* ⚠️ 动态下标只碰普通 uniform 数组(`vec4[]`),不碰 sampler ⇒ ANGLE 那条「sampler 必须常量下标」的限制管不到这里。
|
|
68
|
+
*/
|
|
69
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质一起搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
70
|
+
export declare function panoDistLoopGlsl(colorVar: string, maxPano: number): string;
|
|
12
71
|
/** 末尾 4 色(红/绿/蓝/黄):景点数 > 20 时循环取用 */
|
|
13
72
|
export declare const MKT_PANO_TINT_HEX: readonly number[];
|
|
14
73
|
/** 「第 i 个**景点**」的诊断色(按景点序号,不是槽位):0~19 各一色,>=20 循环末尾 4 色 */
|
|
@@ -228,36 +287,19 @@ export declare function setMktPanoTiled(material: ShaderMaterial | null | undefi
|
|
|
228
287
|
* panorama / textureMatrix 由 MktMesh 在运行时按「最近纹理」动态设置。
|
|
229
288
|
*/
|
|
230
289
|
export declare function createMktShaderMaterial(): ShaderMaterial;
|
|
231
|
-
export interface MktFloorBlendOptions {
|
|
232
|
-
/** 最多参与融合的全景点数(⭐ 10-06 晚旨后每点占左右 **2** 张拼合槽纹理,纹理总数 = maxPano×2,须 ≤ 16),默认 `MKT_PANO_MAX_SLOTS`(=8) ⇒ 8×2 = 16 = 采样器硬顶 */
|
|
233
|
-
maxPano?: number;
|
|
234
|
-
/**
|
|
235
|
-
* 🔬 这一份材质要不要「距离明暗图」(近白远黑):**不传 = 读 URL 开关 `?panoDist=1`**(发布页 / 预览就该走这条)。
|
|
236
|
-
* 编辑器三处建材质点显式传 `mktPanoDistEditorOn()`(默认开)⇒ 墙/地板/立方体**同一份源码**、同一张图。
|
|
237
|
-
* ⚠️ 只能在这里给,⛔ 没有「建完再翻」这条路:这段 GLSL 在 new ShaderMaterial 时一次性拼死。
|
|
238
|
-
*/
|
|
239
|
-
panoDist?: boolean;
|
|
240
|
-
}
|
|
241
|
-
/** 融合材质的全景点数**上限**:每点占 **2** 张拼合槽纹理(32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
242
|
-
* ⭐ 2026-10-06 晚皇上旨「一次能够展示 8 个全景纹理」:靠的就是「每点从 4 槽降到 2 槽」——
|
|
243
|
-
* sampler 总数 16 是硬件硬顶(皇上本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16,一直没变),
|
|
244
|
-
* 原来 16 ÷ 4 槽 = 4 个景点,现在 16 ÷ 2 槽 = **8 个景点**,画质与单全景显存**分毫未动**。 */
|
|
245
|
-
export declare const MKT_PANO_MAX_SLOTS = 8;
|
|
246
|
-
/**
|
|
247
|
-
* 创建「多全景融合」着色器材质:每帧由外部喂入最近 maxPano 个全景点(⭐ 10-06 晚旨后每点 2 张拼合槽纹理)。
|
|
248
|
-
* 同一份着色器同时服务普通 Mesh(墙/地板)与 InstancedMesh(家具立方体):
|
|
249
|
-
* 实例化与否由 three.js 按对象类型自动注入 USE_INSTANCING 宏决定,无需外部传 instanced 开关。
|
|
250
|
-
* 数组 uniform 在创建时即按 maxPano 长度初始化(占位纹理 + 单位矩阵 + 权重 0),运行时由渲染器每帧改写对应槽位。
|
|
251
|
-
* ⚠️ 取图口径只有一条(皇上旨 2026-09-25 晚「都要一起改」→ 09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
252
|
-
* 地板 / 墙 / 家具**全部**按「水平距离最近的一张」取图(09-24~09-25 的夹角门已整链删除),
|
|
253
|
-
* 不再有「地板按覆盖度融合」这条路,故也**没有** `pickNearest` 选项(旧的 0/1 分流 uniform 已删)。
|
|
254
|
-
*/
|
|
255
|
-
export declare function createMktFloorBlendShaderMaterial(options?: MktFloorBlendOptions): ShaderMaterial;
|
|
256
290
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
291
|
+
* 多全景融合着色器:把「最近最多 maxPano 个全景」以数组传入,每个片元对这些张各自做等距柱状投射,
|
|
292
|
+
* 再取**唯一一条**口径(皇上旨 2026-09-25 晚「都要一起改」→ 2026-09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
293
|
+
* - **候选里只取水平距离最近的那一张,满权重**(地板 / 墙 / 家具立方体**同一份、同一条**,
|
|
294
|
+
* 旧的「地板按覆盖度加权融合、交界渐隐」那一路已按旨删除 ⇒ 面上不再有渐隐带,也不再有中央露灰)。
|
|
295
|
+
* - ⚠️ 09-24~09-25 的「夹角门(点在面正面侧才合格)+ 全不合格兜底」已按 09-27 晚旨**整链删除**:
|
|
296
|
+
* 它是「明暗圆对、纹理不对」的第二来源(墙背后更近的点被门否掉,纹理落到正面侧的远槽);
|
|
297
|
+
* 纯距离口径下墙背后的全景也会投过来,皇上知情选定。
|
|
298
|
+
* - 候选池按「槽里有没有全景」筛,**不按覆盖半径(c>0)筛**,否则两个景点距离一远就变成
|
|
299
|
+
* 「各占一片互不相干的 territory、交界处整条露灰底」,距离判据压根轮不到(实测 bothCandidates=0)。
|
|
300
|
+
* - ⚠️ 代价(已向皇上报过并获批):`uFloorCoreRadius` / `uFloorFadeRange` 两根覆盖半径旋钮**从此对任何面都不参与取图**。
|
|
301
|
+
* 控件与 uniform 暂未删(未奉旨),删与不删等皇上下结论。
|
|
302
|
+
* - panoramas[i] : 第 i 张全景纹理
|
|
303
|
+
* - textureMatrices[i]: 第 i 张全景的世界矩阵(位置=投影中心,旋转=朝向)
|
|
304
|
+
* - weights[i] : 第 i 张是否活着(camW,0 = 该槽未绑全景 ⇒ 不进候选池)
|
|
260
305
|
*/
|
|
261
|
-
export declare function createMktFloorSelectedShaderMaterial(options?: {
|
|
262
|
-
maxPano?: number;
|
|
263
|
-
}): ShaderMaterial;
|
package/MktMesh/mktShader.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* 兼容注意:为兼容 Windows / ANGLE 的 GLSL 编译器,本文件刻意不使用全局 const 常量与自定义函数,
|
|
32
32
|
* 所有常量均以字面量内联书写;ShaderMaterial 为 GLSL ES 1.00,用 texture2D / gl_FragColor。
|
|
33
33
|
*/
|
|
34
|
-
import { Color, DataTexture, DoubleSide, Matrix4, ShaderMaterial, SRGBColorSpace, Vector3
|
|
34
|
+
import { Color, DataTexture, DoubleSide, Matrix4, ShaderMaterial, SRGBColorSpace, Vector3 } from "three";
|
|
35
35
|
/**
|
|
36
36
|
* 🔬 瓦片象限诊断开关(2026-09-21)。
|
|
37
37
|
* 背景:皇上为「全景 2×2 瓦片上下方向」连调六轮,当时把「位置」与「块内朝向」绑在一起调
|
|
@@ -66,7 +66,8 @@ function panoDebugOn(name) {
|
|
|
66
66
|
return false;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
/** ⭐ 2026-10-09 随blend 材质搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
70
|
+
export const TILE_DEBUG_GLSL = panoDebugOn("panoTileDebug") ? "1.0" : "0.0";
|
|
70
71
|
/**
|
|
71
72
|
* 🔬 归属诊断配色(皇上旨 2026-09-25「你为每个全景球设置不同的颜色, 然后把全景瓦片映射在墙面上时, 叠加该全景图的颜色,
|
|
72
73
|
* 这样我就能看清楚整个墙面是不是叠加了同一个颜色 —— 若是同一个颜色, 说明整面都映射了同一张瓦片, 根本没按最近取」)。
|
|
@@ -100,7 +101,8 @@ export const MKT_PANO_TINT_ON = PANO_TINT_ON;
|
|
|
100
101
|
* 照片本身看不清);皇上旨 2026-09-26 晚「叠加的颜色比例少一点」⇒ 取 **0.5**:色相仍是主色、一眼分得出归属,
|
|
101
102
|
* 但底下那张全景图的明暗与颜色能同时读出来。两份材质(融合 / 单全景)**共用这一个值**。
|
|
102
103
|
*/
|
|
103
|
-
|
|
104
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质搬去编辑器,故改为导出。 */
|
|
105
|
+
export const PANO_TINT_MIX = 0.5;
|
|
104
106
|
/**
|
|
105
107
|
* 🔬 **距离明暗诊断图**(皇上旨 2026-09-26 晚「你计一下每个点距离最近的一个全景点的距离, 然后距离越小颜色就是白色,
|
|
106
108
|
* 越远颜色就是黑色」)。
|
|
@@ -138,7 +140,9 @@ const PANO_TINT_MIX = 0.5;
|
|
|
138
140
|
* ⛔ 不许再回到「模块顶层翻全局变量」那一路:那份 GLSL 是建材质时一次性拼出来的,谁先谁后取决于 import 顺序,
|
|
139
141
|
* 改一次 import 就悄悄漏一面(且 `统一性检查` 会当场报不是同一份源码)。
|
|
140
142
|
*/
|
|
141
|
-
|
|
143
|
+
/** ⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 本常量改为导出:
|
|
144
|
+
* 编辑器那份 `mktMeshFloorBlendShader.ts` 要用它当默认值。库内的映射材质仍照常用。 */
|
|
145
|
+
export const PANO_DIST_ON = panoDebugOn("panoDist");
|
|
142
146
|
/**
|
|
143
147
|
* 🔬 **编辑器这一页**该不该有近白远黑图:**默认关**(皇上旨 2026-09-27 晚「把颜色换成纹理,全景的纹理」——
|
|
144
148
|
* 灰阶诊断盖住了真投影,默认让位给全景纹理;要看诊断图 URL 显式写 `panoDist=1`,`#` 前后都认)。
|
|
@@ -182,7 +186,8 @@ function panoDistGlsl(colorVar, distExpr) {
|
|
|
182
186
|
* 已整链删除 ⇒ 两边都是「纯水平距离最近」,圆与图永远一致。⛔ 本函数只动颜色,不动取图。
|
|
183
187
|
* ⚠️ 动态下标只碰普通 uniform 数组(`vec4[]`),不碰 sampler ⇒ ANGLE 那条「sampler 必须常量下标」的限制管不到这里。
|
|
184
188
|
*/
|
|
185
|
-
|
|
189
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质一起搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
190
|
+
export function panoDistLoopGlsl(colorVar, maxPano) {
|
|
186
191
|
return /* glsl */ `{
|
|
187
192
|
float distNear = 1e9;
|
|
188
193
|
for (int i = 0; i < ${maxPano}; i++) {
|
|
@@ -842,407 +847,3 @@ export function createMktShaderMaterial() {
|
|
|
842
847
|
* - textureMatrices[i]: 第 i 张全景的世界矩阵(位置=投影中心,旋转=朝向)
|
|
843
848
|
* - weights[i] : 第 i 张是否活着(camW,0 = 该槽未绑全景 ⇒ 不进候选池)
|
|
844
849
|
*/
|
|
845
|
-
/**
|
|
846
|
-
* 生成多全景片元着色器(地板 / 墙 / 家具共用)。
|
|
847
|
-
* ⚠️ 关键约束:Windows/ANGLE(D3D) 后端**禁止用循环变量/非常量索引 sampler 数组**(报错
|
|
848
|
-
* "array index for samplers must be constant integral expressions"),故这里在 JS 侧把循环
|
|
849
|
-
* 完全展开成「字面量下标」的若干代码段(panoramas[0]…panoramas[N-1]),所有数组访问均为常量下标。
|
|
850
|
-
* 未参与融合的槽位权重=0,被 if(w>0.0) 跳过(常量分支,零开销)。
|
|
851
|
-
*/
|
|
852
|
-
function buildFloorBlendFragment(maxPano, panoDistOn) {
|
|
853
|
-
// 每个全景点占 **2** 张拼合槽纹理(32 片每 16 片拼一张:左半幅 / 右半幅)⇒ 8 × 2 = 16 = sampler 硬顶
|
|
854
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
|
|
855
|
-
let slotCalc = ""; // 每槽各自算出:颜色 linK / 水平距离 dK / 夹角 angK(acos+背面+180°)/ 分值 scoreK = d−ang
|
|
856
|
-
let slotReduceLive = ""; // 每槽参与「score 最小值」归约(候选池 = 槽里活着的那几张,score<1e8 即活)
|
|
857
|
-
let slotOne = ""; // 每槽对「只取 score 最小那一张」的贡献(唯一取图口径,地板/墙/家具共用)
|
|
858
|
-
let slotOwner = ""; // 🔬 每槽对「归属诊断色」的贡献(仅 ?panoTint=1 时生成,正常态为空串)
|
|
859
|
-
for (let k = 0; k < maxPano; k++) {
|
|
860
|
-
const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
|
|
861
|
-
slotCalc += `
|
|
862
|
-
// ── 点槽 ${k}(纹理 ${base}..${base + 1})──
|
|
863
|
-
vec3 lin${k} = vec3(0.0);
|
|
864
|
-
float d${k} = 1e9; // 本面这点到本槽全景中心的**水平**距离(score 被减数)
|
|
865
|
-
// float camD${k} —— 14:24 旨曾加「全景中心到相机距离」项,15:07 旨去掉(连声明一并去,注释存档)
|
|
866
|
-
float cosA${k} = -1.0; // 「点→全景」向量 与 正面法线 的夹角余弦(acos 后 = 夹角弧度)
|
|
867
|
-
float ang${k} = 1e9; // 夹角(acos 后 0..180°,背面 +180° ⇒ 270°..360°),score 的减数
|
|
868
|
-
float score${k} = 1e9; // ⭐主判据(皇上 09-28 15:07 旨七修):score = 顶点与全景的距离 − 夹角,取**最小**者定纹理
|
|
869
|
-
// ── 旧原理存档(注释保留不删)──
|
|
870
|
-
// 09-28 14:24 旨「score = 顶点距离 + 相机距离 − 夹角」:camD 项已整条撤(见下方槽内注释行)
|
|
871
|
-
// 09-28 00:44 旨「score = 距离 × 夹角²,取积最小」:见下方槽内注释行
|
|
872
|
-
// 09-28 01:56 旨「按夹角从小到大排序取最小、打平比水平距离」:bestAng/bestDAtAng 两段归约(已撤,git 可查)
|
|
873
|
-
{
|
|
874
|
-
float camW = weights[${k}]; // 该全景的「锚点距离权重」(JS 按**名册那条水平距离**反比算,未归一化;⭐ 10-07 第二十一道旨后那把尺量的端点 = 控制器中心点,未注入时才是相机位置)
|
|
875
|
-
if (camW > 0.0) {
|
|
876
|
-
mat4 tm = textureMatrices[${k}];
|
|
877
|
-
vec3 texPos = tm[3].xyz; // 投影中心 = 纹理矩阵位置
|
|
878
|
-
mat3 texRot = mat3(tm); // 纹理朝向 = 旋转分量
|
|
879
|
-
vec3 dir = normalize(vProjPos - texPos);
|
|
880
|
-
dir = texRot * dir; // 转到纹理局部方向
|
|
881
|
-
float lon = atan(dir.z, dir.x);
|
|
882
|
-
float u = lon * 0.15915494309189535 + 0.5; // 经度 -> u
|
|
883
|
-
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
884
|
-
// 等距柱状线性 v(= 全图 UV),与单全景分支**逐字同口径**,理由见单全景分支说明
|
|
885
|
-
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
886
|
-
// 左右两半 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里 4×4=16 片拼成,见 RT_STITCH_SLOT_TILES)
|
|
887
|
-
// ⭐ 10-06 晚旨「每个全景纹理由左右 2 个 RT 组成」:竖着不再分块 ⇒ 槽只随 u 走,与单全景分支逐字同口径
|
|
888
|
-
int tileIdx = (u >= 0.5) ? 1 : 0;
|
|
889
|
-
float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
|
|
890
|
-
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 2v/2v-1 = 纵向分辨率白丢一半
|
|
891
|
-
float localV = v;
|
|
892
|
-
// 🧩 该点这 2 槽装的是整图(用户切了 whole 形态,或该点压根没切过片)⇒ 还原成全图 UV 再采样,与单全景分支逐字同口径
|
|
893
|
-
// (方向已写死,故横向还原式恒等于 u、纵向 localV 本就等于 v,见单全景分支推导)
|
|
894
|
-
float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
|
|
895
|
-
float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
|
|
896
|
-
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组:base 为本点连槽起点(JS 常量 k*RT_STITCH_SLOT_COUNT),
|
|
897
|
-
// 以下 2 个采样下标均为「base + 字面量 0/1」的常量表达式,编译安全。
|
|
898
|
-
// 🔬 诊断直通(见文件头 TILE_DEBUG_GLSL 说明;正常态内联为 0.0,整段被编译器消除)
|
|
899
|
-
if (${TILE_DEBUG_GLSL} > 0.5) {
|
|
900
|
-
vec3 dbgCol;
|
|
901
|
-
if (tileIdx == 0) dbgCol = vec3(1.0, 0.0, 0.0); // 红 = 左半幅槽 0
|
|
902
|
-
else dbgCol = vec3(0.0, 1.0, 0.0); // 绿 = 右半幅槽 1
|
|
903
|
-
gl_FragColor = vec4(dbgCol, 1.0);
|
|
904
|
-
#include <colorspace_fragment>
|
|
905
|
-
#include <logdepthbuf_fragment>
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
// ⭐ 采样即线性(与单全景分支同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
910
|
-
// colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
|
|
911
|
-
// 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
|
|
912
|
-
if (tileIdx == 0) lin${k} = texture2D(panoramas[${base}], vec2(panoU, panoV)).rgb;
|
|
913
|
-
else lin${k} = texture2D(panoramas[${base + 1}], vec2(panoU, panoV)).rgb;
|
|
914
|
-
// ⭐ 09-28 15:07 旨定版(七修):score = **顶点到全景的距离 − 夹角**,取最小者。
|
|
915
|
-
// 夹角 = acos(cosA)(0..180°),cosA = dot(normalize(全景中心 − 本点), N)(N 已按 gl_FrontFacing 翻到观察面)。
|
|
916
|
-
// 背面一刀 +180°(00:26 旨「背面的夹角该大于 180 度」)保留。
|
|
917
|
-
// 14:24 那版曾加「全景与相机的距离 camD」,15:07 旨「把全景到相机的那个逻辑去掉」,注释保留不删。
|
|
918
|
-
vec3 toPano${k} = texPos - vProjPos;
|
|
919
|
-
float lenP${k} = length(toPano${k});
|
|
920
|
-
cosA${k} = (lenP${k} > 1e-4) ? dot(toPano${k} / lenP${k}, N) : 1.0;
|
|
921
|
-
d${k} = distance(vProjPos.xz, texPos.xz);
|
|
922
|
-
// camD${k} = distance(cameraPosition, texPos); // ⛌ 14:24 旨「全景与相机距离」项,15:07 旨去掉,注释保留不删
|
|
923
|
-
ang${k} = acos(clamp(cosA${k}, -1.0, 1.0));
|
|
924
|
-
if (cosA${k} < 0.0) ang${k} += 3.14159265; // 背面 +180°(π)
|
|
925
|
-
score${k} = d${k} - ang${k}; // ⭐ 15:07 旨:距离 − 角度,取最小
|
|
926
|
-
// score${k} = d${k} + camD${k} - ang${k}; // ⛌ 旧原理(14:24 旨:两距离之和 − 角度),注释保留不删
|
|
927
|
-
// score${k} = d${k} * ang${k} * ang${k}; // ⛌ 旧原理(00:44 旨:距离 × 夹角² 取积最小),注释保留不删
|
|
928
|
-
}
|
|
929
|
-
}`;
|
|
930
|
-
// ⭐ 归约(皇上 09-28 15:07 旨七修「顶点距离 − 夹角」):bestScore = 各活槽分值最小值。
|
|
931
|
-
// score == bestScore 是同值浮点精确比较(min 存的就是同一份 bit 值,== 可靠,与历代口径同一技巧)。
|
|
932
|
-
slotReduceLive += `
|
|
933
|
-
if (score${k} < 1e8) {
|
|
934
|
-
bestScore = min(bestScore, score${k});
|
|
935
|
-
}`;
|
|
936
|
-
// ⭐ 胜者(皇上 09-28 15:07 旨七修):score = 顶点距离 − 角度 最小的那张。
|
|
937
|
-
slotOne += `
|
|
938
|
-
if (score${k} < 1e8 && score${k} == bestScore) {
|
|
939
|
-
wsum += 1.0; acc += lin${k}; cover += 1.0;
|
|
940
|
-
}`;
|
|
941
|
-
// 🔬 归属诊断(皇上旨 2026-09-25「就在最后算出来的颜色上再叠颜色,不用想那么复杂」):
|
|
942
|
-
// 这里只**记账**(这点归哪个景点),染色动作留到 main 末尾对最终颜色做一次。
|
|
943
|
-
// 归属判据与 slotOne **逐字同一条**(距离−角度最小),末了统一「打平归编号小的那个」。
|
|
944
|
-
if (PANO_TINT_ON) {
|
|
945
|
-
slotOwner += `
|
|
946
|
-
if (score${k} < 1e8 && score${k} == bestScore) {
|
|
947
|
-
// ⚠️ tintCnt == 0.0 这道闸 = **打平归编号小的那个**:两张一样近的那条分界带(实测两景点连线的中垂面与墙交线那一带)
|
|
948
|
-
// 会同时命中两个槽,平均出来是「红+绿=橄榄」—— 那不是没上色,但肉眼读不出归属,故只记第一个。
|
|
949
|
-
if (tintCnt == 0.0) { tintAcc += uPanoTintColors[${k}]; tintCnt += 1.0; }
|
|
950
|
-
}`;
|
|
951
|
-
}
|
|
952
|
-
// 🔬 距离明暗图**不在这儿逐槽拼**了(皇上旨 2026-09-27 晚:要一句真循环遍历 4 个坐标)⇒ 见 `panoDistLoopGlsl`。
|
|
953
|
-
}
|
|
954
|
-
return /* glsl */ `
|
|
955
|
-
#include <logdepthbuf_pars_fragment>
|
|
956
|
-
|
|
957
|
-
uniform sampler2D panoramas[${tileCount}];${PANO_TINT_ON ? `
|
|
958
|
-
// 🔬 归属诊断色(线性空间,**仅 ?panoTint=1 时存在**):第 i 个纹理槽里躺的那个景点的固定色,
|
|
959
|
-
// 由应用层每次换绑时写入(见 setMktPanoTint)。⚠️ 刻意不按槽位编译期写死:
|
|
960
|
-
// 「仅映射选中的那一个」模式下地板永远只喂 0 号槽,按槽写死 = 选第几个点都涂同一个红(皇上 09-25 反馈)。
|
|
961
|
-
uniform vec3 uPanoTintColors[${maxPano}];` : ""}${panoDistOn ? `
|
|
962
|
-
// 🔬 距离明暗诊断(这份材质建时 panoDist 选项为真才存在):「多远算全黑」的米数,由应用层每次喂投影时写
|
|
963
|
-
// (见 setMktPanoDistRange)⇒ 全屋同一把尺子,跨面才比得出远近。
|
|
964
|
-
uniform float uPanoDistMax;
|
|
965
|
-
// 🔬 距离明暗诊断的**圆心清单**(皇上旨 2026-09-27「shader 里面有四个全景点的坐标, 每个像素判断距离 4 个点里最小的
|
|
966
|
-
// 那个值, 再用这个值设置颜色」):xyz = 该点的世界坐标,w = 1 ⇒ 这一格**真有一个全景点**。
|
|
967
|
-
// ⛔ 与 weights 的分工(两者刻意不同,别合并):weights 管「这格的**图**能不能取」(瓦片没绑好就 0,防止拿
|
|
968
|
-
// 1×1 占位图刷一片素灰),uPanoPoints 管「这格**有没有点**」⇒ 圆按景点个数画,图按传到位的那几张取。
|
|
969
|
-
// ⚠️ 09-27 晚起明暗那段**只读这一个数组**(纯水平距离最近)⇒ 与取图同把尺(夹角门已废);坐标与上面
|
|
970
|
-
// textureMatrices[k][3].xyz 同源同值(同一批矩阵喂进来,见 setMktPanoPoints),不是第二套数据。
|
|
971
|
-
uniform vec4 uPanoPoints[${maxPano}];` : ""}
|
|
972
|
-
uniform mat4 textureMatrices[${maxPano}];
|
|
973
|
-
uniform float weights[${maxPano}]; // 锚点距离权重 camW(JS 由名册那条水平距离写入,未归一化;着色器内与空间因子相乘后整体归一化)
|
|
974
|
-
uniform vec3 uFloorBaseColor; // 地板底色(线性空间,深灰):只在「一个候选都没有」(maxPano 张全景全未绑定)时露出来
|
|
975
|
-
// ⚠️ 下面两根覆盖半径旋钮**自 09-25 晚「都要一起改」起不再参与取图**(覆盖度融合那一路已删,每个像素纯按最近一张)。
|
|
976
|
-
// 控件与 uniform 暂留(未奉旨删控件),值仍由应用层写入,但着色器不读 ⇒ 调它们没有视觉变化。
|
|
977
|
-
uniform float uFloorCoreRadius;
|
|
978
|
-
uniform float uFloorFadeRange;
|
|
979
|
-
uniform float uFloorOpacity; // 地板全景投影「整体透明度」(0~1,全局对所有全景一起生效):仅作用于全景图映射的可见度,越小全景越淡、越透出地板灰底;地板灰色本身不变
|
|
980
|
-
// 全景投射显隐:1=显示全景(投射到墙/地板),0=仅显示素色(墙体回落中性色,地板恒为 1 不受影响)
|
|
981
|
-
uniform float uPanoramaVisible;
|
|
982
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」):原 uniform float uColorSpace; + 那段 sRGB pow 解码分支已整条撤除,
|
|
983
|
-
// 采样值即线性(纹理标了 SRGBColorSpace ⇒ 硬件解过一次),末端 <colorspace_fragment> 只编码一次。
|
|
984
|
-
// ⭐ 取图方式只有一条(皇上旨 2026-09-25 晚「都要一起改」→ 09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
985
|
-
// 地板 / 墙 / 家具**同一份着色器、同一条判据** —— 候选里只取水平距离最近那**一张**,满权重。
|
|
986
|
-
// 旧的 uPanoPickNearest(0=地板覆盖度融合 / 1=模型表面取最近)已随融合那一路一起删除;
|
|
987
|
-
// 09-24~09-25 的夹角门 + 兜底也已按 09-27 晚旨整链删除(它是「明暗圆对、纹理不对」的第二来源)。
|
|
988
|
-
// ⚠️ 候选池是「槽里活着的全景」(weights>0,瓦片绑好了的),**不受覆盖半径筛掉**。
|
|
989
|
-
// 全景上下方向**已写死**,无 uniform(与单全景材质同口径,见文件头 🎛️ 段)。
|
|
990
|
-
// 每个全景点**各自**的「这 2 槽是瓦片(1)还是同一张整图(0)」—— 融合时不同点可能来源不同(上传的有瓦片、
|
|
991
|
-
// 旧数据/种子图没有),故按点存数组;为 0 的点走全图 UV,理由见单全景分支同注释。
|
|
992
|
-
uniform float uPanoTiled[${maxPano}];
|
|
993
|
-
|
|
994
|
-
// 取样坐标(已由顶点着色器的 uProjInvMatrix 抵消掉 MktMesh 的整体变换,与 textureMatrices 一样对变换免疫)
|
|
995
|
-
varying vec3 vProjPos;
|
|
996
|
-
// 全景序号映射模式:本三角面归属的全局全景序号(顶点着色器从 geometry 的 aPanoIndex 传来;无此 attribute 的对象恒为 0)
|
|
997
|
-
varying float vPanoIndex;
|
|
998
|
-
// 几何法线(顶点着色器按同一条矩阵链变换到与 vProjPos 同一空间):取图「正面夹角」判据用
|
|
999
|
-
varying vec3 vWNormal;
|
|
1000
|
-
// 实例染色(仅当 InstancedMesh 带 instanceColor 时启用):默认白=全景真实色,选中黄=高亮染色
|
|
1001
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1002
|
-
varying vec3 vInstanceColor;
|
|
1003
|
-
#endif
|
|
1004
|
-
|
|
1005
|
-
void main() {
|
|
1006
|
-
// ⭐ 正面法线 N(分值公式里「夹角」的基准,皇上 09-28 凌晨旨「距离 × 夹角」):几何法线归一化后,
|
|
1007
|
-
// 按 gl_FrontFacing 翻到**观察者看的这一面**(墙零厚度 DoubleSide,两面各自以看到的这面算夹角——
|
|
1008
|
-
// 同一面墙从两侧看,分值不同是应该的)。地板/封盖/立方体同理。
|
|
1009
|
-
vec3 N = normalize(vWNormal);
|
|
1010
|
-
if (!gl_FrontFacing) N = -N;
|
|
1011
|
-
${PANO_TINT_ON ? ` // 🔬 归属诊断配色(?panoTint=1):本面这点归哪个景点(tintAcc 累加其固定色,tintCnt 计数)
|
|
1012
|
-
vec3 tintAcc = vec3(0.0);
|
|
1013
|
-
float tintCnt = 0.0;` : ""}
|
|
1014
|
-
${slotCalc}
|
|
1015
|
-
// ⭐ 取图口径(距离+夹角融合,钦定公式):score = 顶点距离 − 角度,取最小的那**一张**(地板/家具/编辑态墙同一份 shader)。
|
|
1016
|
-
// (原「uFaceMappingMode 0/1 运行时分支」已按皇上旨 2026-09-29「三模式三 shader」拆出:
|
|
1017
|
-
// 序号直取在 createMktFloorMappingShaderMaterial、仅显示选中在 createMktFloorSelectedShaderMaterial。)
|
|
1018
|
-
vec3 acc = vec3(0.0);
|
|
1019
|
-
float wsum = 0.0;
|
|
1020
|
-
float cover = 0.0;
|
|
1021
|
-
// 「取图胜者」归约(皇上 09-28 15:07 旨七修定版:score = 顶点距离 − 角度,取最小)
|
|
1022
|
-
float bestScore = 1e9;
|
|
1023
|
-
${slotReduceLive}
|
|
1024
|
-
${PANO_TINT_ON ? " // 🔬 先记账:这点按「距离减夹角最小」归哪个景点(与下面 slotOne 的取图判据同一条)\n" + slotOwner : ""}
|
|
1025
|
-
// 一面只显一张:score 最小的那张(不论多远,绝不留空面)
|
|
1026
|
-
${slotOne}
|
|
1027
|
-
if (wsum > 0.0) acc /= wsum; // 按总权重归一化(总混合值=1)
|
|
1028
|
-
// 覆盖度:有候选即 1(09-25 晚起不再有「渐隐/露灰」的中间态),只在「一个候选都没有」时 = 0
|
|
1029
|
-
// ⇒ 露出地板/墙体本来的底色。
|
|
1030
|
-
float coverage = clamp(cover, 0.0, 1.0);
|
|
1031
|
-
// 整体透明度仅作用于全景图映射:把覆盖度按 uFloorOpacity 缩放后再混合,
|
|
1032
|
-
// 灰底始终不透明(alpha=1),opacity 越小全景越淡、越透出地板灰色;地板灰色本身不变。
|
|
1033
|
-
float coverageEff = clamp(coverage * uFloorOpacity, 0.0, 1.0);
|
|
1034
|
-
vec3 col = mix(uFloorBaseColor, acc, coverageEff);
|
|
1035
|
-
// 全景投射显隐:关闭时(仅墙体,地板恒为 1)回落中性素色,不投射全景
|
|
1036
|
-
if (uPanoramaVisible < 0.5) {
|
|
1037
|
-
col = vec3(0.78, 0.78, 0.80);
|
|
1038
|
-
}
|
|
1039
|
-
// 实例染色:默认白=原全景色;选中黄(FurnitureObject.highlight 写入 instanceColor)染黄高亮。
|
|
1040
|
-
// 普通 Mesh(墙/地板)无 instanceColor,USE_INSTANCING_COLOR 不定义,此分支被编译剔除。
|
|
1041
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1042
|
-
col *= vInstanceColor;
|
|
1043
|
-
#endif
|
|
1044
|
-
${PANO_TINT_ON ? ` // 🔬 归属诊断配色(皇上旨 2026-09-25「就在最后算出来的颜色再叠加上颜色,不用想那么复杂」):
|
|
1045
|
-
// 整段只在 ?panoTint=1 时生成,默认关 ⇒ 正常态一行都没有。色相全交给所属景点,只保留明暗,
|
|
1046
|
-
// 所以亮部/暗部仍看得出是原照片的纹理,但一眼能分「这块面归哪个景点」。
|
|
1047
|
-
// ⚠️ 与上一版(逐槽染 linK)的区别:这里染的是**最终颜色** ⇒ 即使那一片压根没有候选(一个全景都没绑上、
|
|
1048
|
-
// 露底色)之外的任何区域也照样按归属上色;归属判据与取图判据同一条 = 「存活口径最近一张」。
|
|
1049
|
-
// ⚠️ 刻意不用「采样色 × 淡色」:那种叠法叠在亮图上几乎发白,肉眼看不出(09-25 已被打回过一次)。
|
|
1050
|
-
// ⚠️ 强度 = PANO_TINT_MIX(皇上旨 09-26 晚「叠加的颜色比例少一点」):原来整块换成色相 ⇒ 只剩明暗、
|
|
1051
|
-
// 底下一张全景图完全读不出来;现在按 mix(原色, 染色, 本值) 叠,色相仍占主但照片看得见了。
|
|
1052
|
-
if (tintCnt > 0.0) {
|
|
1053
|
-
vec3 tintHue = tintAcc / tintCnt;
|
|
1054
|
-
float tintLum = dot(col, vec3(0.2126, 0.7152, 0.0722));
|
|
1055
|
-
vec3 tintTo = tintHue * (0.55 + 0.45 * clamp(tintLum * 3.0, 0.0, 1.0));
|
|
1056
|
-
col = mix(col, tintTo, ${PANO_TINT_MIX});
|
|
1057
|
-
}` : ""}${panoDistOn ? `
|
|
1058
|
-
// 🔬 距离明暗诊断(皇上旨 09-26 晚「距离越小越白、越远越黑」+ 09-27 早「按我有 4 个全景点来写代码」+
|
|
1059
|
-
// 09-27 晚「我一开始的需求就是要把 4 个全景点的坐标传给 shader,按最近取用」):
|
|
1060
|
-
// **一句真循环**遍历 uPanoPoints[0..${maxPano - 1}],每个像素只留「到最近那个景点」的水平距离。
|
|
1061
|
-
// ⚠️ 纯水平距离最近(09-27 晚定版后与取图**同把尺**,夹角门已废)⇒ 墙背后的景点也往这面墙上画圆,
|
|
1062
|
-
// 一个面能看满 N 个渐变圆;代价 = 明暗图不分身前身后(与取图口径一致)。
|
|
1063
|
-
${panoDistLoopGlsl("col", maxPano)}` : ""}
|
|
1064
|
-
gl_FragColor = vec4(col, 1.0);
|
|
1065
|
-
// 输出颜色空间编码:渲染到线性 RT(主编辑器后处理链)时 passthrough,渲染到 sRGB 屏幕(预览弹窗)时自动编码 sRGB
|
|
1066
|
-
#include <colorspace_fragment>
|
|
1067
|
-
#include <logdepthbuf_fragment>
|
|
1068
|
-
}
|
|
1069
|
-
`;
|
|
1070
|
-
}
|
|
1071
|
-
/** 融合材质的全景点数**上限**:每点占 **2** 张拼合槽纹理(32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
1072
|
-
* ⭐ 2026-10-06 晚皇上旨「一次能够展示 8 个全景纹理」:靠的就是「每点从 4 槽降到 2 槽」——
|
|
1073
|
-
* sampler 总数 16 是硬件硬顶(皇上本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16,一直没变),
|
|
1074
|
-
* 原来 16 ÷ 4 槽 = 4 个景点,现在 16 ÷ 2 槽 = **8 个景点**,画质与单全景显存**分毫未动**。 */
|
|
1075
|
-
export const MKT_PANO_MAX_SLOTS = 8;
|
|
1076
|
-
/**
|
|
1077
|
-
* 创建「多全景融合」着色器材质:每帧由外部喂入最近 maxPano 个全景点(⭐ 10-06 晚旨后每点 2 张拼合槽纹理)。
|
|
1078
|
-
* 同一份着色器同时服务普通 Mesh(墙/地板)与 InstancedMesh(家具立方体):
|
|
1079
|
-
* 实例化与否由 three.js 按对象类型自动注入 USE_INSTANCING 宏决定,无需外部传 instanced 开关。
|
|
1080
|
-
* 数组 uniform 在创建时即按 maxPano 长度初始化(占位纹理 + 单位矩阵 + 权重 0),运行时由渲染器每帧改写对应槽位。
|
|
1081
|
-
* ⚠️ 取图口径只有一条(皇上旨 2026-09-25 晚「都要一起改」→ 09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
1082
|
-
* 地板 / 墙 / 家具**全部**按「水平距离最近的一张」取图(09-24~09-25 的夹角门已整链删除),
|
|
1083
|
-
* 不再有「地板按覆盖度融合」这条路,故也**没有** `pickNearest` 选项(旧的 0/1 分流 uniform 已删)。
|
|
1084
|
-
*/
|
|
1085
|
-
export function createMktFloorBlendShaderMaterial(options = {}) {
|
|
1086
|
-
// 2026-09-20:每个全景点占 N 张纹理槽,故「最多融合点数」maxPano 与纹理上限挂钩:
|
|
1087
|
-
// maxPano × N 张纹理须 ≤ 16(shader sampler 上限)。
|
|
1088
|
-
// 2026-09-24 皇上旨「同一时间要准备 4 个全景的瓦片纹理,一共刚好 16 个」(当时 N=4 ⇒ 上限 4)。
|
|
1089
|
-
// ⭐ 2026-10-06 晚旨「一次能够展示 8 个全景纹理」:N 从 4 降到 **2**(每个全景只占左右两张 RT)
|
|
1090
|
-
// ⇒ 16 ÷ 2 = **上限 8 个景点**,默认就取满 8。画质 / 单全景显存**分毫未动**。
|
|
1091
|
-
// ⚠️ 10-06 切 32 片之后这两个槽各是「16 片拼出来的一张 4096² RT」,sampler 总数仍是 16(硬顶)。
|
|
1092
|
-
// ⚠️ 所有喂同一批数据的材质必须同档:某处写成 3 而喂料方按 8 喂,会往 panos[6..15] 越界写、着色器读到 undefined sampler。
|
|
1093
|
-
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
1094
|
-
// 🔬 这一份材质是否带「近白远黑」图:显式传了听他的(编辑器),没传读 URL(发布页/预览默认关)。
|
|
1095
|
-
const panoDistOn = options.panoDist ?? PANO_DIST_ON;
|
|
1096
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 总纹理槽数 = 点数 × 每点槽数(8 × 2 = 16 = sampler 硬顶)
|
|
1097
|
-
const panoramas = [];
|
|
1098
|
-
const matrices = [];
|
|
1099
|
-
const weights = new Float32Array(maxPano); // 默认全 0(未参与)
|
|
1100
|
-
for (let i = 0; i < tileCount; i++) {
|
|
1101
|
-
panoramas.push(createPlaceholderTexture());
|
|
1102
|
-
}
|
|
1103
|
-
for (let i = 0; i < maxPano; i++) {
|
|
1104
|
-
matrices.push(new Matrix4());
|
|
1105
|
-
}
|
|
1106
|
-
return new ShaderMaterial({
|
|
1107
|
-
uniforms: {
|
|
1108
|
-
panoramas: { value: panoramas },
|
|
1109
|
-
textureMatrices: { value: matrices },
|
|
1110
|
-
weights: { value: weights },
|
|
1111
|
-
// 地板底色(线性空间深灰,约 sRGB 0.27):远处露出此色
|
|
1112
|
-
uFloorBaseColor: { value: new Vector3(0.06, 0.06, 0.06) },
|
|
1113
|
-
// 🔬 归属诊断色(每槽一个 vec3 = 该槽里那个景点的固定色):**只在 ?panoTint=1 时创建**,
|
|
1114
|
-
// 关态连 uniform 都不存在(JS 侧三元)⇒ 线上正常路径零开销。默认白 = 未被应用层写过。
|
|
1115
|
-
...(PANO_TINT_ON
|
|
1116
|
-
? { uPanoTintColors: { value: Array.from({ length: maxPano }, () => new Vector3(1, 1, 1)) } }
|
|
1117
|
-
: {}),
|
|
1118
|
-
// 🔬 距离明暗诊断的「黑端米数」:**这份材质 panoDist 为真才创建**(默认 16 ≈ 常见房间对角线,
|
|
1119
|
-
// 应用层每次喂投影时按现场量出的尺子写实际值,见 setMktPanoDistRange);
|
|
1120
|
-
// uPanoPoints = 同一张图的**圆心清单**(每格一个 vec4,w=1 表示这格有个全景点,见 setMktPanoPoints)
|
|
1121
|
-
...(panoDistOn ? {
|
|
1122
|
-
uPanoDistMax: { value: 16 },
|
|
1123
|
-
uPanoPoints: { value: Array.from({ length: maxPano }, () => new Vector4(0, 0, 0, 0)) },
|
|
1124
|
-
} : {}),
|
|
1125
|
-
// ⚠️ 下面两根覆盖半径:着色器自 09-25 晚「都要一起改」起**不再读它们**(覆盖度融合那一路已删),
|
|
1126
|
-
// uniform 与应用层写入暂留 ⇒ 面板上那两根旋钮调了没有视觉变化,删不删等皇上旨意。
|
|
1127
|
-
uFloorCoreRadius: { value: 4 },
|
|
1128
|
-
uFloorFadeRange: { value: 4 },
|
|
1129
|
-
// 整体透明度(0~1):仅缩放全景图映射的可见度(覆盖度×此值),地板灰底不变;全局对所有全景一起生效;1=全景完全可见
|
|
1130
|
-
uFloorOpacity: { value: 1 },
|
|
1131
|
-
// 全景投射显隐:1=显示全景,0=仅显示素色(墙体回落中性色,地板恒为 1)
|
|
1132
|
-
uPanoramaVisible: { value: 1 },
|
|
1133
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」)⇒ 原 `uColorSpace: { value: 0 }` 已随那段 pow 分支整条撤除
|
|
1134
|
-
// 全景上下方向**已写死**,无 uniform(见文件头 🎛️ 段)。
|
|
1135
|
-
// 每点各自的「这 2 槽是瓦片(1)/同一张整图(0)」,由喂料处按「PanoTexMode + 真实 tiles」写(setMktPanoTiled);
|
|
1136
|
-
// 默认全 1 = 维持改造前的瓦片口径(真实上传的图都是四瓦片)。
|
|
1137
|
-
uPanoTiled: { value: new Float32Array(maxPano).fill(1) },
|
|
1138
|
-
// 投影空间逆矩阵:默认单位阵(= 世界坐标,行为与改造前一致)。
|
|
1139
|
-
// 融合材质默认**永不**写入它 —— 编辑器地板/立方体、预览立方体因此完全不受 MktMesh 变换影响。
|
|
1140
|
-
uProjInvMatrix: { value: new Matrix4() },
|
|
1141
|
-
},
|
|
1142
|
-
vertexShader: floorVertexShader,
|
|
1143
|
-
fragmentShader: buildFloorBlendFragment(maxPano, panoDistOn),
|
|
1144
|
-
side: DoubleSide,
|
|
1145
|
-
transparent: false,
|
|
1146
|
-
toneMapped: false,
|
|
1147
|
-
});
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* 「仅显示选中全景」片元(皇上旨 2026-09-29「三模式三 shader」之三):
|
|
1151
|
-
* 整面恒显示 **0 号点槽**那一张全景 —— 不看距离、不看夹角、不看序号,槽里是谁就投谁
|
|
1152
|
-
* (喂料侧保证 0 号槽 = 当前选中的全景、其余槽留空)。
|
|
1153
|
-
* uniform 形状与 blend 同档 ⇒ 喂料复用 feedBlendProjection 槽位指派路零改动;
|
|
1154
|
-
* GLSL 只读 0 号点槽,其余槽是声明了没人采的死重(开销可忽略)。
|
|
1155
|
-
* 槽没绑好(weights[0]≤0,选中全景瓦片还在路上 / 没选中任何全景)→ 露 uFloorBaseColor 深灰底。
|
|
1156
|
-
*/
|
|
1157
|
-
function buildFloorSelectedFragment(maxPano) {
|
|
1158
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 形状与 blend 同档(喂料共用)
|
|
1159
|
-
return /* glsl */ `
|
|
1160
|
-
#include <logdepthbuf_pars_fragment>
|
|
1161
|
-
uniform sampler2D panoramas[${tileCount}]; // 形状与 blend 同档(喂料共用);本 shader 只采 0 号点槽(纹理 0..1)
|
|
1162
|
-
uniform mat4 textureMatrices[${maxPano}];
|
|
1163
|
-
uniform float weights[${maxPano}]; // 0 号槽 > 0 = 选中全景的瓦片已绑好
|
|
1164
|
-
uniform float uPanoTiled[${maxPano}];
|
|
1165
|
-
uniform vec3 uFloorBaseColor; // 槽没绑好时露出的深灰底(线性空间,约 sRGB 0.27)
|
|
1166
|
-
uniform float uFloorOpacity; // 整体透明度(与 blend 同口径:只缩放全景可见度,底色不变)
|
|
1167
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」):原 uniform float uColorSpace; + 那段 pow 分支已整条撤除(与 blend 同口径)
|
|
1168
|
-
uniform float uPanoramaVisible;
|
|
1169
|
-
varying vec3 vProjPos;
|
|
1170
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1171
|
-
varying vec3 vInstanceColor;
|
|
1172
|
-
#endif
|
|
1173
|
-
void main() {
|
|
1174
|
-
// ── 0 号点槽(纹理 0..1,即左右那 2 张拼合槽):选中的全景独占(采样段与 blend 逐字同口径)──
|
|
1175
|
-
vec3 lin0 = vec3(0.0);
|
|
1176
|
-
if (weights[0] > 0.0) {
|
|
1177
|
-
mat4 tm = textureMatrices[0];
|
|
1178
|
-
vec3 texPos = tm[3].xyz;
|
|
1179
|
-
mat3 texRot = mat3(tm);
|
|
1180
|
-
vec3 dir = normalize(vProjPos - texPos);
|
|
1181
|
-
dir = texRot * dir;
|
|
1182
|
-
float lon = atan(dir.z, dir.x);
|
|
1183
|
-
float u = lon * 0.15915494309189535 + 0.5; // 经度 -> u
|
|
1184
|
-
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
1185
|
-
float v = 0.5 + lat * 0.3183098861837907; // 1/PI(等距柱状线性 v,与 blend 逐字同口径)
|
|
1186
|
-
// ⭐ 10-06 晚旨:竖着不再分块 ⇒ 槽只随 u 走(左右两半:[左半幅=0, 右半幅=1]),与 blend 逐字同口径
|
|
1187
|
-
int tileIdx = (u >= 0.5) ? 1 : 0;
|
|
1188
|
-
float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
|
|
1189
|
-
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v
|
|
1190
|
-
float localV = v;
|
|
1191
|
-
float panoU = (uPanoTiled[0] > 0.5) ? localU : u;
|
|
1192
|
-
float panoV = (uPanoTiled[0] > 0.5) ? localV : v;
|
|
1193
|
-
// ⭐ 采样即线性(与单全景 / blend 那两路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
1194
|
-
// colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
|
|
1195
|
-
// 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
|
|
1196
|
-
if (tileIdx == 0) lin0 = texture2D(panoramas[0], vec2(panoU, panoV)).rgb;
|
|
1197
|
-
else lin0 = texture2D(panoramas[1], vec2(panoU, panoV)).rgb;
|
|
1198
|
-
}
|
|
1199
|
-
float coverage = weights[0] > 0.0 ? 1.0 : 0.0;
|
|
1200
|
-
float coverageEff = clamp(coverage * uFloorOpacity, 0.0, 1.0);
|
|
1201
|
-
vec3 col = mix(uFloorBaseColor, lin0, coverageEff);
|
|
1202
|
-
// 全景投射显隐:关闭时回落中性素色(与 blend 一致)
|
|
1203
|
-
if (uPanoramaVisible < 0.5) col = vec3(0.78, 0.78, 0.80);
|
|
1204
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1205
|
-
col *= vInstanceColor;
|
|
1206
|
-
#endif
|
|
1207
|
-
gl_FragColor = vec4(col, 1.0);
|
|
1208
|
-
#include <colorspace_fragment>
|
|
1209
|
-
#include <logdepthbuf_fragment>
|
|
1210
|
-
}
|
|
1211
|
-
`;
|
|
1212
|
-
}
|
|
1213
|
-
/**
|
|
1214
|
-
* 创建「仅显示选中全景」着色器材质(皇上旨 2026-09-29「三模式三 shader」之三):仅编辑器使用。
|
|
1215
|
-
* uniform 形状与 blend 工厂同档 ⇒ 喂料复用 feedBlendProjection 槽位指派路零改动;
|
|
1216
|
-
* 本 shader 只读 0 号点槽(GLSL 写死),uFloorCoreRadius/uFloorFadeRange 喂料会写但不读(静默忽略)。
|
|
1217
|
-
*/
|
|
1218
|
-
export function createMktFloorSelectedShaderMaterial(options = {}) {
|
|
1219
|
-
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
1220
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 与 blend / mapping 同档(8 点 × 2 槽 = 16)
|
|
1221
|
-
const panoramas = [];
|
|
1222
|
-
const matrices = [];
|
|
1223
|
-
for (let i = 0; i < tileCount; i++)
|
|
1224
|
-
panoramas.push(createPlaceholderTexture());
|
|
1225
|
-
for (let i = 0; i < maxPano; i++)
|
|
1226
|
-
matrices.push(new Matrix4());
|
|
1227
|
-
return new ShaderMaterial({
|
|
1228
|
-
uniforms: {
|
|
1229
|
-
panoramas: { value: panoramas },
|
|
1230
|
-
textureMatrices: { value: matrices },
|
|
1231
|
-
weights: { value: new Float32Array(maxPano) },
|
|
1232
|
-
uPanoTiled: { value: new Float32Array(maxPano).fill(1) },
|
|
1233
|
-
uFloorBaseColor: { value: new Vector3(0.06, 0.06, 0.06) },
|
|
1234
|
-
// 喂料统一入口会写;本 shader 不读 uFloorCoreRadius/uFloorFadeRange(留 JS 项 = 喂料零分支)
|
|
1235
|
-
uFloorCoreRadius: { value: 4 },
|
|
1236
|
-
uFloorFadeRange: { value: 4 },
|
|
1237
|
-
uFloorOpacity: { value: 1 },
|
|
1238
|
-
uPanoramaVisible: { value: 1 },
|
|
1239
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」)⇒ 原 `uColorSpace: { value: 0 }` 已随那段 pow 分支整条撤除
|
|
1240
|
-
uProjInvMatrix: { value: new Matrix4() },
|
|
1241
|
-
},
|
|
1242
|
-
vertexShader: floorVertexShader,
|
|
1243
|
-
fragmentShader: buildFloorSelectedFragment(maxPano),
|
|
1244
|
-
side: DoubleSide,
|
|
1245
|
-
transparent: false,
|
|
1246
|
-
toneMapped: false,
|
|
1247
|
-
});
|
|
1248
|
-
}
|
package/MktMesh/mktShader.ts
CHANGED
|
@@ -66,7 +66,8 @@ function panoDebugOn(name: string): boolean {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
/** ⭐ 2026-10-09 随blend 材质搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
70
|
+
export const TILE_DEBUG_GLSL = panoDebugOn("panoTileDebug") ? "1.0" : "0.0";
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* 🔬 归属诊断配色(皇上旨 2026-09-25「你为每个全景球设置不同的颜色, 然后把全景瓦片映射在墙面上时, 叠加该全景图的颜色,
|
|
@@ -103,7 +104,8 @@ export const MKT_PANO_TINT_ON = PANO_TINT_ON;
|
|
|
103
104
|
* 照片本身看不清);皇上旨 2026-09-26 晚「叠加的颜色比例少一点」⇒ 取 **0.5**:色相仍是主色、一眼分得出归属,
|
|
104
105
|
* 但底下那张全景图的明暗与颜色能同时读出来。两份材质(融合 / 单全景)**共用这一个值**。
|
|
105
106
|
*/
|
|
106
|
-
|
|
107
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质搬去编辑器,故改为导出。 */
|
|
108
|
+
export const PANO_TINT_MIX = 0.5;
|
|
107
109
|
|
|
108
110
|
/**
|
|
109
111
|
* 🔬 **距离明暗诊断图**(皇上旨 2026-09-26 晚「你计一下每个点距离最近的一个全景点的距离, 然后距离越小颜色就是白色,
|
|
@@ -142,7 +144,9 @@ const PANO_TINT_MIX = 0.5;
|
|
|
142
144
|
* ⛔ 不许再回到「模块顶层翻全局变量」那一路:那份 GLSL 是建材质时一次性拼出来的,谁先谁后取决于 import 顺序,
|
|
143
145
|
* 改一次 import 就悄悄漏一面(且 `统一性检查` 会当场报不是同一份源码)。
|
|
144
146
|
*/
|
|
145
|
-
|
|
147
|
+
/** ⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 本常量改为导出:
|
|
148
|
+
* 编辑器那份 `mktMeshFloorBlendShader.ts` 要用它当默认值。库内的映射材质仍照常用。 */
|
|
149
|
+
export const PANO_DIST_ON = panoDebugOn("panoDist");
|
|
146
150
|
|
|
147
151
|
/**
|
|
148
152
|
* 🔬 **编辑器这一页**该不该有近白远黑图:**默认关**(皇上旨 2026-09-27 晚「把颜色换成纹理,全景的纹理」——
|
|
@@ -190,7 +194,8 @@ function panoDistGlsl(colorVar: string, distExpr: string): string {
|
|
|
190
194
|
* 已整链删除 ⇒ 两边都是「纯水平距离最近」,圆与图永远一致。⛔ 本函数只动颜色,不动取图。
|
|
191
195
|
* ⚠️ 动态下标只碰普通 uniform 数组(`vec4[]`),不碰 sampler ⇒ ANGLE 那条「sampler 必须常量下标」的限制管不到这里。
|
|
192
196
|
*/
|
|
193
|
-
|
|
197
|
+
/** ⭐ 2026-10-09 同上:随 blend 材质一起搬去编辑器,故改为导出(那边拼片元 GLSL 时要用)。 */
|
|
198
|
+
export function panoDistLoopGlsl(colorVar: string, maxPano: number): string {
|
|
194
199
|
return /* glsl */ `{
|
|
195
200
|
float distNear = 1e9;
|
|
196
201
|
for (int i = 0; i < ${maxPano}; i++) {
|
|
@@ -922,423 +927,4 @@ export function createMktShaderMaterial(): ShaderMaterial {
|
|
|
922
927
|
* - panoramas[i] : 第 i 张全景纹理
|
|
923
928
|
* - textureMatrices[i]: 第 i 张全景的世界矩阵(位置=投影中心,旋转=朝向)
|
|
924
929
|
* - weights[i] : 第 i 张是否活着(camW,0 = 该槽未绑全景 ⇒ 不进候选池)
|
|
925
|
-
*/
|
|
926
|
-
/**
|
|
927
|
-
* 生成多全景片元着色器(地板 / 墙 / 家具共用)。
|
|
928
|
-
* ⚠️ 关键约束:Windows/ANGLE(D3D) 后端**禁止用循环变量/非常量索引 sampler 数组**(报错
|
|
929
|
-
* "array index for samplers must be constant integral expressions"),故这里在 JS 侧把循环
|
|
930
|
-
* 完全展开成「字面量下标」的若干代码段(panoramas[0]…panoramas[N-1]),所有数组访问均为常量下标。
|
|
931
|
-
* 未参与融合的槽位权重=0,被 if(w>0.0) 跳过(常量分支,零开销)。
|
|
932
|
-
*/
|
|
933
|
-
function buildFloorBlendFragment(maxPano: number, panoDistOn: boolean): string {
|
|
934
|
-
// 每个全景点占 **2** 张拼合槽纹理(32 片每 16 片拼一张:左半幅 / 右半幅)⇒ 8 × 2 = 16 = sampler 硬顶
|
|
935
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
|
|
936
|
-
let slotCalc = ""; // 每槽各自算出:颜色 linK / 水平距离 dK / 夹角 angK(acos+背面+180°)/ 分值 scoreK = d−ang
|
|
937
|
-
let slotReduceLive = ""; // 每槽参与「score 最小值」归约(候选池 = 槽里活着的那几张,score<1e8 即活)
|
|
938
|
-
let slotOne = ""; // 每槽对「只取 score 最小那一张」的贡献(唯一取图口径,地板/墙/家具共用)
|
|
939
|
-
let slotOwner = ""; // 🔬 每槽对「归属诊断色」的贡献(仅 ?panoTint=1 时生成,正常态为空串)
|
|
940
|
-
for (let k = 0; k < maxPano; k++) {
|
|
941
|
-
const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
|
|
942
|
-
slotCalc += `
|
|
943
|
-
// ── 点槽 ${k}(纹理 ${base}..${base + 1})──
|
|
944
|
-
vec3 lin${k} = vec3(0.0);
|
|
945
|
-
float d${k} = 1e9; // 本面这点到本槽全景中心的**水平**距离(score 被减数)
|
|
946
|
-
// float camD${k} —— 14:24 旨曾加「全景中心到相机距离」项,15:07 旨去掉(连声明一并去,注释存档)
|
|
947
|
-
float cosA${k} = -1.0; // 「点→全景」向量 与 正面法线 的夹角余弦(acos 后 = 夹角弧度)
|
|
948
|
-
float ang${k} = 1e9; // 夹角(acos 后 0..180°,背面 +180° ⇒ 270°..360°),score 的减数
|
|
949
|
-
float score${k} = 1e9; // ⭐主判据(皇上 09-28 15:07 旨七修):score = 顶点与全景的距离 − 夹角,取**最小**者定纹理
|
|
950
|
-
// ── 旧原理存档(注释保留不删)──
|
|
951
|
-
// 09-28 14:24 旨「score = 顶点距离 + 相机距离 − 夹角」:camD 项已整条撤(见下方槽内注释行)
|
|
952
|
-
// 09-28 00:44 旨「score = 距离 × 夹角²,取积最小」:见下方槽内注释行
|
|
953
|
-
// 09-28 01:56 旨「按夹角从小到大排序取最小、打平比水平距离」:bestAng/bestDAtAng 两段归约(已撤,git 可查)
|
|
954
|
-
{
|
|
955
|
-
float camW = weights[${k}]; // 该全景的「锚点距离权重」(JS 按**名册那条水平距离**反比算,未归一化;⭐ 10-07 第二十一道旨后那把尺量的端点 = 控制器中心点,未注入时才是相机位置)
|
|
956
|
-
if (camW > 0.0) {
|
|
957
|
-
mat4 tm = textureMatrices[${k}];
|
|
958
|
-
vec3 texPos = tm[3].xyz; // 投影中心 = 纹理矩阵位置
|
|
959
|
-
mat3 texRot = mat3(tm); // 纹理朝向 = 旋转分量
|
|
960
|
-
vec3 dir = normalize(vProjPos - texPos);
|
|
961
|
-
dir = texRot * dir; // 转到纹理局部方向
|
|
962
|
-
float lon = atan(dir.z, dir.x);
|
|
963
|
-
float u = lon * 0.15915494309189535 + 0.5; // 经度 -> u
|
|
964
|
-
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
965
|
-
// 等距柱状线性 v(= 全图 UV),与单全景分支**逐字同口径**,理由见单全景分支说明
|
|
966
|
-
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
967
|
-
// 左右两半 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里 4×4=16 片拼成,见 RT_STITCH_SLOT_TILES)
|
|
968
|
-
// ⭐ 10-06 晚旨「每个全景纹理由左右 2 个 RT 组成」:竖着不再分块 ⇒ 槽只随 u 走,与单全景分支逐字同口径
|
|
969
|
-
int tileIdx = (u >= 0.5) ? 1 : 0;
|
|
970
|
-
float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
|
|
971
|
-
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 2v/2v-1 = 纵向分辨率白丢一半
|
|
972
|
-
float localV = v;
|
|
973
|
-
// 🧩 该点这 2 槽装的是整图(用户切了 whole 形态,或该点压根没切过片)⇒ 还原成全图 UV 再采样,与单全景分支逐字同口径
|
|
974
|
-
// (方向已写死,故横向还原式恒等于 u、纵向 localV 本就等于 v,见单全景分支推导)
|
|
975
|
-
float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
|
|
976
|
-
float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
|
|
977
|
-
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组:base 为本点连槽起点(JS 常量 k*RT_STITCH_SLOT_COUNT),
|
|
978
|
-
// 以下 2 个采样下标均为「base + 字面量 0/1」的常量表达式,编译安全。
|
|
979
|
-
// 🔬 诊断直通(见文件头 TILE_DEBUG_GLSL 说明;正常态内联为 0.0,整段被编译器消除)
|
|
980
|
-
if (${TILE_DEBUG_GLSL} > 0.5) {
|
|
981
|
-
vec3 dbgCol;
|
|
982
|
-
if (tileIdx == 0) dbgCol = vec3(1.0, 0.0, 0.0); // 红 = 左半幅槽 0
|
|
983
|
-
else dbgCol = vec3(0.0, 1.0, 0.0); // 绿 = 右半幅槽 1
|
|
984
|
-
gl_FragColor = vec4(dbgCol, 1.0);
|
|
985
|
-
#include <colorspace_fragment>
|
|
986
|
-
#include <logdepthbuf_fragment>
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
// ⭐ 采样即线性(与单全景分支同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
991
|
-
// colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
|
|
992
|
-
// 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
|
|
993
|
-
if (tileIdx == 0) lin${k} = texture2D(panoramas[${base}], vec2(panoU, panoV)).rgb;
|
|
994
|
-
else lin${k} = texture2D(panoramas[${base + 1}], vec2(panoU, panoV)).rgb;
|
|
995
|
-
// ⭐ 09-28 15:07 旨定版(七修):score = **顶点到全景的距离 − 夹角**,取最小者。
|
|
996
|
-
// 夹角 = acos(cosA)(0..180°),cosA = dot(normalize(全景中心 − 本点), N)(N 已按 gl_FrontFacing 翻到观察面)。
|
|
997
|
-
// 背面一刀 +180°(00:26 旨「背面的夹角该大于 180 度」)保留。
|
|
998
|
-
// 14:24 那版曾加「全景与相机的距离 camD」,15:07 旨「把全景到相机的那个逻辑去掉」,注释保留不删。
|
|
999
|
-
vec3 toPano${k} = texPos - vProjPos;
|
|
1000
|
-
float lenP${k} = length(toPano${k});
|
|
1001
|
-
cosA${k} = (lenP${k} > 1e-4) ? dot(toPano${k} / lenP${k}, N) : 1.0;
|
|
1002
|
-
d${k} = distance(vProjPos.xz, texPos.xz);
|
|
1003
|
-
// camD${k} = distance(cameraPosition, texPos); // ⛌ 14:24 旨「全景与相机距离」项,15:07 旨去掉,注释保留不删
|
|
1004
|
-
ang${k} = acos(clamp(cosA${k}, -1.0, 1.0));
|
|
1005
|
-
if (cosA${k} < 0.0) ang${k} += 3.14159265; // 背面 +180°(π)
|
|
1006
|
-
score${k} = d${k} - ang${k}; // ⭐ 15:07 旨:距离 − 角度,取最小
|
|
1007
|
-
// score${k} = d${k} + camD${k} - ang${k}; // ⛌ 旧原理(14:24 旨:两距离之和 − 角度),注释保留不删
|
|
1008
|
-
// score${k} = d${k} * ang${k} * ang${k}; // ⛌ 旧原理(00:44 旨:距离 × 夹角² 取积最小),注释保留不删
|
|
1009
|
-
}
|
|
1010
|
-
}`;
|
|
1011
|
-
// ⭐ 归约(皇上 09-28 15:07 旨七修「顶点距离 − 夹角」):bestScore = 各活槽分值最小值。
|
|
1012
|
-
// score == bestScore 是同值浮点精确比较(min 存的就是同一份 bit 值,== 可靠,与历代口径同一技巧)。
|
|
1013
|
-
slotReduceLive += `
|
|
1014
|
-
if (score${k} < 1e8) {
|
|
1015
|
-
bestScore = min(bestScore, score${k});
|
|
1016
|
-
}`;
|
|
1017
|
-
// ⭐ 胜者(皇上 09-28 15:07 旨七修):score = 顶点距离 − 角度 最小的那张。
|
|
1018
|
-
slotOne += `
|
|
1019
|
-
if (score${k} < 1e8 && score${k} == bestScore) {
|
|
1020
|
-
wsum += 1.0; acc += lin${k}; cover += 1.0;
|
|
1021
|
-
}`;
|
|
1022
|
-
// 🔬 归属诊断(皇上旨 2026-09-25「就在最后算出来的颜色上再叠颜色,不用想那么复杂」):
|
|
1023
|
-
// 这里只**记账**(这点归哪个景点),染色动作留到 main 末尾对最终颜色做一次。
|
|
1024
|
-
// 归属判据与 slotOne **逐字同一条**(距离−角度最小),末了统一「打平归编号小的那个」。
|
|
1025
|
-
if (PANO_TINT_ON) {
|
|
1026
|
-
slotOwner += `
|
|
1027
|
-
if (score${k} < 1e8 && score${k} == bestScore) {
|
|
1028
|
-
// ⚠️ tintCnt == 0.0 这道闸 = **打平归编号小的那个**:两张一样近的那条分界带(实测两景点连线的中垂面与墙交线那一带)
|
|
1029
|
-
// 会同时命中两个槽,平均出来是「红+绿=橄榄」—— 那不是没上色,但肉眼读不出归属,故只记第一个。
|
|
1030
|
-
if (tintCnt == 0.0) { tintAcc += uPanoTintColors[${k}]; tintCnt += 1.0; }
|
|
1031
|
-
}`;
|
|
1032
|
-
}
|
|
1033
|
-
// 🔬 距离明暗图**不在这儿逐槽拼**了(皇上旨 2026-09-27 晚:要一句真循环遍历 4 个坐标)⇒ 见 `panoDistLoopGlsl`。
|
|
1034
|
-
}
|
|
1035
|
-
return /* glsl */ `
|
|
1036
|
-
#include <logdepthbuf_pars_fragment>
|
|
1037
|
-
|
|
1038
|
-
uniform sampler2D panoramas[${tileCount}];${PANO_TINT_ON ? `
|
|
1039
|
-
// 🔬 归属诊断色(线性空间,**仅 ?panoTint=1 时存在**):第 i 个纹理槽里躺的那个景点的固定色,
|
|
1040
|
-
// 由应用层每次换绑时写入(见 setMktPanoTint)。⚠️ 刻意不按槽位编译期写死:
|
|
1041
|
-
// 「仅映射选中的那一个」模式下地板永远只喂 0 号槽,按槽写死 = 选第几个点都涂同一个红(皇上 09-25 反馈)。
|
|
1042
|
-
uniform vec3 uPanoTintColors[${maxPano}];` : ""}${panoDistOn ? `
|
|
1043
|
-
// 🔬 距离明暗诊断(这份材质建时 panoDist 选项为真才存在):「多远算全黑」的米数,由应用层每次喂投影时写
|
|
1044
|
-
// (见 setMktPanoDistRange)⇒ 全屋同一把尺子,跨面才比得出远近。
|
|
1045
|
-
uniform float uPanoDistMax;
|
|
1046
|
-
// 🔬 距离明暗诊断的**圆心清单**(皇上旨 2026-09-27「shader 里面有四个全景点的坐标, 每个像素判断距离 4 个点里最小的
|
|
1047
|
-
// 那个值, 再用这个值设置颜色」):xyz = 该点的世界坐标,w = 1 ⇒ 这一格**真有一个全景点**。
|
|
1048
|
-
// ⛔ 与 weights 的分工(两者刻意不同,别合并):weights 管「这格的**图**能不能取」(瓦片没绑好就 0,防止拿
|
|
1049
|
-
// 1×1 占位图刷一片素灰),uPanoPoints 管「这格**有没有点**」⇒ 圆按景点个数画,图按传到位的那几张取。
|
|
1050
|
-
// ⚠️ 09-27 晚起明暗那段**只读这一个数组**(纯水平距离最近)⇒ 与取图同把尺(夹角门已废);坐标与上面
|
|
1051
|
-
// textureMatrices[k][3].xyz 同源同值(同一批矩阵喂进来,见 setMktPanoPoints),不是第二套数据。
|
|
1052
|
-
uniform vec4 uPanoPoints[${maxPano}];` : ""}
|
|
1053
|
-
uniform mat4 textureMatrices[${maxPano}];
|
|
1054
|
-
uniform float weights[${maxPano}]; // 锚点距离权重 camW(JS 由名册那条水平距离写入,未归一化;着色器内与空间因子相乘后整体归一化)
|
|
1055
|
-
uniform vec3 uFloorBaseColor; // 地板底色(线性空间,深灰):只在「一个候选都没有」(maxPano 张全景全未绑定)时露出来
|
|
1056
|
-
// ⚠️ 下面两根覆盖半径旋钮**自 09-25 晚「都要一起改」起不再参与取图**(覆盖度融合那一路已删,每个像素纯按最近一张)。
|
|
1057
|
-
// 控件与 uniform 暂留(未奉旨删控件),值仍由应用层写入,但着色器不读 ⇒ 调它们没有视觉变化。
|
|
1058
|
-
uniform float uFloorCoreRadius;
|
|
1059
|
-
uniform float uFloorFadeRange;
|
|
1060
|
-
uniform float uFloorOpacity; // 地板全景投影「整体透明度」(0~1,全局对所有全景一起生效):仅作用于全景图映射的可见度,越小全景越淡、越透出地板灰底;地板灰色本身不变
|
|
1061
|
-
// 全景投射显隐:1=显示全景(投射到墙/地板),0=仅显示素色(墙体回落中性色,地板恒为 1 不受影响)
|
|
1062
|
-
uniform float uPanoramaVisible;
|
|
1063
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」):原 uniform float uColorSpace; + 那段 sRGB pow 解码分支已整条撤除,
|
|
1064
|
-
// 采样值即线性(纹理标了 SRGBColorSpace ⇒ 硬件解过一次),末端 <colorspace_fragment> 只编码一次。
|
|
1065
|
-
// ⭐ 取图方式只有一条(皇上旨 2026-09-25 晚「都要一起改」→ 09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
1066
|
-
// 地板 / 墙 / 家具**同一份着色器、同一条判据** —— 候选里只取水平距离最近那**一张**,满权重。
|
|
1067
|
-
// 旧的 uPanoPickNearest(0=地板覆盖度融合 / 1=模型表面取最近)已随融合那一路一起删除;
|
|
1068
|
-
// 09-24~09-25 的夹角门 + 兜底也已按 09-27 晚旨整链删除(它是「明暗圆对、纹理不对」的第二来源)。
|
|
1069
|
-
// ⚠️ 候选池是「槽里活着的全景」(weights>0,瓦片绑好了的),**不受覆盖半径筛掉**。
|
|
1070
|
-
// 全景上下方向**已写死**,无 uniform(与单全景材质同口径,见文件头 🎛️ 段)。
|
|
1071
|
-
// 每个全景点**各自**的「这 2 槽是瓦片(1)还是同一张整图(0)」—— 融合时不同点可能来源不同(上传的有瓦片、
|
|
1072
|
-
// 旧数据/种子图没有),故按点存数组;为 0 的点走全图 UV,理由见单全景分支同注释。
|
|
1073
|
-
uniform float uPanoTiled[${maxPano}];
|
|
1074
|
-
|
|
1075
|
-
// 取样坐标(已由顶点着色器的 uProjInvMatrix 抵消掉 MktMesh 的整体变换,与 textureMatrices 一样对变换免疫)
|
|
1076
|
-
varying vec3 vProjPos;
|
|
1077
|
-
// 全景序号映射模式:本三角面归属的全局全景序号(顶点着色器从 geometry 的 aPanoIndex 传来;无此 attribute 的对象恒为 0)
|
|
1078
|
-
varying float vPanoIndex;
|
|
1079
|
-
// 几何法线(顶点着色器按同一条矩阵链变换到与 vProjPos 同一空间):取图「正面夹角」判据用
|
|
1080
|
-
varying vec3 vWNormal;
|
|
1081
|
-
// 实例染色(仅当 InstancedMesh 带 instanceColor 时启用):默认白=全景真实色,选中黄=高亮染色
|
|
1082
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1083
|
-
varying vec3 vInstanceColor;
|
|
1084
|
-
#endif
|
|
1085
|
-
|
|
1086
|
-
void main() {
|
|
1087
|
-
// ⭐ 正面法线 N(分值公式里「夹角」的基准,皇上 09-28 凌晨旨「距离 × 夹角」):几何法线归一化后,
|
|
1088
|
-
// 按 gl_FrontFacing 翻到**观察者看的这一面**(墙零厚度 DoubleSide,两面各自以看到的这面算夹角——
|
|
1089
|
-
// 同一面墙从两侧看,分值不同是应该的)。地板/封盖/立方体同理。
|
|
1090
|
-
vec3 N = normalize(vWNormal);
|
|
1091
|
-
if (!gl_FrontFacing) N = -N;
|
|
1092
|
-
${PANO_TINT_ON ? ` // 🔬 归属诊断配色(?panoTint=1):本面这点归哪个景点(tintAcc 累加其固定色,tintCnt 计数)
|
|
1093
|
-
vec3 tintAcc = vec3(0.0);
|
|
1094
|
-
float tintCnt = 0.0;` : ""}
|
|
1095
|
-
${slotCalc}
|
|
1096
|
-
// ⭐ 取图口径(距离+夹角融合,钦定公式):score = 顶点距离 − 角度,取最小的那**一张**(地板/家具/编辑态墙同一份 shader)。
|
|
1097
|
-
// (原「uFaceMappingMode 0/1 运行时分支」已按皇上旨 2026-09-29「三模式三 shader」拆出:
|
|
1098
|
-
// 序号直取在 createMktFloorMappingShaderMaterial、仅显示选中在 createMktFloorSelectedShaderMaterial。)
|
|
1099
|
-
vec3 acc = vec3(0.0);
|
|
1100
|
-
float wsum = 0.0;
|
|
1101
|
-
float cover = 0.0;
|
|
1102
|
-
// 「取图胜者」归约(皇上 09-28 15:07 旨七修定版:score = 顶点距离 − 角度,取最小)
|
|
1103
|
-
float bestScore = 1e9;
|
|
1104
|
-
${slotReduceLive}
|
|
1105
|
-
${PANO_TINT_ON ? " // 🔬 先记账:这点按「距离减夹角最小」归哪个景点(与下面 slotOne 的取图判据同一条)\n" + slotOwner : ""}
|
|
1106
|
-
// 一面只显一张:score 最小的那张(不论多远,绝不留空面)
|
|
1107
|
-
${slotOne}
|
|
1108
|
-
if (wsum > 0.0) acc /= wsum; // 按总权重归一化(总混合值=1)
|
|
1109
|
-
// 覆盖度:有候选即 1(09-25 晚起不再有「渐隐/露灰」的中间态),只在「一个候选都没有」时 = 0
|
|
1110
|
-
// ⇒ 露出地板/墙体本来的底色。
|
|
1111
|
-
float coverage = clamp(cover, 0.0, 1.0);
|
|
1112
|
-
// 整体透明度仅作用于全景图映射:把覆盖度按 uFloorOpacity 缩放后再混合,
|
|
1113
|
-
// 灰底始终不透明(alpha=1),opacity 越小全景越淡、越透出地板灰色;地板灰色本身不变。
|
|
1114
|
-
float coverageEff = clamp(coverage * uFloorOpacity, 0.0, 1.0);
|
|
1115
|
-
vec3 col = mix(uFloorBaseColor, acc, coverageEff);
|
|
1116
|
-
// 全景投射显隐:关闭时(仅墙体,地板恒为 1)回落中性素色,不投射全景
|
|
1117
|
-
if (uPanoramaVisible < 0.5) {
|
|
1118
|
-
col = vec3(0.78, 0.78, 0.80);
|
|
1119
|
-
}
|
|
1120
|
-
// 实例染色:默认白=原全景色;选中黄(FurnitureObject.highlight 写入 instanceColor)染黄高亮。
|
|
1121
|
-
// 普通 Mesh(墙/地板)无 instanceColor,USE_INSTANCING_COLOR 不定义,此分支被编译剔除。
|
|
1122
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1123
|
-
col *= vInstanceColor;
|
|
1124
|
-
#endif
|
|
1125
|
-
${PANO_TINT_ON ? ` // 🔬 归属诊断配色(皇上旨 2026-09-25「就在最后算出来的颜色再叠加上颜色,不用想那么复杂」):
|
|
1126
|
-
// 整段只在 ?panoTint=1 时生成,默认关 ⇒ 正常态一行都没有。色相全交给所属景点,只保留明暗,
|
|
1127
|
-
// 所以亮部/暗部仍看得出是原照片的纹理,但一眼能分「这块面归哪个景点」。
|
|
1128
|
-
// ⚠️ 与上一版(逐槽染 linK)的区别:这里染的是**最终颜色** ⇒ 即使那一片压根没有候选(一个全景都没绑上、
|
|
1129
|
-
// 露底色)之外的任何区域也照样按归属上色;归属判据与取图判据同一条 = 「存活口径最近一张」。
|
|
1130
|
-
// ⚠️ 刻意不用「采样色 × 淡色」:那种叠法叠在亮图上几乎发白,肉眼看不出(09-25 已被打回过一次)。
|
|
1131
|
-
// ⚠️ 强度 = PANO_TINT_MIX(皇上旨 09-26 晚「叠加的颜色比例少一点」):原来整块换成色相 ⇒ 只剩明暗、
|
|
1132
|
-
// 底下一张全景图完全读不出来;现在按 mix(原色, 染色, 本值) 叠,色相仍占主但照片看得见了。
|
|
1133
|
-
if (tintCnt > 0.0) {
|
|
1134
|
-
vec3 tintHue = tintAcc / tintCnt;
|
|
1135
|
-
float tintLum = dot(col, vec3(0.2126, 0.7152, 0.0722));
|
|
1136
|
-
vec3 tintTo = tintHue * (0.55 + 0.45 * clamp(tintLum * 3.0, 0.0, 1.0));
|
|
1137
|
-
col = mix(col, tintTo, ${PANO_TINT_MIX});
|
|
1138
|
-
}` : ""}${panoDistOn ? `
|
|
1139
|
-
// 🔬 距离明暗诊断(皇上旨 09-26 晚「距离越小越白、越远越黑」+ 09-27 早「按我有 4 个全景点来写代码」+
|
|
1140
|
-
// 09-27 晚「我一开始的需求就是要把 4 个全景点的坐标传给 shader,按最近取用」):
|
|
1141
|
-
// **一句真循环**遍历 uPanoPoints[0..${maxPano - 1}],每个像素只留「到最近那个景点」的水平距离。
|
|
1142
|
-
// ⚠️ 纯水平距离最近(09-27 晚定版后与取图**同把尺**,夹角门已废)⇒ 墙背后的景点也往这面墙上画圆,
|
|
1143
|
-
// 一个面能看满 N 个渐变圆;代价 = 明暗图不分身前身后(与取图口径一致)。
|
|
1144
|
-
${panoDistLoopGlsl("col", maxPano)}` : ""}
|
|
1145
|
-
gl_FragColor = vec4(col, 1.0);
|
|
1146
|
-
// 输出颜色空间编码:渲染到线性 RT(主编辑器后处理链)时 passthrough,渲染到 sRGB 屏幕(预览弹窗)时自动编码 sRGB
|
|
1147
|
-
#include <colorspace_fragment>
|
|
1148
|
-
#include <logdepthbuf_fragment>
|
|
1149
|
-
}
|
|
1150
|
-
`;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
export interface MktFloorBlendOptions {
|
|
1154
|
-
/** 最多参与融合的全景点数(⭐ 10-06 晚旨后每点占左右 **2** 张拼合槽纹理,纹理总数 = maxPano×2,须 ≤ 16),默认 `MKT_PANO_MAX_SLOTS`(=8) ⇒ 8×2 = 16 = 采样器硬顶 */
|
|
1155
|
-
maxPano?: number;
|
|
1156
|
-
/**
|
|
1157
|
-
* 🔬 这一份材质要不要「距离明暗图」(近白远黑):**不传 = 读 URL 开关 `?panoDist=1`**(发布页 / 预览就该走这条)。
|
|
1158
|
-
* 编辑器三处建材质点显式传 `mktPanoDistEditorOn()`(默认开)⇒ 墙/地板/立方体**同一份源码**、同一张图。
|
|
1159
|
-
* ⚠️ 只能在这里给,⛔ 没有「建完再翻」这条路:这段 GLSL 在 new ShaderMaterial 时一次性拼死。
|
|
1160
|
-
*/
|
|
1161
|
-
panoDist?: boolean;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
/** 融合材质的全景点数**上限**:每点占 **2** 张拼合槽纹理(32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
|
|
1165
|
-
* ⭐ 2026-10-06 晚皇上旨「一次能够展示 8 个全景纹理」:靠的就是「每点从 4 槽降到 2 槽」——
|
|
1166
|
-
* sampler 总数 16 是硬件硬顶(皇上本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16,一直没变),
|
|
1167
|
-
* 原来 16 ÷ 4 槽 = 4 个景点,现在 16 ÷ 2 槽 = **8 个景点**,画质与单全景显存**分毫未动**。 */
|
|
1168
|
-
export const MKT_PANO_MAX_SLOTS = 8;
|
|
1169
|
-
|
|
1170
|
-
/**
|
|
1171
|
-
* 创建「多全景融合」着色器材质:每帧由外部喂入最近 maxPano 个全景点(⭐ 10-06 晚旨后每点 2 张拼合槽纹理)。
|
|
1172
|
-
* 同一份着色器同时服务普通 Mesh(墙/地板)与 InstancedMesh(家具立方体):
|
|
1173
|
-
* 实例化与否由 three.js 按对象类型自动注入 USE_INSTANCING 宏决定,无需外部传 instanced 开关。
|
|
1174
|
-
* 数组 uniform 在创建时即按 maxPano 长度初始化(占位纹理 + 单位矩阵 + 权重 0),运行时由渲染器每帧改写对应槽位。
|
|
1175
|
-
* ⚠️ 取图口径只有一条(皇上旨 2026-09-25 晚「都要一起改」→ 09-27 晚「取用距离最近的那个全景点的瓦片纹理」定版):
|
|
1176
|
-
* 地板 / 墙 / 家具**全部**按「水平距离最近的一张」取图(09-24~09-25 的夹角门已整链删除),
|
|
1177
|
-
* 不再有「地板按覆盖度融合」这条路,故也**没有** `pickNearest` 选项(旧的 0/1 分流 uniform 已删)。
|
|
1178
|
-
*/
|
|
1179
|
-
export function createMktFloorBlendShaderMaterial(options: MktFloorBlendOptions = {}): ShaderMaterial {
|
|
1180
|
-
// 2026-09-20:每个全景点占 N 张纹理槽,故「最多融合点数」maxPano 与纹理上限挂钩:
|
|
1181
|
-
// maxPano × N 张纹理须 ≤ 16(shader sampler 上限)。
|
|
1182
|
-
// 2026-09-24 皇上旨「同一时间要准备 4 个全景的瓦片纹理,一共刚好 16 个」(当时 N=4 ⇒ 上限 4)。
|
|
1183
|
-
// ⭐ 2026-10-06 晚旨「一次能够展示 8 个全景纹理」:N 从 4 降到 **2**(每个全景只占左右两张 RT)
|
|
1184
|
-
// ⇒ 16 ÷ 2 = **上限 8 个景点**,默认就取满 8。画质 / 单全景显存**分毫未动**。
|
|
1185
|
-
// ⚠️ 10-06 切 32 片之后这两个槽各是「16 片拼出来的一张 4096² RT」,sampler 总数仍是 16(硬顶)。
|
|
1186
|
-
// ⚠️ 所有喂同一批数据的材质必须同档:某处写成 3 而喂料方按 8 喂,会往 panos[6..15] 越界写、着色器读到 undefined sampler。
|
|
1187
|
-
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
1188
|
-
// 🔬 这一份材质是否带「近白远黑」图:显式传了听他的(编辑器),没传读 URL(发布页/预览默认关)。
|
|
1189
|
-
const panoDistOn = options.panoDist ?? PANO_DIST_ON;
|
|
1190
|
-
|
|
1191
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 总纹理槽数 = 点数 × 每点槽数(8 × 2 = 16 = sampler 硬顶)
|
|
1192
|
-
const panoramas: import("three").Texture[] = [];
|
|
1193
|
-
const matrices: Matrix4[] = [];
|
|
1194
|
-
const weights = new Float32Array(maxPano); // 默认全 0(未参与)
|
|
1195
|
-
for (let i = 0; i < tileCount; i++) {
|
|
1196
|
-
panoramas.push(createPlaceholderTexture());
|
|
1197
|
-
}
|
|
1198
|
-
for (let i = 0; i < maxPano; i++) {
|
|
1199
|
-
matrices.push(new Matrix4());
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
return new ShaderMaterial({
|
|
1203
|
-
uniforms: {
|
|
1204
|
-
panoramas: { value: panoramas },
|
|
1205
|
-
textureMatrices: { value: matrices },
|
|
1206
|
-
weights: { value: weights },
|
|
1207
|
-
// 地板底色(线性空间深灰,约 sRGB 0.27):远处露出此色
|
|
1208
|
-
uFloorBaseColor: { value: new Vector3(0.06, 0.06, 0.06) },
|
|
1209
|
-
// 🔬 归属诊断色(每槽一个 vec3 = 该槽里那个景点的固定色):**只在 ?panoTint=1 时创建**,
|
|
1210
|
-
// 关态连 uniform 都不存在(JS 侧三元)⇒ 线上正常路径零开销。默认白 = 未被应用层写过。
|
|
1211
|
-
...(PANO_TINT_ON
|
|
1212
|
-
? { uPanoTintColors: { value: Array.from({ length: maxPano }, () => new Vector3(1, 1, 1)) } }
|
|
1213
|
-
: {}),
|
|
1214
|
-
// 🔬 距离明暗诊断的「黑端米数」:**这份材质 panoDist 为真才创建**(默认 16 ≈ 常见房间对角线,
|
|
1215
|
-
// 应用层每次喂投影时按现场量出的尺子写实际值,见 setMktPanoDistRange);
|
|
1216
|
-
// uPanoPoints = 同一张图的**圆心清单**(每格一个 vec4,w=1 表示这格有个全景点,见 setMktPanoPoints)
|
|
1217
|
-
...(panoDistOn ? {
|
|
1218
|
-
uPanoDistMax: { value: 16 },
|
|
1219
|
-
uPanoPoints: { value: Array.from({ length: maxPano }, () => new Vector4(0, 0, 0, 0)) },
|
|
1220
|
-
} : {}),
|
|
1221
|
-
// ⚠️ 下面两根覆盖半径:着色器自 09-25 晚「都要一起改」起**不再读它们**(覆盖度融合那一路已删),
|
|
1222
|
-
// uniform 与应用层写入暂留 ⇒ 面板上那两根旋钮调了没有视觉变化,删不删等皇上旨意。
|
|
1223
|
-
uFloorCoreRadius: { value: 4 },
|
|
1224
|
-
uFloorFadeRange: { value: 4 },
|
|
1225
|
-
// 整体透明度(0~1):仅缩放全景图映射的可见度(覆盖度×此值),地板灰底不变;全局对所有全景一起生效;1=全景完全可见
|
|
1226
|
-
uFloorOpacity: { value: 1 },
|
|
1227
|
-
// 全景投射显隐:1=显示全景,0=仅显示素色(墙体回落中性色,地板恒为 1)
|
|
1228
|
-
uPanoramaVisible: { value: 1 },
|
|
1229
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」)⇒ 原 `uColorSpace: { value: 0 }` 已随那段 pow 分支整条撤除
|
|
1230
|
-
// 全景上下方向**已写死**,无 uniform(见文件头 🎛️ 段)。
|
|
1231
|
-
// 每点各自的「这 2 槽是瓦片(1)/同一张整图(0)」,由喂料处按「PanoTexMode + 真实 tiles」写(setMktPanoTiled);
|
|
1232
|
-
// 默认全 1 = 维持改造前的瓦片口径(真实上传的图都是四瓦片)。
|
|
1233
|
-
uPanoTiled: { value: new Float32Array(maxPano).fill(1) },
|
|
1234
|
-
// 投影空间逆矩阵:默认单位阵(= 世界坐标,行为与改造前一致)。
|
|
1235
|
-
// 融合材质默认**永不**写入它 —— 编辑器地板/立方体、预览立方体因此完全不受 MktMesh 变换影响。
|
|
1236
|
-
uProjInvMatrix: { value: new Matrix4() },
|
|
1237
|
-
},
|
|
1238
|
-
vertexShader: floorVertexShader,
|
|
1239
|
-
fragmentShader: buildFloorBlendFragment(maxPano, panoDistOn),
|
|
1240
|
-
side: DoubleSide,
|
|
1241
|
-
transparent: false,
|
|
1242
|
-
toneMapped: false,
|
|
1243
|
-
});
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
/**
|
|
1247
|
-
* 「仅显示选中全景」片元(皇上旨 2026-09-29「三模式三 shader」之三):
|
|
1248
|
-
* 整面恒显示 **0 号点槽**那一张全景 —— 不看距离、不看夹角、不看序号,槽里是谁就投谁
|
|
1249
|
-
* (喂料侧保证 0 号槽 = 当前选中的全景、其余槽留空)。
|
|
1250
|
-
* uniform 形状与 blend 同档 ⇒ 喂料复用 feedBlendProjection 槽位指派路零改动;
|
|
1251
|
-
* GLSL 只读 0 号点槽,其余槽是声明了没人采的死重(开销可忽略)。
|
|
1252
|
-
* 槽没绑好(weights[0]≤0,选中全景瓦片还在路上 / 没选中任何全景)→ 露 uFloorBaseColor 深灰底。
|
|
1253
|
-
*/
|
|
1254
|
-
function buildFloorSelectedFragment(maxPano: number): string {
|
|
1255
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 形状与 blend 同档(喂料共用)
|
|
1256
|
-
return /* glsl */ `
|
|
1257
|
-
#include <logdepthbuf_pars_fragment>
|
|
1258
|
-
uniform sampler2D panoramas[${tileCount}]; // 形状与 blend 同档(喂料共用);本 shader 只采 0 号点槽(纹理 0..1)
|
|
1259
|
-
uniform mat4 textureMatrices[${maxPano}];
|
|
1260
|
-
uniform float weights[${maxPano}]; // 0 号槽 > 0 = 选中全景的瓦片已绑好
|
|
1261
|
-
uniform float uPanoTiled[${maxPano}];
|
|
1262
|
-
uniform vec3 uFloorBaseColor; // 槽没绑好时露出的深灰底(线性空间,约 sRGB 0.27)
|
|
1263
|
-
uniform float uFloorOpacity; // 整体透明度(与 blend 同口径:只缩放全景可见度,底色不变)
|
|
1264
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」):原 uniform float uColorSpace; + 那段 pow 分支已整条撤除(与 blend 同口径)
|
|
1265
|
-
uniform float uPanoramaVisible;
|
|
1266
|
-
varying vec3 vProjPos;
|
|
1267
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1268
|
-
varying vec3 vInstanceColor;
|
|
1269
|
-
#endif
|
|
1270
|
-
void main() {
|
|
1271
|
-
// ── 0 号点槽(纹理 0..1,即左右那 2 张拼合槽):选中的全景独占(采样段与 blend 逐字同口径)──
|
|
1272
|
-
vec3 lin0 = vec3(0.0);
|
|
1273
|
-
if (weights[0] > 0.0) {
|
|
1274
|
-
mat4 tm = textureMatrices[0];
|
|
1275
|
-
vec3 texPos = tm[3].xyz;
|
|
1276
|
-
mat3 texRot = mat3(tm);
|
|
1277
|
-
vec3 dir = normalize(vProjPos - texPos);
|
|
1278
|
-
dir = texRot * dir;
|
|
1279
|
-
float lon = atan(dir.z, dir.x);
|
|
1280
|
-
float u = lon * 0.15915494309189535 + 0.5; // 经度 -> u
|
|
1281
|
-
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
1282
|
-
float v = 0.5 + lat * 0.3183098861837907; // 1/PI(等距柱状线性 v,与 blend 逐字同口径)
|
|
1283
|
-
// ⭐ 10-06 晚旨:竖着不再分块 ⇒ 槽只随 u 走(左右两半:[左半幅=0, 右半幅=1]),与 blend 逐字同口径
|
|
1284
|
-
int tileIdx = (u >= 0.5) ? 1 : 0;
|
|
1285
|
-
float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
|
|
1286
|
-
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v
|
|
1287
|
-
float localV = v;
|
|
1288
|
-
float panoU = (uPanoTiled[0] > 0.5) ? localU : u;
|
|
1289
|
-
float panoV = (uPanoTiled[0] > 0.5) ? localV : v;
|
|
1290
|
-
// ⭐ 采样即线性(与单全景 / blend 那两路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
1291
|
-
// colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
|
|
1292
|
-
// 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
|
|
1293
|
-
if (tileIdx == 0) lin0 = texture2D(panoramas[0], vec2(panoU, panoV)).rgb;
|
|
1294
|
-
else lin0 = texture2D(panoramas[1], vec2(panoU, panoV)).rgb;
|
|
1295
|
-
}
|
|
1296
|
-
float coverage = weights[0] > 0.0 ? 1.0 : 0.0;
|
|
1297
|
-
float coverageEff = clamp(coverage * uFloorOpacity, 0.0, 1.0);
|
|
1298
|
-
vec3 col = mix(uFloorBaseColor, lin0, coverageEff);
|
|
1299
|
-
// 全景投射显隐:关闭时回落中性素色(与 blend 一致)
|
|
1300
|
-
if (uPanoramaVisible < 0.5) col = vec3(0.78, 0.78, 0.80);
|
|
1301
|
-
#ifdef USE_INSTANCING_COLOR
|
|
1302
|
-
col *= vInstanceColor;
|
|
1303
|
-
#endif
|
|
1304
|
-
gl_FragColor = vec4(col, 1.0);
|
|
1305
|
-
#include <colorspace_fragment>
|
|
1306
|
-
#include <logdepthbuf_fragment>
|
|
1307
|
-
}
|
|
1308
|
-
`;
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
/**
|
|
1312
|
-
* 创建「仅显示选中全景」着色器材质(皇上旨 2026-09-29「三模式三 shader」之三):仅编辑器使用。
|
|
1313
|
-
* uniform 形状与 blend 工厂同档 ⇒ 喂料复用 feedBlendProjection 槽位指派路零改动;
|
|
1314
|
-
* 本 shader 只读 0 号点槽(GLSL 写死),uFloorCoreRadius/uFloorFadeRange 喂料会写但不读(静默忽略)。
|
|
1315
|
-
*/
|
|
1316
|
-
export function createMktFloorSelectedShaderMaterial(options: { maxPano?: number } = {}): ShaderMaterial {
|
|
1317
|
-
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
1318
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 与 blend / mapping 同档(8 点 × 2 槽 = 16)
|
|
1319
|
-
const panoramas: import("three").Texture[] = [];
|
|
1320
|
-
const matrices: Matrix4[] = [];
|
|
1321
|
-
for (let i = 0; i < tileCount; i++) panoramas.push(createPlaceholderTexture());
|
|
1322
|
-
for (let i = 0; i < maxPano; i++) matrices.push(new Matrix4());
|
|
1323
|
-
return new ShaderMaterial({
|
|
1324
|
-
uniforms: {
|
|
1325
|
-
panoramas: { value: panoramas },
|
|
1326
|
-
textureMatrices: { value: matrices },
|
|
1327
|
-
weights: { value: new Float32Array(maxPano) },
|
|
1328
|
-
uPanoTiled: { value: new Float32Array(maxPano).fill(1) },
|
|
1329
|
-
uFloorBaseColor: { value: new Vector3(0.06, 0.06, 0.06) },
|
|
1330
|
-
// 喂料统一入口会写;本 shader 不读 uFloorCoreRadius/uFloorFadeRange(留 JS 项 = 喂料零分支)
|
|
1331
|
-
uFloorCoreRadius: { value: 4 },
|
|
1332
|
-
uFloorFadeRange: { value: 4 },
|
|
1333
|
-
uFloorOpacity: { value: 1 },
|
|
1334
|
-
uPanoramaVisible: { value: 1 },
|
|
1335
|
-
// 色彩空间只有一条路(10-07 旨「统一使用 liner」)⇒ 原 `uColorSpace: { value: 0 }` 已随那段 pow 分支整条撤除
|
|
1336
|
-
uProjInvMatrix: { value: new Matrix4() },
|
|
1337
|
-
},
|
|
1338
|
-
vertexShader: floorVertexShader,
|
|
1339
|
-
fragmentShader: buildFloorSelectedFragment(maxPano),
|
|
1340
|
-
side: DoubleSide,
|
|
1341
|
-
transparent: false,
|
|
1342
|
-
toneMapped: false,
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
930
|
+
*/
|