@driftengine/core 4.4.2 → 4.5.0
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 +46 -0
- package/README.md +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -0
- package/dist/render/backend/api.d.ts +17 -11
- package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
- package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
- package/dist/render/backend/webgl2/renderer.d.ts +79 -8
- package/dist/render/backend/webgl2/renderer.js +360 -105
- package/dist/render/backend/webgpu/buffers.d.ts +19 -1
- package/dist/render/backend/webgpu/buffers.js +27 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
- package/dist/render/backend/webgpu/depthPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +2 -0
- package/dist/render/backend/webgpu/flatPass.js +20 -1
- package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
- package/dist/render/backend/webgpu/glassTintPass.js +205 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
- package/dist/render/backend/webgpu/instanced.d.ts +12 -1
- package/dist/render/backend/webgpu/instanced.js +20 -1
- package/dist/render/backend/webgpu/latePass.d.ts +26 -0
- package/dist/render/backend/webgpu/latePass.js +133 -0
- package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
- package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
- package/dist/render/backend/webgpu/motionPass.js +491 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
- package/dist/render/backend/webgpu/pipelineCache.js +11 -1
- package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
- package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
- package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
- package/dist/render/backend/webgpu/postPass.d.ts +2 -12
- package/dist/render/backend/webgpu/renderer.d.ts +171 -54
- package/dist/render/backend/webgpu/renderer.js +944 -390
- package/dist/render/backend/webgpu/scatterPass.js +2 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
- package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
- package/dist/render/backend/webgpu/snapshotMips.js +52 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.js +1 -1
- package/dist/render/glass.d.ts +45 -0
- package/dist/render/glass.js +39 -0
- package/dist/render/glassCasters.d.ts +40 -0
- package/dist/render/glassCasters.js +84 -0
- package/dist/render/glassShadow.d.ts +78 -0
- package/dist/render/glassShadow.js +125 -0
- package/dist/render/globalMediumPass.d.ts +2 -3
- package/dist/render/globalMediumPass.js +2 -8
- package/dist/render/gpudriven/lit.d.ts +12 -0
- package/dist/render/gpudriven/lit.js +23 -0
- package/dist/render/gpudriven/materialTable.d.ts +15 -5
- package/dist/render/gpudriven/materialTable.js +26 -6
- package/dist/render/gpudriven/pipeline.d.ts +1 -1
- package/dist/render/gpudriven/pipeline.js +4 -3
- package/dist/render/gpudriven/sunGlass.d.ts +35 -0
- package/dist/render/gpudriven/sunGlass.js +89 -0
- package/dist/render/lightBudget.d.ts +17 -5
- package/dist/render/lightBudget.js +17 -5
- package/dist/render/pointGlassTint.d.ts +59 -0
- package/dist/render/pointGlassTint.js +198 -0
- package/dist/render/pointShadowArray.d.ts +56 -3
- package/dist/render/pointShadowArray.js +127 -16
- package/dist/render/pointShadowMap.d.ts +23 -1
- package/dist/render/pointShadowMap.js +27 -1
- package/dist/render/recon/changeFrames.d.ts +15 -0
- package/dist/render/recon/changeFrames.js +21 -0
- package/dist/render/recon/lateRouting.d.ts +14 -0
- package/dist/render/recon/lateRouting.js +18 -0
- package/dist/render/recon/mover.d.ts +57 -0
- package/dist/render/recon/mover.js +86 -0
- package/dist/render/renderQuality.d.ts +35 -0
- package/dist/render/renderQuality.js +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/sceneTarget.d.ts +7 -1
- package/dist/render/sceneTarget.js +58 -12
- package/dist/render/shaders/depth.d.ts +16 -1
- package/dist/render/shaders/depth.js +85 -9
- package/dist/render/shaders/flat/directionalShadow.js +91 -6
- package/dist/render/shaders/flat/glassTint.d.ts +6 -0
- package/dist/render/shaders/flat/glassTint.js +25 -0
- package/dist/render/shaders/flat/index.d.ts +13 -0
- package/dist/render/shaders/flat/index.js +4 -0
- package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
- package/dist/render/shaders/flat/lampGlass.js +183 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +115 -15
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
- package/dist/render/shaders/flat/pointShadow.js +2 -0
- package/dist/render/shaders/flat/preamble.js +21 -6
- package/dist/render/shaders/generated/depth.wgsl.d.ts +227 -4
- package/dist/render/shaders/generated/depth.wgsl.js +227 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +360 -312
- package/dist/render/shaders/generated/flat.wgsl.js +376 -328
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.js +4 -14
- package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
- package/dist/render/shaders/globalMedium.js +6 -6
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
- package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
- package/dist/render/shaders/lightVolume.js +6 -6
- package/dist/render/shaders/octahedralResolve.d.ts +8 -0
- package/dist/render/shaders/octahedralResolve.js +48 -17
- package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
- package/dist/render/shaders/recon/lateDepth.wgsl.js +44 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +84 -0
- package/dist/render/shadowCasters.d.ts +20 -1
- package/dist/render/shadowCasters.js +15 -1
- package/dist/render/shadowMap.d.ts +54 -5
- package/dist/render/shadowMap.js +190 -36
- package/dist/render/sunGlassTint.d.ts +25 -0
- package/dist/render/sunGlassTint.js +79 -0
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +15 -1
- package/package.json +6 -6
- package/src/index.ts +10 -0
- package/src/render/backend/api.ts +15 -9
- package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
- package/src/render/backend/webgl2/renderer.ts +401 -108
- package/src/render/backend/webgpu/buffers.ts +50 -2
- package/src/render/backend/webgpu/depthPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +22 -1
- package/src/render/backend/webgpu/glassTintPass.ts +244 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
- package/src/render/backend/webgpu/instanced.ts +21 -1
- package/src/render/backend/webgpu/latePass.ts +152 -0
- package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
- package/src/render/backend/webgpu/motionPass.ts +535 -0
- package/src/render/backend/webgpu/pipelineCache.ts +12 -1
- package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
- package/src/render/backend/webgpu/renderer.ts +1108 -421
- package/src/render/backend/webgpu/scatterPass.ts +2 -1
- package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
- package/src/render/backend/webgpu/snapshotMips.ts +80 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +1 -1
- package/src/render/glass.ts +74 -0
- package/src/render/glassCasters.ts +164 -0
- package/src/render/glassShadow.ts +153 -0
- package/src/render/globalMediumPass.ts +4 -11
- package/src/render/gpudriven/lit.ts +31 -0
- package/src/render/gpudriven/materialTable.ts +28 -6
- package/src/render/gpudriven/pipeline.ts +4 -3
- package/src/render/gpudriven/sunGlass.ts +117 -0
- package/src/render/lightBudget.ts +19 -5
- package/src/render/pointGlassTint.ts +250 -0
- package/src/render/pointShadowArray.ts +188 -22
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +12 -0
- package/src/render/sceneTarget.ts +58 -11
- package/src/render/shaders/depth.ts +109 -9
- package/src/render/shaders/flat/directionalShadow.ts +97 -6
- package/src/render/shaders/flat/glassTint.ts +25 -0
- package/src/render/shaders/flat/index.ts +17 -0
- package/src/render/shaders/flat/lampGlass.ts +185 -0
- package/src/render/shaders/flat/main.ts +115 -15
- package/src/render/shaders/flat/pointShadow.ts +2 -0
- package/src/render/shaders/flat/preamble.ts +21 -6
- package/src/render/shaders/generated/depth.wgsl.ts +234 -4
- package/src/render/shaders/generated/flat.wgsl.ts +376 -328
- package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
- package/src/render/shaders/generated/lightVolume.wgsl.ts +4 -14
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
- package/src/render/shaders/globalMedium.ts +6 -6
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
- package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
- package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
- package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
- package/src/render/shaders/lightVolume.ts +6 -6
- package/src/render/shaders/octahedralResolve.ts +50 -17
- package/src/render/shaders/recon/lateDepth.wgsl.ts +47 -0
- package/src/render/shaders/recon/motion.wgsl.ts +84 -0
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/translucentQueue.ts +20 -1
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
glShadowDepthFunc,
|
|
14
14
|
} from '../../depthConvention.ts';
|
|
15
15
|
import type { FrameView } from '../../frameView.ts';
|
|
16
|
+
import type { Mover } from '../../recon/mover.ts';
|
|
17
|
+
import { resolveGlass } from '../../glass.ts';
|
|
18
|
+
import type { GlassOptions, ResolvedGlass } from '../../glass.ts';
|
|
16
19
|
import type { ClipControlExtension } from '../../depthConvention.ts';
|
|
17
20
|
import type { ReadonlyMat4 } from 'gl-matrix';
|
|
18
21
|
import type { Camera } from '../../camera.ts';
|
|
@@ -148,12 +151,16 @@ import {
|
|
|
148
151
|
DEPTH_SKINNED_VERT,
|
|
149
152
|
DEPTH_VERT,
|
|
150
153
|
} from '../../shaders/depth.ts';
|
|
151
|
-
import { PointShadowArray } from '../../pointShadowArray.ts';
|
|
152
|
-
import {
|
|
154
|
+
import { OCTAHEDRAL_EDGE, PointShadowArray, strideLayers } from '../../pointShadowArray.ts';
|
|
155
|
+
import { SunShadowArray, type SunShadowLayer } from '../../shadowMap.ts';
|
|
153
156
|
import { POINT_SHADOW_SAMPLER, PointShadowSystem } from '../../pointShadowSystem.ts';
|
|
154
157
|
import type { ShadowLight } from '../../pointShadowSystem.ts';
|
|
158
|
+
import { castsDepth, glassOf } from '../../shadowCasters.ts';
|
|
159
|
+
import { GlassCasterList, type GlassReplaySink } from '../../glassCasters.ts';
|
|
160
|
+
import { SunGlassTint } from '../../sunGlassTint.ts';
|
|
161
|
+
import { GlassTintPrograms, type GlassTintProgram } from './glassTintPrograms.ts';
|
|
155
162
|
import type { SceneCasterMaterial, ShadowCasterSink, ShadowCasters } from '../../shadowCasters.ts';
|
|
156
|
-
import { FACE_COUNT, PointShadowMap } from '../../pointShadowMap.ts';
|
|
163
|
+
import { FACE_COUNT, PointShadowMap, type PointGlassDraw } from '../../pointShadowMap.ts';
|
|
157
164
|
import { createResolvedPointShadows, DEFAULT_SOURCE_RADIUS } from '../../pointShadowImage.ts';
|
|
158
165
|
import {
|
|
159
166
|
createBakeScratch,
|
|
@@ -162,6 +169,8 @@ import {
|
|
|
162
169
|
} from '../../pointShadowBudget.ts';
|
|
163
170
|
import {
|
|
164
171
|
DIRECTIONAL_SHADOW_UNITS,
|
|
172
|
+
SUN_GLASS_TINT_TEXTURE_UNIT,
|
|
173
|
+
POINT_GLASS_TINT_TEXTURE_UNIT,
|
|
165
174
|
LIVE_POINT_SHADOW_MAPS,
|
|
166
175
|
MAX_POINT_LIGHTS,
|
|
167
176
|
NORMAL_TEXTURE_UNIT,
|
|
@@ -780,6 +789,13 @@ export interface TranslucentMeshOptions {
|
|
|
780
789
|
* clear, and it is the whole difference between this and a flat tint.
|
|
781
790
|
*/
|
|
782
791
|
readonly thicknessM?: number;
|
|
792
|
+
/**
|
|
793
|
+
* Glass: the pane shows what is behind it, by how much it lets through and how little it reflects
|
|
794
|
+
* at the view angle, blurred by how frosted it is, tinted, and glowing with the lights behind it.
|
|
795
|
+
* It keeps its own lighting and highlight, which `refraction` alone replaces. Absent, or letting
|
|
796
|
+
* nothing through, is not glass. See `glass.ts`; `refraction` still bends what a pane shows.
|
|
797
|
+
*/
|
|
798
|
+
readonly glass?: GlassOptions;
|
|
783
799
|
/**
|
|
784
800
|
* Whether this draw writes depth. `true`, which is what it has always done, unless a caller
|
|
785
801
|
* says otherwise.
|
|
@@ -1114,6 +1130,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1114
1130
|
private skinPaletteSet = false;
|
|
1115
1131
|
|
|
1116
1132
|
private readonly emptyTexture2D: WebGLTexture;
|
|
1133
|
+
/** One glass resolution reused by every draw, so a pane allocates nothing. See `glass.ts`. */
|
|
1134
|
+
private readonly glassScratch: ResolvedGlass = { transmission: 0, frost: 0, tint: [1, 1, 1] };
|
|
1117
1135
|
/** DriftLight's stand-ins while no field is whole: no brick anywhere, and no light. */
|
|
1118
1136
|
private readonly emptyDriftIndex: WebGLTexture;
|
|
1119
1137
|
private readonly emptyDriftAtlas: WebGLTexture;
|
|
@@ -1186,6 +1204,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1186
1204
|
refraction: number;
|
|
1187
1205
|
refractTint: Vec3 | undefined;
|
|
1188
1206
|
thicknessM: number;
|
|
1207
|
+
glass: GlassOptions | undefined;
|
|
1189
1208
|
} = {
|
|
1190
1209
|
lit: true,
|
|
1191
1210
|
fog: true,
|
|
@@ -1196,6 +1215,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1196
1215
|
refraction: 0,
|
|
1197
1216
|
refractTint: undefined,
|
|
1198
1217
|
thicknessM: 0,
|
|
1218
|
+
glass: undefined,
|
|
1199
1219
|
};
|
|
1200
1220
|
|
|
1201
1221
|
private motionBlurScale = 1;
|
|
@@ -1324,9 +1344,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1324
1344
|
private readonly depthInstancedCutoutUniforms: Record<string, WebGLUniformLocation>;
|
|
1325
1345
|
private readonly scatterDepthProgram: WebGLProgram;
|
|
1326
1346
|
private readonly scatterDepthUniforms: Record<string, WebGLUniformLocation>;
|
|
1327
|
-
|
|
1328
|
-
private readonly
|
|
1329
|
-
private readonly dynamicShadowMap: ShadowMap | null;
|
|
1347
|
+
/** The sun's static, moving and peeled maps, as layers of one array. See `shadowMap.ts`. */
|
|
1348
|
+
private readonly sunShadows: SunShadowArray | null;
|
|
1330
1349
|
private readonly pointShadows: PointShadowSystem<PointShadowMap> | null;
|
|
1331
1350
|
/**
|
|
1332
1351
|
* The layers a world's casting rectangles hold, above the point pool in the same array.
|
|
@@ -1551,7 +1570,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1551
1570
|
/** Non-zero while the drawing buffer is pinned; see `lockDrawingBuffer`. */
|
|
1552
1571
|
private lockedWidth = 0;
|
|
1553
1572
|
private lockedHeight = 0;
|
|
1554
|
-
private
|
|
1573
|
+
private activeSunLayer: SunShadowLayer | null = null;
|
|
1555
1574
|
private reflectionPassActive = false;
|
|
1556
1575
|
private reflectionReadyThisFrame = false;
|
|
1557
1576
|
private reflectionAtmosphereY = 0;
|
|
@@ -1575,7 +1594,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1575
1594
|
*
|
|
1576
1595
|
* **Not whether the map exists.** That was the test here, on the belief that a GL texture is
|
|
1577
1596
|
* born reading as the far plane; it is born zeroed, and a scene that built the layer and never
|
|
1578
|
-
* peeled it sampled an occluder at the light. `
|
|
1597
|
+
* peeled it sampled an occluder at the light. `SunShadowArray` clears itself at birth, so an
|
|
1579
1598
|
* unfilled layer would read as lit either way — this is what keeps the two backends one
|
|
1580
1599
|
* decision, and a frame that does not peel from paying a fetch per tap for nothing.
|
|
1581
1600
|
*/
|
|
@@ -1602,8 +1621,34 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1602
1621
|
* Built once at construction, arrow properties closing over `this`: a sink created
|
|
1603
1622
|
* per pass would allocate six objects per light per frame.
|
|
1604
1623
|
*/
|
|
1624
|
+
/** What the sun's light keeps through glass, made the first time glass casts: `sunGlassTint.ts`. */
|
|
1625
|
+
private sunGlassTint: SunGlassTint | null = null;
|
|
1626
|
+
/** The five programs a pane casts its colour through, compiled the first time glass casts. */
|
|
1627
|
+
private glassTintPrograms: GlassTintPrograms | null = null;
|
|
1628
|
+
/** True while the glass list is replayed into the glass depth layer through `casterSink`. */
|
|
1629
|
+
private drawingGlassDepth = false;
|
|
1630
|
+
/** How many times a shadow array grew its glass layers: once per family, and never again. */
|
|
1631
|
+
private sunGlassRebuilds = 0;
|
|
1632
|
+
/** The light a tint pass is drawn for, and one pane's colour and clarity: uploaded per entry. */
|
|
1633
|
+
private readonly glassLight = new Float32Array(4);
|
|
1634
|
+
private readonly glassPane = new Float32Array(4);
|
|
1635
|
+
/** The glass the open shadow pass was offered, kept for its own passes: `glassCasters.ts`. */
|
|
1636
|
+
private readonly glassCasters = new GlassCasterList();
|
|
1637
|
+
/** One resolution every glass caster is read through, so recording one allocates nothing. */
|
|
1638
|
+
private readonly glassCasterScratch: ResolvedGlass = {
|
|
1639
|
+
transmission: 0,
|
|
1640
|
+
frost: 0,
|
|
1641
|
+
tint: [1, 1, 1],
|
|
1642
|
+
};
|
|
1605
1643
|
private readonly casterSink: ShadowCasterSink = {
|
|
1606
1644
|
mesh: (mesh, model, material) => {
|
|
1645
|
+
if (!this.drawingGlassDepth && !castsDepth(material)) {
|
|
1646
|
+
/* Glass: kept aside for its own two passes rather than dropped. See `glassCasters.ts`. */
|
|
1647
|
+
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1648
|
+
this.glassCasters.recordMesh(mesh, model, material, this.glassCasterScratch);
|
|
1649
|
+
}
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1607
1652
|
this.shadowDrawBudget.ask();
|
|
1608
1653
|
const { gl } = this;
|
|
1609
1654
|
/* A two-sided caster casts from whichever face the light sees: nothing culled. */
|
|
@@ -1639,6 +1684,12 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1639
1684
|
* columns the batch's own buffer supplies.
|
|
1640
1685
|
*/
|
|
1641
1686
|
instanced: (batch, data, material) => {
|
|
1687
|
+
if (!this.drawingGlassDepth && !castsDepth(material)) {
|
|
1688
|
+
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1689
|
+
this.glassCasters.recordInstanced(batch, data, material, this.glassCasterScratch);
|
|
1690
|
+
}
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1642
1693
|
const { gl } = this;
|
|
1643
1694
|
const gpuBatch = batch as InstancedBatch;
|
|
1644
1695
|
const count = Math.min(data.count, gpuBatch.capacity);
|
|
@@ -1665,7 +1716,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1665
1716
|
if (twoSided && this.depthPassCullsFaces) gl.enable(gl.CULL_FACE);
|
|
1666
1717
|
gl.useProgram(this.depthProgram);
|
|
1667
1718
|
},
|
|
1668
|
-
skinnedMesh: (mesh, model, palette) => {
|
|
1719
|
+
skinnedMesh: (mesh, model, palette, material) => {
|
|
1720
|
+
if (!this.drawingGlassDepth && !castsDepth(material)) {
|
|
1721
|
+
if (this.quality.glassShadows !== 'off' && glassOf(material, this.glassCasterScratch)) {
|
|
1722
|
+
this.glassCasters.recordSkinned(mesh, model, palette, material, this.glassCasterScratch);
|
|
1723
|
+
}
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1669
1726
|
this.shadowDrawBudget.ask();
|
|
1670
1727
|
const { gl } = this;
|
|
1671
1728
|
const u = this.depthSkinnedUniforms;
|
|
@@ -1748,9 +1805,60 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1748
1805
|
gl.useProgram(this.depthProgram);
|
|
1749
1806
|
gl.uniform1i(this.depthUniforms['uPeelShadowLayer'] ?? null, 0);
|
|
1750
1807
|
gl.uniformMatrix4fv(this.depthUniforms['uLightViewProj'] ?? null, false, faceViewProj);
|
|
1808
|
+
/* A face is an enumeration of its own: its glass is its own. */
|
|
1809
|
+
this.glassCasters.clear();
|
|
1751
1810
|
casters(this.casterSink);
|
|
1811
|
+
/*
|
|
1812
|
+
* The first face to offer glass interleaves the array, before its opaque depth is resolved:
|
|
1813
|
+
* `PointShadowArray.growForGlass`. Nothing baked before this saw glass, so nothing re-bakes.
|
|
1814
|
+
*/
|
|
1815
|
+
if (this.glassCasters.count > 0 && this.quality.glassShadows !== 'off') {
|
|
1816
|
+
const tintEdge =
|
|
1817
|
+
this.quality.glassShadows === 'half' ? OCTAHEDRAL_EDGE >> 1 : OCTAHEDRAL_EDGE;
|
|
1818
|
+
this.pointShadowArray?.growForGlass(gl, tintEdge);
|
|
1819
|
+
}
|
|
1752
1820
|
};
|
|
1753
1821
|
|
|
1822
|
+
/**
|
|
1823
|
+
* A lamp's glass, after each face's opaque depth: `PointShadowMap.bake` asks and binds, this
|
|
1824
|
+
* draws, through the same sinks the sun's glass takes and in the face's own matrix.
|
|
1825
|
+
*/
|
|
1826
|
+
private readonly pointGlassDraw: PointGlassDraw = {
|
|
1827
|
+
offered: () => this.glassCasters.count > 0,
|
|
1828
|
+
draw: (pass, x, y, z) => {
|
|
1829
|
+
const { gl } = this;
|
|
1830
|
+
if (pass === 'depth') {
|
|
1831
|
+
/* Nothing on the unit the depth programs declare a previous map on: see `flushSunGlass`. */
|
|
1832
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
1833
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
|
|
1834
|
+
this.activeDepthPeel = false;
|
|
1835
|
+
gl.useProgram(this.depthProgram);
|
|
1836
|
+
gl.uniform1i(this.depthUniforms['uPeelShadowLayer'] ?? null, 0);
|
|
1837
|
+
gl.uniformMatrix4fv(
|
|
1838
|
+
this.depthUniforms['uLightViewProj'] ?? null,
|
|
1839
|
+
false,
|
|
1840
|
+
this.activeDepthViewProj ?? IDENTITY_MAT4,
|
|
1841
|
+
);
|
|
1842
|
+
this.drawingGlassDepth = true;
|
|
1843
|
+
this.glassCasters.replay(this.glassDepthSink);
|
|
1844
|
+
this.drawingGlassDepth = false;
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
this.glassTintPrograms ??= new GlassTintPrograms(gl);
|
|
1848
|
+
/* A place, w 1: the tint takes each pane's angle to the lamp from its own position. */
|
|
1849
|
+
this.glassLight[0] = x;
|
|
1850
|
+
this.glassLight[1] = y;
|
|
1851
|
+
this.glassLight[2] = z;
|
|
1852
|
+
this.glassLight[3] = 1;
|
|
1853
|
+
this.glassCasters.replay(this.glassTintSink);
|
|
1854
|
+
},
|
|
1855
|
+
};
|
|
1856
|
+
|
|
1857
|
+
/** The glass hook a bake is handed: none at all when glass shadows are off. */
|
|
1858
|
+
private get pointGlass(): PointGlassDraw | null {
|
|
1859
|
+
return this.quality.glassShadows === 'off' ? null : this.pointGlassDraw;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1754
1862
|
/**
|
|
1755
1863
|
* Viewport in CSS pixels rather than device pixels.
|
|
1756
1864
|
*
|
|
@@ -2716,20 +2824,18 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2716
2824
|
gl.uniform1i(uniforms['uCutoutMap'] ?? null, SURFACE_TEXTURE_UNIT);
|
|
2717
2825
|
}
|
|
2718
2826
|
gl.useProgram(null);
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
this.dynamicShadowMap = this.quality.directionalShadows
|
|
2732
|
-
? new ShadowMap(gl, this.quality.directionalShadowMapSize)
|
|
2827
|
+
/*
|
|
2828
|
+
* The static world, its movers and — where more than one static depth layer is asked for —
|
|
2829
|
+
* the peel, as layers of one array. Movers get a layer of their own so a moving and a static
|
|
2830
|
+
* caster that overlap keep both distance fades: their transmissions multiply rather than one
|
|
2831
|
+
* depth replacing the other. The peel keeps the second static occluder the same way.
|
|
2832
|
+
*/
|
|
2833
|
+
this.sunShadows = this.quality.directionalShadows
|
|
2834
|
+
? new SunShadowArray(
|
|
2835
|
+
gl,
|
|
2836
|
+
this.quality.directionalShadowMapSize,
|
|
2837
|
+
this.quality.directionalShadowDepthLayers > 1,
|
|
2838
|
+
)
|
|
2733
2839
|
: null;
|
|
2734
2840
|
// Static maps are allocated once the world reports its light count. No
|
|
2735
2841
|
// cubemap resources exist at all when the quality profile disables them.
|
|
@@ -2921,9 +3027,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2921
3027
|
* every one of them, per renderer, for as long as it lived; `renderer.test.ts` counts them.
|
|
2922
3028
|
*/
|
|
2923
3029
|
this.sceneTarget?.dispose();
|
|
2924
|
-
this.
|
|
2925
|
-
this.
|
|
2926
|
-
this.
|
|
3030
|
+
this.sunShadows?.dispose(gl);
|
|
3031
|
+
this.sunGlassTint?.dispose(gl);
|
|
3032
|
+
this.glassTintPrograms?.dispose(gl);
|
|
2927
3033
|
this.planarReflection?.dispose(gl);
|
|
2928
3034
|
this.pointShadows?.dispose();
|
|
2929
3035
|
gl.deleteVertexArray(this.panelVao);
|
|
@@ -3606,8 +3712,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3606
3712
|
const lit = options.lit ?? true;
|
|
3607
3713
|
const fog = options.fog ?? true;
|
|
3608
3714
|
const toneMapped = options.toneMapped ?? true;
|
|
3609
|
-
/*
|
|
3610
|
-
|
|
3715
|
+
/* A blended batch shows what is behind it — refraction or glass — as a single draw does, and
|
|
3716
|
+
counts a material of its own for it by the rule both backends share (`materialChanges.ts`). */
|
|
3717
|
+
const refracting = blend && this.bindSeeThrough(u, options);
|
|
3718
|
+
const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
|
|
3611
3719
|
if (own) this.materials.dirty();
|
|
3612
3720
|
this.takeMaterial();
|
|
3613
3721
|
const depthWrite = options.depthWrite ?? true;
|
|
@@ -3627,20 +3735,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3627
3735
|
* **A null snapshot leaves the strength at zero**, so the draw shades as an ordinary
|
|
3628
3736
|
* translucent one rather than sampling a black texture and painting the pane the colour of a
|
|
3629
3737
|
* hole. That is the defined state the two-backends rule asks for instead of a silent no-op.
|
|
3738
|
+
* The copy is bound above, before the material is counted, because whether it was taken is
|
|
3739
|
+
* part of what the count asks.
|
|
3630
3740
|
*/
|
|
3631
|
-
const refraction = options.refraction ?? 0;
|
|
3632
|
-
let refracting = false;
|
|
3633
|
-
if (refraction > 0) {
|
|
3634
|
-
const snapshot = this.sceneTarget?.snapshotColor() ?? null;
|
|
3635
|
-
if (snapshot !== null) {
|
|
3636
|
-
refracting = true;
|
|
3637
|
-
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3638
|
-
gl.bindTexture(gl.TEXTURE_2D, snapshot);
|
|
3639
|
-
gl.uniform1f(u['uRefractStrength'] ?? null, refraction);
|
|
3640
|
-
gl.uniform3fv(u['uRefractTint'] ?? null, options.refractTint ?? WHITE_TINT);
|
|
3641
|
-
gl.uniform1f(u['uRefractThickness'] ?? null, options.thicknessM ?? 0);
|
|
3642
|
-
}
|
|
3643
|
-
}
|
|
3644
3741
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
3645
3742
|
if (!fog) gl.uniform1i(u['uFogEnabled'] ?? null, 0);
|
|
3646
3743
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.gradeCode(), 1));
|
|
@@ -3658,7 +3755,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3658
3755
|
gl.polygonOffset(offset.slope, offset.units);
|
|
3659
3756
|
}
|
|
3660
3757
|
|
|
3758
|
+
/* Both sides of a double-sided material, as every mesh path does and WebGPU's pipeline does
|
|
3759
|
+
for both: without it a batch's far faces were culled here alone. */
|
|
3760
|
+
if (this.materialDoubleSided) gl.disable(gl.CULL_FACE);
|
|
3661
3761
|
mesh.drawInstances(gl, count);
|
|
3762
|
+
if (this.materialDoubleSided) gl.enable(gl.CULL_FACE);
|
|
3662
3763
|
|
|
3663
3764
|
if (layer > 0) {
|
|
3664
3765
|
gl.polygonOffset(0, 0);
|
|
@@ -3673,11 +3774,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3673
3774
|
if (opacity < 1) gl.uniform1f(u['uOpacity'] ?? null, 1);
|
|
3674
3775
|
/* The binding is released with the uniform, which is the 2026-08-27 rule: a WebGL2 binding
|
|
3675
3776
|
outlives its frame, so a snapshot left on unit 14 is held against the next frame's copy. */
|
|
3676
|
-
if (refracting)
|
|
3677
|
-
gl.uniform1f(u['uRefractStrength'] ?? null, 0);
|
|
3678
|
-
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3679
|
-
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
3680
|
-
}
|
|
3777
|
+
if (refracting) this.unbindSeeThrough(u);
|
|
3681
3778
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
3682
3779
|
if (!fog) gl.uniform1i(u['uFogEnabled'] ?? null, 1);
|
|
3683
3780
|
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
|
|
@@ -3685,6 +3782,53 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3685
3782
|
this.useFlatProgram();
|
|
3686
3783
|
}
|
|
3687
3784
|
|
|
3785
|
+
/**
|
|
3786
|
+
* Bind what a translucent draw shows through it: the frame's copy, refraction's bend and absorption,
|
|
3787
|
+
* and glass. Returns whether the copy is bound, and so whether `unbindSeeThrough` owes it back.
|
|
3788
|
+
*
|
|
3789
|
+
* **A glass draw takes the copy even when it does not bend**, since a pane shows what is behind it
|
|
3790
|
+
* either way, and asks for the copy's mip chain, which a frosted pane reads blurred. A null copy
|
|
3791
|
+
* leaves both off, so the pane shades as ordinary translucency rather than sampling black.
|
|
3792
|
+
*
|
|
3793
|
+
* **Refused inside a probe's face or a mirror**, as WebGPU's `takeRefractSnapshot` refuses: the
|
|
3794
|
+
* copy is of the frame drawn to the screen, so a pane there would show the wrong picture, and
|
|
3795
|
+
* taking it mid-bake is how a probe's next face came to be attached to the scene's framebuffer.
|
|
3796
|
+
*/
|
|
3797
|
+
private bindSeeThrough(
|
|
3798
|
+
u: Record<string, WebGLUniformLocation>,
|
|
3799
|
+
options: TranslucentMeshOptions,
|
|
3800
|
+
): boolean {
|
|
3801
|
+
const { gl } = this;
|
|
3802
|
+
const refraction = options.refraction ?? 0;
|
|
3803
|
+
const glassy = resolveGlass(options.glass, this.glassScratch);
|
|
3804
|
+
if (refraction <= 0 && !glassy) return false;
|
|
3805
|
+
if (this.probePassActive || this.reflectionPassActive) return false;
|
|
3806
|
+
const snapshot = this.sceneTarget?.snapshotColor(false, glassy) ?? null;
|
|
3807
|
+
if (snapshot === null) return false;
|
|
3808
|
+
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3809
|
+
gl.bindTexture(gl.TEXTURE_2D, snapshot);
|
|
3810
|
+
const glass = this.glassScratch;
|
|
3811
|
+
/* Strength, path thickness, transmission, frost: one vector, for the budget the shader states. */
|
|
3812
|
+
gl.uniform4f(
|
|
3813
|
+
u['uSeeThrough'] ?? null,
|
|
3814
|
+
Math.max(refraction, 0),
|
|
3815
|
+
options.thicknessM ?? 0,
|
|
3816
|
+
glass.transmission,
|
|
3817
|
+
glass.frost,
|
|
3818
|
+
);
|
|
3819
|
+
gl.uniform3fv(u['uRefractTint'] ?? null, options.refractTint ?? WHITE_TINT);
|
|
3820
|
+
gl.uniform3fv(u['uGlassTint'] ?? null, glass.tint);
|
|
3821
|
+
return true;
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
/** Put back what `bindSeeThrough` bound: the binding outlives its frame (the 2026-08-27 rule). */
|
|
3825
|
+
private unbindSeeThrough(u: Record<string, WebGLUniformLocation>): void {
|
|
3826
|
+
const { gl } = this;
|
|
3827
|
+
gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
|
|
3828
|
+
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3829
|
+
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3688
3832
|
disposeMesh(mesh: Mesh): void {
|
|
3689
3833
|
/*
|
|
3690
3834
|
* Nothing to release when the context is gone: it took every buffer and VAO with it,
|
|
@@ -4353,6 +4497,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4353
4497
|
*/
|
|
4354
4498
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.pointShadowArray?.texture ?? this.emptyTexture2DArray);
|
|
4355
4499
|
gl.uniform1i(uniforms[POINT_SHADOW_SAMPLER] ?? null, firstUnit);
|
|
4500
|
+
/* What the lamps keep through glass: the one-texel stand-in, read as none, until glass casts. */
|
|
4501
|
+
gl.activeTexture(gl.TEXTURE0 + POINT_GLASS_TINT_TEXTURE_UNIT);
|
|
4502
|
+
gl.bindTexture(
|
|
4503
|
+
gl.TEXTURE_2D_ARRAY,
|
|
4504
|
+
this.pointShadowArray?.tintTexture ?? this.emptyTexture2DArray,
|
|
4505
|
+
);
|
|
4506
|
+
gl.uniform1i(uniforms['uPointGlassTints'] ?? null, POINT_GLASS_TINT_TEXTURE_UNIT);
|
|
4356
4507
|
|
|
4357
4508
|
gl.uniform1iv(uniforms['uPointShadowLayer[0]'] ?? null, resolved.layers);
|
|
4358
4509
|
/* Origin and far plane in one row; see `uPointShadowProjection` in the preamble. */
|
|
@@ -4726,21 +4877,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4726
4877
|
lightViewProj: ReadonlyMat4,
|
|
4727
4878
|
layer: 'static' | 'static-peel' | 'dynamic' = 'static',
|
|
4728
4879
|
): void {
|
|
4729
|
-
const
|
|
4730
|
-
|
|
4731
|
-
? this.shadowMap
|
|
4732
|
-
: layer === 'static-peel'
|
|
4733
|
-
? this.peeledShadowMap
|
|
4734
|
-
: this.dynamicShadowMap;
|
|
4735
|
-
if (shadowMap === null) {
|
|
4880
|
+
const sun = this.sunShadows;
|
|
4881
|
+
if (sun === null || (layer === 'static-peel' && sun.layers < 3)) {
|
|
4736
4882
|
this.shadowPassActive = false;
|
|
4737
|
-
this.
|
|
4883
|
+
this.activeSunLayer = null;
|
|
4738
4884
|
return;
|
|
4739
4885
|
}
|
|
4740
4886
|
const { gl } = this;
|
|
4741
4887
|
this.gpuTimer.begin('shadows');
|
|
4742
4888
|
this.shadowPassActive = true;
|
|
4743
|
-
this.
|
|
4889
|
+
this.activeSunLayer = layer;
|
|
4890
|
+
this.glassCasters.clear();
|
|
4744
4891
|
/* The static layer opens first, so a frame's peel counts from here. See `peelFilled`. */
|
|
4745
4892
|
if (layer === 'static') this.peelFilled = false;
|
|
4746
4893
|
/*
|
|
@@ -4767,16 +4914,16 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4767
4914
|
// The previous mesh pass left all directional maps bound for sampling.
|
|
4768
4915
|
// A texture cannot be sampled while it is attached to the active depth
|
|
4769
4916
|
// target, even when the shader branch would skip that sample.
|
|
4770
|
-
|
|
4771
|
-
gl.
|
|
4772
|
-
|
|
4773
|
-
shadowMap.begin(gl);
|
|
4917
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
4918
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
|
|
4919
|
+
sun.begin(gl, layer);
|
|
4774
4920
|
gl.useProgram(this.depthProgram);
|
|
4775
4921
|
const peel = layer === 'static-peel';
|
|
4776
4922
|
gl.uniform1i(this.depthUniforms['uPeelShadowLayer'] ?? null, peel ? 1 : 0);
|
|
4777
4923
|
if (peel) {
|
|
4924
|
+
/* The static layer, read while the peel is drawn aside: see `SunShadowArray`. */
|
|
4778
4925
|
gl.activeTexture(gl.TEXTURE0);
|
|
4779
|
-
gl.bindTexture(gl.
|
|
4926
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, sun.texture);
|
|
4780
4927
|
gl.uniform1i(this.depthUniforms['uPreviousShadowMap'] ?? null, 0);
|
|
4781
4928
|
}
|
|
4782
4929
|
/* The corrected one, matching `activeDepthViewProj` above: a pass must render its map with the
|
|
@@ -4888,18 +5035,165 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4888
5035
|
casters(this.casterSink);
|
|
4889
5036
|
}
|
|
4890
5037
|
|
|
5038
|
+
/**
|
|
5039
|
+
* Draw the pass's glass twice: where the nearest pane is, and what the panes let through.
|
|
5040
|
+
*
|
|
5041
|
+
* After the opaque casters, in the pass's own light matrix. A layer that has held glass is
|
|
5042
|
+
* redrawn even when this pass offered none, so glass that has gone takes its colour with it. The
|
|
5043
|
+
* first glass grows the array (`SunShadowArray.growForGlass`) and makes the tint target.
|
|
5044
|
+
*/
|
|
5045
|
+
private flushSunGlass(which: 'static' | 'dynamic'): void {
|
|
5046
|
+
const sun = this.sunShadows;
|
|
5047
|
+
const list = this.glassCasters;
|
|
5048
|
+
if (sun === null || this.quality.glassShadows === 'off') return;
|
|
5049
|
+
if (list.count === 0 && !sun.hasGlass) return;
|
|
5050
|
+
const { gl } = this;
|
|
5051
|
+
if (list.count > 0 && sun.growForGlass(gl)) this.sunGlassRebuilds++;
|
|
5052
|
+
|
|
5053
|
+
/* Where the nearest pane is: the depth programs, through the sink every opaque caster took. */
|
|
5054
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
5055
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
|
|
5056
|
+
sun.beginGlass(gl, which);
|
|
5057
|
+
this.activeDepthPeel = false;
|
|
5058
|
+
gl.useProgram(this.depthProgram);
|
|
5059
|
+
gl.uniform1i(this.depthUniforms['uPeelShadowLayer'] ?? null, 0);
|
|
5060
|
+
gl.uniformMatrix4fv(
|
|
5061
|
+
this.depthUniforms['uLightViewProj'] ?? null,
|
|
5062
|
+
false,
|
|
5063
|
+
this.activeDepthViewProj ?? IDENTITY_MAT4,
|
|
5064
|
+
);
|
|
5065
|
+
this.drawingGlassDepth = true;
|
|
5066
|
+
list.replay(this.glassDepthSink);
|
|
5067
|
+
this.drawingGlassDepth = false;
|
|
5068
|
+
sun.end(gl);
|
|
5069
|
+
|
|
5070
|
+
/* What the panes let through, every one on a ray, multiplied. */
|
|
5071
|
+
this.glassTintPrograms ??= new GlassTintPrograms(gl);
|
|
5072
|
+
const size = this.quality.glassShadows === 'half' ? Math.max(1, sun.size >> 1) : sun.size;
|
|
5073
|
+
const tint = (this.sunGlassTint ??= new SunGlassTint(gl, size));
|
|
5074
|
+
/*
|
|
5075
|
+
* The direction the light travels, off the light matrix's depth row: an orthographic
|
|
5076
|
+
* projection's depth grows along it. The sign is immaterial — the tint takes the cosine
|
|
5077
|
+
* absolutely — and w 0 says it is a direction rather than a place.
|
|
5078
|
+
*/
|
|
5079
|
+
const m = this.activeDepthViewProj ?? IDENTITY_MAT4;
|
|
5080
|
+
const length = Math.hypot(m[2] as number, m[6] as number, m[10] as number) || 1;
|
|
5081
|
+
this.glassLight[0] = (m[2] as number) / length;
|
|
5082
|
+
this.glassLight[1] = (m[6] as number) / length;
|
|
5083
|
+
this.glassLight[2] = (m[10] as number) / length;
|
|
5084
|
+
this.glassLight[3] = 0;
|
|
5085
|
+
tint.begin(gl, which === 'static' ? 0 : 1);
|
|
5086
|
+
list.replay(this.glassTintSink);
|
|
5087
|
+
tint.end(gl);
|
|
5088
|
+
gl.useProgram(this.depthProgram);
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5091
|
+
/** The glass list into the glass depth layer: `casterSink` itself, with glass let through. */
|
|
5092
|
+
private readonly glassDepthSink: GlassReplaySink = {
|
|
5093
|
+
mesh: (mesh, model, material) => this.casterSink.mesh(mesh, model, material),
|
|
5094
|
+
instanced: (batch, data, material) => this.casterSink.instanced?.(batch, data, material),
|
|
5095
|
+
skinnedMesh: (mesh, model, palette, material) =>
|
|
5096
|
+
this.casterSink.skinnedMesh(mesh, model, palette, material),
|
|
5097
|
+
};
|
|
5098
|
+
|
|
5099
|
+
/** One pane's tint uniforms, and its cutout where it has one. */
|
|
5100
|
+
private bindGlassTint(
|
|
5101
|
+
program: GlassTintProgram,
|
|
5102
|
+
glass: ResolvedGlass,
|
|
5103
|
+
cutout: CutoutCaster<SurfaceTextureHandle> | null,
|
|
5104
|
+
): void {
|
|
5105
|
+
const { gl } = this;
|
|
5106
|
+
const u = program.uniforms;
|
|
5107
|
+
gl.useProgram(program.program);
|
|
5108
|
+
gl.uniformMatrix4fv(
|
|
5109
|
+
u['uLightViewProj'] ?? null,
|
|
5110
|
+
false,
|
|
5111
|
+
this.activeDepthViewProj ?? IDENTITY_MAT4,
|
|
5112
|
+
);
|
|
5113
|
+
this.uploadWind(u, this.frameWind);
|
|
5114
|
+
this.glassPane[0] = glass.transmission * glass.tint[0];
|
|
5115
|
+
this.glassPane[1] = glass.transmission * glass.tint[1];
|
|
5116
|
+
this.glassPane[2] = glass.transmission * glass.tint[2];
|
|
5117
|
+
this.glassPane[3] = 1 - glass.frost;
|
|
5118
|
+
gl.uniform4fv(u['uGlassPane'] ?? null, this.glassPane);
|
|
5119
|
+
gl.uniform4fv(u['uGlassLight'] ?? null, this.glassLight);
|
|
5120
|
+
if (cutout !== null) {
|
|
5121
|
+
gl.uniform2f(u['uUvScale'] ?? null, cutout.u, cutout.v);
|
|
5122
|
+
gl.uniform1f(u['uAlphaCutout'] ?? null, cutout.cutoff);
|
|
5123
|
+
(cutout.albedo as SurfaceTexture).bind(gl, SURFACE_TEXTURE_UNIT);
|
|
5124
|
+
gl.uniform1i(u['uCutoutMap'] ?? null, SURFACE_TEXTURE_UNIT);
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
|
|
5128
|
+
/**
|
|
5129
|
+
* The glass list into the tint layer, through the tint programs, **culling nothing**: a light
|
|
5130
|
+
* crosses a pane whichever way the pane faces, and a closed glass object has two surfaces on a
|
|
5131
|
+
* ray, so every one counts. What that asks of a model is that a pane be one surface — two-sided
|
|
5132
|
+
* glass says so with `doubleSided`, and a second copy of its triangles is a second pane.
|
|
5133
|
+
*/
|
|
5134
|
+
private readonly glassTintSink: GlassReplaySink = {
|
|
5135
|
+
mesh: (mesh, model, material, glass) => {
|
|
5136
|
+
const programs = this.glassTintPrograms;
|
|
5137
|
+
if (programs === null) return;
|
|
5138
|
+
const { gl } = this;
|
|
5139
|
+
const cutout = cutoutOf(material);
|
|
5140
|
+
const program = cutout !== null ? programs.cutout : programs.rigid;
|
|
5141
|
+
this.bindGlassTint(program, glass, cutout);
|
|
5142
|
+
gl.uniformMatrix4fv(program.uniforms['uModel'] ?? null, false, model);
|
|
5143
|
+
gl.disable(gl.CULL_FACE);
|
|
5144
|
+
(mesh as Mesh).draw(gl);
|
|
5145
|
+
if (this.depthPassCullsFaces) gl.enable(gl.CULL_FACE);
|
|
5146
|
+
if (cutout !== null) this.restoreSurfaceTextureUnit();
|
|
5147
|
+
},
|
|
5148
|
+
instanced: (batch, data, material, glass) => {
|
|
5149
|
+
const programs = this.glassTintPrograms;
|
|
5150
|
+
if (programs === null) return;
|
|
5151
|
+
const { gl } = this;
|
|
5152
|
+
const gpuBatch = batch as InstancedBatch;
|
|
5153
|
+
const count = Math.min(data.count, gpuBatch.capacity);
|
|
5154
|
+
if (count === 0) return;
|
|
5155
|
+
const cutout = cutoutOf(material);
|
|
5156
|
+
this.bindGlassTint(
|
|
5157
|
+
cutout !== null ? programs.instancedCutout : programs.instanced,
|
|
5158
|
+
glass,
|
|
5159
|
+
cutout,
|
|
5160
|
+
);
|
|
5161
|
+
gl.disable(gl.CULL_FACE);
|
|
5162
|
+
gpuBatch.mesh.drawInstances(gl, count);
|
|
5163
|
+
if (this.depthPassCullsFaces) gl.enable(gl.CULL_FACE);
|
|
5164
|
+
if (cutout !== null) this.restoreSurfaceTextureUnit();
|
|
5165
|
+
},
|
|
5166
|
+
skinnedMesh: (mesh, model, palette, _material, glass) => {
|
|
5167
|
+
const programs = this.glassTintPrograms;
|
|
5168
|
+
if (programs === null) return;
|
|
5169
|
+
const { gl } = this;
|
|
5170
|
+
const program = programs.skinned;
|
|
5171
|
+
this.bindGlassTint(program, glass, null);
|
|
5172
|
+
gl.uniformMatrix4fv(program.uniforms['uModel'] ?? null, false, model);
|
|
5173
|
+
this.skinPalette.update(gl, palette);
|
|
5174
|
+
this.skinPalette.bind(gl, SKIN_PALETTE_TEXTURE_UNIT);
|
|
5175
|
+
gl.uniform1i(program.uniforms['uJointPalette'] ?? null, SKIN_PALETTE_TEXTURE_UNIT);
|
|
5176
|
+
gl.disable(gl.CULL_FACE);
|
|
5177
|
+
(mesh as Mesh).draw(gl);
|
|
5178
|
+
if (this.depthPassCullsFaces) gl.enable(gl.CULL_FACE);
|
|
5179
|
+
},
|
|
5180
|
+
};
|
|
5181
|
+
|
|
4891
5182
|
endShadowPass(): void {
|
|
4892
5183
|
if (this.contextLost) return;
|
|
4893
|
-
const
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
5184
|
+
const sun = this.sunShadows;
|
|
5185
|
+
const layer = this.activeSunLayer;
|
|
5186
|
+
if (!this.shadowPassActive || sun === null || layer === null) return;
|
|
5187
|
+
sun.end(this.gl);
|
|
5188
|
+
if (layer === 'static-peel') this.peelFilled = true;
|
|
5189
|
+
/* The peel keeps no glass: its layer is the second opaque occluder and nothing else. */
|
|
5190
|
+
else this.flushSunGlass(layer === 'dynamic' ? 'dynamic' : 'static');
|
|
4897
5191
|
/* Back to the frame's sense; see `beginShadowPass` for why it left it. */
|
|
4898
5192
|
this.gl.depthFunc(glDepthFuncEqual(this.gl));
|
|
4899
5193
|
this.gl.clearDepth(this.depthClear);
|
|
4900
5194
|
this.gpuTimer.end();
|
|
4901
5195
|
this.shadowPassActive = false;
|
|
4902
|
-
this.
|
|
5196
|
+
this.activeSunLayer = null;
|
|
4903
5197
|
// Restore the drawing-buffer viewport the shadow pass overrode.
|
|
4904
5198
|
this.restoreViewport();
|
|
4905
5199
|
}
|
|
@@ -4938,6 +5232,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4938
5232
|
directionalShadows: this.quality.directionalShadows,
|
|
4939
5233
|
environmentProbe: this.probeCapture !== null,
|
|
4940
5234
|
nightEmissive: this.quality.nightEmissive,
|
|
5235
|
+
/* Off compiles none of the glass lookup: see `FlatShaderOptions.glassShadows`. */
|
|
5236
|
+
glassShadows: this.quality.glassShadows !== 'off',
|
|
4941
5237
|
};
|
|
4942
5238
|
const build = (budget: LightBudget): string =>
|
|
4943
5239
|
flatFrag({ ...variant, maxLights: budget.maxLights, maxAreaLights: budget.maxAreaLights });
|
|
@@ -5254,6 +5550,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5254
5550
|
this.bakeOne(map, light, casters as ShadowCasters, maxFaces),
|
|
5255
5551
|
);
|
|
5256
5552
|
this.updateAreaShadows(areaLights, frameDt, staticCasters, dynamicCasters);
|
|
5553
|
+
/* The chain frost reads, once for the round, for the lights whose glass it drew or cleared. */
|
|
5554
|
+
this.pointShadowArray.finishTints(this.gl);
|
|
5257
5555
|
this.restoreViewport();
|
|
5258
5556
|
}
|
|
5259
5557
|
|
|
@@ -5314,6 +5612,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5314
5612
|
* reason: it already holds everything it needs.
|
|
5315
5613
|
*/
|
|
5316
5614
|
set.resolve(areaLights, this.resolvedAreaShadows);
|
|
5615
|
+
/* As the array stores them: 2L once glass has interleaved it. See `strideLayers`. */
|
|
5616
|
+
const stride = this.pointShadowArray?.stride ?? 1;
|
|
5617
|
+
strideLayers(this.resolvedAreaShadows.layer, stride);
|
|
5618
|
+
strideLayers(this.resolvedAreaShadows.liveLayer, stride);
|
|
5317
5619
|
}
|
|
5318
5620
|
|
|
5319
5621
|
/**
|
|
@@ -5378,6 +5680,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5378
5680
|
near,
|
|
5379
5681
|
DEFAULT_SOURCE_RADIUS,
|
|
5380
5682
|
maxFaces,
|
|
5683
|
+
this.pointGlass,
|
|
5381
5684
|
),
|
|
5382
5685
|
);
|
|
5383
5686
|
}
|
|
@@ -5401,6 +5704,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5401
5704
|
light.shadowNear,
|
|
5402
5705
|
light.sourceRadius,
|
|
5403
5706
|
maxFaces,
|
|
5707
|
+
this.pointGlass,
|
|
5404
5708
|
),
|
|
5405
5709
|
);
|
|
5406
5710
|
}
|
|
@@ -5635,6 +5939,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5635
5939
|
*
|
|
5636
5940
|
* What it gives up is one frame of history: the frame after a cut has no blur and no temporal
|
|
5637
5941
|
* blend, as the first frame of a session has none. Nothing else is reset.
|
|
5942
|
+
*
|
|
5943
|
+
* **A reconstructing renderer depends on it**: its history is the last shot's, and without this
|
|
5944
|
+
* call a cut blends that shot into the first frames of the next. Nothing detects a cut on the
|
|
5945
|
+
* caller's behalf, deliberately — a fast pan and a cut look alike from here.
|
|
5638
5946
|
*/
|
|
5639
5947
|
cameraCut(): void {
|
|
5640
5948
|
this.hasPreviousView = false;
|
|
@@ -6425,7 +6733,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6425
6733
|
* flat paint with the effect on. The opaque frame is finished here, which is what a pane
|
|
6426
6734
|
* should show; the latch then serves every pane in the replay. Only when something refracts.
|
|
6427
6735
|
*/
|
|
6428
|
-
if (this.translucentQueue.refracts)
|
|
6736
|
+
if (this.translucentQueue.refracts) {
|
|
6737
|
+
this.sceneTarget?.snapshotColor(false, this.translucentQueue.glassy);
|
|
6738
|
+
}
|
|
6429
6739
|
this.oit.accumulateOit(this.canvas.width, this.canvas.height, oitDepth, (weighted) => {
|
|
6430
6740
|
this.oitReplaying = true;
|
|
6431
6741
|
this.useFlatProgram();
|
|
@@ -6442,6 +6752,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6442
6752
|
options.refraction = draw.refraction;
|
|
6443
6753
|
options.refractTint = draw.refractTint as unknown as Vec3 | undefined;
|
|
6444
6754
|
options.thicknessM = draw.thicknessM;
|
|
6755
|
+
options.glass = draw.glass ?? undefined;
|
|
6445
6756
|
this.drawTranslucentMesh(draw.mesh as Mesh, draw.model, draw.opacity, options);
|
|
6446
6757
|
});
|
|
6447
6758
|
/* Back to zero for every other draw in the frame, exactly as `uOpacity` and `uTint` are. */
|
|
@@ -6504,9 +6815,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6504
6815
|
/* The placeholder rather than null where a map is merely absent, for the reason
|
|
6505
6816
|
`emptyTexture.ts` gives. It is black, which as a depth is an occluder at the light,
|
|
6506
6817
|
so it is safe only because `sunShadow` is 0 whenever these maps do not exist. */
|
|
6507
|
-
|
|
6508
|
-
peeledShadowMap: this.peeledShadowMap?.texture ?? this.emptyTexture2D,
|
|
6509
|
-
dynamicShadowMap: this.dynamicShadowMap?.texture ?? this.emptyTexture2D,
|
|
6818
|
+
sunShadows: this.sunShadows?.texture ?? this.emptyTexture2DArray,
|
|
6510
6819
|
peeledEnabled: this.peelFilled,
|
|
6511
6820
|
},
|
|
6512
6821
|
);
|
|
@@ -6853,9 +7162,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6853
7162
|
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
6854
7163
|
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
6855
7164
|
gl.uniform1i(u['uRefractScene'] ?? null, REFRACT_SCENE_TEXTURE_UNIT);
|
|
6856
|
-
|
|
7165
|
+
/* Neither refracting nor glass, which is every draw that does not say otherwise. See
|
|
7166
|
+
`bindSeeThrough` for the four numbers in the one vector. */
|
|
7167
|
+
gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
|
|
6857
7168
|
gl.uniform3fv(u['uRefractTint'] ?? null, WHITE_TINT);
|
|
6858
|
-
gl.
|
|
7169
|
+
gl.uniform3fv(u['uGlassTint'] ?? null, WHITE_TINT);
|
|
6859
7170
|
gl.uniform3fv(u['uDirectionalDir'] ?? null, env.directionalDir);
|
|
6860
7171
|
gl.uniform3fv(u['uDirectionalColor'] ?? null, env.directionalColor);
|
|
6861
7172
|
gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);
|
|
@@ -6957,7 +7268,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6957
7268
|
* its own copy of this lookup; the two backends have to project the same way.
|
|
6958
7269
|
*/
|
|
6959
7270
|
gl.uniformMatrix4fv(u['uLightViewProj'] ?? null, false, env.lightViewProj);
|
|
6960
|
-
gl.uniform1f(u['uShadowStrength'] ?? null, this.
|
|
7271
|
+
gl.uniform1f(u['uShadowStrength'] ?? null, this.sunShadows === null ? 0 : env.shadowStrength);
|
|
6961
7272
|
gl.uniform1f(u['uShadowMapSize'] ?? null, this.quality.directionalShadowMapSize);
|
|
6962
7273
|
gl.uniform1f(u['uShadowDepthSpan'] ?? null, env.shadowDepthSpan);
|
|
6963
7274
|
gl.uniform1f(u['uShadowMaxDistance'] ?? null, this.quality.directionalShadowMaxDistance);
|
|
@@ -6984,16 +7295,12 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6984
7295
|
*/
|
|
6985
7296
|
if (this.quality.directionalShadows) {
|
|
6986
7297
|
gl.activeTexture(gl.TEXTURE0);
|
|
6987
|
-
gl.bindTexture(gl.
|
|
6988
|
-
gl.uniform1i(u['
|
|
6989
|
-
|
|
6990
|
-
gl.activeTexture(gl.
|
|
6991
|
-
gl.bindTexture(gl.
|
|
6992
|
-
gl.uniform1i(u['
|
|
6993
|
-
|
|
6994
|
-
gl.activeTexture(gl.TEXTURE2);
|
|
6995
|
-
gl.bindTexture(gl.TEXTURE_2D, this.dynamicShadowMap?.texture ?? this.emptyTexture2D);
|
|
6996
|
-
gl.uniform1i(u['uDynamicShadowMap'] ?? null, 2);
|
|
7298
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.sunShadows?.texture ?? this.emptyTexture2DArray);
|
|
7299
|
+
gl.uniform1i(u['uSunShadows'] ?? null, 0);
|
|
7300
|
+
/* What the sun keeps through glass, or the one-texel stand-in the lookup reads as none. */
|
|
7301
|
+
gl.activeTexture(gl.TEXTURE0 + SUN_GLASS_TINT_TEXTURE_UNIT);
|
|
7302
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.sunGlassTint?.texture ?? this.emptyTexture2DArray);
|
|
7303
|
+
gl.uniform1i(u['uSunGlassTints'] ?? null, SUN_GLASS_TINT_TEXTURE_UNIT);
|
|
6997
7304
|
}
|
|
6998
7305
|
|
|
6999
7306
|
if (this.pointShadows === null) {
|
|
@@ -7006,6 +7313,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7006
7313
|
} else {
|
|
7007
7314
|
/* Chosen in `pointShadowSystem.ts` and bound here; see `resolve` for the split. */
|
|
7008
7315
|
this.pointShadows.resolve(this.resolvedPointShadows);
|
|
7316
|
+
/* As the array stores them: 2L once glass has interleaved it. See `strideLayers`. */
|
|
7317
|
+
const stride = this.pointShadowArray?.stride ?? 1;
|
|
7318
|
+
strideLayers(this.resolvedPointShadows.layers, stride);
|
|
7319
|
+
strideLayers(this.resolvedPointShadows.liveLayers, stride);
|
|
7009
7320
|
this.bindPointShadows(u, DIRECTIONAL_SHADOW_UNITS);
|
|
7010
7321
|
/*
|
|
7011
7322
|
* The rectangles' layers, into the array `bindPointShadows` just put on its unit. Resolved
|
|
@@ -7223,13 +7534,14 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7223
7534
|
*/
|
|
7224
7535
|
tint: Vec3 | null = null,
|
|
7225
7536
|
/**
|
|
7226
|
-
* Where the mesh was last frame
|
|
7537
|
+
* Where the mesh was last frame — a `Mover` or a matrix — which this backend takes and ignores.
|
|
7227
7538
|
*
|
|
7228
7539
|
* Accepted rather than absent so that one scene draws through both renderers unchanged — the
|
|
7229
7540
|
* parity rule this repository is built on. Reconstruction is WebGPU's, having no compute stage
|
|
7230
|
-
* here, so there is no motion target for this to be written into
|
|
7541
|
+
* here, so there is no motion target for this to be written into, and a mover passed here is
|
|
7542
|
+
* neither read nor advanced.
|
|
7231
7543
|
*/
|
|
7232
|
-
_previousModel: ReadonlyMat4 | null = null,
|
|
7544
|
+
_previousModel: ReadonlyMat4 | Mover | null = null,
|
|
7233
7545
|
): void {
|
|
7234
7546
|
if (this.contextLost) return;
|
|
7235
7547
|
/* Geometry that has not all arrived is not drawn. See `Mesh.complete`. */
|
|
@@ -7474,19 +7786,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7474
7786
|
* translucent one rather than sampling a black texture and painting the pane the colour of a
|
|
7475
7787
|
* hole. That is the defined state the two-backends rule asks for instead of a silent no-op.
|
|
7476
7788
|
*/
|
|
7477
|
-
const
|
|
7478
|
-
let refracting = false;
|
|
7479
|
-
if (refraction > 0) {
|
|
7480
|
-
const snapshot = this.sceneTarget?.snapshotColor() ?? null;
|
|
7481
|
-
if (snapshot !== null) {
|
|
7482
|
-
refracting = true;
|
|
7483
|
-
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
7484
|
-
gl.bindTexture(gl.TEXTURE_2D, snapshot);
|
|
7485
|
-
gl.uniform1f(u['uRefractStrength'] ?? null, refraction);
|
|
7486
|
-
gl.uniform3fv(u['uRefractTint'] ?? null, options.refractTint ?? WHITE_TINT);
|
|
7487
|
-
gl.uniform1f(u['uRefractThickness'] ?? null, options.thicknessM ?? 0);
|
|
7488
|
-
}
|
|
7489
|
-
}
|
|
7789
|
+
const refracting = this.bindSeeThrough(u, options);
|
|
7490
7790
|
/*
|
|
7491
7791
|
* **The blend and the depth mask belong to whoever owns the pass.** In the ordinary case that
|
|
7492
7792
|
* is this draw; during an order-independent replay it is `OitPass`, which has set an additive
|
|
@@ -7529,6 +7829,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7529
7829
|
if (ownsState) gl.disable(gl.BLEND);
|
|
7530
7830
|
gl.uniform1f(u['uOpacity'] ?? null, 1);
|
|
7531
7831
|
if (tint !== null) gl.uniform3fv(u['uTint'] ?? null, WHITE_TINT);
|
|
7832
|
+
if (refracting) this.unbindSeeThrough(u);
|
|
7532
7833
|
/* Put back for whatever is drawn next, exactly as `uOpacity` and `uTint` are — a pass
|
|
7533
7834
|
cannot inherit a material from the draw before it. */
|
|
7534
7835
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
@@ -7916,16 +8217,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7916
8217
|
gl.uniform1i(u['uPeeledShadowEnabled'] ?? null, this.peelFilled ? 1 : 0);
|
|
7917
8218
|
|
|
7918
8219
|
gl.activeTexture(gl.TEXTURE0);
|
|
7919
|
-
gl.bindTexture(gl.
|
|
7920
|
-
gl.uniform1i(u['
|
|
7921
|
-
|
|
7922
|
-
gl.activeTexture(gl.TEXTURE1);
|
|
7923
|
-
gl.bindTexture(gl.TEXTURE_2D, this.peeledShadowMap?.texture ?? this.emptyTexture2D);
|
|
7924
|
-
gl.uniform1i(u['uPeeledShadowMap'] ?? null, 1);
|
|
7925
|
-
|
|
7926
|
-
gl.activeTexture(gl.TEXTURE2);
|
|
7927
|
-
gl.bindTexture(gl.TEXTURE_2D, this.dynamicShadowMap?.texture ?? this.emptyTexture2D);
|
|
7928
|
-
gl.uniform1i(u['uDynamicShadowMap'] ?? null, 2);
|
|
8220
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.sunShadows?.texture ?? this.emptyTexture2DArray);
|
|
8221
|
+
gl.uniform1i(u['uSunShadows'] ?? null, 0);
|
|
7929
8222
|
}
|
|
7930
8223
|
}
|
|
7931
8224
|
|