@navaramap/three 0.0.5 → 0.0.6
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/README.md +1 -1
- package/dist/assets/fontWorker-JfTCpd38.js +2 -0
- package/dist/assets/fontWorker-JfTCpd38.js.map +1 -0
- package/dist/assets/{index-TKhRxurv.js → index-B3U_DvcP.js} +2 -2
- package/dist/assets/index-B3U_DvcP.js.map +1 -0
- package/dist/assets/{navara_wasm_font_worker_bg-Kk06ArRB.wasm → navara_wasm_font_worker_bg-DympKYVX.wasm} +0 -0
- package/dist/assets/{navara_wasm_worker_bg-BZjLKf4i.wasm → navara_wasm_worker_bg-Bx_l45cW.wasm} +0 -0
- package/dist/index.d.ts +510 -374
- package/dist/index.js +6150 -5810
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1188 -793
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +12 -12
- package/src/core/DescRegistry.ts +3 -2
- package/src/core/EffectDesc.ts +10 -0
- package/src/core/EffectDescRegistry.ts +14 -0
- package/src/core/MeshDesc.ts +39 -2
- package/src/core/MeshDescWithSelectiveEffect.ts +14 -2
- package/src/core/ViewContext.ts +116 -7
- package/src/device.ts +4 -2
- package/src/index.ts +123 -11
- package/src/layer.ts +7 -5
- package/src/layers/effect/MRTPassEffectDesc.ts +34 -3
- package/src/layers/effect/SelectiveEffectDesc.ts +10 -2
- package/src/layers/effect/TransparentPassEffectDesc.ts +5 -4
- package/src/layersManager.ts +32 -1
- package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +3 -2
- package/src/material/enhancer/polygon/polygonBaseEnhancer/index.ts +0 -6
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +0 -6
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +4 -10
- package/src/material/enhancer/polygon/polygonBaseEnhancer/state.ts +1 -4
- package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +0 -9
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/coverage.ts +31 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.test.ts +75 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.ts +26 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +1 -1
- package/src/material/gbufferLayout.test.ts +171 -0
- package/src/material/gbufferLayout.ts +298 -0
- package/src/material/index.ts +1 -0
- package/src/material/macro/tileShader.test.ts +35 -33
- package/src/material/macro/tileShader.ts +33 -10
- package/src/material/overrideMaterialsForMRT.ts +113 -71
- package/src/mesh/DrapedMesh.test.ts +57 -0
- package/src/mesh/DrapedMesh.ts +82 -0
- package/src/mesh/model.ts +3 -0
- package/src/mesh/polygon.ts +3 -2
- package/src/mesh/polyline.ts +3 -0
- package/src/mesh/sdfText/layout.ts +1 -3
- package/src/mesh/tile/index.ts +8 -4
- package/src/passes/CustomRenderPass.test.ts +143 -0
- package/src/passes/CustomRenderPass.ts +273 -30
- package/src/passes/RenderTargetCopyPass.ts +6 -0
- package/src/plugins/AttributionPlugin/index.ts +3 -2
- package/src/shaders/index.ts +16 -0
- package/src/type/index.ts +9 -51
- package/dist/assets/fontWorker-OwvKiQ8o.js +0 -2
- package/dist/assets/fontWorker-OwvKiQ8o.js.map +0 -1
- package/dist/assets/index-TKhRxurv.js.map +0 -1
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
// Ref: https://github.com/takram-design-engineering/three-geospatial/blob/main/packages/effects/src/setupMaterialsForGeometryPass.ts
|
|
2
2
|
|
|
3
3
|
import { packing } from "@takram/three-geospatial/shaders";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ShaderLib,
|
|
6
|
+
ShaderMaterial,
|
|
7
|
+
type Material,
|
|
8
|
+
type ShaderLibShader,
|
|
9
|
+
} from "three";
|
|
5
10
|
import { LineMaterial } from "three-stdlib";
|
|
6
11
|
|
|
7
12
|
import { createReplacer } from "../utils";
|
|
8
13
|
|
|
14
|
+
import {
|
|
15
|
+
GBUFFER_EFFECT_WRITE_BUILTIN,
|
|
16
|
+
GBUFFER_EFFECT_WRITE_ID_ONLY,
|
|
17
|
+
GBUFFER_EFFECT_WRITE_SHADER_MATERIAL,
|
|
18
|
+
GBUFFER_EFFECT_WRITE_ZERO,
|
|
19
|
+
GBUFFER_NORMAL_WRITE_BASIC,
|
|
20
|
+
GBUFFER_NORMAL_WRITE_PHYSICAL,
|
|
21
|
+
GBUFFER_PARS_FRAGMENT,
|
|
22
|
+
} from "./gbufferLayout";
|
|
23
|
+
|
|
9
24
|
const SETUP = Symbol("SETUP");
|
|
10
25
|
|
|
26
|
+
/** `lit: true` – wins over {@link NVR_UNLIT_SCENE_DEFINE}. */
|
|
27
|
+
export const NVR_LIT_DEFINE = "NVR_LIT";
|
|
28
|
+
/** `lit: false` – only the lighting equation is bypassed; the lit pipeline
|
|
29
|
+
* still runs, so normals and the shadow G-buffer keep being written. */
|
|
30
|
+
export const NVR_UNLIT_DEFINE = "NVR_UNLIT";
|
|
31
|
+
/** Scene-level default, stamped by `CustomRenderPass` from `view.lit`. */
|
|
32
|
+
export const NVR_UNLIT_SCENE_DEFINE = "NVR_UNLIT_SCENE";
|
|
33
|
+
/**
|
|
34
|
+
* Stamped from `material.transparent`. Under blending, `normalBuffer.a` is
|
|
35
|
+
* the attachment's blend factor, so a blended material must write 1.0 there
|
|
36
|
+
* instead of roughness or it keeps the normal of whatever lies behind.
|
|
37
|
+
*/
|
|
38
|
+
export const NVR_BLENDED_DEFINE = "NVR_BLENDED";
|
|
39
|
+
|
|
40
|
+
/** Applies a material's three-state `lit` option. */
|
|
41
|
+
export function applyLitOption(
|
|
42
|
+
material: Material,
|
|
43
|
+
lit: boolean | undefined,
|
|
44
|
+
): void {
|
|
45
|
+
// `false` is three's "absent" define value, avoiding a delete.
|
|
46
|
+
const forceLit = lit === true ? 1 : false;
|
|
47
|
+
const forceUnlit = lit === false ? 1 : false;
|
|
48
|
+
material.defines ??= {};
|
|
49
|
+
if (
|
|
50
|
+
(material.defines[NVR_LIT_DEFINE] ?? false) === forceLit &&
|
|
51
|
+
(material.defines[NVR_UNLIT_DEFINE] ?? false) === forceUnlit
|
|
52
|
+
) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
material.defines[NVR_LIT_DEFINE] = forceLit;
|
|
56
|
+
material.defines[NVR_UNLIT_DEFINE] = forceUnlit;
|
|
57
|
+
material.needsUpdate = true;
|
|
58
|
+
}
|
|
59
|
+
|
|
11
60
|
declare module "three" {
|
|
12
61
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
13
62
|
interface ShaderLibShader {
|
|
@@ -94,27 +143,20 @@ function injectGBuffer(
|
|
|
94
143
|
const normalBufferWrite =
|
|
95
144
|
type === "physical"
|
|
96
145
|
? /* glsl */ `
|
|
97
|
-
|
|
146
|
+
${GBUFFER_NORMAL_WRITE_PHYSICAL}
|
|
98
147
|
`
|
|
99
148
|
: /* glsl */ `
|
|
100
149
|
#ifdef USE_ROUGHNESS
|
|
101
150
|
float roughnessFactor = roughness;
|
|
102
151
|
#else
|
|
103
|
-
|
|
152
|
+
// Not just a default: 0.0 here would leak the normal behind a
|
|
153
|
+
// blended surface (see NVR_BLENDED_DEFINE).
|
|
154
|
+
float roughnessFactor = 1.0;
|
|
104
155
|
#endif
|
|
105
|
-
|
|
156
|
+
${GBUFFER_NORMAL_WRITE_BASIC}
|
|
106
157
|
`;
|
|
107
158
|
shader.fragmentShader = /* glsl */ `
|
|
108
|
-
|
|
109
|
-
// location 0: gl_FragColor (color)
|
|
110
|
-
// location 1: normalBuffer (normal + material props)
|
|
111
|
-
// location 2: effectIdBuffer (effectIds: R=bitmask) — SelectiveEffect only
|
|
112
|
-
// location 3: emissiveBuffer (emissive: RGB=diffuseColor×intensity+emissive additive, A=unused) — SelectiveEffect only
|
|
113
|
-
#ifndef USE_SHADOWMAP_DEPTH
|
|
114
|
-
layout(location = 1) out vec4 normalBuffer;
|
|
115
|
-
layout(location = 2) out vec4 effectIdBuffer;
|
|
116
|
-
layout(location = 3) out vec4 emissiveBuffer;
|
|
117
|
-
#endif
|
|
159
|
+
${GBUFFER_PARS_FRAGMENT}
|
|
118
160
|
|
|
119
161
|
#if !defined(USE_ENVMAP)
|
|
120
162
|
uniform float reflectivity;
|
|
@@ -131,23 +173,35 @@ function injectGBuffer(
|
|
|
131
173
|
|
|
132
174
|
${packing}
|
|
133
175
|
${
|
|
134
|
-
createReplacer(shader.fragmentShader)
|
|
135
|
-
|
|
136
|
-
|
|
176
|
+
createReplacer(shader.fragmentShader)
|
|
177
|
+
.replace(
|
|
178
|
+
/* glsl */ `#include <opaque_fragment>`,
|
|
179
|
+
/* glsl */ `
|
|
180
|
+
#if !defined(${NVR_LIT_DEFINE}) && (defined(${NVR_UNLIT_DEFINE}) || defined(${NVR_UNLIT_SCENE_DEFINE}))
|
|
181
|
+
// Overwrite rather than skip the lighting: the G-buffer writes
|
|
182
|
+
// below still need the lit pipeline to have run.
|
|
183
|
+
outgoingLight = diffuseColor.rgb;
|
|
184
|
+
#endif
|
|
185
|
+
#include <opaque_fragment>
|
|
186
|
+
`,
|
|
187
|
+
)
|
|
188
|
+
.replace(
|
|
189
|
+
/}\s*$/, // Assume the last curly brace is of main()
|
|
190
|
+
/* glsl */ `
|
|
137
191
|
#ifndef USE_SHADOWMAP_DEPTH
|
|
138
|
-
${normalBufferWrite}
|
|
192
|
+
${normalBufferWrite}
|
|
139
193
|
|
|
140
194
|
#ifdef USE_SELECTIVE_EFFECT
|
|
141
|
-
|
|
142
|
-
emissiveBuffer = vec4(diffuseColor.rgb * uEmissiveIntensity + emissive, 1.0);
|
|
195
|
+
${GBUFFER_EFFECT_WRITE_BUILTIN}
|
|
143
196
|
#else
|
|
144
|
-
|
|
145
|
-
emissiveBuffer = vec4(0.0);
|
|
197
|
+
${GBUFFER_EFFECT_WRITE_ZERO}
|
|
146
198
|
#endif
|
|
199
|
+
|
|
200
|
+
GBUFFER_WRITE_SHADOW
|
|
147
201
|
#endif
|
|
148
202
|
}
|
|
149
203
|
`,
|
|
150
|
-
|
|
204
|
+
).source
|
|
151
205
|
}
|
|
152
206
|
`;
|
|
153
207
|
shader[SETUP] = true;
|
|
@@ -173,9 +227,7 @@ function injectGBufferToSpriteMaterial(shader: ShaderLibShader) {
|
|
|
173
227
|
`;
|
|
174
228
|
|
|
175
229
|
shader.fragmentShader = /* glsl */ `
|
|
176
|
-
|
|
177
|
-
layout(location = 2) out vec4 effectIdBuffer;
|
|
178
|
-
layout(location = 3) out vec4 emissiveBuffer;
|
|
230
|
+
${GBUFFER_PARS_FRAGMENT}
|
|
179
231
|
|
|
180
232
|
#ifdef USE_SELECTIVE_EFFECT
|
|
181
233
|
uniform float uEffectIdsMask;
|
|
@@ -189,22 +241,21 @@ function injectGBufferToSpriteMaterial(shader: ShaderLibShader) {
|
|
|
189
241
|
createReplacer(shader.fragmentShader).replace(
|
|
190
242
|
/}\s*$/, // Assume the last curly brace is of main()
|
|
191
243
|
/* glsl */ `
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
0.0,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
emissiveBuffer = vec4(0.0);
|
|
244
|
+
#ifndef USE_SHADOWMAP_DEPTH
|
|
245
|
+
// Flat shading
|
|
246
|
+
vec3 fdx = dFdx( vViewPosition );
|
|
247
|
+
vec3 fdy = dFdy( vViewPosition );
|
|
248
|
+
vec3 normal = normalize( cross( fdx, fdy ) );
|
|
249
|
+
// A=1.0 replaces the normal behind under blending.
|
|
250
|
+
GBUFFER_WRITE_NORMAL(normal, 0.0, 1.0)
|
|
251
|
+
|
|
252
|
+
#ifdef USE_SELECTIVE_EFFECT
|
|
253
|
+
${GBUFFER_EFFECT_WRITE_ID_ONLY}
|
|
254
|
+
#else
|
|
255
|
+
${GBUFFER_EFFECT_WRITE_ZERO}
|
|
256
|
+
#endif
|
|
257
|
+
|
|
258
|
+
GBUFFER_WRITE_SHADOW_ZERO
|
|
208
259
|
#endif
|
|
209
260
|
}
|
|
210
261
|
`,
|
|
@@ -269,18 +320,12 @@ function injectGBufferToShaderMaterial(
|
|
|
269
320
|
const logdepthParsFrag = "#include <logdepthbuf_pars_fragment>";
|
|
270
321
|
const logdepthFrag = "#include <logdepthbuf_fragment>";
|
|
271
322
|
const normalBufferWrite = /* glsl */ `
|
|
272
|
-
|
|
273
|
-
packNormalToVec2(${normalVariableName}),
|
|
274
|
-
0.0,
|
|
275
|
-
0.0
|
|
276
|
-
);
|
|
323
|
+
GBUFFER_WRITE_NORMAL(${normalVariableName}, 0.0, 1.0)
|
|
277
324
|
`;
|
|
278
325
|
shader.fragmentShader = /* glsl */ `
|
|
279
|
-
|
|
280
|
-
layout(location = 1) out vec4 normalBuffer;
|
|
281
|
-
layout(location = 2) out vec4 effectIdBuffer;
|
|
282
|
-
layout(location = 3) out vec4 emissiveBuffer;
|
|
326
|
+
${GBUFFER_PARS_FRAGMENT}
|
|
283
327
|
|
|
328
|
+
#ifndef USE_SHADOWMAP_DEPTH
|
|
284
329
|
#ifdef USE_SELECTIVE_EFFECT
|
|
285
330
|
uniform float uEffectIdsMask;
|
|
286
331
|
uniform vec3 uEmissiveColor;
|
|
@@ -299,15 +344,15 @@ function injectGBufferToShaderMaterial(
|
|
|
299
344
|
${shader.fragmentShader.includes(logdepthFrag) ? "" : logdepthFrag}
|
|
300
345
|
|
|
301
346
|
#ifndef USE_SHADOWMAP_DEPTH
|
|
302
|
-
|
|
347
|
+
${normalBufferWrite};
|
|
303
348
|
|
|
304
349
|
#ifdef USE_SELECTIVE_EFFECT
|
|
305
|
-
|
|
306
|
-
emissiveBuffer = vec4((gl_FragColor.rgb + uEmissiveColor) * uEmissiveIntensity, 1.0);
|
|
350
|
+
${GBUFFER_EFFECT_WRITE_SHADER_MATERIAL}
|
|
307
351
|
#else
|
|
308
|
-
|
|
309
|
-
emissiveBuffer = vec4(0.0);
|
|
352
|
+
${GBUFFER_EFFECT_WRITE_ZERO}
|
|
310
353
|
#endif
|
|
354
|
+
|
|
355
|
+
GBUFFER_WRITE_SHADOW_ZERO
|
|
311
356
|
#endif
|
|
312
357
|
}
|
|
313
358
|
`,
|
|
@@ -350,9 +395,7 @@ function injectGBufferToLineMaterial(lineMaterial: LineMaterial) {
|
|
|
350
395
|
// LineMaterial already has proper vertex shader setup, so we only modify fragment shader
|
|
351
396
|
|
|
352
397
|
lineMaterial.fragmentShader = /* glsl */ `
|
|
353
|
-
|
|
354
|
-
layout(location = 2) out vec4 effectIdBuffer;
|
|
355
|
-
layout(location = 3) out vec4 emissiveBuffer;
|
|
398
|
+
${GBUFFER_PARS_FRAGMENT}
|
|
356
399
|
|
|
357
400
|
#ifdef USE_SELECTIVE_EFFECT
|
|
358
401
|
uniform float uEffectIdsMask;
|
|
@@ -378,18 +421,17 @@ function injectGBufferToLineMaterial(lineMaterial: LineMaterial) {
|
|
|
378
421
|
.replace(
|
|
379
422
|
/}\s*$/, // Assume the last curly brace is of main()
|
|
380
423
|
/* glsl */ `
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
0.0,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
emissiveBuffer = vec4(0.0);
|
|
424
|
+
#ifndef USE_SHADOWMAP_DEPTH
|
|
425
|
+
// A=1.0 replaces the normal behind under blending.
|
|
426
|
+
GBUFFER_WRITE_NORMAL(normal, 0.0, 1.0)
|
|
427
|
+
|
|
428
|
+
#ifdef USE_SELECTIVE_EFFECT
|
|
429
|
+
${GBUFFER_EFFECT_WRITE_ID_ONLY}
|
|
430
|
+
#else
|
|
431
|
+
${GBUFFER_EFFECT_WRITE_ZERO}
|
|
432
|
+
#endif
|
|
433
|
+
|
|
434
|
+
GBUFFER_WRITE_SHADOW_ZERO
|
|
393
435
|
#endif
|
|
394
436
|
}
|
|
395
437
|
`,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { MeshLambertMaterial, ShaderLib, type WebGLRenderer } from "three";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { overrideMaterialsForMRT } from "../material";
|
|
5
|
+
|
|
6
|
+
import { setupMaterialForDrape } from "./DrapedMesh";
|
|
7
|
+
|
|
8
|
+
type ShaderStub = Parameters<MeshLambertMaterial["onBeforeCompile"]>[0];
|
|
9
|
+
|
|
10
|
+
const compile = (material: MeshLambertMaterial): ShaderStub => {
|
|
11
|
+
const shader = {
|
|
12
|
+
name: "",
|
|
13
|
+
uniforms: {},
|
|
14
|
+
vertexShader: ShaderLib.lambert.vertexShader,
|
|
15
|
+
fragmentShader: ShaderLib.lambert.fragmentShader,
|
|
16
|
+
defines: {},
|
|
17
|
+
} as unknown as ShaderStub;
|
|
18
|
+
material.onBeforeCompile(shader, null as unknown as WebGLRenderer);
|
|
19
|
+
return shader;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe("setupMaterialForDrape", () => {
|
|
23
|
+
it("substitutes the globe normal ahead of the lighting", () => {
|
|
24
|
+
overrideMaterialsForMRT();
|
|
25
|
+
const material = new MeshLambertMaterial();
|
|
26
|
+
const globeNormal = { value: null };
|
|
27
|
+
|
|
28
|
+
setupMaterialForDrape(material, globeNormal);
|
|
29
|
+
const shader = compile(material);
|
|
30
|
+
|
|
31
|
+
expect(shader.fragmentShader).toContain("nvrDrapeUv");
|
|
32
|
+
expect(shader.uniforms.uGlobeNormal).toBe(globeNormal);
|
|
33
|
+
expect(shader.fragmentShader.indexOf("nvrDrapeUv")).toBeLessThan(
|
|
34
|
+
shader.fragmentShader.indexOf("#include <lights_fragment_begin>"),
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("injects even when an earlier handler consumes the anchor", () => {
|
|
39
|
+
// navara_three_csm swaps `#include <lights_fragment_begin>` for its
|
|
40
|
+
// cascaded-lights chunk. Delegating to it first left nothing to anchor to,
|
|
41
|
+
// so the substitution silently never happened.
|
|
42
|
+
overrideMaterialsForMRT();
|
|
43
|
+
const material = new MeshLambertMaterial();
|
|
44
|
+
material.onBeforeCompile = (shader) => {
|
|
45
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
46
|
+
"#include <lights_fragment_begin>",
|
|
47
|
+
"// cascaded lights",
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
setupMaterialForDrape(material, { value: null });
|
|
52
|
+
const shader = compile(material);
|
|
53
|
+
|
|
54
|
+
expect(shader.fragmentShader).toContain("nvrDrapeUv");
|
|
55
|
+
expect(shader.fragmentShader).toContain("// cascaded lights");
|
|
56
|
+
});
|
|
57
|
+
});
|
package/src/mesh/DrapedMesh.ts
CHANGED
|
@@ -12,8 +12,69 @@ import {
|
|
|
12
12
|
type Material,
|
|
13
13
|
type NormalBufferAttributes,
|
|
14
14
|
type Object3DEventMap,
|
|
15
|
+
type Texture,
|
|
15
16
|
} from "three";
|
|
16
17
|
|
|
18
|
+
import { createReplacer } from "../utils";
|
|
19
|
+
|
|
20
|
+
const DRAPE_SETUP = Symbol("DRAPE_SETUP");
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Shades a draped material with the terrain's normal instead of its own. The
|
|
24
|
+
* visible fragments are the back faces of a volume clipped to the ground by
|
|
25
|
+
* {@link DrapedMesh.process}, so the mesh's own normals point in an arbitrary
|
|
26
|
+
* direction while the ground's normal is what the lighting should use.
|
|
27
|
+
*
|
|
28
|
+
* The decoder (`unpackVec2ToNormal`) comes from the packing helpers that
|
|
29
|
+
* `overrideMaterialsForMRT` puts in every `ShaderLib` material, so a custom
|
|
30
|
+
* `ShaderMaterial` in the draped scene needs to bring its own. Idempotent.
|
|
31
|
+
*
|
|
32
|
+
* @param globeNormal - Uniform ref for the globe normal copy, kept alive by
|
|
33
|
+
* the caller (see `CustomRenderPass`).
|
|
34
|
+
*/
|
|
35
|
+
export function setupMaterialForDrape(
|
|
36
|
+
material: Material,
|
|
37
|
+
globeNormal: { value: Texture | null },
|
|
38
|
+
): void {
|
|
39
|
+
const target = material as Material & { [DRAPE_SETUP]?: boolean };
|
|
40
|
+
if (target[DRAPE_SETUP]) return;
|
|
41
|
+
target[DRAPE_SETUP] = true;
|
|
42
|
+
|
|
43
|
+
// Draped and undraped materials must not share a compiled program.
|
|
44
|
+
const previousCacheKey = material.customProgramCacheKey;
|
|
45
|
+
material.customProgramCacheKey = () =>
|
|
46
|
+
`${previousCacheKey ? previousCacheKey.call(material) : ""}_NvrDraped`;
|
|
47
|
+
|
|
48
|
+
const previousOnBeforeCompile = material.onBeforeCompile;
|
|
49
|
+
material.onBeforeCompile = (shader, renderer) => {
|
|
50
|
+
// Runs BEFORE the previous handler on purpose: navara_three_csm swaps
|
|
51
|
+
// `#include <lights_fragment_begin>` for its cascaded-lights chunk, so
|
|
52
|
+
// delegating first would leave nothing to anchor to. The include survives
|
|
53
|
+
// this replacement, so the CSM swap still finds it afterwards.
|
|
54
|
+
const hook = "#include <lights_fragment_begin>";
|
|
55
|
+
// Absent from unlit materials, where drape shading is moot.
|
|
56
|
+
if (shader.fragmentShader.includes(hook)) {
|
|
57
|
+
shader.uniforms.uGlobeNormal = globeNormal;
|
|
58
|
+
shader.fragmentShader = createReplacer(
|
|
59
|
+
`uniform sampler2D uGlobeNormal;\n${shader.fragmentShader}`,
|
|
60
|
+
).replace(
|
|
61
|
+
hook,
|
|
62
|
+
`
|
|
63
|
+
{
|
|
64
|
+
vec2 nvrDrapeUv = gl_FragCoord.xy / vec2(textureSize(uGlobeNormal, 0));
|
|
65
|
+
normal = normalize(unpackVec2ToNormal(texture2D(uGlobeNormal, nvrDrapeUv).xy));
|
|
66
|
+
}
|
|
67
|
+
${hook}
|
|
68
|
+
`,
|
|
69
|
+
).source;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
previousOnBeforeCompile?.call(material, shader, renderer);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
material.needsUpdate = true;
|
|
76
|
+
}
|
|
77
|
+
|
|
17
78
|
export class DrapedMesh<
|
|
18
79
|
TGeometry extends BufferGeometry = BufferGeometry<NormalBufferAttributes>,
|
|
19
80
|
TMaterial extends Material | Material[] = Material | Material[],
|
|
@@ -24,6 +85,20 @@ export class DrapedMesh<
|
|
|
24
85
|
constructor(geometry?: TGeometry, material?: TMaterial, enable = true) {
|
|
25
86
|
super(geometry, material);
|
|
26
87
|
this.drapedEnable = enable;
|
|
88
|
+
|
|
89
|
+
// Shadows are forced off while draped: see process() for why the shading
|
|
90
|
+
// must not depend on world position. Installed as an own accessor because
|
|
91
|
+
// Object3D declares `receiveShadow` as a plain property, which TypeScript
|
|
92
|
+
// refuses to let a subclass override with a getter/setter (TS2611).
|
|
93
|
+
let receiveShadow = false;
|
|
94
|
+
Object.defineProperty(this, "receiveShadow", {
|
|
95
|
+
get: () => (this.drapedEnable ? false : receiveShadow),
|
|
96
|
+
set: (value: boolean) => {
|
|
97
|
+
receiveShadow = value;
|
|
98
|
+
},
|
|
99
|
+
configurable: true,
|
|
100
|
+
enumerable: true,
|
|
101
|
+
});
|
|
27
102
|
}
|
|
28
103
|
|
|
29
104
|
enabled() {
|
|
@@ -34,6 +109,13 @@ export class DrapedMesh<
|
|
|
34
109
|
* Run the stencil-test draping passes for this mesh.
|
|
35
110
|
* The caller supplies a `render` callback that performs the actual draw call
|
|
36
111
|
* (e.g. `renderer.render(scene, camera)`).
|
|
112
|
+
*
|
|
113
|
+
* The final pass draws every back face with the depth test off, so a pixel
|
|
114
|
+
* can be covered several times where the volume folds over a peak. The
|
|
115
|
+
* shading must therefore not depend on world position, or the far face
|
|
116
|
+
* shows through the near one — hence the screen-space normal from
|
|
117
|
+
* {@link setupMaterialForDrape} and the forced-off `receiveShadow`. The
|
|
118
|
+
* terrain underneath keeps its own shadows; only the drape stays lit.
|
|
37
119
|
*/
|
|
38
120
|
process(render: () => void): void {
|
|
39
121
|
if (!this.enabled()) return;
|
package/src/mesh/model.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import invariant from "tiny-invariant";
|
|
25
25
|
|
|
26
26
|
import type { EventContext } from "../event/context";
|
|
27
|
+
import { applyLitOption } from "../material";
|
|
27
28
|
import {
|
|
28
29
|
createModelMaterialEnhancer,
|
|
29
30
|
createPntsEnhancer,
|
|
@@ -306,6 +307,7 @@ export class ModelMesh
|
|
|
306
307
|
|
|
307
308
|
mesh.castShadow = !!meshMaterial.castShadow;
|
|
308
309
|
mesh.receiveShadow = !!meshMaterial.receiveShadow;
|
|
310
|
+
applyLitOption(mesh.material, meshMaterial.lit);
|
|
309
311
|
|
|
310
312
|
mesh.material.depthTest = true;
|
|
311
313
|
mesh.material.depthWrite = true;
|
|
@@ -369,6 +371,7 @@ export class ModelMesh
|
|
|
369
371
|
enhancer.update(updateProps);
|
|
370
372
|
mesh.castShadow = !!material.castShadow;
|
|
371
373
|
mesh.receiveShadow = !!material.receiveShadow;
|
|
374
|
+
applyLitOption(mesh.material, material.lit);
|
|
372
375
|
}
|
|
373
376
|
|
|
374
377
|
const pntsProps: PntsProps = {
|
package/src/mesh/polygon.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
PolygonMesh as NavaraPolygonMesh,
|
|
4
4
|
PolygonMaterial,
|
|
5
5
|
} from "@navaramap/engine";
|
|
6
|
-
import type { Texture } from "three";
|
|
7
6
|
import {
|
|
8
7
|
BufferAttribute,
|
|
9
8
|
BufferGeometry,
|
|
@@ -19,6 +18,7 @@ import {
|
|
|
19
18
|
|
|
20
19
|
import { PolygonOutlineMesh } from "..";
|
|
21
20
|
import type { EventContext } from "../event/context";
|
|
21
|
+
import { applyLitOption } from "../material";
|
|
22
22
|
import type { PolygonMaterialProps } from "../material/enhancer/polygon";
|
|
23
23
|
import { createPolygonMaterialEnhancer } from "../material/enhancer/polygon/polygonMaterialEnhancer";
|
|
24
24
|
|
|
@@ -286,6 +286,7 @@ export class PolygonMesh extends BatchedFeatureMesh<
|
|
|
286
286
|
|
|
287
287
|
this.castShadow = !!meshMaterial.castShadow;
|
|
288
288
|
this.receiveShadow = !!meshMaterial.receiveShadow;
|
|
289
|
+
applyLitOption(this.material, meshMaterial.lit);
|
|
289
290
|
|
|
290
291
|
// This mesh is texturized if it has a tile handle (terrain attachment).
|
|
291
292
|
// `!= null`, not truthiness: the root vector tile's handle is 0.
|
|
@@ -322,7 +323,6 @@ export class PolygonMesh extends BatchedFeatureMesh<
|
|
|
322
323
|
roughness: meshMaterial.roughness,
|
|
323
324
|
emissiveColor: meshMaterial.emissiveColor,
|
|
324
325
|
emissiveIntensity: meshMaterial.emissiveIntensity,
|
|
325
|
-
globeNormalTexture: uniforms.tGlobeNormal as { value: Texture | null },
|
|
326
326
|
useRTE,
|
|
327
327
|
},
|
|
328
328
|
water: {
|
|
@@ -411,6 +411,7 @@ export class PolygonMesh extends BatchedFeatureMesh<
|
|
|
411
411
|
}
|
|
412
412
|
this.castShadow = !!material.castShadow;
|
|
413
413
|
this.receiveShadow = !!material.receiveShadow;
|
|
414
|
+
applyLitOption(this.material, material.lit);
|
|
414
415
|
|
|
415
416
|
const { base } = enhancer.states();
|
|
416
417
|
|
package/src/mesh/polyline.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "three";
|
|
13
13
|
|
|
14
14
|
import type { EventContext } from "../event/context";
|
|
15
|
+
import { applyLitOption } from "../material";
|
|
15
16
|
import { createPolylineMaterialEnhancer } from "../material/enhancer";
|
|
16
17
|
|
|
17
18
|
import {
|
|
@@ -263,6 +264,7 @@ export class PolylineMesh extends BatchedFeatureMesh<
|
|
|
263
264
|
|
|
264
265
|
this.castShadow = !!meshMaterial.castShadow;
|
|
265
266
|
this.receiveShadow = !!meshMaterial.receiveShadow;
|
|
267
|
+
applyLitOption(this.material, meshMaterial.lit);
|
|
266
268
|
|
|
267
269
|
const isTexturized = mesh.should_be_texturized;
|
|
268
270
|
|
|
@@ -422,6 +424,7 @@ export class PolylineMesh extends BatchedFeatureMesh<
|
|
|
422
424
|
this.visible = enhancer.states().isTexturized ? shown : shown && active;
|
|
423
425
|
this.castShadow = !!material.castShadow;
|
|
424
426
|
this.receiveShadow = !!material.receiveShadow;
|
|
427
|
+
applyLitOption(this.material, material.lit);
|
|
425
428
|
|
|
426
429
|
const base = enhancer.states();
|
|
427
430
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
COLOR_GLYPH_PX_SIZE,
|
|
3
3
|
GlyphCharClass,
|
|
4
|
+
SDF_PX_SIZE,
|
|
4
5
|
type GlyphMetrics,
|
|
5
6
|
type ShapedGlyph,
|
|
6
7
|
type ShapeTextResult,
|
|
@@ -14,9 +15,6 @@ import {
|
|
|
14
15
|
* — the part with all the edge cases — unit-testable without a GL context.
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
/** Must match Rust `SDF_PX_SIZE` in `crates/navara_wasm_font_worker/src/atlas.rs`. */
|
|
18
|
-
export const SDF_PX_SIZE = 64.0;
|
|
19
|
-
|
|
20
18
|
/** Horizontal alignment of lines within a multi-line block, as the fraction
|
|
21
19
|
* of leftover width placed before each line. */
|
|
22
20
|
export const ALIGN_FACTORS: Record<string, number> = {
|
package/src/mesh/tile/index.ts
CHANGED
|
@@ -42,6 +42,8 @@ import {
|
|
|
42
42
|
import { setTransform } from "../../event";
|
|
43
43
|
import type { EventContext, TileHandler } from "../../event/context";
|
|
44
44
|
import {
|
|
45
|
+
GBUFFER_EFFECT_WRITE_BUILTIN,
|
|
46
|
+
GBUFFER_NORMAL_WRITE_BASIC,
|
|
45
47
|
generateTileCommonInjection,
|
|
46
48
|
generateTileMapFragment,
|
|
47
49
|
generateTileNormalFragmentMaps,
|
|
@@ -49,6 +51,7 @@ import {
|
|
|
49
51
|
TILE_NORMAL_BUFFER_REPLACEMENT,
|
|
50
52
|
TILE_PICK_FRAGMENT_OVERRIDE,
|
|
51
53
|
TILE_VERTEX_INJECTIONS,
|
|
54
|
+
applyLitOption,
|
|
52
55
|
} from "../../material";
|
|
53
56
|
import { deriveCompositeFeatures } from "../../material/enhancer/tileComposite";
|
|
54
57
|
import type { CustomObject3DEventMap } from "../../object3DEvent";
|
|
@@ -564,6 +567,7 @@ export class TileMesh
|
|
|
564
567
|
this.castShadow = !!mat.castShadow;
|
|
565
568
|
this.receiveShadow = !!mat.receiveShadow;
|
|
566
569
|
}
|
|
570
|
+
applyLitOption(this.material, mat.lit);
|
|
567
571
|
|
|
568
572
|
this.visible = false;
|
|
569
573
|
this.renderOrder = mesh.render_order;
|
|
@@ -813,7 +817,7 @@ ${generateTileCommonInjection(maxTextures)}
|
|
|
813
817
|
)
|
|
814
818
|
.replace(
|
|
815
819
|
"#include <map_fragment>",
|
|
816
|
-
generateTileMapFragment(maxTextures),
|
|
820
|
+
generateTileMapFragment(maxTextures, features),
|
|
817
821
|
)
|
|
818
822
|
.replaceWithCondition(
|
|
819
823
|
"#include <normal_fragment_maps>",
|
|
@@ -845,13 +849,12 @@ ${generateTileCommonInjection(maxTextures)}
|
|
|
845
849
|
${TILE_PICK_FRAGMENT_OVERRIDE}`,
|
|
846
850
|
)
|
|
847
851
|
.replaceWithCondition(
|
|
848
|
-
|
|
852
|
+
GBUFFER_NORMAL_WRITE_BASIC,
|
|
849
853
|
TILE_NORMAL_BUFFER_REPLACEMENT,
|
|
850
854
|
useNormal,
|
|
851
855
|
)
|
|
852
856
|
.replace(
|
|
853
|
-
|
|
854
|
-
emissiveBuffer = vec4(diffuseColor.rgb * uEmissiveIntensity + emissive, 1.0);`,
|
|
857
|
+
GBUFFER_EFFECT_WRITE_BUILTIN,
|
|
855
858
|
TILE_EMISSIVE_EFFECT_BUFFER_REPLACEMENT,
|
|
856
859
|
).source;
|
|
857
860
|
};
|
|
@@ -923,6 +926,7 @@ ${generateTileCommonInjection(maxTextures)}
|
|
|
923
926
|
if (this.receiveShadow !== changedMaterial.receiveShadow) {
|
|
924
927
|
this.receiveShadow = !!changedMaterial.receiveShadow;
|
|
925
928
|
}
|
|
929
|
+
applyLitOption(this.material, changedMaterial.lit);
|
|
926
930
|
if (this.material.color.getHex() !== globe.color) {
|
|
927
931
|
this.material.color.setHex(globe.color);
|
|
928
932
|
}
|