@driftengine/core 4.8.6 → 4.9.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 +132 -0
- package/README.md +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +8 -1
- package/dist/render/anisotropicLobe.d.ts +10 -0
- package/dist/render/anisotropicLobe.js +19 -0
- package/dist/render/areaLights.d.ts +35 -0
- package/dist/render/areaLights.js +35 -0
- package/dist/render/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +41 -3
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- package/dist/render/backend/webgl2/renderer.d.ts +140 -16
- package/dist/render/backend/webgl2/renderer.js +436 -44
- package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
- package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
- package/dist/render/backend/webgpu/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +16 -1
- package/dist/render/backend/webgpu/flatPass.js +58 -26
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +166 -3
- package/dist/render/backend/webgpu/renderer.js +738 -83
- package/dist/render/backend/webgpu/sceneCaptureTarget.d.ts +24 -0
- package/dist/render/backend/webgpu/sceneCaptureTarget.js +59 -0
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +34 -8
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/clusteredLights.d.ts +23 -5
- package/dist/render/clusteredLights.js +35 -8
- package/dist/render/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/driftLight/bake.d.ts +2 -0
- package/dist/render/driftLight/bake.js +1 -1
- package/dist/render/driftLight/falloff.d.ts +4 -2
- package/dist/render/driftLight/falloff.js +8 -2
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/gi/bounceLights.d.ts +3 -2
- package/dist/render/gi/bounceLights.js +8 -3
- package/dist/render/instanceCull.js +5 -0
- package/dist/render/instances.d.ts +19 -5
- package/dist/render/instances.js +9 -3
- package/dist/render/lightBudget.d.ts +12 -1
- package/dist/render/lightBudget.js +23 -3
- package/dist/render/lightmap.d.ts +23 -9
- package/dist/render/lightmap.js +40 -18
- package/dist/render/particlePool.d.ts +21 -0
- package/dist/render/particlePool.js +7 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +13 -0
- package/dist/render/pointLightSelection.js +3 -1
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +47 -15
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/rendererHarness.js +3 -0
- package/dist/render/rgb9e5.d.ts +22 -0
- package/dist/render/rgb9e5.js +47 -0
- package/dist/render/sceneCapture.d.ts +29 -0
- package/dist/render/sceneCapture.js +36 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +32 -1
- package/dist/render/screenSpaceReflection.js +14 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +7 -1
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.js +11 -0
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/anisotropic.d.ts +1 -1
- package/dist/render/shaders/flat/anisotropic.js +37 -3
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +46 -0
- package/dist/render/shaders/flat/glassTint.d.ts +3 -2
- package/dist/render/shaders/flat/glassTint.js +5 -1
- package/dist/render/shaders/flat/index.d.ts +15 -0
- package/dist/render/shaders/flat/index.js +22 -2
- package/dist/render/shaders/flat/lobes.d.ts +6 -0
- package/dist/render/shaders/flat/lobes.js +49 -43
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +85 -22
- package/dist/render/shaders/flat/models.d.ts +5 -2
- package/dist/render/shaders/flat/models.js +100 -16
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +1 -1
- package/dist/render/shaders/flat/preamble.js +10 -3
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/depth.wgsl.js +4 -4
- package/dist/render/shaders/generated/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +192 -16
- package/dist/render/shaders/generated/flat.wgsl.js +230 -54
- 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 +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +32 -7
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +32 -7
- package/dist/render/shaders/generated/water.wgsl.d.ts +23 -16
- package/dist/render/shaders/generated/water.wgsl.js +23 -16
- package/dist/render/shaders/gi/probeBake.wgsl.js +9 -5
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +13 -2
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +46 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -3
- package/dist/render/skinScatter.d.ts +3 -1
- package/dist/render/skinScatter.js +3 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +107 -1
- package/dist/render/surfaceModel.d.ts +29 -8
- package/dist/render/surfaceModel.js +33 -9
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +44 -1
- package/dist/render/surfaceTexture.js +96 -5
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +22 -2
- package/src/render/anisotropicLobe.ts +29 -0
- package/src/render/areaLights.ts +58 -0
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +58 -2
- package/src/render/backend/createRenderer.ts +18 -1
- package/src/render/backend/webgl2/renderer.ts +548 -50
- package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/flatPass.ts +63 -26
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +927 -100
- package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +44 -14
- package/src/render/clusteredLights.ts +41 -8
- package/src/render/displayRange.ts +61 -0
- package/src/render/driftLight/bake.ts +3 -1
- package/src/render/driftLight/falloff.ts +13 -2
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/gi/bounceLights.ts +12 -3
- package/src/render/instanceCull.ts +4 -0
- package/src/render/instances.ts +26 -6
- package/src/render/lightBudget.ts +40 -2
- package/src/render/lightmap.ts +64 -23
- package/src/render/particlePool.ts +23 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +20 -1
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +52 -15
- package/src/render/rendererHarness.ts +3 -0
- package/src/render/rgb9e5.ts +52 -0
- package/src/render/sceneCapture.ts +56 -0
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +38 -1
- package/src/render/shaders/bolt.ts +7 -1
- package/src/render/shaders/depth.ts +11 -0
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/anisotropic.ts +37 -3
- package/src/render/shaders/flat/areaLight.ts +46 -0
- package/src/render/shaders/flat/glassTint.ts +13 -2
- package/src/render/shaders/flat/index.ts +37 -2
- package/src/render/shaders/flat/lobes.ts +50 -43
- package/src/render/shaders/flat/main.ts +85 -22
- package/src/render/shaders/flat/models.ts +100 -16
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +1 -1
- package/src/render/shaders/flat/preamble.ts +10 -3
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +4 -4
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +230 -54
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +32 -7
- package/src/render/shaders/generated/water.wgsl.ts +23 -16
- package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/recon/motion.wgsl.ts +13 -2
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +46 -1
- package/src/render/shaders/water.ts +12 -3
- package/src/render/skinScatter.ts +3 -1
- package/src/render/ssrPass.ts +139 -1
- package/src/render/surfaceModel.ts +47 -10
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +136 -9
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
|
@@ -4,11 +4,17 @@ import { FOG_OFF, FOG_RECEDE, fogModeOf } from '../drawFog.js';
|
|
|
4
4
|
import { blendCovering, blendKeeping } from '../../sceneCoverage.js';
|
|
5
5
|
import { mat4 } from 'gl-matrix';
|
|
6
6
|
import { GL_DEPTH_REMAP, MAX_DEPTH_LAYER, depthClearFor, depthOffsetForLayer, GL_SHADOW_REMAP, REVERSED_DEPTH, SHADOW_DEPTH_CLEAR, glDepthFuncEqual, glShadowDepthFunc, } from '../../depthConvention.js';
|
|
7
|
+
import { maskOf } from '../../frame/resources.js';
|
|
8
|
+
/** The two copies a registered pass may declare it reads. See `drawPass`. */
|
|
9
|
+
const COLOR_SNAPSHOT = maskOf('colorSnapshot');
|
|
10
|
+
const DEPTH_SNAPSHOT = maskOf('depthSnapshot');
|
|
7
11
|
import { resolveGlass } from '../../glass.js';
|
|
8
12
|
import { PickableSet } from '../../pickable.js';
|
|
9
13
|
import { TEMPORAL_HISTORY_BLEND, TemporalHistory, jitterOffset, jitterProjection, } from '../../temporalAa.js';
|
|
10
14
|
import { DecalPass } from '../../decalPass.js';
|
|
11
15
|
import { SsrPass } from '../../ssrPass.js';
|
|
16
|
+
import { ReflectionSurfaceTargets } from '../../reflectionSurfaceTargets.js';
|
|
17
|
+
import { frameReflectionsRefused, resolveFrameReflections, } from '../../frameReflections.js';
|
|
12
18
|
import { GlobalMediumPass } from '../../globalMediumPass.js';
|
|
13
19
|
import { DEFAULT_GLOBAL_MEDIUM, WEAK_GPU_MEDIUM_STEPS, mediumActive, resolveGlobalMedium, } from '../../globalMedium.js';
|
|
14
20
|
import { REFLECTION_EDGE_FADE, ReflectionQueue } from '../../screenSpaceReflection.js';
|
|
@@ -28,7 +34,8 @@ import { attachContextLoss } from '../../contextLoss.js';
|
|
|
28
34
|
import { isWeakGpuFamily, webgl2RendererName } from '../../gpuCapability.js';
|
|
29
35
|
import { GpuTimer } from '../../gpuTimer.js';
|
|
30
36
|
import { compileProgram, uniformLocations } from '../../shader.js';
|
|
31
|
-
import { FULL_LIGHT_BUDGET, nextLightBudget, planLightBudget, } from '../../uniformVectorBudget.js';
|
|
37
|
+
import { countUniformVectors, FULL_LIGHT_BUDGET, nextLightBudget, planLightBudget, } from '../../uniformVectorBudget.js';
|
|
38
|
+
import { OVERLAY_FLOATS, overlayLays, packSurfaceOverlay, } from '../../surfaceOverlay.js';
|
|
32
39
|
import { FILM_FRAG, FILM_VERT } from '../../shaders/film.js';
|
|
33
40
|
import { SceneTarget } from '../../sceneTarget.js';
|
|
34
41
|
import { FILM_LOOK_WITHOUT_COMPOSITE } from '../../shaders/filmLook.js';
|
|
@@ -41,7 +48,7 @@ import { createDriftLightUniforms, resolveDriftLight } from '../../driftLight/un
|
|
|
41
48
|
import { flatFrag, flatVert } from '../../shaders/flat/index.js';
|
|
42
49
|
import { skinEight } from '../../shaders/skinning.js';
|
|
43
50
|
import { MODEL_MAP_TEXTURE_UNIT, MORPH_DELTA_TEXTURE_UNIT, SKIN_PALETTE_TEXTURE_UNIT, } from '../../lightBudget.js';
|
|
44
|
-
import { MODEL_PARAM_FLOATS, eyeAxisInWorld, packModel } from '../../surfaceModel.js';
|
|
51
|
+
import { MODEL_PARAM_FLOATS, eyeAxisInWorld, packModel, skinProfileDistance, } from '../../surfaceModel.js';
|
|
45
52
|
import { lightmapRegionsBound, modelBound, skinHalfBound } from '../../shaders/flat/models.js';
|
|
46
53
|
import { lightmapTexels, warnRegionsWithoutPage, warnUnpagedLightmap, withLightmapUvs, } from '../../lightmap.js';
|
|
47
54
|
import { GlSkinScatter } from './skinScatter.js';
|
|
@@ -86,6 +93,8 @@ import { resolveRenderQuality } from '../../renderQuality.js';
|
|
|
86
93
|
import { drawingBufferSize } from '../../drawingBuffer.js';
|
|
87
94
|
import { Mesh, createMeshIncremental } from '../../mesh.js';
|
|
88
95
|
import { SurfaceTexture } from '../../surfaceTexture.js';
|
|
96
|
+
import { sceneCaptureTexels } from '../../sceneCapture.js';
|
|
97
|
+
import { GlSceneCaptureTarget } from './sceneCaptureTarget.js';
|
|
89
98
|
import { glCompressedFormats } from '../../glCompressed.js';
|
|
90
99
|
import { PlumeRenderer } from '../../plumeRenderer.js';
|
|
91
100
|
import { createScatterDeform, resolveScatterDeform } from '../../scatterDeform.js';
|
|
@@ -102,8 +111,9 @@ import { SCATTER_DEPTH_VERT, SCATTER_FRAG, SCATTER_VERT } from '../../shaders/sc
|
|
|
102
111
|
import { FlockRenderer } from '../../flockRenderer.js';
|
|
103
112
|
import { TextRenderer } from '../../textRenderer.js';
|
|
104
113
|
import { SdfTextRenderer } from '../../sdfTextRenderer.js';
|
|
105
|
-
import { MOTION_BLUR_MAX_UV, RUSH_REACH_UV } from '../../vertexDefaults.js';
|
|
106
|
-
import { OUTPUT_TRANSFORM_CODE } from '../../vertexDefaults.js';
|
|
114
|
+
import { MOTION_BLUR_MAX_UV, OBJECT_BLUR_UNKEPT, RUSH_REACH_UV, clampMotionShare, } from '../../vertexDefaults.js';
|
|
115
|
+
import { OUTPUT_TRANSFORM_CODE, forwardTransformCode } from '../../vertexDefaults.js';
|
|
116
|
+
import { DEFAULT_FILMIC_CURVE, FILMIC_CLAMPED, FILMIC_CONSTANTS, FILMIC_WITHOUT_COMPOSITE, resolveFilmicCurve, } from '../../filmicCurve.js';
|
|
107
117
|
import { deviceSnappedCellSize } from '../../textLayout.js';
|
|
108
118
|
import { WindStreakRenderer } from '../../windStreakRenderer.js';
|
|
109
119
|
import { InstancedBatch } from './instanced.js';
|
|
@@ -602,6 +612,10 @@ export class WebGL2Renderer {
|
|
|
602
612
|
reflectionQueue = new ReflectionQueue();
|
|
603
613
|
/** Built on the first frame that submits a surface, and never for a scene with none. */
|
|
604
614
|
ssr = null;
|
|
615
|
+
/** The frame's materials' reflections, resolved; null where off. See `frameReflections.ts`. */
|
|
616
|
+
frameReflections;
|
|
617
|
+
/** Their two maps on the scene's framebuffer, null where they cannot be drawn. */
|
|
618
|
+
reflectionTargets;
|
|
605
619
|
/** Said once where a reflection cannot be traced at all. */
|
|
606
620
|
reflectionsRefused = false;
|
|
607
621
|
/** Where the frame's camera stands, which is what gives a reconstructed normal its sign. */
|
|
@@ -672,6 +686,8 @@ export class WebGL2Renderer {
|
|
|
672
686
|
* exactly as it asked to be and nothing about it changes.
|
|
673
687
|
*/
|
|
674
688
|
exposure;
|
|
689
|
+
/** The `filmic` curve's eight constants, held until `setFilmicCurve` is called again. */
|
|
690
|
+
filmConstants = new Float32Array(FILMIC_CONSTANTS);
|
|
675
691
|
/**
|
|
676
692
|
* This frame's veil colour, and how much of it to composite. See `setFrameVeil`.
|
|
677
693
|
*
|
|
@@ -873,8 +889,26 @@ export class WebGL2Renderer {
|
|
|
873
889
|
warnedNoPointShadowArray = false;
|
|
874
890
|
/** Said once, for the retired ambient dial. */
|
|
875
891
|
warnedEnvironmentAmbient = false;
|
|
892
|
+
/** The overlay the draws wear, `uOverlay`: see `setSurfaceOverlay`. */
|
|
893
|
+
overlayFloats = new Float32Array(OVERLAY_FLOATS);
|
|
894
|
+
/** Its atlas, and the 2D copy of it bound where the refraction copy goes. */
|
|
895
|
+
overlayMaps = null;
|
|
896
|
+
overlayTexture = null;
|
|
897
|
+
/** Whether this device's lit stage has room for the overlay's vectors: asked once. */
|
|
898
|
+
overlayRoom = null;
|
|
899
|
+
warnedOverlayRoom = false;
|
|
900
|
+
warnedOverlayBlocks = false;
|
|
876
901
|
/** Whether a probe is being baked, so the passes that would recurse into one can tell. */
|
|
877
902
|
probePassActive = false;
|
|
903
|
+
/**
|
|
904
|
+
* Whether a scene capture is being drawn (`captureScene`): an off-screen pass like a bake, so the
|
|
905
|
+
* frame's own view, its refraction copy and skin's spread are left alone, but lit as the frame is.
|
|
906
|
+
*/
|
|
907
|
+
capturePassActive = false;
|
|
908
|
+
/** Each capture's framebuffer, beside the texture a material binds. See `createSceneCapture`. */
|
|
909
|
+
captureTargets = new WeakMap();
|
|
910
|
+
/** Said once, where a driver refuses to draw into a capture. */
|
|
911
|
+
warnedCapture = false;
|
|
878
912
|
/** Whether the bake under way lights its faces by the grid. `ProbeBakeOptions.bounce`. */
|
|
879
913
|
probeBounce = false;
|
|
880
914
|
/** The clip-control extension, or null where this context does not offer it. */
|
|
@@ -941,7 +975,8 @@ export class WebGL2Renderer {
|
|
|
941
975
|
* the camera's matrix unchanged and multiplies nothing.
|
|
942
976
|
*/
|
|
943
977
|
viewProjFor(camera) {
|
|
944
|
-
|
|
978
|
+
/* A capture's rows are flipped as a probe face's are, so it reads as an image does. */
|
|
979
|
+
const scene = this.probePassActive || this.capturePassActive
|
|
945
980
|
? cubeFaceProjection(this.cubeFaceViewProj, this.sceneMatrix(camera.viewProjection))
|
|
946
981
|
: this.sceneMatrix(camera.viewProjection);
|
|
947
982
|
/*
|
|
@@ -1491,6 +1526,8 @@ export class WebGL2Renderer {
|
|
|
1491
1526
|
* call. `init` runs now rather than at the first frame, because building a pipeline in the
|
|
1492
1527
|
* frame loop is the allocation the house rules are about.
|
|
1493
1528
|
*/
|
|
1529
|
+
/** Each registered pass's declared reads, as a mask, resolved once at registration. */
|
|
1530
|
+
passReads = new Map();
|
|
1494
1531
|
registerPass(definition) {
|
|
1495
1532
|
const handle = registerIn(this.passes, definition);
|
|
1496
1533
|
/*
|
|
@@ -1510,6 +1547,8 @@ export class WebGL2Renderer {
|
|
|
1510
1547
|
};
|
|
1511
1548
|
if (definition.prepare !== undefined)
|
|
1512
1549
|
this.preparingPasses++;
|
|
1550
|
+
/* Resolved once: `maskOf` builds an array, and the frame path may not. */
|
|
1551
|
+
this.passReads.set(handle, maskOf(...(definition.reads ?? [])));
|
|
1513
1552
|
definition.init?.(this.passDevice);
|
|
1514
1553
|
return handle;
|
|
1515
1554
|
}
|
|
@@ -1561,10 +1600,28 @@ export class WebGL2Renderer {
|
|
|
1561
1600
|
gl: this.gl,
|
|
1562
1601
|
outputTransform: 0,
|
|
1563
1602
|
outputExposure: 1,
|
|
1603
|
+
sceneColor: null,
|
|
1604
|
+
sceneDepth: null,
|
|
1564
1605
|
};
|
|
1565
1606
|
const context = this.passContext;
|
|
1566
1607
|
context.outputTransform = this.gradeCode();
|
|
1567
1608
|
context.outputExposure = this.gradeExposure();
|
|
1609
|
+
/*
|
|
1610
|
+
* The copies a pass declared it reads, taken here with everything drawn before it: colour
|
|
1611
|
+
* afresh at each reading pass, as WebGPU's `takePassColour` does, so a full-screen effect drawn
|
|
1612
|
+
* last reads the whole frame; depth afresh too, since a blit is the whole cost of either here.
|
|
1613
|
+
* Not in a mirror, a probe's face or a capture, whose pictures are not the frame's.
|
|
1614
|
+
*/
|
|
1615
|
+
const reads = this.passReads.get(handle) ?? 0;
|
|
1616
|
+
const own = !this.reflectionPassActive && !this.probePassActive && !this.capturePassActive;
|
|
1617
|
+
context.sceneColor =
|
|
1618
|
+
own && (reads & COLOR_SNAPSHOT) !== 0
|
|
1619
|
+
? (this.sceneTarget?.snapshotColor(true) ?? null)
|
|
1620
|
+
: null;
|
|
1621
|
+
context.sceneDepth =
|
|
1622
|
+
own && (reads & DEPTH_SNAPSHOT) !== 0
|
|
1623
|
+
? (this.sceneTarget?.snapshotDepth(true) ?? null)
|
|
1624
|
+
: null;
|
|
1568
1625
|
definition.draw(context);
|
|
1569
1626
|
}
|
|
1570
1627
|
/** Let go of a pass. A handle kept past this draws nothing; see `PassHandle`. */
|
|
@@ -1572,6 +1629,7 @@ export class WebGL2Renderer {
|
|
|
1572
1629
|
const definition = unregisterIn(this.passes, handle);
|
|
1573
1630
|
if (definition?.prepare !== undefined)
|
|
1574
1631
|
this.preparingPasses--;
|
|
1632
|
+
this.passReads.delete(handle);
|
|
1575
1633
|
if (definition !== undefined && this.passDevice !== null)
|
|
1576
1634
|
definition.dispose?.(this.passDevice);
|
|
1577
1635
|
}
|
|
@@ -1722,10 +1780,10 @@ export class WebGL2Renderer {
|
|
|
1722
1780
|
gl.bindTexture(gl.TEXTURE_2D, this.clusterTexture);
|
|
1723
1781
|
gl.uniform1i(u['uClusterTable'] ?? null, CLUSTER_TABLE_TEXTURE_UNIT);
|
|
1724
1782
|
gl.uniform1i(u['uClustered'] ?? null, on ? 1 : 0);
|
|
1725
|
-
if (!on)
|
|
1726
|
-
return;
|
|
1727
1783
|
/*
|
|
1728
|
-
* The frustum, read off the projection rather than taken as a parameter
|
|
1784
|
+
* The frustum, read off the projection rather than taken as a parameter — **and with the view,
|
|
1785
|
+
* written whether or not the lights are clustered**: a surface overlay's rim finds its place on
|
|
1786
|
+
* the screen through the same two (`overlayScreen`).
|
|
1729
1787
|
*
|
|
1730
1788
|
* A perspective matrix carries `1 / tan(fovY/2)` at [5] and that over the aspect at [0], and
|
|
1731
1789
|
* the near and far planes in [14] and [10]. Deriving them here means the binner and the shader
|
|
@@ -1743,6 +1801,8 @@ export class WebGL2Renderer {
|
|
|
1743
1801
|
this.clusterFrustum[3] = aspect;
|
|
1744
1802
|
gl.uniform4fv(u['uClusterFrustum'] ?? null, this.clusterFrustum);
|
|
1745
1803
|
gl.uniformMatrix4fv(u['uView'] ?? null, false, camera.view);
|
|
1804
|
+
if (!on)
|
|
1805
|
+
return;
|
|
1746
1806
|
this.clusterTable ??= createClusterTable();
|
|
1747
1807
|
/* The rectangles past the fixed arm's go into the table. See `ClusterLightSet.areas`. */
|
|
1748
1808
|
const lights = fillClusterLightSet(env, this.clusterLights, this.shadedAreaLights);
|
|
@@ -1816,6 +1876,11 @@ export class WebGL2Renderer {
|
|
|
1816
1876
|
this.quality = resolveRenderQuality(qualityOptions);
|
|
1817
1877
|
/* The grade this world asked for, until a frame says otherwise. See `setOutputExposure`. */
|
|
1818
1878
|
this.exposure = this.quality.outputExposure;
|
|
1879
|
+
resolveFilmicCurve(DEFAULT_FILMIC_CURVE, this.filmConstants);
|
|
1880
|
+
if (this.quality.outputTransform === 'filmic' &&
|
|
1881
|
+
!(this.quality.screenEffects && this.quality.hdrScene)) {
|
|
1882
|
+
console.warn(FILMIC_WITHOUT_COMPOSITE);
|
|
1883
|
+
}
|
|
1819
1884
|
/*
|
|
1820
1885
|
* Multisampling, but only when anything can use it.
|
|
1821
1886
|
*
|
|
@@ -2074,6 +2139,29 @@ export class WebGL2Renderer {
|
|
|
2074
2139
|
this.sceneTarget = this.quality.screenEffects
|
|
2075
2140
|
? new SceneTarget(gl, this.quality.sceneSamples, this.quality.hdrScene, this.quality.discardResolvedAttachments)
|
|
2076
2141
|
: null;
|
|
2142
|
+
/*
|
|
2143
|
+
* The frame's materials' reflections, where the frame can carry them: scene light to swap the
|
|
2144
|
+
* probe's share in, and one sample, which the trace's depth copy and both maps are. Said once
|
|
2145
|
+
* where it cannot, in the words the other backend uses. See `frameReflections.ts`.
|
|
2146
|
+
*/
|
|
2147
|
+
this.frameReflections = resolveFrameReflections(this.quality.screenSpaceReflections);
|
|
2148
|
+
const reflectionsRefusal = this.frameReflections === null
|
|
2149
|
+
? null
|
|
2150
|
+
: this.sceneTarget === null || !this.sceneTarget.keepsRange
|
|
2151
|
+
? 'the frame keeps no scene light to swap the probe in (`screenEffects` and `hdrScene`)'
|
|
2152
|
+
: this.sceneTarget.sampleCount > 1
|
|
2153
|
+
? 'a multisampled frame has no single depth or colour to march through'
|
|
2154
|
+
: null;
|
|
2155
|
+
if (reflectionsRefusal !== null) {
|
|
2156
|
+
console.warn(`WebGL2: ${frameReflectionsRefused(reflectionsRefusal)}`);
|
|
2157
|
+
}
|
|
2158
|
+
this.reflectionTargets =
|
|
2159
|
+
this.frameReflections !== null && reflectionsRefusal === null
|
|
2160
|
+
? new ReflectionSurfaceTargets(gl)
|
|
2161
|
+
: null;
|
|
2162
|
+
/* The lit programs write the maps from the first frame they are rebuilt in. See `litOn`. */
|
|
2163
|
+
if (this.reflectionTargets !== null)
|
|
2164
|
+
this.askLit('REFLECTION_MAPS');
|
|
2077
2165
|
/* Screen-space skin needs the composite to add into; without one it is pre-integrated, said once. */
|
|
2078
2166
|
if (this.quality.skinScattering === 'screen-space' && this.sceneTarget === null) {
|
|
2079
2167
|
console.warn("WebGL2: skinScattering 'screen-space' needs screenEffects to add into; skin is pre-integrated");
|
|
@@ -2545,6 +2633,76 @@ export class WebGL2Renderer {
|
|
|
2545
2633
|
createLightmap(page) {
|
|
2546
2634
|
return new SurfaceTexture(this.gl, lightmapTexels(page), { wrap: 'clamp', mipmap: false });
|
|
2547
2635
|
}
|
|
2636
|
+
/**
|
|
2637
|
+
* A texture the scene can be drawn into, for a material to show. See `RendererApi` and
|
|
2638
|
+
* `sceneCapture.ts`. Half floats where the frame keeps range, as a probe does.
|
|
2639
|
+
*/
|
|
2640
|
+
createSceneCapture(width, height) {
|
|
2641
|
+
const float = this.quality.hdrScene && this.gl.getExtension('EXT_color_buffer_float') !== null;
|
|
2642
|
+
const texture = new SurfaceTexture(this.gl, sceneCaptureTexels(width, height, float), {
|
|
2643
|
+
wrap: 'clamp',
|
|
2644
|
+
mipmap: false,
|
|
2645
|
+
});
|
|
2646
|
+
this.captureTargets.set(texture, new GlSceneCaptureTarget(this.gl, texture, width, height, this.sceneTarget?.sampleCount ?? 1, float));
|
|
2647
|
+
return texture;
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Draw the scene into a capture from `camera`: `draw` is handed the camera, its matrices updated
|
|
2651
|
+
* for the capture's shape, and submits the scene as it would to the screen. See `RendererApi`.
|
|
2652
|
+
*
|
|
2653
|
+
* **Radiance, as a probe bake stores it**: the output transform and exposure are held off for the
|
|
2654
|
+
* pass, so the frame grades a screen showing it once. No temporal jitter, which a capture has no
|
|
2655
|
+
* resolve to undo. Returns whether it drew: false for a texture that is not a capture, or one the
|
|
2656
|
+
* driver will not draw into.
|
|
2657
|
+
*/
|
|
2658
|
+
captureScene(capture, camera, clearColor, draw) {
|
|
2659
|
+
if (this.contextLost)
|
|
2660
|
+
return false;
|
|
2661
|
+
const target = this.captureTargets.get(capture);
|
|
2662
|
+
if (target === undefined)
|
|
2663
|
+
return false;
|
|
2664
|
+
if (!target.usable) {
|
|
2665
|
+
if (!this.warnedCapture) {
|
|
2666
|
+
this.warnedCapture = true;
|
|
2667
|
+
console.warn('Renderer: this driver will not draw into a scene capture, so it keeps its clear. ' +
|
|
2668
|
+
'Nothing else is affected.');
|
|
2669
|
+
}
|
|
2670
|
+
return false;
|
|
2671
|
+
}
|
|
2672
|
+
camera.updateMatrices(target.width / target.height);
|
|
2673
|
+
const { gl } = this;
|
|
2674
|
+
const jittering = this.temporalJittering;
|
|
2675
|
+
this.temporalJittering = false;
|
|
2676
|
+
this.capturePassActive = true;
|
|
2677
|
+
this.useFlatProgram();
|
|
2678
|
+
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, 0);
|
|
2679
|
+
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, 1);
|
|
2680
|
+
this.materials.dirty();
|
|
2681
|
+
target.begin(gl, clearColor, this.depthClear);
|
|
2682
|
+
/*
|
|
2683
|
+
* **Rows flipped, as a probe face's are.** A GL framebuffer's first row is its bottom and an
|
|
2684
|
+
* image's is its top, so a capture drawn upright would be shown upside down by every material
|
|
2685
|
+
* reading it as the image it is; `viewProjFor` negates clip y for the pass, and negating one axis
|
|
2686
|
+
* reverses every triangle's winding, which the front face follows. WebGPU's rows already run
|
|
2687
|
+
* the image's way.
|
|
2688
|
+
*/
|
|
2689
|
+
gl.frontFace(gl.CW);
|
|
2690
|
+
try {
|
|
2691
|
+
draw(camera);
|
|
2692
|
+
}
|
|
2693
|
+
finally {
|
|
2694
|
+
target.end(gl);
|
|
2695
|
+
gl.frontFace(gl.CCW);
|
|
2696
|
+
this.useFlatProgram();
|
|
2697
|
+
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.gradeCode());
|
|
2698
|
+
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.gradeExposure());
|
|
2699
|
+
this.materials.dirty();
|
|
2700
|
+
this.capturePassActive = false;
|
|
2701
|
+
this.temporalJittering = jittering;
|
|
2702
|
+
this.restoreViewport();
|
|
2703
|
+
}
|
|
2704
|
+
return true;
|
|
2705
|
+
}
|
|
2548
2706
|
/**
|
|
2549
2707
|
* Replace a surface texture's pixels, keeping the GPU object and its sampler state.
|
|
2550
2708
|
*
|
|
@@ -2561,11 +2719,18 @@ export class WebGL2Renderer {
|
|
|
2561
2719
|
if (this.contextLost)
|
|
2562
2720
|
return;
|
|
2563
2721
|
texture.update(this.gl, source);
|
|
2722
|
+
/* New pixels are a new copy for the overlay's slot: see `SurfaceTexture.flatLayer`. */
|
|
2723
|
+
if (texture === this.overlayMaps)
|
|
2724
|
+
this.bindOverlayMaps(texture);
|
|
2564
2725
|
}
|
|
2565
2726
|
disposeSurfaceTexture(texture) {
|
|
2566
2727
|
if (this.contextLost)
|
|
2567
2728
|
return;
|
|
2729
|
+
if (texture === this.overlayMaps)
|
|
2730
|
+
this.bindOverlayMaps(null);
|
|
2568
2731
|
texture.dispose(this.gl);
|
|
2732
|
+
this.captureTargets.get(texture)?.dispose(this.gl);
|
|
2733
|
+
this.captureTargets.delete(texture);
|
|
2569
2734
|
}
|
|
2570
2735
|
/**
|
|
2571
2736
|
* Choose the surface texture the following `drawMesh` calls sample, or `null` for none.
|
|
@@ -2768,7 +2933,7 @@ export class WebGL2Renderer {
|
|
|
2768
2933
|
const model = material?.model;
|
|
2769
2934
|
warnUnpagedLightmap(model, material?.modelMap);
|
|
2770
2935
|
if (model?.kind === 'skin' && this.skinScatter !== null) {
|
|
2771
|
-
this.skinScatter.setProfile(model.profile, model
|
|
2936
|
+
this.skinScatter.setProfile(model.profile, skinProfileDistance(model, 0), skinProfileDistance(model, 1), skinProfileDistance(model, 2));
|
|
2772
2937
|
}
|
|
2773
2938
|
/*
|
|
2774
2939
|
* Written to every flat program, because material state persists across draws and a skinned
|
|
@@ -2892,8 +3057,13 @@ export class WebGL2Renderer {
|
|
|
2892
3057
|
if (modelMap !== null)
|
|
2893
3058
|
modelMap.bind(gl, MODEL_MAP_TEXTURE_UNIT);
|
|
2894
3059
|
gl.uniform1i(u['uModelMap'] ?? null, MODEL_MAP_TEXTURE_UNIT);
|
|
2895
|
-
packModel(material?.model ?? null, modelMap !== null, this.modelParams);
|
|
3060
|
+
packModel(material?.model ?? null, modelMap !== null, this.modelParams, material?.physicalSpecular === true);
|
|
3061
|
+
/* The first physical highlight asked for is when the lit programs start carrying one. */
|
|
3062
|
+
if (material?.physicalSpecular === true)
|
|
3063
|
+
this.askLit('PHYSICAL_SPECULAR');
|
|
2896
3064
|
gl.uniform4fv(u['uModelParams'] ?? null, this.modelParams);
|
|
3065
|
+
/* The draw's overlay, which a program born mid-pass must wear too: see `setSurfaceOverlay`. */
|
|
3066
|
+
gl.uniform4fv(u['uOverlay'] ?? null, this.overlayFloats);
|
|
2897
3067
|
/* The albedo's effects table, or the stand-in the shader reads as none. Before the early
|
|
2898
3068
|
return, so a material with no albedo still leaves a complete texture on the unit. */
|
|
2899
3069
|
if (albedo === null) {
|
|
@@ -2952,18 +3122,6 @@ export class WebGL2Renderer {
|
|
|
2952
3122
|
gl.activeTexture(gl.TEXTURE0 + SURFACE_TEXTURE_UNIT);
|
|
2953
3123
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
|
|
2954
3124
|
}
|
|
2955
|
-
/**
|
|
2956
|
-
* A pass-level scale over the grain the geometry itself declared, 0 to 1.
|
|
2957
|
-
*
|
|
2958
|
-
* Which surfaces are mineral is now `MeshData.grain`, stated per vertex through
|
|
2959
|
-
* `MeshBuilder.setGrain` — because it is a property of a material, and absent means none.
|
|
2960
|
-
* This stays as the override for the case that has no answer to state: an imported model
|
|
2961
|
-
* arrives with no grain information at all, and a caller drawing one decides for it.
|
|
2962
|
-
*
|
|
2963
|
-
* Pass state, like `setSurfaceTexture`, because a material covers many draws. The default
|
|
2964
|
-
* is 1 and `bindMeshPass` restores it, so it scales geometry that declared grain and
|
|
2965
|
-
* leaves geometry that did not exactly as it is.
|
|
2966
|
-
*/
|
|
2967
3125
|
/**
|
|
2968
3126
|
* The ambient the following draws take, as nine spherical-harmonic coefficients of incoming
|
|
2969
3127
|
* radiance — red, green and blue of each, twenty-seven numbers — or `null` for the frame's own:
|
|
@@ -2975,16 +3133,6 @@ export class WebGL2Renderer {
|
|
|
2975
3133
|
* only — a glossy surface still reflects the probes — and it is pass state like the material,
|
|
2976
3134
|
* which `bindMeshPass` clears, so a mirror or a probe bake drawn after does not inherit it.
|
|
2977
3135
|
*/
|
|
2978
|
-
/**
|
|
2979
|
-
* How much of the environment the following draws mirror, 0 to 1.
|
|
2980
|
-
*
|
|
2981
|
-
* Pass state beside the grain, and the counterpart to it: grain is a surface being uneven,
|
|
2982
|
-
* this is a surface being smooth enough to carry an image. Polished paint, glass, chrome
|
|
2983
|
-
* and still water want it; plaster and stone want none.
|
|
2984
|
-
*
|
|
2985
|
-
* Defaults to zero and bindMeshPass restores it, so a scene that never calls this looks
|
|
2986
|
-
* exactly as it did.
|
|
2987
|
-
*/
|
|
2988
3136
|
setAmbientSH(coefficients) {
|
|
2989
3137
|
if (this.contextLost)
|
|
2990
3138
|
return;
|
|
@@ -2996,6 +3144,16 @@ export class WebGL2Renderer {
|
|
|
2996
3144
|
}
|
|
2997
3145
|
this.useFlatProgram();
|
|
2998
3146
|
}
|
|
3147
|
+
/**
|
|
3148
|
+
* How much of the environment the following draws mirror, 0 to 1.
|
|
3149
|
+
*
|
|
3150
|
+
* Pass state beside the grain, and the counterpart to it: grain is a surface being uneven,
|
|
3151
|
+
* this is a surface being smooth enough to carry an image. Polished paint, glass, chrome
|
|
3152
|
+
* and still water want it; plaster and stone want none.
|
|
3153
|
+
*
|
|
3154
|
+
* Defaults to zero and bindMeshPass restores it, so a scene that never calls this looks
|
|
3155
|
+
* exactly as it did.
|
|
3156
|
+
*/
|
|
2999
3157
|
setSurfaceReflectivity(amount) {
|
|
3000
3158
|
if (this.contextLost)
|
|
3001
3159
|
return;
|
|
@@ -3003,6 +3161,67 @@ export class WebGL2Renderer {
|
|
|
3003
3161
|
this.environmentDials[1] = Math.min(1, Math.max(0, amount));
|
|
3004
3162
|
this.writeFlatVector('uEnvironmentDials', this.environmentDials);
|
|
3005
3163
|
}
|
|
3164
|
+
/**
|
|
3165
|
+
* The overlay the following draws wear — a rim of light, a dissolve, wrinkles by region — or null
|
|
3166
|
+
* for none. Pass state, as the material is: `bindMeshPass` puts it back to none. See
|
|
3167
|
+
* `surfaceOverlay.ts` for what it lays and `shaders/flat/overlay.ts` for how.
|
|
3168
|
+
*
|
|
3169
|
+
* **Refused, said once, where the lit stage has no room for it.** Fifteen vectors more than the
|
|
3170
|
+
* program this device fits: counted from the source as `fitFlatProgram` counts, and on a device
|
|
3171
|
+
* whose limit is the 256 an Adreno 740 reports, the eight-light build at 254 has none. The draws
|
|
3172
|
+
* then wear nothing, which is the picture a game without the feature draws. Its atlas is bound as
|
|
3173
|
+
* a 2D copy of its first layer, in the refraction copy's unit (`SurfaceTexture.flatLayer`); a
|
|
3174
|
+
* compressed atlas has no copy and is read as none, also said once.
|
|
3175
|
+
*/
|
|
3176
|
+
setSurfaceOverlay(overlay) {
|
|
3177
|
+
if (this.contextLost)
|
|
3178
|
+
return;
|
|
3179
|
+
let wanted = overlay;
|
|
3180
|
+
if (overlayLays(wanted) && !this.overlayFits()) {
|
|
3181
|
+
if (!this.warnedOverlayRoom) {
|
|
3182
|
+
this.warnedOverlayRoom = true;
|
|
3183
|
+
console.warn('Renderer: setSurfaceOverlay is refused on this device. The overlay takes fifteen ' +
|
|
3184
|
+
'fragment uniform vectors and the lit shader already uses all but ' +
|
|
3185
|
+
`${this.overlayRoomLeft()} of the ${this.fragmentVectorLimit()} this GPU offers; ` +
|
|
3186
|
+
'draws wear no overlay. A lower `maxLights` makes the room, or WebGPU has it.');
|
|
3187
|
+
}
|
|
3188
|
+
wanted = null;
|
|
3189
|
+
}
|
|
3190
|
+
packSurfaceOverlay(wanted, this.overlayFloats);
|
|
3191
|
+
if (overlayLays(wanted))
|
|
3192
|
+
this.askLit('SURFACE_OVERLAY');
|
|
3193
|
+
this.materials.dirty();
|
|
3194
|
+
this.writeFlatVector('uOverlay', this.overlayFloats);
|
|
3195
|
+
this.bindOverlayMaps((wanted?.maps ?? null));
|
|
3196
|
+
}
|
|
3197
|
+
/** The overlay's atlas into the refraction copy's unit, as a 2D copy, or the empty texture. */
|
|
3198
|
+
bindOverlayMaps(maps) {
|
|
3199
|
+
const { gl } = this;
|
|
3200
|
+
this.overlayMaps = maps;
|
|
3201
|
+
this.overlayTexture = maps === null ? null : maps.flatLayer(gl);
|
|
3202
|
+
if (maps !== null && this.overlayTexture === null && !this.warnedOverlayBlocks) {
|
|
3203
|
+
this.warnedOverlayBlocks = true;
|
|
3204
|
+
console.warn("Renderer: a surface overlay's maps are a compressed texture, which WebGL2 cannot copy " +
|
|
3205
|
+
'into the 2D image the lit stage reads them from. The overlay is drawn without its ' +
|
|
3206
|
+
'images; upload the atlas from an image instead.');
|
|
3207
|
+
}
|
|
3208
|
+
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3209
|
+
gl.bindTexture(gl.TEXTURE_2D, this.overlayTexture ?? this.emptyTexture2D);
|
|
3210
|
+
}
|
|
3211
|
+
/** The most fragment uniform vectors this GPU offers a stage. */
|
|
3212
|
+
fragmentVectorLimit() {
|
|
3213
|
+
return this.gl.getParameter(this.gl.MAX_FRAGMENT_UNIFORM_VECTORS);
|
|
3214
|
+
}
|
|
3215
|
+
/** What the lit shader at this renderer's budget leaves of the limit, with no overlay. */
|
|
3216
|
+
overlayRoomLeft() {
|
|
3217
|
+
return (this.fragmentVectorLimit() - countUniformVectors(this.flatFragAt(this.lightBudget, false)));
|
|
3218
|
+
}
|
|
3219
|
+
/** Whether the lit shader with the overlay compiled in fits this GPU: counted once. */
|
|
3220
|
+
overlayFits() {
|
|
3221
|
+
this.overlayRoom ??=
|
|
3222
|
+
countUniformVectors(this.flatFragAt(this.lightBudget, true)) <= this.fragmentVectorLimit();
|
|
3223
|
+
return this.overlayRoom;
|
|
3224
|
+
}
|
|
3006
3225
|
/**
|
|
3007
3226
|
* How bright the environment the surfaces drawn next reflect is. 1 is the default and identity.
|
|
3008
3227
|
*
|
|
@@ -3043,6 +3262,18 @@ export class WebGL2Renderer {
|
|
|
3043
3262
|
console.warn('Renderer: setEnvironmentAmbient no longer does anything. A baked probe now lights a ' +
|
|
3044
3263
|
'surface through projected irradiance, and there is nothing left to tune.');
|
|
3045
3264
|
}
|
|
3265
|
+
/**
|
|
3266
|
+
* A pass-level scale over the grain the geometry itself declared, 0 to 1.
|
|
3267
|
+
*
|
|
3268
|
+
* Which surfaces are mineral is now `MeshData.grain`, stated per vertex through
|
|
3269
|
+
* `MeshBuilder.setGrain` — because it is a property of a material, and absent means none.
|
|
3270
|
+
* This stays as the override for the case that has no answer to state: an imported model
|
|
3271
|
+
* arrives with no grain information at all, and a caller drawing one decides for it.
|
|
3272
|
+
*
|
|
3273
|
+
* Pass state, like `setSurfaceTexture`, because a material covers many draws. The default
|
|
3274
|
+
* is 1 and `bindMeshPass` restores it, so it scales geometry that declared grain and
|
|
3275
|
+
* leaves geometry that did not exactly as it is.
|
|
3276
|
+
*/
|
|
3046
3277
|
setSurfaceGrain(amount) {
|
|
3047
3278
|
if (this.contextLost)
|
|
3048
3279
|
return;
|
|
@@ -3409,10 +3640,15 @@ export class WebGL2Renderer {
|
|
|
3409
3640
|
gl.enable(gl.SAMPLE_ALPHA_TO_COVERAGE);
|
|
3410
3641
|
if (ditheredBlend)
|
|
3411
3642
|
gl.uniform4fv(u['uCutout'] ?? null, this.cutoutUniform(this.currentMaterial, true));
|
|
3643
|
+
const keeps = !blend && this.reflectionKeeps();
|
|
3644
|
+
if (keeps)
|
|
3645
|
+
this.reflectionTargets?.on();
|
|
3412
3646
|
if (culling && cullsInstances(count, mesh.indexCount))
|
|
3413
3647
|
batch.drawCulled(gl, data, this.frustum);
|
|
3414
3648
|
else
|
|
3415
3649
|
batch.draw(gl, count);
|
|
3650
|
+
if (keeps)
|
|
3651
|
+
this.reflectionTargets?.off();
|
|
3416
3652
|
if (coverage)
|
|
3417
3653
|
gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE);
|
|
3418
3654
|
if (ditheredBlend)
|
|
@@ -3464,7 +3700,7 @@ export class WebGL2Renderer {
|
|
|
3464
3700
|
const glassy = resolveGlass(options.glass, this.glassScratch);
|
|
3465
3701
|
if (refraction <= 0 && !glassy)
|
|
3466
3702
|
return false;
|
|
3467
|
-
if (this.probePassActive || this.reflectionPassActive)
|
|
3703
|
+
if (this.probePassActive || this.reflectionPassActive || this.capturePassActive)
|
|
3468
3704
|
return false;
|
|
3469
3705
|
const snapshot = this.sceneTarget?.snapshotColor(false, glassy) ?? null;
|
|
3470
3706
|
if (snapshot === null)
|
|
@@ -3483,7 +3719,8 @@ export class WebGL2Renderer {
|
|
|
3483
3719
|
const { gl } = this;
|
|
3484
3720
|
gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
|
|
3485
3721
|
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
3486
|
-
|
|
3722
|
+
/* The overlay's atlas, where one is held: it shares the unit. See `setSurfaceOverlay`. */
|
|
3723
|
+
gl.bindTexture(gl.TEXTURE_2D, this.overlayTexture ?? this.emptyTexture2D);
|
|
3487
3724
|
}
|
|
3488
3725
|
disposeMesh(mesh) {
|
|
3489
3726
|
/*
|
|
@@ -3694,7 +3931,7 @@ export class WebGL2Renderer {
|
|
|
3694
3931
|
*/
|
|
3695
3932
|
gradeCode() {
|
|
3696
3933
|
return this.sceneTarget === null || !this.quality.hdrScene
|
|
3697
|
-
?
|
|
3934
|
+
? forwardTransformCode(this.quality.outputTransform)
|
|
3698
3935
|
: 0;
|
|
3699
3936
|
}
|
|
3700
3937
|
gradeExposure() {
|
|
@@ -3763,6 +4000,20 @@ export class WebGL2Renderer {
|
|
|
3763
4000
|
createParticles(capacity, options) {
|
|
3764
4001
|
return new ParticleBatch(this.gl, capacity, options);
|
|
3765
4002
|
}
|
|
4003
|
+
/**
|
|
4004
|
+
* Particles a caller's own compute wrote: WebGPU's alone, since this backend has no compute stage
|
|
4005
|
+
* to have written them (`computeSupported`). Said once, and nothing is drawn.
|
|
4006
|
+
*/
|
|
4007
|
+
drawDeviceParticles(_batch, _particles, _camera, _env, _timeSeconds) {
|
|
4008
|
+
if (this.warnedDeviceParticles)
|
|
4009
|
+
return;
|
|
4010
|
+
this.warnedDeviceParticles = true;
|
|
4011
|
+
console.warn('Renderer: drawDeviceParticles draws particles a compute shader wrote, and WebGL2 has no ' +
|
|
4012
|
+
'compute stage, so nothing is drawn. Check `computeSupported`, and draw a pool with ' +
|
|
4013
|
+
'`drawParticles` where it is false.');
|
|
4014
|
+
}
|
|
4015
|
+
/** Said once: see `drawDeviceParticles`. */
|
|
4016
|
+
warnedDeviceParticles = false;
|
|
3766
4017
|
/**
|
|
3767
4018
|
* Draw a live particle pool.
|
|
3768
4019
|
*
|
|
@@ -3820,7 +4071,10 @@ export class WebGL2Renderer {
|
|
|
3820
4071
|
const u = batch.uniforms;
|
|
3821
4072
|
const scene = this.sceneTarget;
|
|
3822
4073
|
let depth = null;
|
|
3823
|
-
if (batch.softDepth > 0 &&
|
|
4074
|
+
if (batch.softDepth > 0 &&
|
|
4075
|
+
!this.reflectionPassActive &&
|
|
4076
|
+
!this.probePassActive &&
|
|
4077
|
+
!this.capturePassActive) {
|
|
3824
4078
|
depth = scene?.snapshotDepth(true) ?? null;
|
|
3825
4079
|
if (depth === null && !this.warnedSpriteDepth) {
|
|
3826
4080
|
this.warnedSpriteDepth = true;
|
|
@@ -4680,7 +4934,7 @@ export class WebGL2Renderer {
|
|
|
4680
4934
|
* throws a sentence with the device's numbers in it rather than a bare driver string.
|
|
4681
4935
|
*/
|
|
4682
4936
|
/** The lit fragment source this renderer's profile compiles, at a light budget. */
|
|
4683
|
-
flatFragAt(budget) {
|
|
4937
|
+
flatFragAt(budget, overlay = this.litOn.SURFACE_OVERLAY) {
|
|
4684
4938
|
return flatFrag({
|
|
4685
4939
|
pointShadows: this.quality.pointShadows,
|
|
4686
4940
|
directionalShadows: this.quality.directionalShadows,
|
|
@@ -4692,6 +4946,9 @@ export class WebGL2Renderer {
|
|
|
4692
4946
|
lightFixtures: this.litOn.LIGHT_FIXTURES,
|
|
4693
4947
|
surfaceEffects: this.litOn.SURFACE_EFFECTS,
|
|
4694
4948
|
driftLight: this.litOn.DRIFT_LIGHT,
|
|
4949
|
+
physicalSpecular: this.litOn.PHYSICAL_SPECULAR,
|
|
4950
|
+
surfaceOverlay: overlay,
|
|
4951
|
+
reflectionMaps: this.litOn.REFLECTION_MAPS,
|
|
4695
4952
|
maxLights: budget.maxLights,
|
|
4696
4953
|
maxAreaLights: budget.maxAreaLights,
|
|
4697
4954
|
});
|
|
@@ -5363,10 +5620,20 @@ export class WebGL2Renderer {
|
|
|
5363
5620
|
* Set before `beginFrame` and held until changed, like `setSpeedRush`, which it sits
|
|
5364
5621
|
* beside for the same reason: both describe how the finished image is presented rather
|
|
5365
5622
|
* than anything in the world.
|
|
5623
|
+
*
|
|
5624
|
+
* `maxShare` is the longest smear, as a share of the frame (0.03 unless given, at most half): a
|
|
5625
|
+
* fast turn softens the frame rather than erasing it. **Each drawn object's own motion is
|
|
5626
|
+
* followed only under a reconstruction on WebGPU**, which draws the motion target it reads; here,
|
|
5627
|
+
* and on WebGPU without one, the camera's motion alone smears the frame, and a draw that names
|
|
5628
|
+
* where it was last frame is told so once.
|
|
5366
5629
|
*/
|
|
5367
|
-
setCameraMotionBlur(scale) {
|
|
5630
|
+
setCameraMotionBlur(scale, maxShare = MOTION_BLUR_MAX_UV) {
|
|
5368
5631
|
this.motionBlurScale = Math.min(Math.max(scale, 0), 1);
|
|
5632
|
+
this.motionBlurMax = clampMotionShare(maxShare);
|
|
5369
5633
|
}
|
|
5634
|
+
/** The longest smear, as a share of the frame. See `setCameraMotionBlur`. */
|
|
5635
|
+
motionBlurMax = MOTION_BLUR_MAX_UV;
|
|
5636
|
+
warnedObjectBlur = false;
|
|
5370
5637
|
/**
|
|
5371
5638
|
* The camera has cut: this frame is a new shot, not the next moment of the last one.
|
|
5372
5639
|
*
|
|
@@ -5566,6 +5833,42 @@ export class WebGL2Renderer {
|
|
|
5566
5833
|
? Math.max(exposure, 1e-3)
|
|
5567
5834
|
: this.quality.outputExposure;
|
|
5568
5835
|
}
|
|
5836
|
+
/**
|
|
5837
|
+
* The `filmic` curve this and every later frame is graded through, until it is set again: a
|
|
5838
|
+
* grading volume's five numbers, solved once here into the constants the resolve reads. Ignored
|
|
5839
|
+
* unless `outputTransform` is `filmic`. A number out of range is clamped into it and said once,
|
|
5840
|
+
* since a frame loop must not throw. See `filmicCurve.ts`.
|
|
5841
|
+
*/
|
|
5842
|
+
setFilmicCurve(curve) {
|
|
5843
|
+
if (resolveFilmicCurve(curve, this.filmConstants) && !this.warnedFilmClamped) {
|
|
5844
|
+
this.warnedFilmClamped = true;
|
|
5845
|
+
console.warn(FILMIC_CLAMPED);
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
warnedFilmClamped = false;
|
|
5849
|
+
/**
|
|
5850
|
+
* The range the frame goes out in: `'high'` where the profile asked for `highDynamicRange`, the
|
|
5851
|
+
* frame holds light past white and the display shows it — on WebGPU — and `'standard'` otherwise.
|
|
5852
|
+
* **Always standard here**: this backend draws into a canvas of eight bits a channel, which has
|
|
5853
|
+
* nothing above white to show. Typed as the question rather than this backend's answer, because
|
|
5854
|
+
* the shared surface is derived from this class.
|
|
5855
|
+
*/
|
|
5856
|
+
displayRange = 'standard';
|
|
5857
|
+
/** Why it is that range, in words, for a game choosing its look and for a bug report. */
|
|
5858
|
+
get displayRangeReason() {
|
|
5859
|
+
return this.quality.highDynamicRange
|
|
5860
|
+
? 'WebGL2 draws into an eight-bit canvas, which has no range above white'
|
|
5861
|
+
: 'highDynamicRange was not asked for';
|
|
5862
|
+
}
|
|
5863
|
+
/**
|
|
5864
|
+
* How bright paper white and the display's peak are, in one unit, held until changed: their
|
|
5865
|
+
* ratio is how far above white the highlights may run where `displayRange` is `'high'`, and
|
|
5866
|
+
* nothing changes where it is standard, which is always here.
|
|
5867
|
+
*/
|
|
5868
|
+
setDisplayLuminance(paperWhite, peak) {
|
|
5869
|
+
void paperWhite;
|
|
5870
|
+
void peak;
|
|
5871
|
+
}
|
|
5569
5872
|
/**
|
|
5570
5873
|
* Composite a flat colour over the finished frame — for a cut dipping to white or to black.
|
|
5571
5874
|
*
|
|
@@ -5652,6 +5955,20 @@ export class WebGL2Renderer {
|
|
|
5652
5955
|
}
|
|
5653
5956
|
this.sceneTarget.setVignette(strength);
|
|
5654
5957
|
}
|
|
5958
|
+
/**
|
|
5959
|
+
* The lens's colour fringe, held until changed: `intensity` is a percentage, 0 is none, and red
|
|
5960
|
+
* and green are pulled toward the centre by their wavelength's distance from blue, growing from
|
|
5961
|
+
* `start` — a share of the half-frame, 0 the centre — to the whole of it at the edge. Applied to
|
|
5962
|
+
* scene light at the composite's first read. Needs `screenEffects`, and says so once rather than
|
|
5963
|
+
* doing nothing. See `shaders/fringe.ts`.
|
|
5964
|
+
*/
|
|
5965
|
+
setChromaticAberration(intensity, start = 0) {
|
|
5966
|
+
if (this.sceneTarget === null) {
|
|
5967
|
+
this.warnLookWithoutComposite(intensity);
|
|
5968
|
+
return;
|
|
5969
|
+
}
|
|
5970
|
+
this.sceneTarget.setChromaticAberration(intensity, start);
|
|
5971
|
+
}
|
|
5655
5972
|
/**
|
|
5656
5973
|
* Film grain, held until changed: an amplitude in display values (0 is none, 0.03 is a fine
|
|
5657
5974
|
* grain) and this frame's seed. **The seed is the caller's**, because the engine takes time from
|
|
@@ -5832,6 +6149,8 @@ export class WebGL2Renderer {
|
|
|
5832
6149
|
beginFrame(clearColor) {
|
|
5833
6150
|
if (this.contextLost)
|
|
5834
6151
|
return;
|
|
6152
|
+
/* One frame of the jitter's sequence however many times the frame binds its camera. */
|
|
6153
|
+
this.temporalHistory.nextFrame();
|
|
5835
6154
|
this.skinScattered = false;
|
|
5836
6155
|
this.skinScatter?.reset();
|
|
5837
6156
|
if (this.litAsked) {
|
|
@@ -5898,6 +6217,8 @@ export class WebGL2Renderer {
|
|
|
5898
6217
|
}
|
|
5899
6218
|
}
|
|
5900
6219
|
this.sceneTarget?.begin(this.canvas.width, this.canvas.height);
|
|
6220
|
+
/* The materials' maps on the scene's framebuffer, cleared and disabled: `reflectionKeeps`. */
|
|
6221
|
+
this.reflectionTargets?.begin(this.canvas.width, this.canvas.height);
|
|
5901
6222
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], 1);
|
|
5902
6223
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
5903
6224
|
}
|
|
@@ -5947,7 +6268,7 @@ export class WebGL2Renderer {
|
|
|
5947
6268
|
motion = {
|
|
5948
6269
|
reprojection: this.reprojection,
|
|
5949
6270
|
strength: blur,
|
|
5950
|
-
max:
|
|
6271
|
+
max: this.motionBlurMax,
|
|
5951
6272
|
};
|
|
5952
6273
|
}
|
|
5953
6274
|
}
|
|
@@ -6027,7 +6348,11 @@ export class WebGL2Renderer {
|
|
|
6027
6348
|
: undefined;
|
|
6028
6349
|
/* The grade travels to the resolve only where the mesh pass gave it up. See `bindMeshPass`. */
|
|
6029
6350
|
const lateGrade = this.quality.hdrScene
|
|
6030
|
-
? {
|
|
6351
|
+
? {
|
|
6352
|
+
transform: OUTPUT_TRANSFORM_CODE[this.quality.outputTransform] ?? 0,
|
|
6353
|
+
exposure: this.exposure,
|
|
6354
|
+
film: this.filmConstants,
|
|
6355
|
+
}
|
|
6031
6356
|
: { transform: 0, exposure: 1 };
|
|
6032
6357
|
/*
|
|
6033
6358
|
* Depth of field, on the same ceiling-and-dial split as bloom above: `depthOfField` decides
|
|
@@ -6089,6 +6414,30 @@ export class WebGL2Renderer {
|
|
|
6089
6414
|
* drawn over a reflective floor rather than under it, and before the post chain so bloom and
|
|
6090
6415
|
* the grade see a reflection exactly as they would see any other part of the picture.
|
|
6091
6416
|
*/
|
|
6417
|
+
/*
|
|
6418
|
+
* **The frame's materials' reflections first**, on the same terms: every pixel the opaque lit
|
|
6419
|
+
* draws left a reflection for, marched and swapped for the probe's share. The maps leave the
|
|
6420
|
+
* scene's framebuffer before the resolve draws into it while sampling them.
|
|
6421
|
+
*/
|
|
6422
|
+
const reflectionTargets = this.reflectionTargets;
|
|
6423
|
+
const probeMap = reflectionTargets?.probeTexture ?? null;
|
|
6424
|
+
const tintMap = reflectionTargets?.tintTexture ?? null;
|
|
6425
|
+
if (reflectionTargets !== null &&
|
|
6426
|
+
this.frameReflections !== null &&
|
|
6427
|
+
probeMap !== null &&
|
|
6428
|
+
tintMap !== null &&
|
|
6429
|
+
this.frameViewProj !== null &&
|
|
6430
|
+
this.sceneTarget !== null) {
|
|
6431
|
+
const scene = this.sceneTarget.colorAttachment();
|
|
6432
|
+
const depth = this.sceneTarget.snapshotDepth(true);
|
|
6433
|
+
if (scene !== null && depth !== null) {
|
|
6434
|
+
this.ssr ??= new SsrPass(this.gl, this.sceneTarget.keepsRange);
|
|
6435
|
+
this.ssr.traceMaterials(scene, depth, probeMap, tintMap, this.frameViewProj, this.frameEye, this.canvas.width, this.canvas.height, REFLECTION_EDGE_FADE, this.frameReflections);
|
|
6436
|
+
this.sceneTarget.bind();
|
|
6437
|
+
reflectionTargets.detach();
|
|
6438
|
+
this.ssr.resolveMaterials(probeMap, tintMap, this.canvas.width, this.canvas.height, this.frameReflections);
|
|
6439
|
+
}
|
|
6440
|
+
}
|
|
6092
6441
|
if (this.reflectionQueue.length > 0 && this.frameViewProj !== null) {
|
|
6093
6442
|
const scene = this.sceneTarget?.colorAttachment() ?? null;
|
|
6094
6443
|
const depth = this.sceneTarget?.snapshotDepth(true) ?? null;
|
|
@@ -6328,7 +6677,10 @@ export class WebGL2Renderer {
|
|
|
6328
6677
|
*/
|
|
6329
6678
|
if (this.framePresented)
|
|
6330
6679
|
this.temporalJittering = false;
|
|
6331
|
-
if (!this.reflectionPassActive &&
|
|
6680
|
+
if (!this.reflectionPassActive &&
|
|
6681
|
+
!this.probePassActive &&
|
|
6682
|
+
!this.capturePassActive &&
|
|
6683
|
+
!this.framePresented) {
|
|
6332
6684
|
this.frameViewProj = camera.viewProjection;
|
|
6333
6685
|
/* Copied rather than referenced: a caller moves its camera in place, and the decal pass
|
|
6334
6686
|
reads this at the end of the frame. */
|
|
@@ -6423,6 +6775,10 @@ export class WebGL2Renderer {
|
|
|
6423
6775
|
this.materialHasMaps = false;
|
|
6424
6776
|
this.currentMaterial = null;
|
|
6425
6777
|
this.currentSurfaceTexture = null;
|
|
6778
|
+
/* Nor an overlay: the atlas's unit is given the empty texture with the refraction copy's. */
|
|
6779
|
+
this.overlayFloats.fill(0);
|
|
6780
|
+
this.overlayMaps = null;
|
|
6781
|
+
this.overlayTexture = null;
|
|
6426
6782
|
/* Nor an ambient of its own: the frame's, until a draw asks. See `setAmbientSH`. */
|
|
6427
6783
|
this.ambientSH.fill(0);
|
|
6428
6784
|
/* No reflection and an environment at its own brightness; the emission the world asks for. */
|
|
@@ -6548,8 +6904,10 @@ export class WebGL2Renderer {
|
|
|
6548
6904
|
* unless a draw sets the strength above zero.
|
|
6549
6905
|
*/
|
|
6550
6906
|
gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
|
|
6551
|
-
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture2D);
|
|
6907
|
+
gl.bindTexture(gl.TEXTURE_2D, this.overlayTexture ?? this.emptyTexture2D);
|
|
6552
6908
|
gl.uniform1i(u['uRefractScene'] ?? null, REFRACT_SCENE_TEXTURE_UNIT);
|
|
6909
|
+
/* The draws' overlay, none at a pass's start, and its atlas above: see `setSurfaceOverlay`. */
|
|
6910
|
+
gl.uniform4fv(u['uOverlay'] ?? null, this.overlayFloats);
|
|
6553
6911
|
/* Neither refracting nor glass, which is every draw that does not say otherwise. See
|
|
6554
6912
|
`bindSeeThrough` for the four numbers in the one vector. */
|
|
6555
6913
|
gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
|
|
@@ -6928,9 +7286,16 @@ export class WebGL2Renderer {
|
|
|
6928
7286
|
* here, so there is no motion target for this to be written into, and a mover passed here is
|
|
6929
7287
|
* neither read nor advanced.
|
|
6930
7288
|
*/
|
|
6931
|
-
|
|
7289
|
+
previousModel = null) {
|
|
6932
7290
|
if (this.contextLost)
|
|
6933
7291
|
return;
|
|
7292
|
+
/* A mover's own motion is not blurred here: see `setCameraMotionBlur`. Said once. */
|
|
7293
|
+
if (previousModel !== null &&
|
|
7294
|
+
!this.warnedObjectBlur &&
|
|
7295
|
+
this.quality.cameraMotionBlur * this.motionBlurScale > 0) {
|
|
7296
|
+
this.warnedObjectBlur = true;
|
|
7297
|
+
console.warn(OBJECT_BLUR_UNKEPT);
|
|
7298
|
+
}
|
|
6934
7299
|
/* Geometry that has not all arrived is not drawn, nor a mesh with none. See `Mesh.complete`
|
|
6935
7300
|
and `Mesh.indexCount`. */
|
|
6936
7301
|
if (!mesh.complete || mesh.indexCount === 0)
|
|
@@ -6963,7 +7328,13 @@ export class WebGL2Renderer {
|
|
|
6963
7328
|
* light and its colour, each into the blur's own target.
|
|
6964
7329
|
*/
|
|
6965
7330
|
const splits = this.skinSplits();
|
|
7331
|
+
/* An opaque lit draw into the frame writes its material's reflection too: see `reflectionKeeps`. */
|
|
7332
|
+
const keeps = this.reflectionKeeps();
|
|
7333
|
+
if (keeps)
|
|
7334
|
+
this.reflectionTargets?.on();
|
|
6966
7335
|
this.drawMeshHalf(mesh, model, depthLayer, tint, splits ? 'scene' : 'whole');
|
|
7336
|
+
if (keeps)
|
|
7337
|
+
this.reflectionTargets?.off();
|
|
6967
7338
|
if (splits && this.skinScatter !== null) {
|
|
6968
7339
|
this.skinScatter.begin();
|
|
6969
7340
|
this.drawMeshHalf(mesh, model, depthLayer, tint, 'diffuse');
|
|
@@ -6977,6 +7348,18 @@ export class WebGL2Renderer {
|
|
|
6977
7348
|
* skin yet, this is the frame's own picture — not a mirror's or a probe's, nor an overlay after
|
|
6978
7349
|
* the frame — and the blur's target can be had.
|
|
6979
7350
|
*/
|
|
7351
|
+
/**
|
|
7352
|
+
* Whether a draw now is the frame's own, opaque and lit, and so writes the two maps beside its
|
|
7353
|
+
* colour: not a mirror's, a probe's or a capture's, whose framebuffers have no maps, and not after
|
|
7354
|
+
* the frame. See `reflectionSurfaceTargets.ts`.
|
|
7355
|
+
*/
|
|
7356
|
+
reflectionKeeps() {
|
|
7357
|
+
return (this.reflectionTargets !== null &&
|
|
7358
|
+
!this.reflectionPassActive &&
|
|
7359
|
+
!this.probePassActive &&
|
|
7360
|
+
!this.capturePassActive &&
|
|
7361
|
+
!this.framePresented);
|
|
7362
|
+
}
|
|
6980
7363
|
skinSplits() {
|
|
6981
7364
|
const skin = this.skinScatter;
|
|
6982
7365
|
const scene = this.sceneTarget;
|
|
@@ -6986,6 +7369,7 @@ export class WebGL2Renderer {
|
|
|
6986
7369
|
!this.skinScattered &&
|
|
6987
7370
|
!this.reflectionPassActive &&
|
|
6988
7371
|
!this.probePassActive &&
|
|
7372
|
+
!this.capturePassActive &&
|
|
6989
7373
|
!this.framePresented &&
|
|
6990
7374
|
skin.ready(scene));
|
|
6991
7375
|
}
|
|
@@ -7002,11 +7386,19 @@ export class WebGL2Renderer {
|
|
|
7002
7386
|
const projection = this.frameProjection;
|
|
7003
7387
|
if (skin === null || scene === null || this.skinScattered)
|
|
7004
7388
|
return;
|
|
7389
|
+
/*
|
|
7390
|
+
* **Not the frame's picture, so not the frame's moment**: a blended draw in a mirror, a probe
|
|
7391
|
+
* bake or a scene capture lands over none of the frame's skin. Latching there switched the
|
|
7392
|
+
* spread off for the frame, so a capture with a glowing sign in it left every face drawn after
|
|
7393
|
+
* it flat. `scripts/capture-check.mjs`.
|
|
7394
|
+
*/
|
|
7395
|
+
if (this.reflectionPassActive || this.probePassActive || this.capturePassActive)
|
|
7396
|
+
return;
|
|
7005
7397
|
/* Latched whether or not skin was drawn: a skin drawn after this point is the whole surface. */
|
|
7006
7398
|
this.skinScattered = true;
|
|
7007
7399
|
if (!skin.pending)
|
|
7008
7400
|
return;
|
|
7009
|
-
if (
|
|
7401
|
+
if (projection === null)
|
|
7010
7402
|
return;
|
|
7011
7403
|
const depth = scene.snapshotDepth(true);
|
|
7012
7404
|
mat4.invert(this.skinInverseProjection, projection);
|