s3m-three 0.4.18 → 0.4.20
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/dist/browser/assets/s3mWorker-DvAUA8NJ.js +1 -0
- package/dist/browser/s3m-three.iife.ext-three.js +619 -304
- package/dist/browser/s3m-three.iife.js +647 -332
- package/dist/core/Draco.d.ts.map +1 -1
- package/dist/core/Draco.js +0 -1
- package/dist/core/Draco.js.map +1 -1
- package/dist/core/GaussianSplat.d.ts +64 -0
- package/dist/core/GaussianSplat.d.ts.map +1 -0
- package/dist/core/GaussianSplat.js +139 -0
- package/dist/core/GaussianSplat.js.map +1 -0
- package/dist/core/S3M1Parser.d.ts +1 -1
- package/dist/core/S3M1Parser.d.ts.map +1 -1
- package/dist/core/S3M1Parser.js +320 -25
- package/dist/core/S3M1Parser.js.map +1 -1
- package/dist/core/S3MBParser.d.ts.map +1 -1
- package/dist/core/S3MBParser.js +13 -0
- package/dist/core/S3MBParser.js.map +1 -1
- package/dist/core/S3MBlockParser.d.ts.map +1 -1
- package/dist/core/S3MBlockParser.js +83 -28
- package/dist/core/S3MBlockParser.js.map +1 -1
- package/dist/core/SplatLod.d.ts +36 -0
- package/dist/core/SplatLod.d.ts.map +1 -0
- package/dist/core/SplatLod.js +54 -0
- package/dist/core/SplatLod.js.map +1 -0
- package/dist/core/SplatProjection.d.ts +75 -0
- package/dist/core/SplatProjection.d.ts.map +1 -0
- package/dist/core/SplatProjection.js +162 -0
- package/dist/core/SplatProjection.js.map +1 -0
- package/dist/core/SplatSort.d.ts +26 -0
- package/dist/core/SplatSort.d.ts.map +1 -0
- package/dist/core/SplatSort.js +61 -0
- package/dist/core/SplatSort.js.map +1 -0
- package/dist/core/TexCoordZ.d.ts +94 -0
- package/dist/core/TexCoordZ.d.ts.map +1 -0
- package/dist/core/TexCoordZ.js +125 -0
- package/dist/core/TexCoordZ.js.map +1 -0
- package/dist/core/TextureDecode.d.ts +19 -0
- package/dist/core/TextureDecode.d.ts.map +1 -1
- package/dist/core/TextureDecode.js +53 -11
- package/dist/core/TextureDecode.js.map +1 -1
- package/dist/core/TileGeometry.d.ts +39 -0
- package/dist/core/TileGeometry.d.ts.map +1 -1
- package/dist/core/TileGeometry.js +133 -14
- package/dist/core/TileGeometry.js.map +1 -1
- package/dist/core/degradations.d.ts +37 -0
- package/dist/core/degradations.d.ts.map +1 -0
- package/dist/core/degradations.js +32 -0
- package/dist/core/degradations.js.map +1 -0
- package/dist/core/types.d.ts +36 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/render/DatasetManager.d.ts +11 -0
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +2 -0
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/FeatureStyleManager.d.ts.map +1 -1
- package/dist/render/FeatureStyleManager.js +7 -5
- package/dist/render/FeatureStyleManager.js.map +1 -1
- package/dist/render/GeometryBuilder.d.ts +31 -0
- package/dist/render/GeometryBuilder.d.ts.map +1 -1
- package/dist/render/GeometryBuilder.js +229 -6
- package/dist/render/GeometryBuilder.js.map +1 -1
- package/dist/render/Picker.d.ts.map +1 -1
- package/dist/render/Picker.js +19 -5
- package/dist/render/Picker.js.map +1 -1
- package/dist/render/S3MViewer.d.ts +106 -379
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +324 -1494
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/SplatMaterial.d.ts +103 -0
- package/dist/render/SplatMaterial.d.ts.map +1 -0
- package/dist/render/SplatMaterial.js +388 -0
- package/dist/render/SplatMaterial.js.map +1 -0
- package/dist/render/SplatSorter.d.ts +14 -0
- package/dist/render/SplatSorter.d.ts.map +1 -0
- package/dist/render/SplatSorter.js +66 -0
- package/dist/render/SplatSorter.js.map +1 -0
- package/dist/render/StyleMaterial.d.ts +48 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +292 -69
- package/dist/render/StyleMaterial.js.map +1 -1
- package/dist/render/TextureFactory.d.ts +10 -0
- package/dist/render/TextureFactory.d.ts.map +1 -1
- package/dist/render/TextureFactory.js +35 -5
- package/dist/render/TextureFactory.js.map +1 -1
- package/dist/render/lightingPreset.d.ts +53 -0
- package/dist/render/lightingPreset.d.ts.map +1 -0
- package/dist/render/lightingPreset.js +36 -0
- package/dist/render/lightingPreset.js.map +1 -0
- package/dist/render/materialAlpha.d.ts +51 -0
- package/dist/render/materialAlpha.d.ts.map +1 -0
- package/dist/render/materialAlpha.js +68 -0
- package/dist/render/materialAlpha.js.map +1 -0
- package/dist/render/viewer/EdgeDecorator.d.ts +206 -0
- package/dist/render/viewer/EdgeDecorator.d.ts.map +1 -0
- package/dist/render/viewer/EdgeDecorator.js +628 -0
- package/dist/render/viewer/EdgeDecorator.js.map +1 -0
- package/dist/render/viewer/HeightIndex.d.ts +36 -0
- package/dist/render/viewer/HeightIndex.d.ts.map +1 -0
- package/dist/render/viewer/HeightIndex.js +98 -0
- package/dist/render/viewer/HeightIndex.js.map +1 -0
- package/dist/render/viewer/LightRig.d.ts +88 -0
- package/dist/render/viewer/LightRig.d.ts.map +1 -0
- package/dist/render/viewer/LightRig.js +229 -0
- package/dist/render/viewer/LightRig.js.map +1 -0
- package/dist/render/viewer/PickService.d.ts +109 -0
- package/dist/render/viewer/PickService.d.ts.map +1 -0
- package/dist/render/viewer/PickService.js +591 -0
- package/dist/render/viewer/PickService.js.map +1 -0
- package/dist/render/viewer/SelectionDecorator.d.ts +84 -0
- package/dist/render/viewer/SelectionDecorator.d.ts.map +1 -0
- package/dist/render/viewer/SelectionDecorator.js +339 -0
- package/dist/render/viewer/SelectionDecorator.js.map +1 -0
- package/dist/render/viewer/SplatLayer.d.ts +26 -0
- package/dist/render/viewer/SplatLayer.d.ts.map +1 -0
- package/dist/render/viewer/SplatLayer.js +44 -0
- package/dist/render/viewer/SplatLayer.js.map +1 -0
- package/dist/render/viewer/types.d.ts +250 -0
- package/dist/render/viewer/types.d.ts.map +1 -0
- package/dist/render/viewer/types.js +3 -0
- package/dist/render/viewer/types.js.map +1 -0
- package/dist/tileset/S3MTileset.d.ts +42 -1
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +52 -2
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/dist/vendor/browser-node-stub.js +10 -0
- package/dist/worker/s3mWorker.js +1166 -979
- package/dist/worker/s3mWorker.js.map +1 -1
- package/docs/API.md +55 -1
- package/docs/FORMAT-NOTES.md +362 -0
- package/package.json +1 -1
- package/src/core/Draco.ts +1 -2
- package/src/core/GaussianSplat.ts +175 -0
- package/src/core/S3M1Parser.ts +330 -24
- package/src/core/S3MBParser.ts +18 -0
- package/src/core/S3MBlockParser.ts +83 -27
- package/src/core/SplatLod.ts +83 -0
- package/src/core/SplatProjection.ts +231 -0
- package/src/core/SplatSort.ts +92 -0
- package/src/core/TexCoordZ.ts +160 -0
- package/src/core/TextureDecode.ts +63 -11
- package/src/core/TileGeometry.ts +151 -14
- package/src/core/degradations.ts +74 -0
- package/src/core/types.ts +32 -0
- package/src/index.ts +8 -1
- package/src/render/DatasetManager.ts +10 -0
- package/src/render/FeatureStyleManager.ts +8 -6
- package/src/render/GeometryBuilder.ts +271 -7
- package/src/render/Picker.ts +21 -5
- package/src/render/S3MViewer.ts +358 -1727
- package/src/render/SplatMaterial.ts +433 -0
- package/src/render/SplatSorter.ts +66 -0
- package/src/render/StyleMaterial.ts +339 -69
- package/src/render/TextureFactory.ts +39 -5
- package/src/render/lightingPreset.ts +76 -0
- package/src/render/materialAlpha.ts +75 -0
- package/src/render/viewer/EdgeDecorator.ts +722 -0
- package/src/render/viewer/HeightIndex.ts +94 -0
- package/src/render/viewer/LightRig.ts +267 -0
- package/src/render/viewer/PickService.ts +651 -0
- package/src/render/viewer/SelectionDecorator.ts +377 -0
- package/src/render/viewer/SplatLayer.ts +44 -0
- package/src/render/viewer/types.ts +258 -0
- package/src/tileset/S3MTileset.ts +78 -2
- package/src/vendor/browser-node-stub.js +10 -0
- package/dist/browser/assets/s3mWorker-BjPOUgjg.js +0 -1
|
@@ -207,6 +207,17 @@ export interface S3MStyle {
|
|
|
207
207
|
* 绕过光照夹角直接补偿表面暗部底色,让 TOP_SIDE / 自定义等模式下的背光阴影面保持通透、不至于过黑。
|
|
208
208
|
*/
|
|
209
209
|
ambientGain?: number;
|
|
210
|
+
/**
|
|
211
|
+
* 金属度(0~1)。不传 = 保持数据/材质自身的值(实测 S3M 数据恒为 0)。
|
|
212
|
+
*
|
|
213
|
+
* 只对 pbr 光照模型有效(`materialQuality: 'lambert'` 时忽略)。
|
|
214
|
+
* ⚠️ 金属度越高,漫反射越少、几乎全靠环境反射成像:场景没有 `scene.environment`
|
|
215
|
+
* 时会明显发黑(只剩两盏平行光的高光点)。要用先把环境贴图挂上
|
|
216
|
+
* (`viewer.setEnvironment(url)` / `layer.setEnvironment(url)`)。
|
|
217
|
+
*/
|
|
218
|
+
metalness?: number;
|
|
219
|
+
/** 粗糙度(0~1)。不传 = 保持数据自身的值(S3M 的 shininess 映射,常见 0.95) */
|
|
220
|
+
roughness?: number;
|
|
210
221
|
/** 半透明时是否保持深度写入(默认 true,保持写入可彻底遮挡背面与内部棱线,避免背面透出) */
|
|
211
222
|
depthWrite?: boolean;
|
|
212
223
|
/**
|
|
@@ -283,6 +294,26 @@ export function getMaterialQuality(): MaterialQuality {
|
|
|
283
294
|
return materialQuality;
|
|
284
295
|
}
|
|
285
296
|
|
|
297
|
+
/**
|
|
298
|
+
* 颜色管线:
|
|
299
|
+
* - `'linear'`(默认):纹理 sRGB 解码 → 线性 PBR 光照 → linear→sRGB 输出,three 的标准姿势;
|
|
300
|
+
* - `'direct'`:官方 iClient3D 的做法 —— 字节值不解码、sRGB 数值空间直乘 Lambert
|
|
301
|
+
* (0.8·NdotL + 0.7)、输出前抵消 renderer 的 OETF。与 `setSrgbTextureDecode(false)`
|
|
302
|
+
* 配套使用,`lightingPreset: 'supermap'` 会同时打开两者。
|
|
303
|
+
*
|
|
304
|
+
* 与 materialQuality 同一套全局约定:只影响之后创建的材质,已加载瓦片要重载才换。
|
|
305
|
+
*/
|
|
306
|
+
export type ColorPipeline = 'linear' | 'direct';
|
|
307
|
+
let colorPipeline: ColorPipeline = 'linear';
|
|
308
|
+
|
|
309
|
+
export function setColorPipeline(p: ColorPipeline): void {
|
|
310
|
+
colorPipeline = p === 'direct' ? 'direct' : 'linear';
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function getColorPipeline(): ColorPipeline {
|
|
314
|
+
return colorPipeline;
|
|
315
|
+
}
|
|
316
|
+
|
|
286
317
|
export type StyledMaterial = (THREE.MeshStandardMaterial | THREE.MeshLambertMaterial) & {
|
|
287
318
|
userData: {
|
|
288
319
|
uSelBatch: { value: number };
|
|
@@ -315,6 +346,8 @@ DUMMY_BATCH_TEX.needsUpdate = true;
|
|
|
315
346
|
export function createSharedUniforms(): StyleUniforms {
|
|
316
347
|
return {
|
|
317
348
|
uMode: { value: STYLE.TEXTURE },
|
|
349
|
+
/** 主光世界方向(direct 管线的官方 Lambert 用;headlamp/fixed 都随 _updateLights 更新) */
|
|
350
|
+
uSunDirection: { value: new THREE.Vector3(0.5, 0.5, 0.7071).normalize() },
|
|
318
351
|
uColorA: { value: new THREE.Color('#dfe6ee') },
|
|
319
352
|
uColorB: { value: new THREE.Color('#1d4ed8') },
|
|
320
353
|
uColorC: { value: new THREE.Color('#fbbf24') },
|
|
@@ -350,6 +383,10 @@ export function createSharedUniforms(): StyleUniforms {
|
|
|
350
383
|
uTexMix: { value: 0 },
|
|
351
384
|
/** 基础底色增益 / 暗部补偿(0~1,默认 0.0) */
|
|
352
385
|
uAmbientGain: { value: 0 },
|
|
386
|
+
/** 金属度覆盖(<0 = 不覆盖,用材质自身的值) */
|
|
387
|
+
uMetalness: { value: -1 },
|
|
388
|
+
/** 粗糙度覆盖(<0 = 不覆盖,用材质自身的值) */
|
|
389
|
+
uRoughness: { value: -1 },
|
|
353
390
|
/** 双纹理交叉淡化插值系数(0 = 纯 uBatchTex, 1 = 纯 uBatchTex2) */
|
|
354
391
|
uBatchMix: { value: 0 },
|
|
355
392
|
/** GPU 路径数据采样纹理 */
|
|
@@ -385,7 +422,8 @@ export function createSharedUniforms(): StyleUniforms {
|
|
|
385
422
|
}
|
|
386
423
|
const VERT_PARS = /* glsl */ `
|
|
387
424
|
attribute float aBatchId;
|
|
388
|
-
|
|
425
|
+
// vec4:alpha 是「材质不透明、顶点半透明」这类数据的唯一透明度来源(官方 baseColorWithAlpha = vColor)
|
|
426
|
+
attribute vec4 aColor;
|
|
389
427
|
#ifdef S3M_ATLAS
|
|
390
428
|
attribute vec4 aAtlasRect;
|
|
391
429
|
#ifdef S3M_ATLAS_SEC
|
|
@@ -400,6 +438,15 @@ const VERT_PARS = /* glsl */ `
|
|
|
400
438
|
#ifdef USE_INSTANCING
|
|
401
439
|
attribute float aInstanceBatchId;
|
|
402
440
|
#endif
|
|
441
|
+
// uv 第三分量:官方 aTextureCoordMatrix,决定该顶点采不采样纹理 / 用图集哪一块。
|
|
442
|
+
// 解码必须在**顶点着色器**做:z 的量级是 65536~327680,片元里若落到 mediump(fp16
|
|
443
|
+
// 上限 65504)会直接溢出成 inf,官方也是在 VS 解完再用 varying 传。
|
|
444
|
+
#ifdef S3M_TEXCOORD_Z
|
|
445
|
+
attribute float aTexCoordZ;
|
|
446
|
+
varying vec4 vTexMatrix; // x=xTran y=yTran z=scale w=log2(scale*texWidth)
|
|
447
|
+
varying float vTexCoordTransform; // 原始 z,-90000 以下表示不采样
|
|
448
|
+
uniform vec2 uAtlasDim; // 与片元共用:纹理像素尺寸
|
|
449
|
+
#endif
|
|
403
450
|
uniform float uSelBatch;
|
|
404
451
|
uniform float uSelWhole;
|
|
405
452
|
uniform float uSelElevation;
|
|
@@ -413,7 +460,7 @@ const VERT_PARS = /* glsl */ `
|
|
|
413
460
|
uniform float uPathTime;
|
|
414
461
|
uniform int uPathTexActive;
|
|
415
462
|
varying float vBatchId;
|
|
416
|
-
varying
|
|
463
|
+
varying vec4 vVertColor;
|
|
417
464
|
varying float vWorldZ;
|
|
418
465
|
varying vec3 vWorldNormal;
|
|
419
466
|
varying vec3 vWorldPos;
|
|
@@ -443,29 +490,37 @@ const VERT_PARS = /* glsl */ `
|
|
|
443
490
|
|
|
444
491
|
vec4 s3mSampleBatchRow0( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
445
492
|
vec4 vA = texture2D( texA, uv );
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
493
|
+
vec4 res;
|
|
494
|
+
if ( mixVal <= 0.0001 ) {
|
|
495
|
+
res = vA;
|
|
496
|
+
} else {
|
|
497
|
+
vec4 vB = texture2D( texB, uv );
|
|
498
|
+
res = mix( vA, vB, mixVal );
|
|
499
|
+
if ( vA.r < 0.0 && vB.r >= 0.0 ) {
|
|
500
|
+
res.rgb = vB.rgb;
|
|
501
|
+
} else if ( vA.r >= 0.0 && vB.r < 0.0 ) {
|
|
502
|
+
res.rgb = vA.rgb;
|
|
503
|
+
}
|
|
504
|
+
if ( vA.a < -0.5 || vB.a < -0.5 ) {
|
|
505
|
+
res.a = ( mixVal >= 0.5 ) ? vB.a : vA.a;
|
|
506
|
+
}
|
|
456
507
|
}
|
|
457
508
|
return res;
|
|
458
509
|
}
|
|
459
510
|
|
|
460
511
|
vec4 s3mSampleBatchRow1( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
461
512
|
vec4 vA = texture2D( texA, uv );
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
513
|
+
vec4 res;
|
|
514
|
+
if ( mixVal <= 0.0001 ) {
|
|
515
|
+
res = vA;
|
|
516
|
+
} else {
|
|
517
|
+
vec4 vB = texture2D( texB, uv );
|
|
518
|
+
res = mix( vA, vB, mixVal );
|
|
519
|
+
if ( vA.a == 0.0 && vB.a > 0.0 ) {
|
|
520
|
+
res.a = mix( 1.0, vB.a, mixVal );
|
|
521
|
+
} else if ( vA.a > 0.0 && vB.a == 0.0 ) {
|
|
522
|
+
res.a = mix( vA.a, 1.0, mixVal );
|
|
523
|
+
}
|
|
469
524
|
}
|
|
470
525
|
return res;
|
|
471
526
|
}
|
|
@@ -569,6 +624,31 @@ const VERT_WORLD = /* glsl */ `
|
|
|
569
624
|
vWorldPos = s3mWorld.xyz;
|
|
570
625
|
vBatchId = s3mBatchRaw();
|
|
571
626
|
vVertColor = aColor;
|
|
627
|
+
#ifdef S3M_TEXCOORD_Z
|
|
628
|
+
// 官方 S3MTilesVS.js:192-198(getTextureMatrixFromZValue)+ bundle getTextureColor
|
|
629
|
+
// 的三档哨兵,档位编码在 vTexMatrix.z 的符号上:
|
|
630
|
+
// -2 → 白(z < -99900 档:官方 texCoordZ < -99900 返回 vec4(1.0),平涂顶点色面)
|
|
631
|
+
// -1 → 平铺(-99900 ≤ z < -9000:uv 原样采样)
|
|
632
|
+
// >0 → 图集子区域公式
|
|
633
|
+
vTexCoordTransform = aTexCoordZ;
|
|
634
|
+
vTexMatrix = vec4( 0.0, 0.0, 1.0, 0.0 );
|
|
635
|
+
if ( vTexCoordTransform < -99900.0 ) {
|
|
636
|
+
vTexMatrix.z = -2.0;
|
|
637
|
+
} else if ( vTexCoordTransform < -9000.0 ) {
|
|
638
|
+
vTexMatrix.z = -1.0;
|
|
639
|
+
} else {
|
|
640
|
+
float s3mNz = floor( vTexCoordTransform );
|
|
641
|
+
if ( s3mNz > 0.0 ) {
|
|
642
|
+
float nDel8 = floor( s3mNz / 256.0 );
|
|
643
|
+
float nDel16 = floor( nDel8 / 256.0 );
|
|
644
|
+
float nDel20 = floor( nDel16 / 16.0 );
|
|
645
|
+
vTexMatrix.x = nDel8 - nDel16 * 256.0;
|
|
646
|
+
vTexMatrix.y = s3mNz - nDel8 * 256.0;
|
|
647
|
+
vTexMatrix.z = 1.0 / pow( 2.0, nDel16 - nDel20 * 16.0 );
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
vTexMatrix.w = vTexMatrix.z > 0.0 ? log2( uAtlasDim.x * vTexMatrix.z ) : 0.0;
|
|
651
|
+
#endif
|
|
572
652
|
|
|
573
653
|
#ifdef S3M_ATLAS
|
|
574
654
|
vAtlasRect = aAtlasRect;
|
|
@@ -590,31 +670,85 @@ const VERT_WORLD = /* glsl */ `
|
|
|
590
670
|
`;
|
|
591
671
|
|
|
592
672
|
const FRAG_PARS = /* glsl */ `
|
|
673
|
+
// 纹理像素尺寸:图集分支用它把 rect 换算成像素宽,uv-z 分支用它算 uv 周期。
|
|
674
|
+
// 两个分支都需要,所以无条件声明(值恒为 map 的实际像素尺寸)。
|
|
675
|
+
uniform vec2 uAtlasDim;
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* 官方 CalculateMipLevel(vec2 版),逐字照抄 iClient3D 12.1.1。
|
|
679
|
+
* 用**未 fract** 的 uv 求屏幕空间导数 —— 先 fract 再求导会在平铺接缝处炸出
|
|
680
|
+
* 一个巨大导数,GPU 直接把整块砖采成最糊的 mip,表现为每块砖边缘一条暗线。
|
|
681
|
+
*/
|
|
682
|
+
void s3mMipLevel( vec2 uv, vec2 texSize, float maxMip, out float mip ) {
|
|
683
|
+
vec2 dx = dFdx( uv * texSize.x );
|
|
684
|
+
vec2 dy = dFdy( uv * texSize.y );
|
|
685
|
+
float dotX = dot( dx, dx );
|
|
686
|
+
float dotY = dot( dy, dy );
|
|
687
|
+
float dMax = max( dotX, dotY );
|
|
688
|
+
float dMin = min( dotX, dotY );
|
|
689
|
+
float off = clamp( ( dMax - dMin ) / max( dMax + dMin, 1e-8 ), 0.0, 1.0 );
|
|
690
|
+
float d = dMax * ( 1.0 - off ) + dMin * off;
|
|
691
|
+
mip = clamp( 0.5 * log2( max( d, 1e-8 ) ), 0.0, maxMip - 1.62 );
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
#ifdef S3M_TEXCOORD_Z
|
|
695
|
+
// 矩阵在顶点着色器解好(vTexMatrix),这里只做 mip 收缩 + 采样。
|
|
696
|
+
varying vec4 vTexMatrix;
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* 官方 S3MTilesFS.js 的 getTextureColor → getTexColorForS3M → calculateTexCoord
|
|
700
|
+
* 逐行移植,数学等价物见 core/TexCoordZ.ts(单测钉住两边一致):
|
|
701
|
+
*
|
|
702
|
+
* vTexMatrix.z < 0 → 不采样,返回白(官方 if ( vTexMatrix.z < 0.0 ))
|
|
703
|
+
* fTile = scale * texWidth
|
|
704
|
+
* inner = 2^mip / fTile; f = clamp( fract(uv), inner, 1 - inner )
|
|
705
|
+
* out = ( f + T ) * scale
|
|
706
|
+
*
|
|
707
|
+
* ★ 采样必须用**显式 LOD**(官方 textureLod / texture2DLodEXT)。
|
|
708
|
+
* 交给硬件自动求导时,导数从 (fract(uv)+T)*scale 上取,而 fract 每个周期
|
|
709
|
+
* 都有一次跳变,接缝像素的导数会炸掉 → GPU 采到最糊的 mip,画面上每隔一个
|
|
710
|
+
* 周期就出现一条暗带 / 摩尔纹。近处周期密,这些带子最明显。
|
|
711
|
+
*/
|
|
712
|
+
vec4 s3mTexCoordZUnit( vec2 uv, vec4 m, sampler2D tex, float texWidth ) {
|
|
713
|
+
// 官方 bundle getTextureColor 三档语义(逐行核对 SuperMap3D.js):
|
|
714
|
+
// texCoordZ < -99900 → vec4(1.0) 纯白,不采样(平涂顶点色面,如 SMID 3464)
|
|
715
|
+
// texCoordZ < -9000 → uv 原样平铺(自动 mip 平均成贴图色)
|
|
716
|
+
// 其余 → 图集子区域公式
|
|
717
|
+
// 之前误读成「-99999 也平铺」,3464 的米制 uv 就把整张纹理平铺上百次 = 「uv 整图」。
|
|
718
|
+
// 单出口结构:ANGLE 把返回值翻译成 out 参数,函数内提前 return
|
|
719
|
+
// 会让 D3D 编译器报 X4000「use of potentially uninitialized variable」。
|
|
720
|
+
vec4 s3mResult;
|
|
721
|
+
if ( m.z < -1.5 ) {
|
|
722
|
+
s3mResult = vec4( 1.0 );
|
|
723
|
+
} else if ( m.z < 0.0 ) {
|
|
724
|
+
s3mResult = texture2D( tex, uv );
|
|
725
|
+
} else {
|
|
726
|
+
float fTile = max( m.z * texWidth, 1.0 );
|
|
727
|
+
float mip = 0.0;
|
|
728
|
+
s3mMipLevel( uv, vec2( fTile ), m.w, mip );
|
|
729
|
+
|
|
730
|
+
vec2 f = fract( uv );
|
|
731
|
+
float inner = pow( 2.0, mip ) / fTile;
|
|
732
|
+
f = clamp( f, vec2( inner ), vec2( 1.0 - inner ) );
|
|
733
|
+
vec2 c = ( f + m.xy ) * m.z;
|
|
734
|
+
|
|
735
|
+
#if __VERSION__ >= 300
|
|
736
|
+
s3mResult = textureLod( tex, c, mip );
|
|
737
|
+
#else
|
|
738
|
+
s3mResult = texture2D( tex, c );
|
|
739
|
+
#endif
|
|
740
|
+
}
|
|
741
|
+
return s3mResult;
|
|
742
|
+
}
|
|
743
|
+
#endif
|
|
593
744
|
#ifdef S3M_ATLAS
|
|
594
745
|
varying vec4 vAtlasRect;
|
|
595
|
-
uniform vec2 uAtlasDim;
|
|
596
746
|
#ifdef S3M_ATLAS_SEC
|
|
597
747
|
uniform sampler2D uSecMap;
|
|
598
748
|
uniform vec2 uAtlasDim1;
|
|
599
749
|
varying vec2 vSecUv;
|
|
600
750
|
varying vec4 vSecRect;
|
|
601
751
|
#endif
|
|
602
|
-
/**
|
|
603
|
-
* 官方 CalculateMipLevel(vec2 版),逐字照抄 iClient3D 12.1.1。
|
|
604
|
-
* 用**未 fract** 的 uv 求屏幕空间导数 —— 先 fract 再求导会在平铺接缝处炸出
|
|
605
|
-
* 一个巨大导数,GPU 直接把整块砖采成最糊的 mip,表现为每块砖边缘一条暗线。
|
|
606
|
-
*/
|
|
607
|
-
void s3mMipLevel( vec2 uv, vec2 texSize, float maxMip, out float mip ) {
|
|
608
|
-
vec2 dx = dFdx( uv * texSize.x );
|
|
609
|
-
vec2 dy = dFdy( uv * texSize.y );
|
|
610
|
-
float dotX = dot( dx, dx );
|
|
611
|
-
float dotY = dot( dy, dy );
|
|
612
|
-
float dMax = max( dotX, dotY );
|
|
613
|
-
float dMin = min( dotX, dotY );
|
|
614
|
-
float off = clamp( ( dMax - dMin ) / max( dMax + dMin, 1e-8 ), 0.0, 1.0 );
|
|
615
|
-
float d = dMax * ( 1.0 - off ) + dMin * off;
|
|
616
|
-
mip = clamp( 0.5 * log2( max( d, 1e-8 ) ), 0.0, maxMip - 1.62 );
|
|
617
|
-
}
|
|
618
752
|
|
|
619
753
|
/**
|
|
620
754
|
* 按指定 mip 档采样子区域(官方 czm_getTexColorForS3M 的内层循环体)。
|
|
@@ -646,17 +780,22 @@ const FRAG_PARS = /* glsl */ `
|
|
|
646
780
|
* 因为内联金字塔只有 2 的整数次幂,中间档必须靠混合。
|
|
647
781
|
*/
|
|
648
782
|
vec4 s3mAtlasUnit( vec2 uv, vec4 rect, vec2 atlasDim, sampler2D tex ) {
|
|
649
|
-
// 退化矩形 = 官方 batchId < 0
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
783
|
+
// 退化矩形 = 官方 batchId < 0:该纹理单元不参与合成(单出口,同 X4000 规避)
|
|
784
|
+
vec4 s3mResult;
|
|
785
|
+
if ( rect.z <= 0.0 || rect.w <= 0.0 ) {
|
|
786
|
+
s3mResult = vec4( 1.0 );
|
|
787
|
+
} else {
|
|
788
|
+
vec2 dimPx = vec2( rect.z * atlasDim.x, rect.w * atlasDim.y );
|
|
789
|
+
vec2 texSize = vec2( dimPx.x * ( 2.0 / 3.0 ), dimPx.y );
|
|
790
|
+
float maxMip = log2( max( min( texSize.x, texSize.y ), 1.0 ) );
|
|
791
|
+
vec2 scale = texSize / atlasDim;
|
|
792
|
+
float mip = 0.0;
|
|
793
|
+
s3mMipLevel( uv, texSize, maxMip, mip );
|
|
794
|
+
vec4 hi = s3mAtlasLod( uv, rect.xy, scale, texSize, tex, ceil( mip ) );
|
|
795
|
+
vec4 lo = s3mAtlasLod( uv, rect.xy, scale, texSize, tex, floor( mip ) );
|
|
796
|
+
s3mResult = hi * 0.5 + lo * 0.5;
|
|
797
|
+
}
|
|
798
|
+
return s3mResult;
|
|
660
799
|
}
|
|
661
800
|
#endif
|
|
662
801
|
uniform int uMode;
|
|
@@ -687,11 +826,13 @@ const FRAG_PARS = /* glsl */ `
|
|
|
687
826
|
uniform float uRoofThreshold;
|
|
688
827
|
uniform float uTexMix;
|
|
689
828
|
uniform float uAmbientGain;
|
|
829
|
+
uniform float uMetalness;
|
|
830
|
+
uniform float uRoughness;
|
|
690
831
|
uniform float uOpacity;
|
|
691
832
|
uniform float uTileFade;
|
|
692
833
|
uniform float uFade;
|
|
693
834
|
varying float vBatchId;
|
|
694
|
-
varying
|
|
835
|
+
varying vec4 vVertColor;
|
|
695
836
|
varying float vWorldZ;
|
|
696
837
|
varying vec3 vWorldNormal;
|
|
697
838
|
varying vec3 vWorldPos;
|
|
@@ -700,29 +841,37 @@ const FRAG_PARS = /* glsl */ `
|
|
|
700
841
|
|
|
701
842
|
vec4 s3mSampleBatchRow0( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
702
843
|
vec4 vA = texture2D( texA, uv );
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
844
|
+
vec4 res;
|
|
845
|
+
if ( mixVal <= 0.0001 ) {
|
|
846
|
+
res = vA;
|
|
847
|
+
} else {
|
|
848
|
+
vec4 vB = texture2D( texB, uv );
|
|
849
|
+
res = mix( vA, vB, mixVal );
|
|
850
|
+
if ( vA.r < 0.0 && vB.r >= 0.0 ) {
|
|
851
|
+
res.rgb = vB.rgb;
|
|
852
|
+
} else if ( vA.r >= 0.0 && vB.r < 0.0 ) {
|
|
853
|
+
res.rgb = vA.rgb;
|
|
854
|
+
}
|
|
855
|
+
if ( vA.a < -0.5 || vB.a < -0.5 ) {
|
|
856
|
+
res.a = ( mixVal >= 0.5 ) ? vB.a : vA.a;
|
|
857
|
+
}
|
|
713
858
|
}
|
|
714
859
|
return res;
|
|
715
860
|
}
|
|
716
861
|
|
|
717
862
|
vec4 s3mSampleBatchRow1( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
718
863
|
vec4 vA = texture2D( texA, uv );
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
864
|
+
vec4 res;
|
|
865
|
+
if ( mixVal <= 0.0001 ) {
|
|
866
|
+
res = vA;
|
|
867
|
+
} else {
|
|
868
|
+
vec4 vB = texture2D( texB, uv );
|
|
869
|
+
res = mix( vA, vB, mixVal );
|
|
870
|
+
if ( vA.a == 0.0 && vB.a > 0.0 ) {
|
|
871
|
+
res.a = mix( 1.0, vB.a, mixVal );
|
|
872
|
+
} else if ( vA.a > 0.0 && vB.a == 0.0 ) {
|
|
873
|
+
res.a = mix( vA.a, 1.0, mixVal );
|
|
874
|
+
}
|
|
726
875
|
}
|
|
727
876
|
return res;
|
|
728
877
|
}
|
|
@@ -762,6 +911,10 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
762
911
|
vec3 s3mBase = diffuseColor.rgb; // 已含 diffuse × map
|
|
763
912
|
// 图层整体透明度(共享 uniform)+ 单瓦片淡入系数(逐材质),逐帧改都不产生重编译
|
|
764
913
|
diffuseColor.a *= uOpacity * uTileFade;
|
|
914
|
+
// 顶点色 alpha:官方 outColor = baseColorWithAlpha * uDiffuseColor,alpha 走的就是这条路。
|
|
915
|
+
// 实测 3D-BIMbuilding-2 / SMID 4421 的材质无纹理、diffuse.a = 1,透明度只存在于
|
|
916
|
+
// 顶点色 alpha(u8 63/255 ≈ 0.247)。不乘进来,这一片就是实心色。
|
|
917
|
+
diffuseColor.a *= vVertColor.a;
|
|
765
918
|
// 所有按单体取值(配色 / 状态纹理 / 选中判定)都走取整后的 id,避免插值噪声
|
|
766
919
|
float s3mBid = s3mBatchId();
|
|
767
920
|
|
|
@@ -773,7 +926,7 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
773
926
|
diffuseColor.rgb = uColorA;
|
|
774
927
|
} else if ( uMode == 1 ) {
|
|
775
928
|
// 原色:贴图 × 顶点色
|
|
776
|
-
diffuseColor.rgb = s3mBase * vVertColor;
|
|
929
|
+
diffuseColor.rgb = s3mBase * vVertColor.rgb;
|
|
777
930
|
} else if ( uMode == 2 ) {
|
|
778
931
|
diffuseColor.rgb = uColorA;
|
|
779
932
|
} else if ( uMode == 3 ) {
|
|
@@ -808,7 +961,7 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
808
961
|
|
|
809
962
|
// 叠加在原色贴图上:保留窗框、玻璃幕墙、材质纹理与顶点色
|
|
810
963
|
if ( uMode != 1 && uTexMix > 0.001 ) {
|
|
811
|
-
vec3 origTex = s3mBase * vVertColor;
|
|
964
|
+
vec3 origTex = s3mBase * vVertColor.rgb;
|
|
812
965
|
vec3 overlay = origTex * diffuseColor.rgb * 1.35;
|
|
813
966
|
diffuseColor.rgb = mix( diffuseColor.rgb, overlay, uTexMix );
|
|
814
967
|
}
|
|
@@ -870,6 +1023,36 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
870
1023
|
diffuseColor.rgb *= uFade;
|
|
871
1024
|
`;
|
|
872
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* direct 管线(lightingPreset: 'supermap' 完整版)的着色器片段。
|
|
1028
|
+
*
|
|
1029
|
+
* 官方整条管线(S3MTilesFS.js):贴图字节值不解码 → sRGB 数值空间直乘
|
|
1030
|
+
* Lambert(Sun 0.8 / Ambient 0.7,无高光无 tonemap)→ 直出。
|
|
1031
|
+
* 我们保留 three 的 sRGB 输出 OETF(不动共享 renderer,底图不受影响),
|
|
1032
|
+
* 在片元末尾把颜色先压回 linear,OETF 再把它还原成官方直乘的原始数值。
|
|
1033
|
+
*/
|
|
1034
|
+
const FRAG_DIRECT_PARS = /* glsl */ `
|
|
1035
|
+
#ifdef S3M_DIRECT_COLOR
|
|
1036
|
+
uniform vec3 uSunDirection;
|
|
1037
|
+
|
|
1038
|
+
// 精确 sRGB EOTF 逆(与 renderer 输出端的 OETF 互逆),不是 pow 2.2 近似
|
|
1039
|
+
vec3 s3mSRGBToLinear( vec3 c ) {
|
|
1040
|
+
return mix( c / 12.92, pow( ( c + 0.055 ) / 1.055, vec3( 2.4 ) ), step( vec3( 0.04045 ), c ) );
|
|
1041
|
+
}
|
|
1042
|
+
#endif
|
|
1043
|
+
`;
|
|
1044
|
+
|
|
1045
|
+
const FRAG_DIRECT_MAIN = /* glsl */ `
|
|
1046
|
+
#ifdef S3M_DIRECT_COLOR
|
|
1047
|
+
// 官方 S3MTilesFS.js:255-263:uDiffuseColor.rgb * (SunLightColor * NdotL + AmbientLightColor)
|
|
1048
|
+
// Sun=0.8、Ambient=0.7;uAmbientColor 数据里恒为 (1,1,1),并入常数
|
|
1049
|
+
float s3mNL = max( dot( s3mNorm, normalize( uSunDirection ) ), 0.0 );
|
|
1050
|
+
vec3 s3mDirectOut = diffuseColor.rgb * ( 0.8 * s3mNL + vec3( 0.7 ) );
|
|
1051
|
+
s3mDirectOut = s3mSRGBToLinear( max( s3mDirectOut, vec3( 0.0 ) ) );
|
|
1052
|
+
outgoingLight = s3mDirectOut;
|
|
1053
|
+
#endif
|
|
1054
|
+
`;
|
|
1055
|
+
|
|
873
1056
|
const FRAG_EMISSIVE = /* glsl */ `
|
|
874
1057
|
float s3mSelE = max( step( 0.0, uSelBatch ) * step( abs( s3mBatchId() - uSelBatch ), 0.5 ), uSelWhole );
|
|
875
1058
|
// glowOnly 模式下表面不自发光,只保留描边边框;其他模式下适度发光
|
|
@@ -909,6 +1092,17 @@ export interface StyledMaterialOptions {
|
|
|
909
1092
|
alphaTest?: number;
|
|
910
1093
|
/** 贴图为 S3MBLOCK 图集:几何需带 aAtlasRect,平铺改由片元按子区域做 */
|
|
911
1094
|
atlas?: boolean;
|
|
1095
|
+
/**
|
|
1096
|
+
* 几何带 uv 第三分量(`aTexCoordZ`,来自文件里的 `custom0`)。
|
|
1097
|
+
*
|
|
1098
|
+
* 官方 iClient3D 用它决定采样方式:`z < -9000` 时 uv 原样平铺整图(非白)
|
|
1099
|
+
* `vec4(1.0)`(纯色),否则把 uv 按 `czm_getTextureMatrixFromZValue` 解出的
|
|
1100
|
+
* 平移/缩放送进图集子区域。BIM / OSGB 转出来的数据大量依赖它——忽略就会把
|
|
1101
|
+
* 本该纯色的墙面贴上整张材质图并高频重复。
|
|
1102
|
+
*
|
|
1103
|
+
* 不传 = 与改动前完全一致(走 three 原生的 `texture2D( map, vMapUv )`)。
|
|
1104
|
+
*/
|
|
1105
|
+
texCoordZ?: boolean;
|
|
912
1106
|
/** 图集材质的第二套纹理(官方 BakeTex,光照烘焙),与 base 相乘 */
|
|
913
1107
|
secMap?: THREE.Texture | null;
|
|
914
1108
|
}
|
|
@@ -938,6 +1132,24 @@ const FRAG_NORMAL = /* glsl */ `
|
|
|
938
1132
|
}
|
|
939
1133
|
`;
|
|
940
1134
|
|
|
1135
|
+
/**
|
|
1136
|
+
* 金属度 / 粗糙度覆盖。
|
|
1137
|
+
*
|
|
1138
|
+
* 注入点必须是 `#include <metalnessmap_fragment>` 之后 —— 两个 chunk 各自
|
|
1139
|
+
* `float roughnessFactor = roughness;` / `float metalnessFactor = metalness;`,
|
|
1140
|
+
* 之前引用会「变量未声明」,之后就落在 `lights_physical_fragment` 之前,
|
|
1141
|
+
* 改完立刻参与 GGX 计算。
|
|
1142
|
+
*
|
|
1143
|
+
* 用共享 uniform 而不是改 `material.metalness`:材质是一 mesh 一份,逐 mesh 改是
|
|
1144
|
+
* O(meshes);uniform 改一次全场景生效,也能走样式动画插值。
|
|
1145
|
+
*
|
|
1146
|
+
* 注意:`lambert` 光照模型里没有这两个 include,注入是 no-op,金属度自然无效。
|
|
1147
|
+
*/
|
|
1148
|
+
const FRAG_SURFACE = /* glsl */ `
|
|
1149
|
+
if ( uMetalness >= 0.0 ) metalnessFactor = clamp( uMetalness, 0.0, 1.0 );
|
|
1150
|
+
if ( uRoughness >= 0.0 ) roughnessFactor = clamp( uRoughness, 0.04, 1.0 );
|
|
1151
|
+
`;
|
|
1152
|
+
|
|
941
1153
|
export function createStyledMaterial(opts: StyledMaterialOptions): StyledMaterial {
|
|
942
1154
|
const uniforms = opts.uniforms;
|
|
943
1155
|
// 两种光照模型共用的参数。注入的 chunk 只动 diffuseColor / normal / transformed,
|
|
@@ -984,9 +1196,16 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
984
1196
|
|
|
985
1197
|
// 图集材质:只有几何确实带了 aAtlasRect 才开这个宏,否则缺属性会采到 (0,0) 的默认值
|
|
986
1198
|
const atlas = !!opts.atlas && !!opts.map;
|
|
1199
|
+
// uv 第三分量:同样要求几何真的带 aTexCoordZ,且没有贴图时没有意义。
|
|
1200
|
+
// atlas 优先——S3MBLOCK 图集的 aAtlasRect 已经表达了子区域,两者不会同时出现。
|
|
1201
|
+
const texCoordZ = !atlas && !!opts.texCoordZ && !!opts.map;
|
|
987
1202
|
const secMap = atlas ? (opts.secMap ?? null) : null;
|
|
988
1203
|
if (atlas) mat.defines = { ...(mat.defines as Record<string, string>), S3M_ATLAS: '' };
|
|
1204
|
+
if (texCoordZ) mat.defines = { ...(mat.defines as Record<string, string>), S3M_TEXCOORD_Z: '' };
|
|
989
1205
|
if (secMap) mat.defines = { ...mat.defines, S3M_ATLAS_SEC: '' };
|
|
1206
|
+
// supermap 完整版:官方 sRGB 直乘管线(配合 setSrgbTextureDecode(false))
|
|
1207
|
+
const direct = colorPipeline === 'direct';
|
|
1208
|
+
if (direct) mat.defines = { ...mat.defines, S3M_DIRECT_COLOR: '' };
|
|
990
1209
|
// 官方 uTextureDim = (base宽, base高, bake宽, bake高),取实际绑定纹理的像素尺寸
|
|
991
1210
|
const uAtlasDim = { value: new THREE.Vector2(opts.map?.image?.width || 1, opts.map?.image?.height || 1) };
|
|
992
1211
|
const uAtlasDim1 = { value: new THREE.Vector2(secMap?.image?.width || 1, secMap?.image?.height || 1) };
|
|
@@ -1002,6 +1221,8 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
1002
1221
|
uBatchTexActive,
|
|
1003
1222
|
uTileFade,
|
|
1004
1223
|
uSecMap: { value: secMap },
|
|
1224
|
+
// direct 管线需要主光方向;没接共享 uniforms 时(单测/独立构建)给个默认值保证能编译
|
|
1225
|
+
...(direct ? { uSunDirection: uniforms?.uSunDirection ?? { value: new THREE.Vector3(0.5, 0.5, 0.7071).normalize() } } : {}),
|
|
1005
1226
|
uAtlasDim,
|
|
1006
1227
|
uAtlasDim1,
|
|
1007
1228
|
});
|
|
@@ -1013,9 +1234,17 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
1013
1234
|
.replace('#include <worldpos_vertex>', VERT_WORLD);
|
|
1014
1235
|
|
|
1015
1236
|
shader.fragmentShader = shader.fragmentShader
|
|
1016
|
-
.replace('#include <common>', `#include <common>\n${FRAG_PARS}`)
|
|
1237
|
+
.replace('#include <common>', `#include <common>\n${FRAG_PARS}${direct ? FRAG_DIRECT_PARS : ''}`)
|
|
1017
1238
|
.replace('#include <color_fragment>', `#include <color_fragment>\n${FRAG_COLOR}`)
|
|
1018
1239
|
.replace('#include <emissivemap_fragment>', `#include <emissivemap_fragment>\n${FRAG_EMISSIVE}`);
|
|
1240
|
+
if (direct) {
|
|
1241
|
+
// s3mNorm(FRAG_COLOR 里定义)之后、three 组装 outgoingLight 之前整体接管:
|
|
1242
|
+
// PBR 的 specular / 环境项全被丢弃 —— 官方模型里 totalSpecularLight 恒为 0
|
|
1243
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
1244
|
+
'#include <opaque_fragment>',
|
|
1245
|
+
`${FRAG_DIRECT_MAIN}\n#include <opaque_fragment>`
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1019
1248
|
|
|
1020
1249
|
if (atlas) {
|
|
1021
1250
|
// onBeforeCompile 收到的还是未展开的 `#include <map_fragment>`,不是 include 里的
|
|
@@ -1030,6 +1259,16 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
1030
1259
|
'#include <map_fragment>',
|
|
1031
1260
|
`${atlasMapFragment}${secMap ? `\n${FRAG_BAKE}` : ''}`
|
|
1032
1261
|
);
|
|
1262
|
+
} else if (texCoordZ) {
|
|
1263
|
+
// 普通 S3M + uv 第三分量:逐顶点决定「用不用贴图 / 用哪块子区域」。
|
|
1264
|
+
// 官方就是这个分支让 BIM 的墙体保持纯色(custom0 = -99999 的顶点直接返回白),
|
|
1265
|
+
// 而我们过去一律整张平铺,才会出现「一个面重复铺满整张 uv 贴片」。
|
|
1266
|
+
const texCoordZFragment = /* glsl */ `
|
|
1267
|
+
#ifdef USE_MAP
|
|
1268
|
+
diffuseColor *= s3mTexCoordZUnit( vMapUv, vTexMatrix, map, uAtlasDim.x );
|
|
1269
|
+
#endif
|
|
1270
|
+
`;
|
|
1271
|
+
shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', texCoordZFragment);
|
|
1033
1272
|
} else if (secMap) {
|
|
1034
1273
|
shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', `#include <map_fragment>\n${FRAG_BAKE}`);
|
|
1035
1274
|
}
|
|
@@ -1039,12 +1278,19 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
1039
1278
|
'#include <normal_fragment_begin>',
|
|
1040
1279
|
`#include <normal_fragment_begin>\n${FRAG_NORMAL}`
|
|
1041
1280
|
);
|
|
1281
|
+
|
|
1282
|
+
// 金属度 / 粗糙度覆盖:紧跟在 metalnessmap_fragment 之后
|
|
1283
|
+
// (lambert 模板里没有这个 include,replace 会静默 no-op,符合预期)
|
|
1284
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
1285
|
+
'#include <metalnessmap_fragment>',
|
|
1286
|
+
`#include <metalnessmap_fragment>\n${FRAG_SURFACE}`
|
|
1287
|
+
);
|
|
1042
1288
|
};
|
|
1043
1289
|
|
|
1044
1290
|
// 不同材质共用同一段注入代码,必须让 three 认为它们的 program 可复用;
|
|
1045
1291
|
// 但图集 / 烘焙两套宏会改注入结果,必须进 cacheKey,否则会复用错 program。
|
|
1046
1292
|
mat.customProgramCacheKey = () =>
|
|
1047
|
-
`s3m-styled${atlas ? '-atlas' : ''}${secMap ? '-bake' : ''}`;
|
|
1293
|
+
`s3m-styled${atlas ? '-atlas' : ''}${texCoordZ ? '-texz' : ''}${secMap ? '-bake' : ''}${direct ? '-direct' : ''}`;
|
|
1048
1294
|
|
|
1049
1295
|
mat.userData.uSelBatch = uSelBatch;
|
|
1050
1296
|
mat.userData.uSelWhole = uSelWhole;
|
|
@@ -1069,6 +1315,30 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
1069
1315
|
return mat;
|
|
1070
1316
|
}
|
|
1071
1317
|
|
|
1318
|
+
/**
|
|
1319
|
+
* 恢复材质的「基础」混合状态(淡入结束 / 清除单体淡化 / 全局透明度滑回 1 时调用)。
|
|
1320
|
+
*
|
|
1321
|
+
* 材质的最终透明 = **自身语义透明**(alphaMode blend / 顶点色 alpha < 1 / 水面,
|
|
1322
|
+
* 创建时算好记在 `userData.s3mOpts.transparent`)|| 图层全局半透明。
|
|
1323
|
+
*
|
|
1324
|
+
* 以前各处恢复逻辑只看图层透明度(`transparent && !layerTransparent → false`),
|
|
1325
|
+
* 会把自身就是透明的材质(如 3D-BIMbuilding-2 的 SMID 4421)误关成不透明——
|
|
1326
|
+
* 症状是「刚进场景没透明度,切换材质质感重建后又有了」。
|
|
1327
|
+
*
|
|
1328
|
+
* depthWrite 跟随:自身 blend 材质保持创建时的 false;临时透明(淡入 / 全局淡出)
|
|
1329
|
+
* 则尊重调用方的 keepDepthWrite(默认 true,保持深度写入防漏背面)。
|
|
1330
|
+
*/
|
|
1331
|
+
export function restoreBaseBlendState(
|
|
1332
|
+
mat: THREE.Material,
|
|
1333
|
+
layerTransparent: boolean,
|
|
1334
|
+
keepDepthWrite = true
|
|
1335
|
+
): void {
|
|
1336
|
+
const opts = (mat as StyledMaterial).userData?.s3mOpts as StyledMaterialOptions | undefined;
|
|
1337
|
+
const baseTransparent = opts?.transparent === true;
|
|
1338
|
+
mat.transparent = baseTransparent || layerTransparent;
|
|
1339
|
+
mat.depthWrite = baseTransparent ? false : mat.transparent ? keepDepthWrite : true;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1072
1342
|
/* ------------------------------------------------------------------ 选中描边 */
|
|
1073
1343
|
|
|
1074
1344
|
const OUTLINE_VERT = /* glsl */ `
|