s3m-three 0.3.8 → 0.3.10
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/s3m-three.iife.ext-three.js +322 -47
- package/dist/browser/s3m-three.iife.js +322 -47
- package/dist/core/types.d.ts +20 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/render/EdgeLines.d.ts +18 -0
- package/dist/render/EdgeLines.d.ts.map +1 -1
- package/dist/render/EdgeLines.js +95 -13
- package/dist/render/EdgeLines.js.map +1 -1
- package/dist/render/FeatureStyleManager.d.ts +78 -0
- package/dist/render/FeatureStyleManager.d.ts.map +1 -1
- package/dist/render/FeatureStyleManager.js +407 -59
- package/dist/render/FeatureStyleManager.js.map +1 -1
- package/dist/render/GPUPathManager.d.ts +95 -0
- package/dist/render/GPUPathManager.d.ts.map +1 -0
- package/dist/render/GPUPathManager.js +265 -0
- package/dist/render/GPUPathManager.js.map +1 -0
- package/dist/render/OrthoProjection.d.ts +6 -0
- package/dist/render/OrthoProjection.d.ts.map +1 -1
- package/dist/render/OrthoProjection.js +48 -0
- package/dist/render/OrthoProjection.js.map +1 -1
- package/dist/render/S3MViewer.d.ts +66 -0
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +218 -6
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +21 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +256 -21
- package/dist/render/StyleMaterial.js.map +1 -1
- package/package.json +1 -1
- package/src/core/types.ts +10 -0
- package/src/index.ts +8 -0
- package/src/render/EdgeLines.ts +101 -13
- package/src/render/FeatureStyleManager.ts +524 -64
- package/src/render/GPUPathManager.ts +306 -0
- package/src/render/OrthoProjection.ts +52 -0
- package/src/render/S3MViewer.ts +272 -5
- package/src/render/StyleMaterial.ts +264 -21
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import * as THREE from 'three';
|
|
12
12
|
import type { StyleUniforms } from '../core/types.js';
|
|
13
13
|
import { DEFAULT_FLOOR_HEIGHT } from '../core/FeatureInfo.js';
|
|
14
|
+
import { GPUPathManager } from './GPUPathManager.js';
|
|
14
15
|
|
|
15
16
|
/** 着色模式,数值与着色器里的 uMode 一一对应 */
|
|
16
17
|
export const STYLE = {
|
|
@@ -172,6 +173,7 @@ export interface StyledMaterial extends THREE.MeshStandardMaterial {
|
|
|
172
173
|
uSelBatch: { value: number };
|
|
173
174
|
uSelWhole: { value: number };
|
|
174
175
|
uBatchTex: { value: THREE.Texture };
|
|
176
|
+
uBatchTex2: { value: THREE.Texture };
|
|
175
177
|
uBatchTexWidth: { value: number };
|
|
176
178
|
uBatchTexActive: { value: number };
|
|
177
179
|
/** 单块瓦片的淡入系数(1 = 完全显示) */
|
|
@@ -181,8 +183,15 @@ export interface StyledMaterial extends THREE.MeshStandardMaterial {
|
|
|
181
183
|
};
|
|
182
184
|
}
|
|
183
185
|
|
|
184
|
-
const DUMMY_DATA = new Float32Array([
|
|
185
|
-
|
|
186
|
+
const DUMMY_DATA = new Float32Array([
|
|
187
|
+
-1, -1, -1, 0, // Row 0: color rgb, elevation/hidden
|
|
188
|
+
0, 0, 0, 0, // Row 1: translation xyz, opacity
|
|
189
|
+
1, 0, 0, 0, // Row 2: rot row 0, pivot.x
|
|
190
|
+
0, 1, 0, 0, // Row 3: rot row 1, pivot.y
|
|
191
|
+
0, 0, 1, 0, // Row 4: rot row 2, pivot.z
|
|
192
|
+
-1, 0, 0, 0, // Row 5: pathId (-1=none), speed, phase, modeFlag
|
|
193
|
+
]);
|
|
194
|
+
export const DUMMY_BATCH_TEX = new THREE.DataTexture(DUMMY_DATA, 1, 6, THREE.RGBAFormat, THREE.FloatType);
|
|
186
195
|
DUMMY_BATCH_TEX.minFilter = THREE.NearestFilter;
|
|
187
196
|
DUMMY_BATCH_TEX.magFilter = THREE.NearestFilter;
|
|
188
197
|
DUMMY_BATCH_TEX.needsUpdate = true;
|
|
@@ -226,6 +235,16 @@ export function createSharedUniforms(): StyleUniforms {
|
|
|
226
235
|
uTexMix: { value: 0 },
|
|
227
236
|
/** 基础底色增益 / 暗部补偿(0~1,默认 0.0) */
|
|
228
237
|
uAmbientGain: { value: 0 },
|
|
238
|
+
/** 双纹理交叉淡化插值系数(0 = 纯 uBatchTex, 1 = 纯 uBatchTex2) */
|
|
239
|
+
uBatchMix: { value: 0 },
|
|
240
|
+
/** GPU 路径数据采样纹理 */
|
|
241
|
+
uPathTex: { value: GPUPathManager.DUMMY_PATH_TEX },
|
|
242
|
+
/** GPU 路径纹理中包含的路径条数(高度) */
|
|
243
|
+
uPathCount: { value: 1 },
|
|
244
|
+
/** 是否激活 GPU 路径动画(0 = 未激活,1 = 激活) */
|
|
245
|
+
uPathTexActive: { value: 0 },
|
|
246
|
+
/** GPU 路径时间戳(秒) */
|
|
247
|
+
uPathTime: { value: 0 },
|
|
229
248
|
/**
|
|
230
249
|
* 图层整体透明度:在片元里乘进 diffuseColor.a。
|
|
231
250
|
*
|
|
@@ -264,14 +283,25 @@ const VERT_PARS = /* glsl */ `
|
|
|
264
283
|
uniform float uSelWhole;
|
|
265
284
|
uniform float uSelElevation;
|
|
266
285
|
uniform sampler2D uBatchTex;
|
|
286
|
+
uniform sampler2D uBatchTex2;
|
|
287
|
+
uniform float uBatchMix;
|
|
267
288
|
uniform float uBatchTexWidth;
|
|
268
289
|
uniform int uBatchTexActive;
|
|
290
|
+
uniform sampler2D uPathTex;
|
|
291
|
+
uniform float uPathCount;
|
|
292
|
+
uniform float uPathTime;
|
|
293
|
+
uniform int uPathTexActive;
|
|
269
294
|
varying float vBatchId;
|
|
270
295
|
varying vec3 vVertColor;
|
|
271
296
|
varying float vWorldZ;
|
|
272
297
|
varying vec3 vWorldNormal;
|
|
273
298
|
varying vec3 vWorldPos;
|
|
274
299
|
|
|
300
|
+
// 跨 chunk 共享的顶点姿态变量(在 beginnormal_vertex 建立,begin_vertex / worldpos 使用)
|
|
301
|
+
vec3 s3mCustomOffset;
|
|
302
|
+
mat3 s3mRot;
|
|
303
|
+
vec3 s3mPivot;
|
|
304
|
+
|
|
275
305
|
/** 当前图元所属单体的控制位:实例化取实例属性,其余取逐顶点属性 */
|
|
276
306
|
float s3mBatchRaw() {
|
|
277
307
|
#ifdef USE_INSTANCING
|
|
@@ -280,27 +310,126 @@ const VERT_PARS = /* glsl */ `
|
|
|
280
310
|
return aBatchId;
|
|
281
311
|
#endif
|
|
282
312
|
}
|
|
313
|
+
|
|
314
|
+
vec4 s3mSampleBatch( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
315
|
+
vec4 vA = texture2D( texA, uv );
|
|
316
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
317
|
+
vec4 vB = texture2D( texB, uv );
|
|
318
|
+
return mix( vA, vB, mixVal );
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
vec4 s3mSampleBatchRow0( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
322
|
+
vec4 vA = texture2D( texA, uv );
|
|
323
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
324
|
+
vec4 vB = texture2D( texB, uv );
|
|
325
|
+
vec4 res = mix( vA, vB, mixVal );
|
|
326
|
+
if ( vA.r < 0.0 && vB.r >= 0.0 ) {
|
|
327
|
+
res.rgb = vB.rgb;
|
|
328
|
+
} else if ( vA.r >= 0.0 && vB.r < 0.0 ) {
|
|
329
|
+
res.rgb = vA.rgb;
|
|
330
|
+
}
|
|
331
|
+
if ( vA.a < -0.5 || vB.a < -0.5 ) {
|
|
332
|
+
res.a = ( mixVal >= 0.5 ) ? vB.a : vA.a;
|
|
333
|
+
}
|
|
334
|
+
return res;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
vec4 s3mSampleBatchRow1( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
338
|
+
vec4 vA = texture2D( texA, uv );
|
|
339
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
340
|
+
vec4 vB = texture2D( texB, uv );
|
|
341
|
+
vec4 res = mix( vA, vB, mixVal );
|
|
342
|
+
if ( vA.a == 0.0 && vB.a > 0.0 ) {
|
|
343
|
+
res.a = mix( 1.0, vB.a, mixVal );
|
|
344
|
+
} else if ( vA.a > 0.0 && vB.a == 0.0 ) {
|
|
345
|
+
res.a = mix( vA.a, 1.0, mixVal );
|
|
346
|
+
}
|
|
347
|
+
return res;
|
|
348
|
+
}
|
|
283
349
|
`;
|
|
284
350
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
351
|
+
const VERT_SETUP = /* glsl */ `
|
|
352
|
+
s3mCustomOffset = vec3( 0.0 );
|
|
353
|
+
s3mRot = mat3( 1.0 );
|
|
354
|
+
s3mPivot = vec3( 0.0 );
|
|
355
|
+
float s3mBatchSetup = s3mBatchRaw();
|
|
356
|
+
if ( uBatchTexActive > 0 && s3mBatchSetup >= 0.0 ) {
|
|
357
|
+
float s3mU = ( s3mBatchSetup + 0.5 ) / uBatchTexWidth;
|
|
358
|
+
vec4 bState = s3mSampleBatchRow0( uBatchTex, uBatchTex2, vec2( s3mU, 0.08333333 ), uBatchMix );
|
|
359
|
+
if ( bState.a >= -0.5 ) {
|
|
360
|
+
vec4 bOffset = s3mSampleBatchRow1( uBatchTex, uBatchTex2, vec2( s3mU, 0.25 ), uBatchMix );
|
|
294
361
|
s3mCustomOffset = bOffset.xyz;
|
|
295
362
|
if ( s3mCustomOffset.z == 0.0 && bState.a > 0.0 ) {
|
|
296
363
|
s3mCustomOffset.z = bState.a;
|
|
297
364
|
}
|
|
365
|
+
vec4 r2 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.41666667 ), uBatchMix );
|
|
366
|
+
vec4 r3 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.58333333 ), uBatchMix );
|
|
367
|
+
vec4 r4 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.75 ), uBatchMix );
|
|
368
|
+
s3mRot = mat3(
|
|
369
|
+
vec3( r2.x, r3.x, r4.x ),
|
|
370
|
+
vec3( r2.y, r3.y, r4.y ),
|
|
371
|
+
vec3( r2.z, r3.z, r4.z )
|
|
372
|
+
);
|
|
373
|
+
s3mPivot = vec3( r2.w, r3.w, r4.w );
|
|
374
|
+
|
|
375
|
+
// Row 5: GPU 路径动画计算
|
|
376
|
+
if ( uPathTexActive > 0 ) {
|
|
377
|
+
vec4 r5 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.91666667 ), uBatchMix );
|
|
378
|
+
float pathId = r5.x;
|
|
379
|
+
float speed = r5.y;
|
|
380
|
+
float phase = r5.z;
|
|
381
|
+
float mode = r5.w;
|
|
382
|
+
if ( pathId >= 0.0 && mode > 0.5 && uPathCount > 0.0 ) {
|
|
383
|
+
float t = phase + uPathTime * speed;
|
|
384
|
+
bool autoHeading = true;
|
|
385
|
+
if ( mode >= 4.0 ) {
|
|
386
|
+
autoHeading = false;
|
|
387
|
+
mode -= 3.0;
|
|
388
|
+
}
|
|
389
|
+
if ( mode < 1.5 ) {
|
|
390
|
+
t = fract( t );
|
|
391
|
+
} else if ( mode < 2.5 ) {
|
|
392
|
+
t = clamp( t, 0.0, 1.0 );
|
|
393
|
+
} else {
|
|
394
|
+
t = mod( t, 2.0 );
|
|
395
|
+
t = ( t > 1.0 ) ? ( 2.0 - t ) : t;
|
|
396
|
+
}
|
|
397
|
+
float pathU = ( t * 255.0 + 0.5 ) / 256.0;
|
|
398
|
+
float pathV = ( pathId + 0.5 ) / uPathCount;
|
|
399
|
+
vec4 pathSample = texture2D( uPathTex, vec2( pathU, pathV ) );
|
|
400
|
+
vec3 pathPos = pathSample.xyz;
|
|
401
|
+
float pathYaw = pathSample.w;
|
|
402
|
+
if ( autoHeading ) {
|
|
403
|
+
float c = cos( pathYaw );
|
|
404
|
+
float s = sin( pathYaw );
|
|
405
|
+
mat3 rotHeading = mat3(
|
|
406
|
+
c, -s, 0.0,
|
|
407
|
+
s, c, 0.0,
|
|
408
|
+
0.0, 0.0, 1.0
|
|
409
|
+
);
|
|
410
|
+
s3mRot = rotHeading * s3mRot;
|
|
411
|
+
}
|
|
412
|
+
s3mCustomOffset += pathPos;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
298
415
|
}
|
|
299
416
|
}
|
|
417
|
+
objectNormal = normalize( s3mRot * objectNormal );
|
|
418
|
+
`;
|
|
300
419
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
420
|
+
const VERT_ELEVATION = /* glsl */ `
|
|
421
|
+
float s3mBatchElev = s3mBatchRaw();
|
|
422
|
+
if ( uBatchTexActive > 0 && s3mBatchElev >= 0.0 ) {
|
|
423
|
+
float s3mU = ( s3mBatchElev + 0.5 ) / uBatchTexWidth;
|
|
424
|
+
vec4 bState = s3mSampleBatchRow0( uBatchTex, uBatchTex2, vec2( s3mU, 0.08333333 ), uBatchMix );
|
|
425
|
+
if ( bState.a < -0.5 ) {
|
|
426
|
+
transformed = vec3( 0.0 );
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
float s3mSelElev = max( step( 0.0, uSelBatch ) * step( abs( s3mBatchElev - uSelBatch ), 0.5 ), uSelWhole );
|
|
431
|
+
// 刚体旋转以 s3mPivot 为中心,再叠加自定义平移与选中拔高
|
|
432
|
+
transformed = s3mRot * ( transformed - s3mPivot ) + s3mPivot + s3mCustomOffset;
|
|
304
433
|
transformed.z += s3mSelElev * uSelElevation;
|
|
305
434
|
`;
|
|
306
435
|
|
|
@@ -328,7 +457,7 @@ const VERT_WORLD = /* glsl */ `
|
|
|
328
457
|
#else
|
|
329
458
|
mat3 s3mNormMat = mat3( modelMatrix );
|
|
330
459
|
#endif
|
|
331
|
-
vWorldNormal = normalize( s3mNormMat * normal );
|
|
460
|
+
vWorldNormal = normalize( s3mNormMat * ( s3mRot * normal ) );
|
|
332
461
|
`;
|
|
333
462
|
|
|
334
463
|
const FRAG_PARS = /* glsl */ `
|
|
@@ -411,6 +540,8 @@ const FRAG_PARS = /* glsl */ `
|
|
|
411
540
|
uniform float uSelEmissive;
|
|
412
541
|
uniform float uDimFactor;
|
|
413
542
|
uniform sampler2D uBatchTex;
|
|
543
|
+
uniform sampler2D uBatchTex2;
|
|
544
|
+
uniform float uBatchMix;
|
|
414
545
|
uniform float uBatchTexWidth;
|
|
415
546
|
uniform int uBatchTexActive;
|
|
416
547
|
uniform float uFilterMinZ;
|
|
@@ -436,6 +567,35 @@ const FRAG_PARS = /* glsl */ `
|
|
|
436
567
|
varying vec3 vWorldNormal;
|
|
437
568
|
varying vec3 vWorldPos;
|
|
438
569
|
|
|
570
|
+
vec4 s3mSampleBatchRow0( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
571
|
+
vec4 vA = texture2D( texA, uv );
|
|
572
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
573
|
+
vec4 vB = texture2D( texB, uv );
|
|
574
|
+
vec4 res = mix( vA, vB, mixVal );
|
|
575
|
+
if ( vA.r < 0.0 && vB.r >= 0.0 ) {
|
|
576
|
+
res.rgb = vB.rgb;
|
|
577
|
+
} else if ( vA.r >= 0.0 && vB.r < 0.0 ) {
|
|
578
|
+
res.rgb = vA.rgb;
|
|
579
|
+
}
|
|
580
|
+
if ( vA.a < -0.5 || vB.a < -0.5 ) {
|
|
581
|
+
res.a = ( mixVal >= 0.5 ) ? vB.a : vA.a;
|
|
582
|
+
}
|
|
583
|
+
return res;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
vec4 s3mSampleBatchRow1( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
587
|
+
vec4 vA = texture2D( texA, uv );
|
|
588
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
589
|
+
vec4 vB = texture2D( texB, uv );
|
|
590
|
+
vec4 res = mix( vA, vB, mixVal );
|
|
591
|
+
if ( vA.a == 0.0 && vB.a > 0.0 ) {
|
|
592
|
+
res.a = mix( 1.0, vB.a, mixVal );
|
|
593
|
+
} else if ( vA.a > 0.0 && vB.a == 0.0 ) {
|
|
594
|
+
res.a = mix( vA.a, 1.0, mixVal );
|
|
595
|
+
}
|
|
596
|
+
return res;
|
|
597
|
+
}
|
|
598
|
+
|
|
439
599
|
float s3mHash( float p ) {
|
|
440
600
|
p = fract( p * 0.1031 );
|
|
441
601
|
p *= p + 33.33;
|
|
@@ -531,7 +691,8 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
531
691
|
bool hasCustomColor = false;
|
|
532
692
|
if ( uBatchTexActive > 0 && s3mBid >= 0.0 ) {
|
|
533
693
|
// 用取整后的 id 采样:否则逐像素的插值误差会让纹素在边界上来回跳,同样出彩色噪点
|
|
534
|
-
|
|
694
|
+
float s3mU = ( s3mBid + 0.5 ) / uBatchTexWidth;
|
|
695
|
+
vec4 bState = s3mSampleBatchRow0( uBatchTex, uBatchTex2, vec2( s3mU, 0.08333333 ), uBatchMix );
|
|
535
696
|
if ( bState.a < -0.5 ) {
|
|
536
697
|
discard; // 属于被过滤隐藏的单体
|
|
537
698
|
}
|
|
@@ -542,7 +703,7 @@ const FRAG_COLOR = /* glsl */ `
|
|
|
542
703
|
}
|
|
543
704
|
// 单体独立透明度(状态纹理第 2 行 alpha,0 = 无覆盖)。
|
|
544
705
|
// 与全局 uOpacity(diffuseColor.a 初值)和图集贴图自带 alpha 逐级叠乘
|
|
545
|
-
vec4 bOffset =
|
|
706
|
+
vec4 bOffset = s3mSampleBatchRow1( uBatchTex, uBatchTex2, vec2( s3mU, 0.25 ), uBatchMix );
|
|
546
707
|
if ( bOffset.a > 0.0 ) {
|
|
547
708
|
diffuseColor.a *= bOffset.a;
|
|
548
709
|
}
|
|
@@ -643,6 +804,7 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
643
804
|
// 没有单体化信息的几何(batchId = -1)只能整块选中
|
|
644
805
|
const uSelWhole = { value: 0 };
|
|
645
806
|
const uBatchTex = { value: DUMMY_BATCH_TEX };
|
|
807
|
+
const uBatchTex2 = { value: DUMMY_BATCH_TEX };
|
|
646
808
|
const uBatchTexWidth = { value: 1.0 };
|
|
647
809
|
const uBatchTexActive = { value: 0 };
|
|
648
810
|
/** 单块瓦片的淡入系数:逐材质独享(每块网格一份材质),默认 1 = 完全显示 */
|
|
@@ -662,6 +824,7 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
662
824
|
uSelBatch,
|
|
663
825
|
uSelWhole,
|
|
664
826
|
uBatchTex,
|
|
827
|
+
uBatchTex2,
|
|
665
828
|
uBatchTexWidth,
|
|
666
829
|
uBatchTexActive,
|
|
667
830
|
uTileFade,
|
|
@@ -672,6 +835,7 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
672
835
|
|
|
673
836
|
shader.vertexShader = shader.vertexShader
|
|
674
837
|
.replace('#include <common>', `#include <common>\n${VERT_PARS}`)
|
|
838
|
+
.replace('#include <beginnormal_vertex>', `#include <beginnormal_vertex>\n${VERT_SETUP}`)
|
|
675
839
|
.replace('#include <begin_vertex>', `#include <begin_vertex>\n${VERT_ELEVATION}`)
|
|
676
840
|
.replace('#include <worldpos_vertex>', VERT_WORLD);
|
|
677
841
|
|
|
@@ -706,6 +870,7 @@ export function createStyledMaterial(opts: StyledMaterialOptions): StyledMateria
|
|
|
706
870
|
mat.userData.uSelBatch = uSelBatch;
|
|
707
871
|
mat.userData.uSelWhole = uSelWhole;
|
|
708
872
|
mat.userData.uBatchTex = uBatchTex;
|
|
873
|
+
mat.userData.uBatchTex2 = uBatchTex2;
|
|
709
874
|
mat.userData.uBatchTexWidth = uBatchTexWidth;
|
|
710
875
|
mat.userData.uBatchTexActive = uBatchTexActive;
|
|
711
876
|
mat.userData.uTileFade = uTileFade;
|
|
@@ -722,26 +887,92 @@ const OUTLINE_VERT = /* glsl */ `
|
|
|
722
887
|
uniform float uWidth;
|
|
723
888
|
uniform float uElevation;
|
|
724
889
|
uniform sampler2D uBatchTex;
|
|
890
|
+
uniform sampler2D uBatchTex2;
|
|
891
|
+
uniform float uBatchMix;
|
|
725
892
|
uniform float uBatchTexWidth;
|
|
726
893
|
uniform int uBatchTexActive;
|
|
894
|
+
uniform sampler2D uPathTex;
|
|
895
|
+
uniform float uPathCount;
|
|
896
|
+
uniform float uPathTime;
|
|
897
|
+
uniform int uPathTexActive;
|
|
727
898
|
varying float vSel;
|
|
899
|
+
|
|
900
|
+
vec4 s3mSampleBatch( sampler2D texA, sampler2D texB, vec2 uv, float mixVal ) {
|
|
901
|
+
vec4 vA = texture2D( texA, uv );
|
|
902
|
+
if ( mixVal <= 0.0001 ) return vA;
|
|
903
|
+
vec4 vB = texture2D( texB, uv );
|
|
904
|
+
return mix( vA, vB, mixVal );
|
|
905
|
+
}
|
|
906
|
+
|
|
728
907
|
void main() {
|
|
729
908
|
vSel = max( step( 0.0, uSelBatch ) * step( abs( aBatchId - uSelBatch ), 0.5 ), uSelWhole );
|
|
730
909
|
vec3 s3mCustomOffset = vec3( 0.0 );
|
|
910
|
+
mat3 s3mRot = mat3( 1.0 );
|
|
911
|
+
vec3 s3mPivot = vec3( 0.0 );
|
|
731
912
|
if ( uBatchTexActive > 0 && aBatchId >= 0.0 ) {
|
|
732
|
-
|
|
913
|
+
float s3mU = ( aBatchId + 0.5 ) / uBatchTexWidth;
|
|
914
|
+
vec4 bState = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.08333333 ), uBatchMix );
|
|
733
915
|
if ( bState.a < -0.5 ) {
|
|
734
916
|
vSel = 0.0; // 过滤隐藏的单体不显示描边
|
|
735
917
|
} else {
|
|
736
|
-
vec4 bOffset =
|
|
918
|
+
vec4 bOffset = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.25 ), uBatchMix );
|
|
737
919
|
s3mCustomOffset = bOffset.xyz;
|
|
738
920
|
if ( s3mCustomOffset.z == 0.0 && bState.a > 0.0 ) {
|
|
739
921
|
s3mCustomOffset.z = bState.a;
|
|
740
922
|
}
|
|
923
|
+
vec4 r2 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.41666667 ), uBatchMix );
|
|
924
|
+
vec4 r3 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.58333333 ), uBatchMix );
|
|
925
|
+
vec4 r4 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.75 ), uBatchMix );
|
|
926
|
+
s3mRot = mat3(
|
|
927
|
+
vec3( r2.x, r3.x, r4.x ),
|
|
928
|
+
vec3( r2.y, r3.y, r4.y ),
|
|
929
|
+
vec3( r2.z, r3.z, r4.z )
|
|
930
|
+
);
|
|
931
|
+
s3mPivot = vec3( r2.w, r3.w, r4.w );
|
|
932
|
+
|
|
933
|
+
if ( uPathTexActive > 0 ) {
|
|
934
|
+
vec4 r5 = s3mSampleBatch( uBatchTex, uBatchTex2, vec2( s3mU, 0.91666667 ), uBatchMix );
|
|
935
|
+
float pathId = r5.x;
|
|
936
|
+
float speed = r5.y;
|
|
937
|
+
float phase = r5.z;
|
|
938
|
+
float mode = r5.w;
|
|
939
|
+
if ( pathId >= 0.0 && mode > 0.5 && uPathCount > 0.0 ) {
|
|
940
|
+
float t = phase + uPathTime * speed;
|
|
941
|
+
bool autoHeading = true;
|
|
942
|
+
if ( mode >= 4.0 ) {
|
|
943
|
+
autoHeading = false;
|
|
944
|
+
mode -= 3.0;
|
|
945
|
+
}
|
|
946
|
+
if ( mode < 1.5 ) {
|
|
947
|
+
t = fract( t );
|
|
948
|
+
} else if ( mode < 2.5 ) {
|
|
949
|
+
t = clamp( t, 0.0, 1.0 );
|
|
950
|
+
} else {
|
|
951
|
+
t = mod( t, 2.0 );
|
|
952
|
+
t = ( t > 1.0 ) ? ( 2.0 - t ) : t;
|
|
953
|
+
}
|
|
954
|
+
float pathU = ( t * 255.0 + 0.5 ) / 256.0;
|
|
955
|
+
float pathV = ( pathId + 0.5 ) / uPathCount;
|
|
956
|
+
vec4 pathSample = texture2D( uPathTex, vec2( pathU, pathV ) );
|
|
957
|
+
vec3 pathPos = pathSample.xyz;
|
|
958
|
+
float pathYaw = pathSample.w;
|
|
959
|
+
if ( autoHeading ) {
|
|
960
|
+
float c = cos( pathYaw );
|
|
961
|
+
float s = sin( pathYaw );
|
|
962
|
+
mat3 rotHeading = mat3(
|
|
963
|
+
c, -s, 0.0,
|
|
964
|
+
s, c, 0.0,
|
|
965
|
+
0.0, 0.0, 1.0
|
|
966
|
+
);
|
|
967
|
+
s3mRot = rotHeading * s3mRot;
|
|
968
|
+
}
|
|
969
|
+
s3mCustomOffset += pathPos;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
741
972
|
}
|
|
742
973
|
}
|
|
743
|
-
vec3 p = position + normal * uWidth * vSel;
|
|
744
|
-
p
|
|
974
|
+
vec3 p = position + ( s3mRot * normal ) * uWidth * vSel;
|
|
975
|
+
p = s3mRot * ( p - s3mPivot ) + s3mPivot + s3mCustomOffset;
|
|
745
976
|
p.z += vSel * uElevation;
|
|
746
977
|
gl_Position = projectionMatrix * modelViewMatrix * vec4( p, 1.0 );
|
|
747
978
|
}
|
|
@@ -763,8 +994,14 @@ export interface OutlineMaterial extends THREE.ShaderMaterial {
|
|
|
763
994
|
uWidth: { value: number };
|
|
764
995
|
uElevation: { value: number };
|
|
765
996
|
uBatchTex: { value: THREE.Texture };
|
|
997
|
+
uBatchTex2: { value: THREE.Texture };
|
|
998
|
+
uBatchMix: { value: number };
|
|
766
999
|
uBatchTexWidth: { value: number };
|
|
767
1000
|
uBatchTexActive: { value: number };
|
|
1001
|
+
uPathTex: { value: unknown };
|
|
1002
|
+
uPathCount: { value: number };
|
|
1003
|
+
uPathTexActive: { value: number };
|
|
1004
|
+
uPathTime: { value: number };
|
|
768
1005
|
uColor: { value: THREE.Color };
|
|
769
1006
|
};
|
|
770
1007
|
}
|
|
@@ -778,8 +1015,14 @@ export function createOutlineMaterial(shared: StyleUniforms, initialWidth = 0.9)
|
|
|
778
1015
|
uWidth: { value: initialWidth },
|
|
779
1016
|
uElevation: { value: 0 },
|
|
780
1017
|
uBatchTex: { value: DUMMY_BATCH_TEX },
|
|
1018
|
+
uBatchTex2: { value: DUMMY_BATCH_TEX },
|
|
1019
|
+
uBatchMix: shared.uBatchMix ?? { value: 0 },
|
|
781
1020
|
uBatchTexWidth: { value: 1.0 },
|
|
782
1021
|
uBatchTexActive: { value: 0 },
|
|
1022
|
+
uPathTex: shared.uPathTex ?? { value: GPUPathManager.DUMMY_PATH_TEX },
|
|
1023
|
+
uPathCount: shared.uPathCount ?? { value: 1 },
|
|
1024
|
+
uPathTexActive: shared.uPathTexActive ?? { value: 0 },
|
|
1025
|
+
uPathTime: shared.uPathTime ?? { value: 0 },
|
|
783
1026
|
uColor: { value: shared.uSelColor.value.clone() },
|
|
784
1027
|
},
|
|
785
1028
|
vertexShader: OUTLINE_VERT,
|