@driftengine/core 4.8.2 → 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 +56 -0
- package/README.md +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- 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 +23 -0
- package/dist/render/backend/webgl2/renderer.js +58 -17
- 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 +2 -1
- 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/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 +10 -1
- package/dist/render/backend/webgpu/renderer.js +38 -12
- 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/oitPass.js +2 -1
- package/dist/render/particleBatch.js +3 -2
- package/dist/render/particlePool.d.ts +6 -2
- package/dist/render/plumeRenderer.js +3 -2
- package/dist/render/renderQuality.d.ts +9 -2
- 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/index.js +6 -1
- 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 +25 -0
- package/dist/render/shaders/generated/flat.wgsl.js +47 -22
- 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 +11 -0
- package/dist/render/textRenderer.js +2 -1
- package/dist/render/vertexDefaults.js +1 -0
- package/dist/render/waterRenderer.js +2 -1
- package/dist/render/windStreakRenderer.js +2 -1
- package/package.json +6 -6
- package/src/index.ts +13 -0
- package/src/render/backend/materialChanges.ts +8 -3
- package/src/render/backend/webgl2/renderer.ts +57 -16
- 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 +2 -1
- 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/plumePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +20 -5
- package/src/render/backend/webgpu/renderer.ts +40 -11
- 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/oitPass.ts +2 -1
- package/src/render/particleBatch.ts +3 -2
- package/src/render/particlePool.ts +6 -2
- package/src/render/plumeRenderer.ts +3 -2
- package/src/render/renderQuality.ts +9 -2
- 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/index.ts +6 -1
- package/src/render/shaders/generated/depth.wgsl.ts +32 -12
- package/src/render/shaders/generated/flat.wgsl.ts +47 -22
- 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 +11 -0
- package/src/render/textRenderer.ts +2 -1
- package/src/render/vertexDefaults.ts +1 -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,
|
|
@@ -1249,6 +1250,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1249
1250
|
private readonly surfaceScene = new Float32Array(4);
|
|
1250
1251
|
/** The two halves of `uWriteMode`, kept here because a `vec2` is written whole. */
|
|
1251
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;
|
|
1252
1258
|
private ditherFade = 0;
|
|
1253
1259
|
/** Said once, not per frame, where the context cannot give the float target the sum needs. */
|
|
1254
1260
|
private oitRefused = false;
|
|
@@ -1882,6 +1888,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1882
1888
|
gl.uniform1i(u['uPeelShadowLayer'] ?? null, this.activeDepthPeel ? 1 : 0);
|
|
1883
1889
|
if (this.activeDepthPeel) gl.uniform1i(u['uPreviousShadowMap'] ?? null, 0);
|
|
1884
1890
|
gl.uniform2f(u['uUvScale'] ?? null, cutout.u, cutout.v);
|
|
1891
|
+
gl.uniform2f(u['uUvOffset'] ?? null, cutout.uOffset, cutout.vOffset);
|
|
1885
1892
|
gl.uniform1f(u['uAlphaCutout'] ?? null, cutout.cutoff);
|
|
1886
1893
|
/* Narrowed for the reason the sink's own `mesh` gives: this renderer only hands out its own. */
|
|
1887
1894
|
(cutout.albedo as SurfaceTexture).bind(gl, SURFACE_TEXTURE_UNIT);
|
|
@@ -3453,6 +3460,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3453
3460
|
* how big a dome was — WebGPU writes it before its own early return and WebGL2 did not.
|
|
3454
3461
|
*/
|
|
3455
3462
|
gl.uniform2f(u['uUvScale'] ?? null, material?.uScale ?? 1, material?.vScale ?? 1);
|
|
3463
|
+
gl.uniform2f(u['uUvOffset'] ?? null, material?.uOffset ?? 0, material?.vOffset ?? 0);
|
|
3456
3464
|
gl.uniform1i(u['uDoubleSided'] ?? null, material?.doubleSided === true ? 1 : 0);
|
|
3457
3465
|
|
|
3458
3466
|
/* The albedo's effects table, or the stand-in the shader reads as none. Before the early
|
|
@@ -3585,6 +3593,28 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3585
3593
|
this.writeFlatFloat('uGrain', Math.min(1, Math.max(0, amount)));
|
|
3586
3594
|
}
|
|
3587
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
|
+
|
|
3588
3618
|
/**
|
|
3589
3619
|
* One float of material state, into every flat program.
|
|
3590
3620
|
*
|
|
@@ -3602,6 +3632,15 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3602
3632
|
this.useFlatProgram();
|
|
3603
3633
|
}
|
|
3604
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
|
+
|
|
3605
3644
|
/**
|
|
3606
3645
|
* How much of the surfaces drawn next survives a screen-door dither, for crossfading two levels
|
|
3607
3646
|
* of detail of one thing.
|
|
@@ -3852,7 +3891,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3852
3891
|
/* A blended batch shows what is behind it — refraction or glass — as a single draw does, and
|
|
3853
3892
|
counts a material of its own for it by the rule both backends share (`materialChanges.ts`). */
|
|
3854
3893
|
const refracting = blend && this.bindSeeThrough(u, options);
|
|
3855
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
3894
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
3856
3895
|
if (own) this.materials.dirty();
|
|
3857
3896
|
this.takeMaterial();
|
|
3858
3897
|
const depthWrite = options.depthWrite ?? true;
|
|
@@ -3876,14 +3915,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3876
3915
|
* part of what the count asks.
|
|
3877
3916
|
*/
|
|
3878
3917
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
3879
|
-
if (fog !==
|
|
3918
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
3880
3919
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.gradeCode(), 1));
|
|
3881
3920
|
|
|
3882
3921
|
if (blend) {
|
|
3883
3922
|
gl.enable(gl.BLEND);
|
|
3884
|
-
if (options.additive === true)
|
|
3885
|
-
else
|
|
3886
|
-
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);
|
|
3887
3925
|
if (!depthWrite) gl.depthMask(false);
|
|
3888
3926
|
}
|
|
3889
3927
|
/* The sign follows the compare, which `depthOffsetForLayer` owns — see `drawMesh`, where the
|
|
@@ -3916,7 +3954,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3916
3954
|
outlives its frame, so a snapshot left on unit 14 is held against the next frame's copy. */
|
|
3917
3955
|
if (refracting) this.unbindSeeThrough(u);
|
|
3918
3956
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
3919
|
-
if (fog !==
|
|
3957
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
3920
3958
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
|
|
3921
3959
|
if (own) this.materials.dirty();
|
|
3922
3960
|
this.useFlatProgram();
|
|
@@ -5256,6 +5294,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5256
5294
|
gl.uniform4fv(u['uGlassLight'] ?? null, this.glassLight);
|
|
5257
5295
|
if (cutout !== null) {
|
|
5258
5296
|
gl.uniform2f(u['uUvScale'] ?? null, cutout.u, cutout.v);
|
|
5297
|
+
gl.uniform2f(u['uUvOffset'] ?? null, cutout.uOffset, cutout.vOffset);
|
|
5259
5298
|
gl.uniform1f(u['uAlphaCutout'] ?? null, cutout.cutoff);
|
|
5260
5299
|
(cutout.albedo as SurfaceTexture).bind(gl, SURFACE_TEXTURE_UNIT);
|
|
5261
5300
|
gl.uniform1i(u['uCutoutMap'] ?? null, SURFACE_TEXTURE_UNIT);
|
|
@@ -6072,7 +6111,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6072
6111
|
*/
|
|
6073
6112
|
gl.disable(gl.CULL_FACE);
|
|
6074
6113
|
gl.enable(gl.BLEND);
|
|
6075
|
-
|
|
6114
|
+
blendCovering(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
6076
6115
|
|
|
6077
6116
|
gl.uniform4f(this.panelUniforms['uRect'] ?? null, rect.left, rect.top, rect.width, rect.height);
|
|
6078
6117
|
gl.uniform2f(
|
|
@@ -7509,7 +7548,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7509
7548
|
* shape `uOpacity` and `uTint` already use.
|
|
7510
7549
|
*/
|
|
7511
7550
|
gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
7512
|
-
gl.uniform1i(u['uFogEnabled'] ?? null,
|
|
7551
|
+
gl.uniform1i(u['uFogEnabled'] ?? null, FOG_RECEDE);
|
|
7552
|
+
this.surfaceFog = FOG_RECEDE;
|
|
7513
7553
|
/* Grain on by default, so every scene written before it was a choice looks unchanged. */
|
|
7514
7554
|
gl.uniform1f(u['uGrain'] ?? null, 1);
|
|
7515
7555
|
/* No dither and no weighting: every draw whole, until a crossfade asks. See `setDitherFade`. */
|
|
@@ -7709,6 +7749,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7709
7749
|
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
7710
7750
|
gl.uniform1i(u['uSurfaceEffects'] ?? null, SURFACE_EFFECTS_TEXTURE_UNIT);
|
|
7711
7751
|
gl.uniform2f(u['uUvScale'] ?? null, 1, 1);
|
|
7752
|
+
gl.uniform2f(u['uUvOffset'] ?? null, 0, 0);
|
|
7712
7753
|
gl.uniform1f(u['uAlbedoCutout'] ?? null, 0);
|
|
7713
7754
|
gl.uniform1i(u['uDoubleSided'] ?? null, 0);
|
|
7714
7755
|
this.materialDoubleSided = false;
|
|
@@ -8061,7 +8102,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8061
8102
|
const fog = fogModeOf(options.fog ?? true, options.additive === true);
|
|
8062
8103
|
const toneMapped = options.toneMapped ?? true;
|
|
8063
8104
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
8064
|
-
if (fog !==
|
|
8105
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
8065
8106
|
/* `1` is sRGB alone: the conversion without the curve, which is what dropping the tone map
|
|
8066
8107
|
means rather than dropping the whole transform. `Math.min` rather than a literal, so a
|
|
8067
8108
|
renderer asked for `none` stays at none and one asked for `srgb` is already there. */
|
|
@@ -8093,15 +8134,15 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8093
8134
|
*/
|
|
8094
8135
|
/* Taken for itself when any option differs from the pass, and put back below: the rule both
|
|
8095
8136
|
backends count material changes by. See `materialChanges.ts`. */
|
|
8096
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
8137
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
8097
8138
|
if (own) this.materials.dirty();
|
|
8098
8139
|
this.takeMaterial();
|
|
8099
8140
|
const ownsState = !this.oitReplaying;
|
|
8100
8141
|
if (ownsState) {
|
|
8101
8142
|
gl.enable(gl.BLEND);
|
|
8102
8143
|
/* Added, where asked: colour times alpha onto what is there, and the target's alpha kept. */
|
|
8103
|
-
if (options.additive === true)
|
|
8104
|
-
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);
|
|
8105
8146
|
}
|
|
8106
8147
|
/*
|
|
8107
8148
|
* The two depth options, both scoped to this draw and handed straight back — the same
|
|
@@ -8133,7 +8174,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8133
8174
|
/* Put back for whatever is drawn next, exactly as `uOpacity` and `uTint` are — a pass
|
|
8134
8175
|
cannot inherit a material from the draw before it. */
|
|
8135
8176
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
8136
|
-
if (fog !==
|
|
8177
|
+
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
8137
8178
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
|
|
8138
8179
|
if (own) this.materials.dirty();
|
|
8139
8180
|
}
|
|
@@ -8561,7 +8602,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8561
8602
|
}
|
|
8562
8603
|
|
|
8563
8604
|
gl.enable(gl.BLEND);
|
|
8564
|
-
|
|
8605
|
+
blendKeeping(gl, gl.SRC_ALPHA, gl.ONE);
|
|
8565
8606
|
gl.depthMask(false);
|
|
8566
8607
|
gl.cullFace(inside ? gl.FRONT : gl.BACK);
|
|
8567
8608
|
mesh.draw(gl);
|
|
@@ -8656,7 +8697,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8656
8697
|
);
|
|
8657
8698
|
|
|
8658
8699
|
gl.enable(gl.BLEND);
|
|
8659
|
-
|
|
8700
|
+
blendKeeping(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
8660
8701
|
gl.depthMask(false);
|
|
8661
8702
|
mesh.draw(gl);
|
|
8662
8703
|
gl.depthMask(true);
|
|
@@ -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
|
],
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { vertexBufferLayouts } from './buffers.ts';
|
|
8
8
|
import type { LitSwitch, PipelineCache } from './pipelineCache.ts';
|
|
9
9
|
import { shaderModule } from './shaderModules.ts';
|
|
10
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
10
11
|
|
|
11
12
|
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
12
13
|
const SURFACE_MAPS: ReadonlySet<string> = new Set([
|
|
@@ -681,7 +682,7 @@ function flatDescriptor(
|
|
|
681
682
|
dstFactor: 'one-minus-src-alpha',
|
|
682
683
|
operation: 'add',
|
|
683
684
|
},
|
|
684
|
-
alpha:
|
|
685
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
685
686
|
},
|
|
686
687
|
}
|
|
687
688
|
: { format: cache.format }),
|
|
@@ -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_COVERS } from '../../sceneCoverage.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The line pass: a polyline with a real width, four vertices a segment.
|
|
@@ -222,7 +223,7 @@ export function linePipeline(
|
|
|
222
223
|
dstFactor: 'one-minus-src-alpha',
|
|
223
224
|
operation: 'add',
|
|
224
225
|
},
|
|
225
|
-
alpha:
|
|
226
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
226
227
|
},
|
|
227
228
|
},
|
|
228
229
|
],
|
|
@@ -7,6 +7,7 @@ import type { UniformFields } from './scatterPass.ts';
|
|
|
7
7
|
import { DEPTH_FORMAT } from './flatPass.ts';
|
|
8
8
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
9
9
|
import { shaderModule } from './shaderModules.ts';
|
|
10
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* The panel pass: two triangles in screen space, one colour, one alpha.
|
|
@@ -121,7 +122,7 @@ export function panelPipeline(
|
|
|
121
122
|
format: cache.format,
|
|
122
123
|
blend: {
|
|
123
124
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
124
|
-
alpha:
|
|
125
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
125
126
|
},
|
|
126
127
|
},
|
|
127
128
|
],
|
|
@@ -8,6 +8,7 @@ import { DEPTH_FORMAT } from './flatPass.ts';
|
|
|
8
8
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
9
9
|
import type { UniformFields } from './scatterPass.ts';
|
|
10
10
|
import { shaderModule } from './shaderModules.ts';
|
|
11
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The particle pass: a crossed pair of quads per live particle, rebuilt every frame.
|
|
@@ -367,7 +368,7 @@ export function particlePipeline(
|
|
|
367
368
|
dstFactor: 'one-minus-src-alpha',
|
|
368
369
|
operation: 'add',
|
|
369
370
|
},
|
|
370
|
-
alpha:
|
|
371
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
371
372
|
},
|
|
372
373
|
},
|
|
373
374
|
],
|
|
@@ -9,6 +9,7 @@ import { DEPTH_FORMAT } from './flatPass.ts';
|
|
|
9
9
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
10
10
|
import type { UniformFields } from './scatterPass.ts';
|
|
11
11
|
import { shaderModule } from './shaderModules.ts';
|
|
12
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The plume pass: crossed quads per plume, displaced and faded in the shaders.
|
|
@@ -251,7 +252,7 @@ function blendState(blend: 'additive' | 'alpha'): GPUBlendState {
|
|
|
251
252
|
}
|
|
252
253
|
: {
|
|
253
254
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
254
|
-
alpha:
|
|
255
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
255
256
|
};
|
|
256
257
|
}
|
|
257
258
|
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
import type { UniformFields } from './scatterPass.ts';
|
|
40
40
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
41
41
|
import { shaderModule } from './shaderModules.ts';
|
|
42
|
+
import { SCENE_ALPHA_KEEPS, SCENE_ALPHA_TRANSMITS } from '../../sceneCoverage.ts';
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
45
|
* The composite: everything that happens to the frame after the world is drawn.
|
|
@@ -271,7 +272,7 @@ export function createPostStageLayout(
|
|
|
271
272
|
*/
|
|
272
273
|
export const OIT_COMPOSITE_BLEND: GPUBlendState = {
|
|
273
274
|
color: { srcFactor: 'one-minus-src-alpha', dstFactor: 'src-alpha', operation: 'add' },
|
|
274
|
-
alpha:
|
|
275
|
+
alpha: SCENE_ALPHA_TRANSMITS,
|
|
275
276
|
};
|
|
276
277
|
|
|
277
278
|
/**
|
|
@@ -290,17 +291,19 @@ export const OIT_COMPOSITE_BLEND: GPUBlendState = {
|
|
|
290
291
|
* exactly the integral — and the composite therefore never samples the colour it is modifying,
|
|
291
292
|
* which is the read both backends are entitled to call undefined.
|
|
292
293
|
*
|
|
293
|
-
* Alpha is
|
|
294
|
-
*
|
|
294
|
+
* Alpha is the transmittance again, `share * a`: the scene's alpha is how much of the pixel is
|
|
295
|
+
* still the opaque surface, which is what the composite lets ambient occlusion darken, and a
|
|
296
|
+
* medium thick enough to hide a corner hides its occlusion too (`sceneCoverage.ts`). It reaches
|
|
297
|
+
* no canvas: both are opaque, and the composite writes 1.
|
|
295
298
|
*/
|
|
296
299
|
export const MEDIUM_TRANSMIT_BLEND: GPUBlendState = {
|
|
297
300
|
color: { srcFactor: 'one', dstFactor: 'src-alpha', operation: 'add' },
|
|
298
|
-
alpha:
|
|
301
|
+
alpha: SCENE_ALPHA_TRANSMITS,
|
|
299
302
|
};
|
|
300
303
|
|
|
301
304
|
export const DECAL_MULTIPLY_BLEND: GPUBlendState = {
|
|
302
305
|
color: { srcFactor: 'zero', dstFactor: 'src', operation: 'add' },
|
|
303
|
-
alpha:
|
|
306
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
304
307
|
};
|
|
305
308
|
|
|
306
309
|
/**
|
|
@@ -316,6 +319,18 @@ export const PREMULTIPLIED_OVER_BLEND: GPUBlendState = {
|
|
|
316
319
|
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
317
320
|
};
|
|
318
321
|
|
|
322
|
+
/**
|
|
323
|
+
* The same `over` for the resolve that lands a reflection on the scene, keeping the scene's alpha.
|
|
324
|
+
*
|
|
325
|
+
* A reflection is a layer of the surface it is seen in, so the surface's share of the pixel is
|
|
326
|
+
* unchanged (`sceneCoverage.ts`). The trace keeps `PREMULTIPLIED_OVER_BLEND`, because its target is
|
|
327
|
+
* the reflection's own and its alpha is the coverage this resolve reads.
|
|
328
|
+
*/
|
|
329
|
+
export const REFLECTION_OVER_BLEND: GPUBlendState = {
|
|
330
|
+
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
331
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
332
|
+
};
|
|
333
|
+
|
|
319
334
|
export const ADDITIVE_BLEND: GPUBlendState = {
|
|
320
335
|
color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
321
336
|
alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
@@ -254,6 +254,7 @@ import {
|
|
|
254
254
|
DECAL_TEXTURES,
|
|
255
255
|
DECAL_UNIFORMS,
|
|
256
256
|
PREMULTIPLIED_OVER_BLEND,
|
|
257
|
+
REFLECTION_OVER_BLEND,
|
|
257
258
|
SSR_FRAG_FIELDS,
|
|
258
259
|
SSR_FRAG_SIZE,
|
|
259
260
|
SSR_RESOLVE_FRAG_WGSL,
|
|
@@ -492,7 +493,7 @@ import {
|
|
|
492
493
|
import { aimReflection, createGpuReflection, type GpuReflection } from './reflectionPass.ts';
|
|
493
494
|
import { FrameBudget } from '../budget.ts';
|
|
494
495
|
import { MaterialChanges, ownsMaterial } from '../materialChanges.ts';
|
|
495
|
-
import { FOG_RECEDE, fogModeOf } from '../drawFog.ts';
|
|
496
|
+
import { FOG_OFF, FOG_RECEDE, fogModeOf } from '../drawFog.ts';
|
|
496
497
|
import { DYNAMIC_ALIGNMENT as DYNAMIC_UNIFORM_ALIGNMENT, UniformRing } from './uniformRing.ts';
|
|
497
498
|
import { DecalQueue, MAX_DRAWN_DECALS } from '../../decalQueue.ts';
|
|
498
499
|
import { DistanceFieldScene } from '../../gi/fieldScene.ts';
|
|
@@ -2805,6 +2806,13 @@ export class WebGPURenderer implements RendererApi {
|
|
|
2805
2806
|
private blankAlbedoBindGroup: GPUBindGroup;
|
|
2806
2807
|
/** Repeats across the mesh's own UV range. Per draw, because `uUvScale` is a vertex uniform. */
|
|
2807
2808
|
private readonly uvScale = new Float32Array([1, 1]);
|
|
2809
|
+
/** Where the texture starts, after the scale. Per draw, beside `uvScale`. */
|
|
2810
|
+
private readonly uvOffset = new Float32Array([0, 0]);
|
|
2811
|
+
/**
|
|
2812
|
+
* How the surfaces drawn next meet the medium: what `setSurfaceFog` set, and `FOG_RECEDE` from
|
|
2813
|
+
* each `bindMeshPass`. A translucent draw's own fog is measured against this and puts it back.
|
|
2814
|
+
*/
|
|
2815
|
+
private surfaceFog = FOG_RECEDE;
|
|
2808
2816
|
/** Whether the bound material is seen from both faces. See `SurfaceMaterial.doubleSided`. */
|
|
2809
2817
|
private materialDoubleSided = false;
|
|
2810
2818
|
/** Whether the bound material has a map, for the warning a mesh with no coordinates earns. */
|
|
@@ -2940,6 +2948,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
2940
2948
|
const albedo = material?.albedo ?? null;
|
|
2941
2949
|
this.uvScale[0] = material?.uScale ?? 1;
|
|
2942
2950
|
this.uvScale[1] = material?.vScale ?? 1;
|
|
2951
|
+
this.uvOffset[0] = material?.uOffset ?? 0;
|
|
2952
|
+
this.uvOffset[1] = material?.vOffset ?? 0;
|
|
2943
2953
|
this.materialDoubleSided = material?.doubleSided === true;
|
|
2944
2954
|
this.materialHasMaps = materialHasMaps(material);
|
|
2945
2955
|
const normal = (material?.normal ?? null) as GpuSurfaceTexture | null;
|
|
@@ -3104,6 +3114,14 @@ export class WebGPURenderer implements RendererApi {
|
|
|
3104
3114
|
});
|
|
3105
3115
|
}
|
|
3106
3116
|
|
|
3117
|
+
/** Whether the surfaces drawn next meet the medium. See `renderer.ts`. */
|
|
3118
|
+
setSurfaceFog(enabled: boolean): void {
|
|
3119
|
+
this.surfaceFog = enabled ? FOG_RECEDE : FOG_OFF;
|
|
3120
|
+
this.material((_f, i) => {
|
|
3121
|
+
i[this.materialField('uFogEnabled')] = this.surfaceFog;
|
|
3122
|
+
});
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3107
3125
|
/**
|
|
3108
3126
|
* How much of the surfaces drawn next survives a screen-door dither. See `renderer.ts`.
|
|
3109
3127
|
*
|
|
@@ -5392,17 +5410,20 @@ export class WebGPURenderer implements RendererApi {
|
|
|
5392
5410
|
return group;
|
|
5393
5411
|
}
|
|
5394
5412
|
|
|
5395
|
-
/** The cutoff and UV scale into a cutout draw's slot, at
|
|
5413
|
+
/** The cutoff and UV scale and offset into a cutout draw's slot, at its own variant's offsets. */
|
|
5396
5414
|
private writeCutout(
|
|
5397
5415
|
slot: number,
|
|
5398
5416
|
cutout: CutoutCaster<unknown>,
|
|
5399
5417
|
fields: {
|
|
5400
5418
|
readonly uUvScale: { readonly offset: number };
|
|
5419
|
+
readonly uUvOffset: { readonly offset: number };
|
|
5401
5420
|
readonly uAlphaCutout: { readonly offset: number };
|
|
5402
5421
|
},
|
|
5403
5422
|
): void {
|
|
5404
5423
|
this.shadowDraws.writeFloat(slot, fields.uUvScale.offset, cutout.u);
|
|
5405
5424
|
this.shadowDraws.writeFloat(slot, fields.uUvScale.offset + 4, cutout.v);
|
|
5425
|
+
this.shadowDraws.writeFloat(slot, fields.uUvOffset.offset, cutout.uOffset);
|
|
5426
|
+
this.shadowDraws.writeFloat(slot, fields.uUvOffset.offset + 4, cutout.vOffset);
|
|
5406
5427
|
this.shadowDraws.writeFloat(slot, fields.uAlphaCutout.offset, cutout.cutoff);
|
|
5407
5428
|
}
|
|
5408
5429
|
|
|
@@ -7783,7 +7804,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
7783
7804
|
* these per draw through the material block, the same shape `uOpacity` already uses.
|
|
7784
7805
|
*/
|
|
7785
7806
|
i[at('uLightingEnabled')] = 1;
|
|
7786
|
-
i[at('uFogEnabled')] =
|
|
7807
|
+
i[at('uFogEnabled')] = FOG_RECEDE;
|
|
7808
|
+
this.surfaceFog = FOG_RECEDE;
|
|
7787
7809
|
i[at('uAlbedoEnabled')] = 0;
|
|
7788
7810
|
this.materialHasMaps = false;
|
|
7789
7811
|
|
|
@@ -8235,6 +8257,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8235
8257
|
this.bindGroup = this.blankAlbedoBindGroup;
|
|
8236
8258
|
this.uvScale[0] = 1;
|
|
8237
8259
|
this.uvScale[1] = 1;
|
|
8260
|
+
this.uvOffset[0] = 0;
|
|
8261
|
+
this.uvOffset[1] = 0;
|
|
8238
8262
|
}
|
|
8239
8263
|
|
|
8240
8264
|
/**
|
|
@@ -8319,7 +8343,10 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8319
8343
|
*/
|
|
8320
8344
|
if (this.tracksMotionNow()) this.recordDrawMotion(mesh, model, previousModel);
|
|
8321
8345
|
noteMapsWithoutUvs(mesh, mesh.hasUvs, this.materialHasMaps);
|
|
8322
|
-
|
|
8346
|
+
/* An opaque draw meets the medium as the dial says: `submitMesh` reads an absent `fog` as
|
|
8347
|
+
true, which is a translucent draw's default and would put every opaque draw back in the fog
|
|
8348
|
+
`setSurfaceFog(false)` took it out of. */
|
|
8349
|
+
this.submitMesh(mesh, model, tint, 1, false, { depthLayer, fog: this.surfaceFog !== FOG_OFF });
|
|
8323
8350
|
}
|
|
8324
8351
|
|
|
8325
8352
|
/**
|
|
@@ -8501,6 +8528,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8501
8528
|
/* The material's repeats, not a constant: geometry authored in metres is textured at
|
|
8502
8529
|
whatever density the material asks for without rebuilding it. */
|
|
8503
8530
|
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uUvScale.offset, this.uvScale);
|
|
8531
|
+
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uUvOffset.offset, this.uvOffset);
|
|
8504
8532
|
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uLightViewProj.offset, this.lightViewProj);
|
|
8505
8533
|
/*
|
|
8506
8534
|
* Whether this mesh's tangent frame is real. WebGPU has no disabled attribute, so location 10
|
|
@@ -8534,7 +8562,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8534
8562
|
/* Added light fades in the medium rather than receding into it. See `drawFog.ts`. */
|
|
8535
8563
|
const fog = fogModeOf(options.fog ?? true, blend && options.additive === true);
|
|
8536
8564
|
const toneMapped = options.toneMapped ?? true;
|
|
8537
|
-
const unlitOrUnfogged = !lit || fog !==
|
|
8565
|
+
const unlitOrUnfogged = !lit || fog !== this.surfaceFog;
|
|
8538
8566
|
if (unlitOrUnfogged) {
|
|
8539
8567
|
if (!lit) this.perFrameInts[this.materialField('uLightingEnabled')] = 0;
|
|
8540
8568
|
this.perFrameInts[this.materialField('uFogEnabled')] = fog;
|
|
@@ -8556,7 +8584,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8556
8584
|
const refracting = this.bindSeeThrough(options);
|
|
8557
8585
|
/* Taken for itself when any of those differs from the pass, and put back below: the rule both
|
|
8558
8586
|
backends count material changes by. See `materialChanges.ts`. */
|
|
8559
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
8587
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
8560
8588
|
if (own) this.materials.dirty();
|
|
8561
8589
|
const base = (mesh as GpuMesh & { key?: string }).key ?? 'flat:s0:u0';
|
|
8562
8590
|
/*
|
|
@@ -8700,7 +8728,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8700
8728
|
}
|
|
8701
8729
|
if (unlitOrUnfogged) {
|
|
8702
8730
|
if (!lit) this.perFrameInts[this.materialField('uLightingEnabled')] = 1;
|
|
8703
|
-
this.perFrameInts[this.materialField('uFogEnabled')] =
|
|
8731
|
+
this.perFrameInts[this.materialField('uFogEnabled')] = this.surfaceFog;
|
|
8704
8732
|
}
|
|
8705
8733
|
/* Back to off for every other draw in the frame, exactly as `uOpacity` is: this scratch is
|
|
8706
8734
|
shared, so a strength left set is worn by everything drawn after it. */
|
|
@@ -8947,6 +8975,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8947
8975
|
lands ? this.correctedViewProj : this.viewProj,
|
|
8948
8976
|
);
|
|
8949
8977
|
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uUvScale.offset, this.uvScale);
|
|
8978
|
+
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uUvOffset.offset, this.uvOffset);
|
|
8950
8979
|
this.perDraw.writeFloats(slot, FLAT_VERT_FIELDS.uLightViewProj.offset, this.lightViewProj);
|
|
8951
8980
|
this.perDraw.writeInt(slot, FLAT_VERT_FIELDS.uHasTangents.offset, mesh.hasTangents ? 1 : 0);
|
|
8952
8981
|
|
|
@@ -8957,7 +8986,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8957
8986
|
const lit = options.lit ?? true;
|
|
8958
8987
|
const fog = fogModeOf(options.fog ?? true, blend && options.additive === true);
|
|
8959
8988
|
const toneMapped = options.toneMapped ?? true;
|
|
8960
|
-
const unlitOrUnfogged = !lit || fog !==
|
|
8989
|
+
const unlitOrUnfogged = !lit || fog !== this.surfaceFog;
|
|
8961
8990
|
if (unlitOrUnfogged) {
|
|
8962
8991
|
if (!lit) this.perFrameInts[this.materialField('uLightingEnabled')] = 0;
|
|
8963
8992
|
this.perFrameInts[this.materialField('uFogEnabled')] = fog;
|
|
@@ -8970,7 +8999,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8970
8999
|
const layer = Math.min(Math.max(Math.round(options.depthLayer ?? 0), 0), MAX_DEPTH_LAYER);
|
|
8971
9000
|
/* A blended batch shows what is behind it — refraction or glass — as a single draw does. */
|
|
8972
9001
|
const refracting = blend && this.bindSeeThrough(options);
|
|
8973
|
-
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
9002
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting }, this.surfaceFog);
|
|
8974
9003
|
if (own) this.materials.dirty();
|
|
8975
9004
|
const base = (mesh as GpuMesh & { key?: string }).key ?? 'flat:s0:u0';
|
|
8976
9005
|
/* `|inst` in the key, for the reason every other suffix is there: an instanced pipeline binds
|
|
@@ -9052,7 +9081,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
9052
9081
|
}
|
|
9053
9082
|
if (unlitOrUnfogged) {
|
|
9054
9083
|
this.perFrameInts[this.materialField('uLightingEnabled')] = 1;
|
|
9055
|
-
this.perFrameInts[this.materialField('uFogEnabled')] =
|
|
9084
|
+
this.perFrameInts[this.materialField('uFogEnabled')] = this.surfaceFog;
|
|
9056
9085
|
}
|
|
9057
9086
|
if (!toneMapped) {
|
|
9058
9087
|
this.perFrameInts[this.materialField('uOutputTransform')] = this.gradeCode();
|
|
@@ -11614,7 +11643,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
11614
11643
|
'post.ssrResolve',
|
|
11615
11644
|
SSR_RESOLVE_FRAG_WGSL,
|
|
11616
11645
|
this.pipelines.format,
|
|
11617
|
-
|
|
11646
|
+
REFLECTION_OVER_BLEND,
|
|
11618
11647
|
),
|
|
11619
11648
|
);
|
|
11620
11649
|
resolve.setBindGroup(0, resolveGroup);
|
|
@@ -11,6 +11,7 @@ import type { SdfFont } from '../../sdfFont.ts';
|
|
|
11
11
|
import { SdfTextLayout, type SdfTextStyle } from '../../sdfTextLayout.ts';
|
|
12
12
|
import type { GpuSurfaceTexture } from './surfaceTexturePass.ts';
|
|
13
13
|
import { shaderModule } from './shaderModules.ts';
|
|
14
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* The SDF text pass: a string as flat, textured quads, drawn into the scene.
|
|
@@ -213,7 +214,7 @@ export function sdfTextPipeline(
|
|
|
213
214
|
format: cache.format,
|
|
214
215
|
blend: {
|
|
215
216
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
216
|
-
alpha:
|
|
217
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
217
218
|
},
|
|
218
219
|
},
|
|
219
220
|
],
|
|
@@ -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_COVERS } from '../../sceneCoverage.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The text pass: a string as instanced glyph cubes, drawn over the scene.
|
|
@@ -208,7 +209,7 @@ export function textPipeline(
|
|
|
208
209
|
format: cache.format,
|
|
209
210
|
blend: {
|
|
210
211
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
211
|
-
alpha:
|
|
212
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
212
213
|
},
|
|
213
214
|
},
|
|
214
215
|
],
|
|
@@ -9,6 +9,7 @@ import { DEPTH_FORMAT } from './flatPass.ts';
|
|
|
9
9
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
10
10
|
import type { UniformFields } from './scatterPass.ts';
|
|
11
11
|
import { shaderModule } from './shaderModules.ts';
|
|
12
|
+
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The water pass: two sheets and a patch, displaced by a wave field in the vertex stage.
|
|
@@ -199,7 +200,7 @@ export function waterPipeline(
|
|
|
199
200
|
format: cache.format,
|
|
200
201
|
blend: {
|
|
201
202
|
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
202
|
-
alpha:
|
|
203
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
203
204
|
},
|
|
204
205
|
},
|
|
205
206
|
],
|