@driftengine/core 4.8.1 → 4.8.3
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/CHANGELOG.json +142 -0
- package/README.md +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8 -0
- package/dist/input/actionMap.d.ts +6 -1
- package/dist/input/actionMap.js +20 -7
- package/dist/input/input.d.ts +28 -0
- package/dist/input/input.js +71 -9
- package/dist/input/inputHarness.d.ts +9 -0
- package/dist/input/inputHarness.js +34 -2
- package/dist/render/backend/materialChanges.d.ts +7 -2
- package/dist/render/backend/materialChanges.js +8 -3
- package/dist/render/backend/webgl2/renderer.d.ts +75 -3
- package/dist/render/backend/webgl2/renderer.js +209 -22
- package/dist/render/backend/webgpu/buffers.d.ts +2 -0
- package/dist/render/backend/webgpu/buffers.js +2 -0
- package/dist/render/backend/webgpu/causticsPass.js +2 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +13 -3
- package/dist/render/backend/webgpu/depthPass.js +4 -3
- package/dist/render/backend/webgpu/filmPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +5 -0
- package/dist/render/backend/webgpu/flatPass.js +18 -8
- package/dist/render/backend/webgpu/linePass.js +2 -1
- package/dist/render/backend/webgpu/panelPass.js +2 -1
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/pipelineCache.d.ts +40 -8
- package/dist/render/backend/webgpu/pipelineCache.js +76 -9
- package/dist/render/backend/webgpu/plumePass.js +2 -1
- package/dist/render/backend/webgpu/postPass.d.ts +12 -2
- package/dist/render/backend/webgpu/postPass.js +19 -5
- package/dist/render/backend/webgpu/renderer.d.ts +66 -2
- package/dist/render/backend/webgpu/renderer.js +189 -38
- package/dist/render/backend/webgpu/sdfTextPass.js +2 -1
- package/dist/render/backend/webgpu/textPass.js +2 -1
- package/dist/render/backend/webgpu/waterPass.js +2 -1
- package/dist/render/backend/webgpu/windStreakPass.js +2 -1
- package/dist/render/boltBatch.js +2 -1
- package/dist/render/causticsRenderer.js +2 -1
- package/dist/render/cutoutCaster.d.ts +3 -1
- package/dist/render/cutoutCaster.js +4 -0
- package/dist/render/decalPass.js +2 -1
- package/dist/render/globalMediumPass.js +3 -2
- package/dist/render/lineBatch.js +5 -1
- package/dist/render/mapsWithoutUvs.d.ts +24 -0
- package/dist/render/mapsWithoutUvs.js +24 -0
- package/dist/render/mesh.d.ts +2 -0
- package/dist/render/mesh.js +3 -0
- package/dist/render/oitPass.js +2 -1
- package/dist/render/particleBatch.js +3 -2
- package/dist/render/particlePool.d.ts +21 -2
- package/dist/render/particlePool.js +72 -37
- package/dist/render/pass.d.ts +12 -0
- package/dist/render/plumeRenderer.js +3 -2
- package/dist/render/renderQuality.d.ts +16 -8
- package/dist/render/sceneCoverage.d.ts +54 -0
- package/dist/render/sceneCoverage.js +72 -0
- package/dist/render/sdfTextRenderer.js +2 -1
- package/dist/render/shaders/depth.js +3 -2
- package/dist/render/shaders/flat/glassTint.d.ts +28 -0
- package/dist/render/shaders/flat/glassTint.js +31 -0
- package/dist/render/shaders/flat/index.d.ts +12 -0
- package/dist/render/shaders/flat/index.js +13 -2
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +60 -25
- package/dist/render/shaders/flat/surfaceEffects.d.ts +1 -1
- package/dist/render/shaders/flat/surfaceEffects.js +6 -2
- package/dist/render/shaders/generated/depth.wgsl.d.ts +32 -12
- package/dist/render/shaders/generated/depth.wgsl.js +32 -12
- package/dist/render/shaders/generated/flat.wgsl.d.ts +89 -0
- package/dist/render/shaders/generated/flat.wgsl.js +127 -38
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +3 -3
- package/dist/render/shaders/generated/particle.wgsl.js +3 -3
- package/dist/render/shaders/generated/rush.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/rush.wgsl.js +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.js +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +14 -1
- package/dist/render/shaders/outputTransform.js +23 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/recon/resolve.wgsl.js +15 -1
- package/dist/render/shaders/rush.js +13 -2
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/temporalResolve.js +12 -5
- package/dist/render/ssrPass.js +2 -1
- package/dist/render/surfaceTexture.d.ts +13 -0
- package/dist/render/surfaceTexture.js +4 -0
- package/dist/render/textRenderer.js +2 -1
- package/dist/render/vertexDefaults.js +1 -0
- package/dist/render/viewModel.d.ts +29 -0
- package/dist/render/viewModel.js +35 -0
- package/dist/render/waterRenderer.js +2 -1
- package/dist/render/windStreakRenderer.js +2 -1
- package/package.json +6 -6
- package/src/index.ts +22 -1
- package/src/input/actionMap.ts +23 -8
- package/src/input/input.ts +79 -9
- package/src/input/inputHarness.ts +27 -2
- package/src/render/backend/materialChanges.ts +8 -3
- package/src/render/backend/webgl2/renderer.ts +223 -29
- package/src/render/backend/webgpu/buffers.ts +5 -0
- package/src/render/backend/webgpu/causticsPass.ts +2 -1
- package/src/render/backend/webgpu/depthPass.ts +4 -3
- package/src/render/backend/webgpu/filmPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +43 -26
- package/src/render/backend/webgpu/linePass.ts +2 -1
- package/src/render/backend/webgpu/panelPass.ts +2 -1
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/pipelineCache.ts +82 -8
- package/src/render/backend/webgpu/plumePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +20 -5
- package/src/render/backend/webgpu/renderer.ts +191 -37
- package/src/render/backend/webgpu/sdfTextPass.ts +2 -1
- package/src/render/backend/webgpu/textPass.ts +2 -1
- package/src/render/backend/webgpu/waterPass.ts +2 -1
- package/src/render/backend/webgpu/windStreakPass.ts +2 -1
- package/src/render/boltBatch.ts +2 -1
- package/src/render/causticsRenderer.ts +2 -1
- package/src/render/cutoutCaster.ts +15 -2
- package/src/render/decalPass.ts +2 -1
- package/src/render/globalMediumPass.ts +3 -2
- package/src/render/lineBatch.ts +3 -1
- package/src/render/mapsWithoutUvs.ts +43 -0
- package/src/render/mesh.ts +3 -0
- package/src/render/oitPass.ts +2 -1
- package/src/render/particleBatch.ts +3 -2
- package/src/render/particlePool.ts +107 -56
- package/src/render/pass.ts +12 -0
- package/src/render/plumeRenderer.ts +3 -2
- package/src/render/renderQuality.ts +16 -8
- package/src/render/sceneCoverage.ts +78 -0
- package/src/render/sdfTextRenderer.ts +2 -1
- package/src/render/shaders/depth.ts +3 -2
- package/src/render/shaders/flat/glassTint.ts +48 -0
- package/src/render/shaders/flat/index.ts +25 -2
- package/src/render/shaders/flat/main.ts +60 -25
- package/src/render/shaders/flat/surfaceEffects.ts +6 -2
- package/src/render/shaders/generated/depth.wgsl.ts +32 -12
- package/src/render/shaders/generated/flat.wgsl.ts +127 -38
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +3 -3
- package/src/render/shaders/generated/rush.wgsl.ts +1 -1
- package/src/render/shaders/generated/sdfText.wgsl.ts +1 -1
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
- package/src/render/shaders/outputTransform.ts +24 -1
- package/src/render/shaders/recon/resolve.wgsl.ts +15 -1
- package/src/render/shaders/rush.ts +13 -2
- package/src/render/shaders/temporalResolve.ts +12 -5
- package/src/render/ssrPass.ts +2 -1
- package/src/render/surfaceTexture.ts +16 -0
- package/src/render/textRenderer.ts +2 -1
- package/src/render/vertexDefaults.ts +1 -0
- package/src/render/viewModel.ts +41 -0
- package/src/render/waterRenderer.ts +2 -1
- package/src/render/windStreakRenderer.ts +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FrameBudget } from '../budget.ts';
|
|
2
2
|
import { MaterialChanges, ownsMaterial } from '../materialChanges.ts';
|
|
3
|
-
import { FOG_RECEDE, fogModeOf } from '../drawFog.ts';
|
|
3
|
+
import { FOG_OFF, FOG_RECEDE, fogModeOf } from '../drawFog.ts';
|
|
4
|
+
import { blendCovering, blendKeeping } from '../../sceneCoverage.ts';
|
|
4
5
|
import { mat4 } from 'gl-matrix';
|
|
5
6
|
import {
|
|
6
7
|
GL_DEPTH_REMAP,
|
|
@@ -257,6 +258,9 @@ import type { InstancedOptions, MeshInstances } from '../../instances.ts';
|
|
|
257
258
|
import { cutoutOf } from '../../cutoutCaster.ts';
|
|
258
259
|
import type { CutoutCaster } from '../../cutoutCaster.ts';
|
|
259
260
|
import type { SurfaceTextureHandle } from '../api.ts';
|
|
261
|
+
import { materialHasMaps, noteMapsWithoutUvs } from '../../mapsWithoutUvs.ts';
|
|
262
|
+
import { VIEW_MODEL_DEPTH_SHARE, viewModelDepthRange } from '../../viewModel.ts';
|
|
263
|
+
import { noLitSwitches, type LitSwitch } from '../../shaders/flat/glassTint.ts';
|
|
260
264
|
|
|
261
265
|
/**
|
|
262
266
|
* How many frames `firstFrameSettled` will ask before it stops asking.
|
|
@@ -1087,8 +1091,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1087
1091
|
|
|
1088
1092
|
private presentedFrameCount = 0;
|
|
1089
1093
|
|
|
1090
|
-
private
|
|
1091
|
-
private
|
|
1094
|
+
private flatProgram: WebGLProgram;
|
|
1095
|
+
private flatUniforms: Record<string, WebGLUniformLocation>;
|
|
1092
1096
|
/**
|
|
1093
1097
|
* The lit fragment source every flat program is built from, and the budget it was built at.
|
|
1094
1098
|
*
|
|
@@ -1099,7 +1103,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1099
1103
|
* for a lazily compiled variant to end up at a different light budget from the one the renderer
|
|
1100
1104
|
* uploads for, which is a picture nobody could explain.
|
|
1101
1105
|
*/
|
|
1102
|
-
private
|
|
1106
|
+
private flatFragSource: string;
|
|
1103
1107
|
/**
|
|
1104
1108
|
* How many lights this renderer's shader has room for, after the device had its say.
|
|
1105
1109
|
*
|
|
@@ -1246,6 +1250,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1246
1250
|
private readonly surfaceScene = new Float32Array(4);
|
|
1247
1251
|
/** The two halves of `uWriteMode`, kept here because a `vec2` is written whole. */
|
|
1248
1252
|
private oitWeight = 0;
|
|
1253
|
+
/**
|
|
1254
|
+
* How the surfaces drawn next meet the medium: what `setSurfaceFog` set, and `FOG_RECEDE` from
|
|
1255
|
+
* each `bindMeshPass`. A translucent draw's own fog is measured against this and puts it back.
|
|
1256
|
+
*/
|
|
1257
|
+
private surfaceFog = FOG_RECEDE;
|
|
1249
1258
|
private ditherFade = 0;
|
|
1250
1259
|
/** Said once, not per frame, where the context cannot give the float target the sum needs. */
|
|
1251
1260
|
private oitRefused = false;
|
|
@@ -1683,6 +1692,33 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1683
1692
|
* each such draw and handed back, where the other backend bakes it into a pipeline.
|
|
1684
1693
|
*/
|
|
1685
1694
|
private materialDoubleSided = false;
|
|
1695
|
+
/** Whether the bound material has a map, for the warning a mesh with no coordinates earns. */
|
|
1696
|
+
private materialHasMaps = false;
|
|
1697
|
+
/** The material last set, so a lit program rebuilt for glass can be given it. */
|
|
1698
|
+
private currentMaterial: SurfaceMaterial | null = null;
|
|
1699
|
+
/**
|
|
1700
|
+
* The lit stage's switches: what the lit programs were compiled with (`litOn`), and what the
|
|
1701
|
+
* profile and the content have asked for since (`litWanted`).
|
|
1702
|
+
*
|
|
1703
|
+
* **Each is off until it is used** — glass until a pane is offered, a fixture until one is loaded,
|
|
1704
|
+
* the effects until a material carries a table, DriftLight until a volume is set — and then on for
|
|
1705
|
+
* good, rebuilt at the next `beginFrame`. Clustering is the profile's. The code costs the lit pass
|
|
1706
|
+
* registers on every surface whether it finds anything or not, and a world without the feature
|
|
1707
|
+
* draws the same picture without it. `PipelineCache.litSwitches` makes the same decision on the
|
|
1708
|
+
* other backend. The frame a feature is first used in draws without it; the rebuild is a
|
|
1709
|
+
* synchronous compile, and the next frame waits for it.
|
|
1710
|
+
*/
|
|
1711
|
+
private readonly litOn = noLitSwitches();
|
|
1712
|
+
private readonly litWanted = noLitSwitches();
|
|
1713
|
+
private litAsked = false;
|
|
1714
|
+
|
|
1715
|
+
/** Ask for a switch, which the next `beginFrame` compiles in. Never glass with it turned off. */
|
|
1716
|
+
private askLit(feature: LitSwitch): void {
|
|
1717
|
+
if (this.litWanted[feature]) return;
|
|
1718
|
+
if (feature === 'GLASS_SHADOWS' && this.quality.glassShadows === 'off') return;
|
|
1719
|
+
this.litWanted[feature] = true;
|
|
1720
|
+
this.litAsked = true;
|
|
1721
|
+
}
|
|
1686
1722
|
|
|
1687
1723
|
/**
|
|
1688
1724
|
* The one sink handed to every caster enumeration.
|
|
@@ -1715,6 +1751,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1715
1751
|
/* Glass: kept aside for its own two passes rather than dropped. See `glassCasters.ts`. */
|
|
1716
1752
|
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1717
1753
|
this.glassCasters.recordMesh(mesh, model, material, this.glassCasterScratch);
|
|
1754
|
+
this.askLit('GLASS_SHADOWS');
|
|
1718
1755
|
}
|
|
1719
1756
|
return;
|
|
1720
1757
|
}
|
|
@@ -1756,6 +1793,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1756
1793
|
if (!this.drawingGlassDepth && !castsDepth(material)) {
|
|
1757
1794
|
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1758
1795
|
this.glassCasters.recordInstanced(batch, data, material, this.glassCasterScratch);
|
|
1796
|
+
this.askLit('GLASS_SHADOWS');
|
|
1759
1797
|
}
|
|
1760
1798
|
return;
|
|
1761
1799
|
}
|
|
@@ -1789,6 +1827,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1789
1827
|
if (!this.drawingGlassDepth && !castsDepth(material)) {
|
|
1790
1828
|
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1791
1829
|
this.glassCasters.recordSkinned(mesh, model, palette, material, this.glassCasterScratch);
|
|
1830
|
+
this.askLit('GLASS_SHADOWS');
|
|
1792
1831
|
}
|
|
1793
1832
|
return;
|
|
1794
1833
|
}
|
|
@@ -1849,6 +1888,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1849
1888
|
gl.uniform1i(u['uPeelShadowLayer'] ?? null, this.activeDepthPeel ? 1 : 0);
|
|
1850
1889
|
if (this.activeDepthPeel) gl.uniform1i(u['uPreviousShadowMap'] ?? null, 0);
|
|
1851
1890
|
gl.uniform2f(u['uUvScale'] ?? null, cutout.u, cutout.v);
|
|
1891
|
+
gl.uniform2f(u['uUvOffset'] ?? null, cutout.uOffset, cutout.vOffset);
|
|
1852
1892
|
gl.uniform1f(u['uAlphaCutout'] ?? null, cutout.cutoff);
|
|
1853
1893
|
/* Narrowed for the reason the sink's own `mesh` gives: this renderer only hands out its own. */
|
|
1854
1894
|
(cutout.albedo as SurfaceTexture).bind(gl, SURFACE_TEXTURE_UNIT);
|
|
@@ -2297,6 +2337,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2297
2337
|
this.iesRows = this.iesAtlas.height;
|
|
2298
2338
|
this.iesPlanes = this.iesAtlas.planes;
|
|
2299
2339
|
this.cookieTiles = this.cookieImages.length;
|
|
2340
|
+
/* The first profile or cookie is when the lit programs start reading them. See `litOn`. */
|
|
2341
|
+
if (this.iesRows > 1 || this.cookieTiles > 0) this.askLit('LIGHT_FIXTURES');
|
|
2300
2342
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2301
2343
|
gl.activeTexture(gl.TEXTURE0);
|
|
2302
2344
|
}
|
|
@@ -2714,6 +2756,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2714
2756
|
* Built for the profile this renderer resolved, not for every profile at once — so a
|
|
2715
2757
|
* world with shadows off compiles none of the shadow path. See `shaders/flat.ts`.
|
|
2716
2758
|
*/
|
|
2759
|
+
/* The one switch the profile decides; the rest wait for their content. See `litOn`. */
|
|
2760
|
+
this.litOn.CLUSTERED_LIGHTS = this.quality.clusteredLights;
|
|
2761
|
+
this.litWanted.CLUSTERED_LIGHTS = this.quality.clusteredLights;
|
|
2717
2762
|
const fitted = this.fitFlatProgram(gl);
|
|
2718
2763
|
this.flatProgram = fitted.program;
|
|
2719
2764
|
this.flatFragSource = fitted.source;
|
|
@@ -3306,6 +3351,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3306
3351
|
this.materials.dirty();
|
|
3307
3352
|
this.currentSurfaceTexture = material?.albedo ?? null;
|
|
3308
3353
|
this.materialDoubleSided = material?.doubleSided === true;
|
|
3354
|
+
this.materialHasMaps = materialHasMaps(material);
|
|
3355
|
+
this.currentMaterial = material;
|
|
3309
3356
|
/*
|
|
3310
3357
|
* Written to every flat program, because material state persists across draws and a skinned
|
|
3311
3358
|
* draw is entitled to the material the caller set before it. A second program holding none of
|
|
@@ -3413,6 +3460,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3413
3460
|
* how big a dome was — WebGPU writes it before its own early return and WebGL2 did not.
|
|
3414
3461
|
*/
|
|
3415
3462
|
gl.uniform2f(u['uUvScale'] ?? null, material?.uScale ?? 1, material?.vScale ?? 1);
|
|
3463
|
+
gl.uniform2f(u['uUvOffset'] ?? null, material?.uOffset ?? 0, material?.vOffset ?? 0);
|
|
3416
3464
|
gl.uniform1i(u['uDoubleSided'] ?? null, material?.doubleSided === true ? 1 : 0);
|
|
3417
3465
|
|
|
3418
3466
|
/* The albedo's effects table, or the stand-in the shader reads as none. Before the early
|
|
@@ -3422,6 +3470,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3422
3470
|
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
3423
3471
|
} else {
|
|
3424
3472
|
albedo.bindEffects(gl, SURFACE_EFFECTS_TEXTURE_UNIT, this.emptyTexture2D);
|
|
3473
|
+
/* The first table bound is when the lit programs start reading one. See `litOn`. */
|
|
3474
|
+
if (albedo.hasEffects) this.askLit('SURFACE_EFFECTS');
|
|
3425
3475
|
}
|
|
3426
3476
|
gl.uniform1i(u['uSurfaceEffects'] ?? null, SURFACE_EFFECTS_TEXTURE_UNIT);
|
|
3427
3477
|
if (albedo === null) {
|
|
@@ -3543,6 +3593,28 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3543
3593
|
this.writeFlatFloat('uGrain', Math.min(1, Math.max(0, amount)));
|
|
3544
3594
|
}
|
|
3545
3595
|
|
|
3596
|
+
/**
|
|
3597
|
+
* Whether the surfaces drawn next meet the medium: distance fog and the global medium's haze.
|
|
3598
|
+
* True is the default, and what `bindMeshPass` restores.
|
|
3599
|
+
*
|
|
3600
|
+
* **The opaque counterpart of `TranslucentMeshOptions.fog`**, which a translucent draw has had
|
|
3601
|
+
* all along; the shader's per-draw switch was there, and nothing reached it for an ordinary mesh.
|
|
3602
|
+
* What it is for is a medium that darkens one thing and not another — a floor receding into the
|
|
3603
|
+
* distance under figures that must keep their full value however far from the camera they stand.
|
|
3604
|
+
* Material state like `setSurfaceGrain`: instanced and skinned draws read it too, and a
|
|
3605
|
+
* translucent draw's own `fog` is measured against it and puts it back.
|
|
3606
|
+
*
|
|
3607
|
+
* **What it gives up** is the medium's honesty: a surface out of the fog is drawn as though the
|
|
3608
|
+
* air between it and the eye were empty, so it should be a surface the scene means to stand
|
|
3609
|
+
* apart, not one whose distance is the point.
|
|
3610
|
+
*/
|
|
3611
|
+
setSurfaceFog(enabled: boolean): void {
|
|
3612
|
+
if (this.contextLost) return;
|
|
3613
|
+
this.materials.dirty();
|
|
3614
|
+
this.surfaceFog = enabled ? FOG_RECEDE : FOG_OFF;
|
|
3615
|
+
this.writeFlatInt('uFogEnabled', this.surfaceFog);
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3546
3618
|
/**
|
|
3547
3619
|
* One float of material state, into every flat program.
|
|
3548
3620
|
*
|
|
@@ -3560,6 +3632,15 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3560
3632
|
this.useFlatProgram();
|
|
3561
3633
|
}
|
|
3562
3634
|
|
|
3635
|
+
/** One int of material state, into every flat program, for `writeFlatFloat`'s reason. */
|
|
3636
|
+
private writeFlatInt(name: string, value: number): void {
|
|
3637
|
+
for (const target of this.flatTargets) {
|
|
3638
|
+
this.gl.useProgram(target.program);
|
|
3639
|
+
this.gl.uniform1i(target.uniforms[name] ?? null, value);
|
|
3640
|
+
}
|
|
3641
|
+
this.useFlatProgram();
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3563
3644
|
/**
|
|
3564
3645
|
* How much of the surfaces drawn next survives a screen-door dither, for crossfading two levels
|
|
3565
3646
|
* of detail of one thing.
|
|
@@ -3810,7 +3891,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3810
3891
|
/* A blended batch shows what is behind it — refraction or glass — as a single draw does, and
|
|
3811
3892
|
counts a material of its own for it by the rule both backends share (`materialChanges.ts`). */
|
|
3812
3893
|
const refracting = blend && this.bindSeeThrough(u, options);
|
|
3813
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
3894
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
3814
3895
|
if (own) this.materials.dirty();
|
|
3815
3896
|
this.takeMaterial();
|
|
3816
3897
|
const depthWrite = options.depthWrite ?? true;
|
|
@@ -3834,14 +3915,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3834
3915
|
* part of what the count asks.
|
|
3835
3916
|
*/
|
|
3836
3917
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
3837
|
-
if (fog !==
|
|
3918
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
3838
3919
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.gradeCode(), 1));
|
|
3839
3920
|
|
|
3840
3921
|
if (blend) {
|
|
3841
3922
|
gl.enable(gl.BLEND);
|
|
3842
|
-
if (options.additive === true)
|
|
3843
|
-
else
|
|
3844
|
-
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
3923
|
+
if (options.additive === true) blendKeeping(gl, gl.SRC_ALPHA, gl.ONE);
|
|
3924
|
+
else blendCovering(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
3845
3925
|
if (!depthWrite) gl.depthMask(false);
|
|
3846
3926
|
}
|
|
3847
3927
|
/* The sign follows the compare, which `depthOffsetForLayer` owns — see `drawMesh`, where the
|
|
@@ -3874,7 +3954,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3874
3954
|
outlives its frame, so a snapshot left on unit 14 is held against the next frame's copy. */
|
|
3875
3955
|
if (refracting) this.unbindSeeThrough(u);
|
|
3876
3956
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
3877
|
-
if (fog !==
|
|
3957
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
3878
3958
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
|
|
3879
3959
|
if (own) this.materials.dirty();
|
|
3880
3960
|
this.useFlatProgram();
|
|
@@ -5214,6 +5294,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5214
5294
|
gl.uniform4fv(u['uGlassLight'] ?? null, this.glassLight);
|
|
5215
5295
|
if (cutout !== null) {
|
|
5216
5296
|
gl.uniform2f(u['uUvScale'] ?? null, cutout.u, cutout.v);
|
|
5297
|
+
gl.uniform2f(u['uUvOffset'] ?? null, cutout.uOffset, cutout.vOffset);
|
|
5217
5298
|
gl.uniform1f(u['uAlphaCutout'] ?? null, cutout.cutoff);
|
|
5218
5299
|
(cutout.albedo as SurfaceTexture).bind(gl, SURFACE_TEXTURE_UNIT);
|
|
5219
5300
|
gl.uniform1i(u['uCutoutMap'] ?? null, SURFACE_TEXTURE_UNIT);
|
|
@@ -5317,21 +5398,91 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5317
5398
|
* rather than propagating. Only a shader that will not link at *any* budget throws, and it
|
|
5318
5399
|
* throws a sentence with the device's numbers in it rather than a bare driver string.
|
|
5319
5400
|
*/
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
budget: LightBudget;
|
|
5324
|
-
} {
|
|
5325
|
-
const variant = {
|
|
5401
|
+
/** The lit fragment source this renderer's profile compiles, at a light budget. */
|
|
5402
|
+
private flatFragAt(budget: LightBudget): string {
|
|
5403
|
+
return flatFrag({
|
|
5326
5404
|
pointShadows: this.quality.pointShadows,
|
|
5327
5405
|
directionalShadows: this.quality.directionalShadows,
|
|
5328
5406
|
environmentProbe: this.probeCapture !== null,
|
|
5329
5407
|
nightEmissive: this.quality.nightEmissive,
|
|
5330
|
-
/*
|
|
5331
|
-
glassShadows: this.
|
|
5408
|
+
/* Each off until it is used: see `litOn`. */
|
|
5409
|
+
glassShadows: this.litOn.GLASS_SHADOWS,
|
|
5410
|
+
clusteredLights: this.litOn.CLUSTERED_LIGHTS,
|
|
5411
|
+
lightFixtures: this.litOn.LIGHT_FIXTURES,
|
|
5412
|
+
surfaceEffects: this.litOn.SURFACE_EFFECTS,
|
|
5413
|
+
driftLight: this.litOn.DRIFT_LIGHT,
|
|
5414
|
+
maxLights: budget.maxLights,
|
|
5415
|
+
maxAreaLights: budget.maxAreaLights,
|
|
5416
|
+
});
|
|
5417
|
+
}
|
|
5418
|
+
|
|
5419
|
+
/**
|
|
5420
|
+
* Every lit program that exists, compiled again with the switches asked for since, at the budget
|
|
5421
|
+
* the renderer already uploads for, and given the pass and the material the old one held.
|
|
5422
|
+
*
|
|
5423
|
+
* At `beginFrame`, not where a feature was first used: a pane is offered inside a shadow pass
|
|
5424
|
+
* with the depth program bound, and a program swapped under it would draw the next caster with
|
|
5425
|
+
* the lit one.
|
|
5426
|
+
*/
|
|
5427
|
+
private rebuildLit(): void {
|
|
5428
|
+
const { gl } = this;
|
|
5429
|
+
Object.assign(this.litOn, this.litWanted);
|
|
5430
|
+
this.flatFragSource = this.flatFragAt(this.lightBudget);
|
|
5431
|
+
const recompile = (
|
|
5432
|
+
old: WebGLProgram | null,
|
|
5433
|
+
skinned: boolean,
|
|
5434
|
+
morphed: boolean,
|
|
5435
|
+
instanced: boolean,
|
|
5436
|
+
label: string,
|
|
5437
|
+
): { program: WebGLProgram; uniforms: Record<string, WebGLUniformLocation> } | null => {
|
|
5438
|
+
if (old === null) return null;
|
|
5439
|
+
const program = compileProgram(
|
|
5440
|
+
gl,
|
|
5441
|
+
flatVert({ skinned, morphed, instanced }),
|
|
5442
|
+
this.flatFragSource,
|
|
5443
|
+
label,
|
|
5444
|
+
);
|
|
5445
|
+
gl.deleteProgram(old);
|
|
5446
|
+
return { program, uniforms: uniformLocations(gl, program, label) };
|
|
5332
5447
|
};
|
|
5333
|
-
const
|
|
5334
|
-
|
|
5448
|
+
const plain = recompile(this.flatProgram, false, false, false, 'flat');
|
|
5449
|
+
if (plain !== null) {
|
|
5450
|
+
this.flatProgram = plain.program;
|
|
5451
|
+
this.flatUniforms = plain.uniforms;
|
|
5452
|
+
}
|
|
5453
|
+
const skinned = recompile(this.flatSkinnedProgram, true, false, false, 'flat.skinned');
|
|
5454
|
+
this.flatSkinnedProgram = skinned?.program ?? null;
|
|
5455
|
+
this.flatSkinnedUniforms = skinned?.uniforms ?? null;
|
|
5456
|
+
const morphed = recompile(this.flatMorphedProgram, false, true, false, 'flat.morphed');
|
|
5457
|
+
this.flatMorphedProgram = morphed?.program ?? null;
|
|
5458
|
+
this.flatMorphedUniforms = morphed?.uniforms ?? null;
|
|
5459
|
+
const both = recompile(this.flatBothProgram, true, true, false, 'flat.morphedskinned');
|
|
5460
|
+
this.flatBothProgram = both?.program ?? null;
|
|
5461
|
+
this.flatBothUniforms = both?.uniforms ?? null;
|
|
5462
|
+
const instanced = recompile(this.flatInstancedProgram, false, false, true, 'flat.instanced');
|
|
5463
|
+
this.flatInstancedProgram = instanced?.program ?? null;
|
|
5464
|
+
this.flatInstancedUniforms = instanced?.uniforms ?? null;
|
|
5465
|
+
|
|
5466
|
+
this.flatTargets.length = 0;
|
|
5467
|
+
for (const target of [plain, skinned, morphed, both, instanced]) {
|
|
5468
|
+
if (target !== null) this.flatTargets.push(target);
|
|
5469
|
+
}
|
|
5470
|
+
const camera = this.lastPassCamera;
|
|
5471
|
+
const env = this.lastPassEnv;
|
|
5472
|
+
for (const target of this.flatTargets) {
|
|
5473
|
+
gl.useProgram(target.program);
|
|
5474
|
+
if (camera !== null && env !== null) this.writeMeshPassState(target.uniforms, camera, env);
|
|
5475
|
+
this.writeMaterialState(target.uniforms, this.currentMaterial);
|
|
5476
|
+
}
|
|
5477
|
+
this.useFlatProgram();
|
|
5478
|
+
}
|
|
5479
|
+
|
|
5480
|
+
private fitFlatProgram(gl: WebGL2RenderingContext): {
|
|
5481
|
+
program: WebGLProgram;
|
|
5482
|
+
source: string;
|
|
5483
|
+
budget: LightBudget;
|
|
5484
|
+
} {
|
|
5485
|
+
const build = (budget: LightBudget): string => this.flatFragAt(budget);
|
|
5335
5486
|
const vert = flatVert({ skinned: false, morphed: false, instanced: false });
|
|
5336
5487
|
const limit = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS) as number;
|
|
5337
5488
|
const ceiling: LightBudget = {
|
|
@@ -5960,7 +6111,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5960
6111
|
*/
|
|
5961
6112
|
gl.disable(gl.CULL_FACE);
|
|
5962
6113
|
gl.enable(gl.BLEND);
|
|
5963
|
-
|
|
6114
|
+
blendCovering(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
5964
6115
|
|
|
5965
6116
|
gl.uniform4f(this.panelUniforms['uRect'] ?? null, rect.left, rect.top, rect.width, rect.height);
|
|
5966
6117
|
gl.uniform2f(
|
|
@@ -5989,6 +6140,35 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5989
6140
|
this.restoreViewport();
|
|
5990
6141
|
}
|
|
5991
6142
|
|
|
6143
|
+
/**
|
|
6144
|
+
* Draw what follows as a **view model**, in the nearest sliver of depth, until `endViewModel`.
|
|
6145
|
+
*
|
|
6146
|
+
* A first-person view model — arms and a held weapon — drawn with the frame's camera, or with one
|
|
6147
|
+
* of its own through `bindMeshPass`, lands in front of anything past the near plane without the
|
|
6148
|
+
* world's depth being cleared, so every pass that reads depth afterwards still sees the world.
|
|
6149
|
+
* `share` is how much of the range it takes, 1% by default. See `viewModel.ts` for what it gives
|
|
6150
|
+
* up, which includes temporal reconstruction: draw a view model with multisampling.
|
|
6151
|
+
*
|
|
6152
|
+
* Not inside an inset: an inset has its own depth, cleared for it, and needs no squeeze.
|
|
6153
|
+
*/
|
|
6154
|
+
beginViewModel(share = VIEW_MODEL_DEPTH_SHARE): void {
|
|
6155
|
+
if (this.contextLost) return;
|
|
6156
|
+
viewModelDepthRange(this.reversedDepth, share, this.viewModelRange);
|
|
6157
|
+
this.gl.depthRange(this.viewModelRange[0], this.viewModelRange[1]);
|
|
6158
|
+
this.viewModelActive = true;
|
|
6159
|
+
}
|
|
6160
|
+
|
|
6161
|
+
/** Give the whole depth range back. Safe to call without a matching `beginViewModel`. */
|
|
6162
|
+
endViewModel(): void {
|
|
6163
|
+
this.viewModelActive = false;
|
|
6164
|
+
if (this.contextLost) return;
|
|
6165
|
+
this.gl.depthRange(0, 1);
|
|
6166
|
+
}
|
|
6167
|
+
|
|
6168
|
+
/** Whether a view model is being drawn, so `endFrame` can close one the caller left open. */
|
|
6169
|
+
private viewModelActive = false;
|
|
6170
|
+
private readonly viewModelRange: [number, number] = [0, 1];
|
|
6171
|
+
|
|
5992
6172
|
/**
|
|
5993
6173
|
* How much speed blur the frame about to be drawn should resolve with, 0 to 1.
|
|
5994
6174
|
*
|
|
@@ -6508,6 +6688,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6508
6688
|
|
|
6509
6689
|
beginFrame(clearColor: Vec3): void {
|
|
6510
6690
|
if (this.contextLost) return;
|
|
6691
|
+
if (this.litAsked) {
|
|
6692
|
+
this.litAsked = false;
|
|
6693
|
+
this.rebuildLit();
|
|
6694
|
+
}
|
|
6511
6695
|
this.budget.reset();
|
|
6512
6696
|
this.materials.dirty();
|
|
6513
6697
|
/*
|
|
@@ -6584,6 +6768,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6584
6768
|
*/
|
|
6585
6769
|
endFrame(): void {
|
|
6586
6770
|
if (this.contextLost) return;
|
|
6771
|
+
/* A view model left open would squeeze every pass after the world, the composite included. */
|
|
6772
|
+
if (this.viewModelActive) this.endViewModel();
|
|
6587
6773
|
|
|
6588
6774
|
/*
|
|
6589
6775
|
* Camera motion blur, built from the camera the frame was *rendered* with.
|
|
@@ -7240,6 +7426,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7240
7426
|
gl.bindTexture(gl.TEXTURE_3D, null);
|
|
7241
7427
|
this.driftIndex = index;
|
|
7242
7428
|
this.driftAtlas = atlas;
|
|
7429
|
+
/* The first volume is when the lit programs start reading one. See `litOn`. */
|
|
7430
|
+
this.askLit('DRIFT_LIGHT');
|
|
7243
7431
|
}
|
|
7244
7432
|
|
|
7245
7433
|
/** The field's uniforms and volumes for this pass, or the stand-ins that switch it off. */
|
|
@@ -7360,7 +7548,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7360
7548
|
* shape `uOpacity` and `uTint` already use.
|
|
7361
7549
|
*/
|
|
7362
7550
|
gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
7363
|
-
gl.uniform1i(u['uFogEnabled'] ?? null,
|
|
7551
|
+
gl.uniform1i(u['uFogEnabled'] ?? null, FOG_RECEDE);
|
|
7552
|
+
this.surfaceFog = FOG_RECEDE;
|
|
7364
7553
|
/* Grain on by default, so every scene written before it was a choice looks unchanged. */
|
|
7365
7554
|
gl.uniform1f(u['uGrain'] ?? null, 1);
|
|
7366
7555
|
/* No dither and no weighting: every draw whole, until a crossfade asks. See `setDitherFade`. */
|
|
@@ -7560,9 +7749,12 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7560
7749
|
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
7561
7750
|
gl.uniform1i(u['uSurfaceEffects'] ?? null, SURFACE_EFFECTS_TEXTURE_UNIT);
|
|
7562
7751
|
gl.uniform2f(u['uUvScale'] ?? null, 1, 1);
|
|
7752
|
+
gl.uniform2f(u['uUvOffset'] ?? null, 0, 0);
|
|
7563
7753
|
gl.uniform1f(u['uAlbedoCutout'] ?? null, 0);
|
|
7564
7754
|
gl.uniform1i(u['uDoubleSided'] ?? null, 0);
|
|
7565
7755
|
this.materialDoubleSided = false;
|
|
7756
|
+
this.materialHasMaps = false;
|
|
7757
|
+
this.currentMaterial = null;
|
|
7566
7758
|
this.currentSurfaceTexture = null;
|
|
7567
7759
|
|
|
7568
7760
|
/*
|
|
@@ -7689,6 +7881,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7689
7881
|
/* Geometry that has not all arrived is not drawn, nor a mesh with none. See `Mesh.complete`
|
|
7690
7882
|
and `Mesh.indexCount`. */
|
|
7691
7883
|
if (!mesh.complete || mesh.indexCount === 0) return;
|
|
7884
|
+
noteMapsWithoutUvs(mesh, mesh.hasUvs, this.materialHasMaps);
|
|
7692
7885
|
|
|
7693
7886
|
/*
|
|
7694
7887
|
* Skipped where the flag asks and the bounds say so.
|
|
@@ -7877,6 +8070,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7877
8070
|
/* Geometry that has not all arrived is not drawn, nor a mesh with none. See `Mesh.complete`
|
|
7878
8071
|
and `Mesh.indexCount`. */
|
|
7879
8072
|
if (!mesh.complete || mesh.indexCount === 0) return;
|
|
8073
|
+
noteMapsWithoutUvs(mesh, mesh.hasUvs, this.materialHasMaps);
|
|
7880
8074
|
|
|
7881
8075
|
if (opacity <= 0) return;
|
|
7882
8076
|
|
|
@@ -7908,7 +8102,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7908
8102
|
const fog = fogModeOf(options.fog ?? true, options.additive === true);
|
|
7909
8103
|
const toneMapped = options.toneMapped ?? true;
|
|
7910
8104
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
7911
|
-
if (fog !==
|
|
8105
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
7912
8106
|
/* `1` is sRGB alone: the conversion without the curve, which is what dropping the tone map
|
|
7913
8107
|
means rather than dropping the whole transform. `Math.min` rather than a literal, so a
|
|
7914
8108
|
renderer asked for `none` stays at none and one asked for `srgb` is already there. */
|
|
@@ -7940,15 +8134,15 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7940
8134
|
*/
|
|
7941
8135
|
/* Taken for itself when any option differs from the pass, and put back below: the rule both
|
|
7942
8136
|
backends count material changes by. See `materialChanges.ts`. */
|
|
7943
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
8137
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
7944
8138
|
if (own) this.materials.dirty();
|
|
7945
8139
|
this.takeMaterial();
|
|
7946
8140
|
const ownsState = !this.oitReplaying;
|
|
7947
8141
|
if (ownsState) {
|
|
7948
8142
|
gl.enable(gl.BLEND);
|
|
7949
8143
|
/* Added, where asked: colour times alpha onto what is there, and the target's alpha kept. */
|
|
7950
|
-
if (options.additive === true)
|
|
7951
|
-
else
|
|
8144
|
+
if (options.additive === true) blendKeeping(gl, gl.SRC_ALPHA, gl.ONE);
|
|
8145
|
+
else blendCovering(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
7952
8146
|
}
|
|
7953
8147
|
/*
|
|
7954
8148
|
* The two depth options, both scoped to this draw and handed straight back — the same
|
|
@@ -7980,7 +8174,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7980
8174
|
/* Put back for whatever is drawn next, exactly as `uOpacity` and `uTint` are — a pass
|
|
7981
8175
|
cannot inherit a material from the draw before it. */
|
|
7982
8176
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
7983
|
-
if (fog !==
|
|
8177
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
7984
8178
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
|
|
7985
8179
|
if (own) this.materials.dirty();
|
|
7986
8180
|
}
|
|
@@ -8408,7 +8602,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8408
8602
|
}
|
|
8409
8603
|
|
|
8410
8604
|
gl.enable(gl.BLEND);
|
|
8411
|
-
|
|
8605
|
+
blendKeeping(gl, gl.SRC_ALPHA, gl.ONE);
|
|
8412
8606
|
gl.depthMask(false);
|
|
8413
8607
|
gl.cullFace(inside ? gl.FRONT : gl.BACK);
|
|
8414
8608
|
mesh.draw(gl);
|
|
@@ -8503,7 +8697,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8503
8697
|
);
|
|
8504
8698
|
|
|
8505
8699
|
gl.enable(gl.BLEND);
|
|
8506
|
-
|
|
8700
|
+
blendKeeping(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
8507
8701
|
gl.depthMask(false);
|
|
8508
8702
|
mesh.draw(gl);
|
|
8509
8703
|
gl.depthMask(true);
|
|
@@ -200,6 +200,8 @@ export interface GpuMesh {
|
|
|
200
200
|
* the key is built before the present map is consulted.
|
|
201
201
|
*/
|
|
202
202
|
readonly isSkinned: boolean;
|
|
203
|
+
/** Whether it has texture coordinates, without which a material's maps read one texel. */
|
|
204
|
+
readonly hasUvs: boolean;
|
|
203
205
|
/**
|
|
204
206
|
* Whether this mesh carries the per-vertex channel, which an instanced draw cannot.
|
|
205
207
|
*
|
|
@@ -425,6 +427,7 @@ export function createGpuMeshIncremental(
|
|
|
425
427
|
progress,
|
|
426
428
|
hasTangents: data.tangents !== undefined,
|
|
427
429
|
isSkinned: data.joints !== undefined,
|
|
430
|
+
hasUvs: data.uvs !== undefined,
|
|
428
431
|
skinOffsets: skinOffsetsOf(supplied),
|
|
429
432
|
hasChannel: data.channel !== undefined,
|
|
430
433
|
morph:
|
|
@@ -595,6 +598,7 @@ function gpuMeshOf(parts: {
|
|
|
595
598
|
readonly progress: { readonly uploaded: boolean };
|
|
596
599
|
readonly hasTangents: boolean;
|
|
597
600
|
readonly isSkinned: boolean;
|
|
601
|
+
readonly hasUvs: boolean;
|
|
598
602
|
readonly skinOffsets: GpuMesh['skinOffsets'];
|
|
599
603
|
readonly hasChannel: boolean;
|
|
600
604
|
readonly morph: MorphTexture | null;
|
|
@@ -614,6 +618,7 @@ function gpuMeshOf(parts: {
|
|
|
614
618
|
},
|
|
615
619
|
hasTangents: parts.hasTangents,
|
|
616
620
|
isSkinned: parts.isSkinned,
|
|
621
|
+
hasUvs: parts.hasUvs,
|
|
617
622
|
hasChannel: parts.hasChannel,
|
|
618
623
|
morph: parts.morph,
|
|
619
624
|
update: parts.update,
|
|
@@ -8,6 +8,7 @@ import type { UniformFields } from './scatterPass.ts';
|
|
|
8
8
|
import { DEPTH_FORMAT } from './flatPass.ts';
|
|
9
9
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
10
10
|
import { shaderModule } from './shaderModules.ts';
|
|
11
|
+
import { SCENE_ALPHA_KEEPS } from '../../sceneCoverage.ts';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The caustics pass: a surface lit by nearby water.
|
|
@@ -162,7 +163,7 @@ export function causticsPipeline(
|
|
|
162
163
|
format: cache.format,
|
|
163
164
|
blend: {
|
|
164
165
|
color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
165
|
-
alpha:
|
|
166
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
166
167
|
},
|
|
167
168
|
},
|
|
168
169
|
],
|
|
@@ -24,9 +24,10 @@ export const DEPTH_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_VERT.fields;
|
|
|
24
24
|
export const DEPTH_VERT_SIZE = DEPTH_BINDINGS.DEPTH_VERT.uniformSize;
|
|
25
25
|
export const DEPTH_FRAG_SIZE = DEPTH_BINDINGS.DEPTH_FRAG.uniformSize;
|
|
26
26
|
/*
|
|
27
|
-
* The cutout variants' vertex blocks. The rigid one is the plain block with `uUvScale
|
|
28
|
-
* `uAlphaCutout` after every other field, so a slot written for it is written with
|
|
29
|
-
* offsets plus these
|
|
27
|
+
* The cutout variants' vertex blocks. The rigid one is the plain block with `uUvScale`,
|
|
28
|
+
* `uUvOffset` and `uAlphaCutout` after every other field, so a slot written for it is written with
|
|
29
|
+
* the plain offsets plus these three; the instanced one has no model and no wind, so its three sit
|
|
30
|
+
* earlier.
|
|
30
31
|
*/
|
|
31
32
|
export const DEPTH_CUTOUT_VERT_FIELDS = DEPTH_BINDINGS.DEPTH_CUTOUT_VERT.fields;
|
|
32
33
|
export const DEPTH_CUTOUT_VERT_SIZE = DEPTH_BINDINGS.DEPTH_CUTOUT_VERT.uniformSize;
|
|
@@ -9,6 +9,7 @@ import type { UniformFields } from './scatterPass.ts';
|
|
|
9
9
|
import { DEPTH_FORMAT } from './flatPass.ts';
|
|
10
10
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
11
11
|
import { shaderModule } from './shaderModules.ts';
|
|
12
|
+
import { SCENE_ALPHA_KEEPS } from '../../sceneCoverage.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The film pass: a thin wet layer — an oil slick, a puddle — lying over the world.
|
|
@@ -111,7 +112,7 @@ export function filmPipeline(
|
|
|
111
112
|
format: cache.format,
|
|
112
113
|
blend: {
|
|
113
114
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
114
|
-
alpha:
|
|
115
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
115
116
|
},
|
|
116
117
|
},
|
|
117
118
|
],
|