@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
|
@@ -23,6 +23,52 @@ float areaSignedForm(vec3 n, vec3 centre, vec3 right, vec3 up, vec2 halfSize) {
|
|
|
23
23
|
return quadFormFactor(n, vWorldPos, c0, c1, c2, c3);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* How far along one of a rectangle's axes a fragment still sees it past the barn door on that axis's
|
|
28
|
+
* positive edge: \`p\` the fragment's place along the axis, \`height\` its height above the
|
|
29
|
+
* rectangle's plane, \`halfSize\` the rectangle's half extent, and the door's tip \`tipOut\` beyond
|
|
30
|
+
* the edge and \`tipUp\` above the plane. Points of the rectangle past the answer are hidden.
|
|
31
|
+
*
|
|
32
|
+
* Above the tip, the tip's shadow on the plane as seen from the fragment is the limit. Below it, a
|
|
33
|
+
* fragment beside the door and outside its line is hidden from all of it, and one inside the door's
|
|
34
|
+
* reach is hidden from none of it.
|
|
35
|
+
*/
|
|
36
|
+
float barnDoorLimit(float p, float height, float halfSize, float tipOut, float tipUp) {
|
|
37
|
+
float tipAt = halfSize + tipOut;
|
|
38
|
+
if (height > tipUp) return (height * tipAt - tipUp * p) / (height - tipUp);
|
|
39
|
+
if (p > halfSize && height * tipOut < tipUp * (p - halfSize)) return -1e9;
|
|
40
|
+
return 1e9;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The part of a rectangle a fragment sees past its barn doors, written into \`centre\` and
|
|
45
|
+
* \`halfSize\` as the smaller rectangle that is left, or false where the doors hide all of it.
|
|
46
|
+
* \`doors\` is the cosine of their angle from the normal and their length; a length of 0 is no doors.
|
|
47
|
+
* Each axis is clipped by its own two doors, which is what makes this four projections and a min.
|
|
48
|
+
*/
|
|
49
|
+
bool areaBarnDoors(inout vec3 centre, vec3 right, vec3 up, inout vec2 halfSize, vec2 doors) {
|
|
50
|
+
if (doors.y <= 0.0) return true;
|
|
51
|
+
vec3 toFragment = vWorldPos - centre;
|
|
52
|
+
float height = dot(toFragment, cross(right, up));
|
|
53
|
+
/* Behind the emitting side: nothing to clip, and the form factor already answers it. */
|
|
54
|
+
if (height <= 0.0) return true;
|
|
55
|
+
float tipOut = doors.y * sqrt(max(1.0 - doors.x * doors.x, 0.0));
|
|
56
|
+
float tipUp = doors.y * doors.x;
|
|
57
|
+
vec2 p = vec2(dot(toFragment, right), dot(toFragment, up));
|
|
58
|
+
vec2 hi = vec2(
|
|
59
|
+
min(halfSize.x, barnDoorLimit(p.x, height, halfSize.x, tipOut, tipUp)),
|
|
60
|
+
min(halfSize.y, barnDoorLimit(p.y, height, halfSize.y, tipOut, tipUp))
|
|
61
|
+
);
|
|
62
|
+
vec2 lo = vec2(
|
|
63
|
+
max(-halfSize.x, -barnDoorLimit(-p.x, height, halfSize.x, tipOut, tipUp)),
|
|
64
|
+
max(-halfSize.y, -barnDoorLimit(-p.y, height, halfSize.y, tipOut, tipUp))
|
|
65
|
+
);
|
|
66
|
+
if (hi.x <= lo.x || hi.y <= lo.y) return false;
|
|
67
|
+
centre += right * (0.5 * (lo.x + hi.x)) + up * (0.5 * (lo.y + hi.y));
|
|
68
|
+
halfSize = 0.5 * (hi - lo);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
26
72
|
/**
|
|
27
73
|
* What one rectangle of colour \`color\` and form factor \`form\` adds to the lamps' two sums, open
|
|
28
74
|
* and shadowed by \`occl\` and \`glass\`.
|
|
@@ -29,7 +29,14 @@ vec4 glassUnmix(vec4 mip, float centreClarity) {
|
|
|
29
29
|
* about which optional code a lit program carries. See `litSwitchesGlsl`.
|
|
30
30
|
*/
|
|
31
31
|
export type LitSwitch =
|
|
32
|
-
|
|
32
|
+
| 'GLASS_SHADOWS'
|
|
33
|
+
| 'CLUSTERED_LIGHTS'
|
|
34
|
+
| 'LIGHT_FIXTURES'
|
|
35
|
+
| 'SURFACE_EFFECTS'
|
|
36
|
+
| 'DRIFT_LIGHT'
|
|
37
|
+
| 'PHYSICAL_SPECULAR'
|
|
38
|
+
| 'SURFACE_OVERLAY'
|
|
39
|
+
| 'REFLECTION_MAPS';
|
|
33
40
|
|
|
34
41
|
/** Every switch off: what a renderer starts from before its profile and its content say otherwise. */
|
|
35
42
|
export function noLitSwitches(): Record<LitSwitch, boolean> {
|
|
@@ -39,6 +46,9 @@ export function noLitSwitches(): Record<LitSwitch, boolean> {
|
|
|
39
46
|
LIGHT_FIXTURES: false,
|
|
40
47
|
SURFACE_EFFECTS: false,
|
|
41
48
|
DRIFT_LIGHT: false,
|
|
49
|
+
PHYSICAL_SPECULAR: false,
|
|
50
|
+
SURFACE_OVERLAY: false,
|
|
51
|
+
REFLECTION_MAPS: false,
|
|
42
52
|
};
|
|
43
53
|
}
|
|
44
54
|
|
|
@@ -61,7 +71,8 @@ export interface LitSwitches {
|
|
|
61
71
|
* first uses them — a measured profile or a cookie, a material with an effects table, a DriftLight
|
|
62
72
|
* volume — and then on for good; see `PipelineCache.enable` and the WebGL2 renderer's rebuild.
|
|
63
73
|
* Measured on RADV against the lit shader with glass already out: 6,852 instructions and 120
|
|
64
|
-
* registers, 4,641 and 96 with all four out.
|
|
74
|
+
* registers, 4,641 and 96 with all four out. `PHYSICAL_SPECULAR` is a sixth, declared with the
|
|
75
|
+
* models so that theirs keep their ids (`modelsGlsl`).
|
|
65
76
|
*/
|
|
66
77
|
export function litSwitchesGlsl(switches: LitSwitches): string {
|
|
67
78
|
return /* glsl */ `
|
|
@@ -14,11 +14,13 @@ import { CLOTH_BINDING_GLSL } from '../clothBinding.ts';
|
|
|
14
14
|
import { SKINNING_GLSL } from '../skinning.ts';
|
|
15
15
|
import { SURFACE_GLSL } from './surface.ts';
|
|
16
16
|
import { MAIN_GLSL } from './main.ts';
|
|
17
|
-
import {
|
|
17
|
+
import { modelsGlsl } from './models.ts';
|
|
18
18
|
import { AREA_LIGHT_GLSL } from './areaLight.ts';
|
|
19
19
|
import { NORMAL_MAP_GLSL } from './normalMap.ts';
|
|
20
20
|
import { DRIFT_LIGHT_GLSL } from './driftLight.ts';
|
|
21
21
|
import { SURFACE_EFFECTS_GLSL } from './surfaceEffects.ts';
|
|
22
|
+
import { overlayGlsl } from './overlay.ts';
|
|
23
|
+
import { reflectionSurfaceGlsl } from './reflectionSurface.ts';
|
|
22
24
|
import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from '../vertexChannel.ts';
|
|
23
25
|
import { FULL_LIGHT_BUDGET, type LightBudget } from '../../uniformVectorBudget.ts';
|
|
24
26
|
|
|
@@ -245,6 +247,15 @@ void main() {
|
|
|
245
247
|
#endif
|
|
246
248
|
#if INSTANCED
|
|
247
249
|
mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
|
|
250
|
+
/*
|
|
251
|
+
* **The bottom row is the instance's texture cell** (\`MeshInstances.uvRegions\`), which an
|
|
252
|
+
* affine placement leaves free: read, and rebuilt as the \`[0, 0, 0, 1]\` it stands for.
|
|
253
|
+
*/
|
|
254
|
+
vec4 instanceCell = vec4(model[0].w, model[1].w, model[2].w, model[3].w);
|
|
255
|
+
model[0].w = 0.0;
|
|
256
|
+
model[1].w = 0.0;
|
|
257
|
+
model[2].w = 0.0;
|
|
258
|
+
model[3].w = 1.0;
|
|
248
259
|
vec3 tint = aInstanceTint.rgb;
|
|
249
260
|
if (LIGHTMAP_REGIONS) tint = vec3(1.0);
|
|
250
261
|
#else
|
|
@@ -293,7 +304,12 @@ void main() {
|
|
|
293
304
|
vColor = aColor * tint;
|
|
294
305
|
vEmissive = aEmissive;
|
|
295
306
|
vSpecular = aSpecular;
|
|
307
|
+
#if INSTANCED
|
|
308
|
+
/* The instance's cell first, then the material's scale and offset. */
|
|
309
|
+
vUv = vec3((aUv.xy * instanceCell.xy + instanceCell.zw) * uUvScale + uUvOffset, aUv.z);
|
|
310
|
+
#else
|
|
296
311
|
vUv = vec3(aUv.xy * uUvScale + uUvOffset, aUv.z);
|
|
312
|
+
#endif
|
|
297
313
|
vEmissiveColor = aEmissiveColor;
|
|
298
314
|
vRoughness = aRoughness;
|
|
299
315
|
vGrain = aGrain;
|
|
@@ -449,6 +465,21 @@ export interface FlatShaderOptions {
|
|
|
449
465
|
readonly surfaceEffects?: boolean;
|
|
450
466
|
/** Whether it reads a DriftLight volume. True when absent. See `litSwitchesGlsl`. */
|
|
451
467
|
readonly driftLight?: boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Whether it carries GGX's own highlight for a material that asks (`physicalSpecular`). True
|
|
470
|
+
* when absent. See `modelsGlsl`.
|
|
471
|
+
*/
|
|
472
|
+
readonly physicalSpecular?: boolean;
|
|
473
|
+
/**
|
|
474
|
+
* Whether it carries a draw's surface overlay, `uOverlay` and all (`setSurfaceOverlay`). True
|
|
475
|
+
* when absent. See `overlayGlsl`.
|
|
476
|
+
*/
|
|
477
|
+
readonly surfaceOverlay?: boolean;
|
|
478
|
+
/**
|
|
479
|
+
* Whether the frame's own draws write the reflection maps beside their colour: WebGL2's way to
|
|
480
|
+
* the frame's materials' reflections. True when absent. See `reflectionSurfaceGlsl`.
|
|
481
|
+
*/
|
|
482
|
+
readonly reflectionMaps?: boolean;
|
|
452
483
|
/**
|
|
453
484
|
* How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
|
|
454
485
|
*
|
|
@@ -593,7 +624,11 @@ export function flatFrag(options: FlatShaderOptions): string {
|
|
|
593
624
|
DRIFT_LIGHT_GLSL,
|
|
594
625
|
SURFACE_EFFECTS_GLSL,
|
|
595
626
|
/* Depth zero and after the tangent frame and the lobes it calls; see models.ts. */
|
|
596
|
-
|
|
627
|
+
modelsGlsl(options.physicalSpecular ?? true),
|
|
628
|
+
/* After the models, so its switch takes the next id; depth zero, as main calls it. */
|
|
629
|
+
overlayGlsl(options.surfaceOverlay ?? true),
|
|
630
|
+
/* After the overlay, so its switch takes the next id. See reflectionSurface.ts. */
|
|
631
|
+
reflectionSurfaceGlsl(options.reflectionMaps ?? true),
|
|
597
632
|
/* After the models, whose answer to a rectangle it asks for. See areaLight.ts. */
|
|
598
633
|
AREA_LIGHT_GLSL,
|
|
599
634
|
MAIN_GLSL,
|
|
@@ -30,6 +30,55 @@ export const EMISSIVE_SHADOW_SHARE = 0.55;
|
|
|
30
30
|
*/
|
|
31
31
|
export const MIN_LOBE_ALPHA = 0.01;
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Karis's fit to the split-sum environment BRDF, as GLSL: the lit stage's, and the screen-space
|
|
35
|
+
* reflection's when a surface asks for its Fresnel (`ReflectiveSurface.fresnel`). One text, so the
|
|
36
|
+
* two cannot drift.
|
|
37
|
+
*/
|
|
38
|
+
export const ENV_BRDF_GLSL = `/**
|
|
39
|
+
* The other half of the split-sum approximation: what fraction of an environment a surface returns.
|
|
40
|
+
*
|
|
41
|
+
* The convolution decides *what* a surface reflects at a given roughness; this decides *how much*.
|
|
42
|
+
* Before it the amount was fresnel times one-minus-roughness, which is a curve somebody chose
|
|
43
|
+
* standing in for an integral.
|
|
44
|
+
*
|
|
45
|
+
* Karis's analytic fit to the environment BRDF, so there is **no lookup texture and no texture
|
|
46
|
+
* unit**: a few multiply-adds against roughness and the view angle. x scales the surface's own
|
|
47
|
+
* reflectance at normal incidence and y is the additive grazing term, so a smooth dielectric at
|
|
48
|
+
* f0 0.04 returns about 0.046 head-on and approaches 1 at the edge, which is what a dielectric
|
|
49
|
+
* does. At roughness 1 it returns about 0.016 rather than the zero one-minus-roughness gave, which
|
|
50
|
+
* is the substantive difference: a fully rough dielectric does reflect its surroundings.
|
|
51
|
+
*
|
|
52
|
+
* **It replaces the Fresnel factor as well as the thinning**, because the fit already contains the
|
|
53
|
+
* angular dependence; multiplying by a separate Fresnel term would apply it twice.
|
|
54
|
+
*
|
|
55
|
+
* **How much this is worth was measured, and it is worth less than it looks on a dark room.**
|
|
56
|
+
* On demo/dev/ibl.html?ladder=1 the whole ladder moved by at most 0.2 of 255 when the old term was
|
|
57
|
+
* replaced. That is not the term failing: at high roughness the surface reads the coarsest levels
|
|
58
|
+
* of the chain, and in a room of five dark walls and one bright one those levels are dark, so a
|
|
59
|
+
* weight three times larger against a near-zero radiance is still near zero. It is worth much more
|
|
60
|
+
* against a bright environment, which is what a loaded sky is and what no captured room here is.
|
|
61
|
+
*
|
|
62
|
+
* **A warning about reading that page, paid for once.** The ladder falls about five-fold from
|
|
63
|
+
* mirror to rough, and that reads as energy being lost. It is not: a mirror concentrates the one
|
|
64
|
+
* bright wall into a sharp image and a rough surface averages it against five dark ones, so the
|
|
65
|
+
* falloff is the room's own content. The normalised falloff also happens to track one-minus-
|
|
66
|
+
* roughness closely, which made the old term look like the cause — and removing that term entirely
|
|
67
|
+
* changed nothing, which is what settled it. Perturb before believing a match.
|
|
68
|
+
*
|
|
69
|
+
* **What it costs** is a fit rather than the integral: the published error is around one per cent
|
|
70
|
+
* of the tabulated term, far below what an eight-bit frame can show. **What would make it wrong**
|
|
71
|
+
* is a material model this shader does not have — a clearcoat or a sheen lobe carries its own BRDF
|
|
72
|
+
* and its own integral, and this fit is Trowbridge-Reitz with Smith masking and nothing else.
|
|
73
|
+
*/
|
|
74
|
+
vec2 envBrdfApprox(float ndv, float roughness) {
|
|
75
|
+
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
|
76
|
+
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
|
77
|
+
vec4 r = roughness * c0 + c1;
|
|
78
|
+
float a004 = min(r.x * r.x, exp2(-9.28 * ndv)) * r.x + r.y;
|
|
79
|
+
return vec2(-1.04, 1.04) * a004 + r.zw;
|
|
80
|
+
}`;
|
|
81
|
+
|
|
33
82
|
export const LOBES_GLSL = `float shadowReach(float distance, float maxDistance) {
|
|
34
83
|
return 1.0 - smoothstep(
|
|
35
84
|
maxDistance * ${POINT_SHADOW_FADE_START.toFixed(2)},
|
|
@@ -156,49 +205,7 @@ float sphereLobe(float ndh, float roughness, float sourceRadius, float dist) {
|
|
|
156
205
|
return energy * (w2 * w2) / max(d * d, 1e-8);
|
|
157
206
|
}
|
|
158
207
|
|
|
159
|
-
|
|
160
|
-
* The other half of the split-sum approximation: what fraction of an environment a surface returns.
|
|
161
|
-
*
|
|
162
|
-
* The convolution decides *what* a surface reflects at a given roughness; this decides *how much*.
|
|
163
|
-
* Before it the amount was fresnel times one-minus-roughness, which is a curve somebody chose
|
|
164
|
-
* standing in for an integral.
|
|
165
|
-
*
|
|
166
|
-
* Karis's analytic fit to the environment BRDF, so there is **no lookup texture and no texture
|
|
167
|
-
* unit**: a few multiply-adds against roughness and the view angle. x scales the surface's own
|
|
168
|
-
* reflectance at normal incidence and y is the additive grazing term, so a smooth dielectric at
|
|
169
|
-
* f0 0.04 returns about 0.046 head-on and approaches 1 at the edge, which is what a dielectric
|
|
170
|
-
* does. At roughness 1 it returns about 0.016 rather than the zero one-minus-roughness gave, which
|
|
171
|
-
* is the substantive difference: a fully rough dielectric does reflect its surroundings.
|
|
172
|
-
*
|
|
173
|
-
* **It replaces the Fresnel factor as well as the thinning**, because the fit already contains the
|
|
174
|
-
* angular dependence; multiplying by a separate Fresnel term would apply it twice.
|
|
175
|
-
*
|
|
176
|
-
* **How much this is worth was measured, and it is worth less than it looks on a dark room.**
|
|
177
|
-
* On demo/dev/ibl.html?ladder=1 the whole ladder moved by at most 0.2 of 255 when the old term was
|
|
178
|
-
* replaced. That is not the term failing: at high roughness the surface reads the coarsest levels
|
|
179
|
-
* of the chain, and in a room of five dark walls and one bright one those levels are dark, so a
|
|
180
|
-
* weight three times larger against a near-zero radiance is still near zero. It is worth much more
|
|
181
|
-
* against a bright environment, which is what a loaded sky is and what no captured room here is.
|
|
182
|
-
*
|
|
183
|
-
* **A warning about reading that page, paid for once.** The ladder falls about five-fold from
|
|
184
|
-
* mirror to rough, and that reads as energy being lost. It is not: a mirror concentrates the one
|
|
185
|
-
* bright wall into a sharp image and a rough surface averages it against five dark ones, so the
|
|
186
|
-
* falloff is the room's own content. The normalised falloff also happens to track one-minus-
|
|
187
|
-
* roughness closely, which made the old term look like the cause — and removing that term entirely
|
|
188
|
-
* changed nothing, which is what settled it. Perturb before believing a match.
|
|
189
|
-
*
|
|
190
|
-
* **What it costs** is a fit rather than the integral: the published error is around one per cent
|
|
191
|
-
* of the tabulated term, far below what an eight-bit frame can show. **What would make it wrong**
|
|
192
|
-
* is a material model this shader does not have — a clearcoat or a sheen lobe carries its own BRDF
|
|
193
|
-
* and its own integral, and this fit is Trowbridge-Reitz with Smith masking and nothing else.
|
|
194
|
-
*/
|
|
195
|
-
vec2 envBrdfApprox(float ndv, float roughness) {
|
|
196
|
-
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
|
197
|
-
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
|
198
|
-
vec4 r = roughness * c0 + c1;
|
|
199
|
-
float a004 = min(r.x * r.x, exp2(-9.28 * ndv)) * r.x + r.y;
|
|
200
|
-
return vec2(-1.04, 1.04) * a004 + r.zw;
|
|
201
|
-
}
|
|
208
|
+
${ENV_BRDF_GLSL}
|
|
202
209
|
|
|
203
210
|
/**
|
|
204
211
|
* How much of a prefiltered environment a surface returns, with the light that bounces more than
|
|
@@ -26,6 +26,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
26
26
|
vec2 fxDx = dFdx(surfaceAt.xy);
|
|
27
27
|
vec2 fxDy = dFdy(surfaceAt.xy);
|
|
28
28
|
if (uWriteMode.y != 0.0 && !ditherKeeps(uWriteMode.y)) discard;
|
|
29
|
+
/* A draw's dissolve cuts the surface away before anything is shaded: overlay.ts. */
|
|
30
|
+
if (SURFACE_OVERLAY) {
|
|
31
|
+
if (overlayCuts(surfaceAt.xy)) discard;
|
|
32
|
+
}
|
|
29
33
|
|
|
30
34
|
/*
|
|
31
35
|
* Surface colour and its coverage, resolved before anything else — including before it is
|
|
@@ -140,6 +144,11 @@ export const MAIN_GLSL = `void main() {
|
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
vec3 lit = albedo;
|
|
147
|
+
/* How much of the environment the frame shows here, and how a found reflection would land:
|
|
148
|
+
reflectionSurface.ts. None where nothing is reflected. */
|
|
149
|
+
vec3 reflectedProbe = vec3(0.0);
|
|
150
|
+
vec3 reflectedTint = vec3(0.0);
|
|
151
|
+
float reflectedRoughness = 1.0;
|
|
143
152
|
/* Skin's diffuse, held before emission for the screen-space blur's own pass: models.ts. */
|
|
144
153
|
vec3 diffuseAlone = vec3(0.0);
|
|
145
154
|
/* The light arriving at a glass pane from behind it, gathered in each light loop below and added
|
|
@@ -187,7 +196,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
187
196
|
* right: a mipped colour image, sampled under uniform control flow, exactly as uAlbedo is
|
|
188
197
|
* below. The rule is about non-uniform branches, and this branch is on a uniform.
|
|
189
198
|
*/
|
|
199
|
+
vec3 unmapped = n;
|
|
190
200
|
if (uNormalStrength > 0.0) n = normalMapped(n, surfaceAt);
|
|
201
|
+
/* A draw's wrinkles, by region, over whatever the map made: overlay.ts. */
|
|
202
|
+
if (SURFACE_OVERLAY) n = overlayWrinkle(n, unmapped, surfaceAt.xy);
|
|
191
203
|
|
|
192
204
|
/*
|
|
193
205
|
* Microscopic relief: the surface's own texture, as a turn of the normal rather than a change
|
|
@@ -543,7 +555,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
543
555
|
* specularLobe's header argues for at length.
|
|
544
556
|
*/
|
|
545
557
|
float sunVoH = max(dot(normalize(uCameraPos - vWorldPos), halfway), 0.0);
|
|
546
|
-
vec3 sunSpec =
|
|
558
|
+
vec3 sunSpec = highlightTint(specColor, sunVoH, metal);
|
|
547
559
|
/*
|
|
548
560
|
* **Held back until after the environment blend, because that blend is a mix and would
|
|
549
561
|
* otherwise erase this.**
|
|
@@ -562,8 +574,12 @@ export const MAIN_GLSL = `void main() {
|
|
|
562
574
|
* Zero for the whole world that carries no specular attribute and no metalness, exactly as
|
|
563
575
|
* before: \`sunSpec\` is \`vec3(vSpecular)\` at metal 0 and \`vSpecular\` defaults to 0.
|
|
564
576
|
*/
|
|
565
|
-
|
|
566
|
-
|
|
577
|
+
/* GGX's own where the surface asks (\`physicalSpecular\`): the sun is a point, so nothing widens it. */
|
|
578
|
+
float sunNdh = max(dot(n, halfway), 0.0);
|
|
579
|
+
float sunLobe = physicalSpecular()
|
|
580
|
+
? physicalLobe(sunNdh, ndl, dot(n, normalize(uCameraPos - vWorldPos)), surfaceRoughness, 0.0, 1.0)
|
|
581
|
+
: specularLobe(sunNdh, surfaceRoughness);
|
|
582
|
+
vec3 sunHighlight = sunColor * sunLobe * sunSpec * sunShade * sunFacing;
|
|
567
583
|
if (modelled) sunHighlight = sunModelSpecular;
|
|
568
584
|
/*
|
|
569
585
|
* The dielectric's share goes in here, where it has always gone, so the environment blend
|
|
@@ -912,6 +928,15 @@ export const MAIN_GLSL = `void main() {
|
|
|
912
928
|
environment * mix(vec3(1.0), albedo, metal),
|
|
913
929
|
weight
|
|
914
930
|
);
|
|
931
|
+
reflectedTint = mix(vec3(1.0), albedo, metal) * weight;
|
|
932
|
+
reflectedProbe = environment * reflectedTint;
|
|
933
|
+
reflectedRoughness = surfaceRoughness;
|
|
934
|
+
}
|
|
935
|
+
/* The reflection pass's surface half leaves here, before the lamps: reflectionSurface.ts. */
|
|
936
|
+
if (REFLECTION_SURFACE) {
|
|
937
|
+
reflectionSurfaceOut(reflectedProbe, reflectedTint, reflectedRoughness, ormOcclusion,
|
|
938
|
+
reflectionAir());
|
|
939
|
+
return;
|
|
915
940
|
}
|
|
916
941
|
/*
|
|
917
942
|
* The sun's highlight, on top of whatever the surface reflects rather than underneath it —
|
|
@@ -1067,6 +1092,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
1067
1092
|
float cookie;
|
|
1068
1093
|
/* The light's lighting channels, a mask: 1 unless it names others. See \`uLightIesAxis\`. */
|
|
1069
1094
|
float lightChannels = 1.0;
|
|
1095
|
+
/* The light's own falloff exponent, or 0 for the frame's falloff. See \`uLightCone\`. */
|
|
1096
|
+
float lightExponent = 0.0;
|
|
1097
|
+
/* A clustered rectangle's barn doors: their cosine and length, none at 0. See \`areaBarnDoors\`. */
|
|
1098
|
+
vec2 areaDoors = vec2(0.0);
|
|
1070
1099
|
/*
|
|
1071
1100
|
* **A rectangle in the froxel table** — one past the fixed arm's \`maxAreaLights\` — which
|
|
1072
1101
|
* its record says with a negative radius, its reach negated. Its fields come out of the
|
|
@@ -1117,8 +1146,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
1117
1146
|
lightWeight = sizeAndWeight.y;
|
|
1118
1147
|
/*
|
|
1119
1148
|
* **The fixture, read only for a light that has one.** What a plain light's record holds in
|
|
1120
|
-
* the last
|
|
1121
|
-
* profile or
|
|
1149
|
+
* the last four texels is exactly these values, so a light carrying no shadow slot, cone,
|
|
1150
|
+
* profile, cookie, channels or falloff of its own shades the same whether they are read or assumed, and at heavy overlap
|
|
1122
1151
|
* reading them was a third of the pass. A branch on a value from a texture around
|
|
1123
1152
|
* \`texelFetch\` is not the 2026-08-07 case: an integer fetch takes no derivative.
|
|
1124
1153
|
*
|
|
@@ -1138,6 +1167,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1138
1167
|
uvec4 rec2 = clusterTexel(record + 2);
|
|
1139
1168
|
uvec4 rec3 = clusterTexel(record + 3);
|
|
1140
1169
|
uvec4 rec4 = clusterTexel(record + 4);
|
|
1170
|
+
uvec4 rec5 = clusterTexel(record + 5);
|
|
1141
1171
|
shadowSlot = clusteredArea ? -1 : int(uintBitsToFloat(rec2.x));
|
|
1142
1172
|
areaTwoSided = uintBitsToFloat(rec2.x);
|
|
1143
1173
|
lightDir = vec3(
|
|
@@ -1150,6 +1180,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
1150
1180
|
iesAxis = vec3(
|
|
1151
1181
|
uintBitsToFloat(rec4.x), uintBitsToFloat(rec4.y), uintBitsToFloat(rec4.z));
|
|
1152
1182
|
lightChannels = uintBitsToFloat(rec4.w);
|
|
1183
|
+
lightExponent = uintBitsToFloat(rec5.x);
|
|
1184
|
+
areaDoors = vec2(uintBitsToFloat(rec5.y), uintBitsToFloat(rec5.z));
|
|
1153
1185
|
}
|
|
1154
1186
|
}
|
|
1155
1187
|
} else {
|
|
@@ -1162,7 +1194,8 @@ export const MAIN_GLSL = `void main() {
|
|
|
1162
1194
|
lightWeight = uLightWeight[i];
|
|
1163
1195
|
shadowSlot = i;
|
|
1164
1196
|
lightDir = uLightDir[i];
|
|
1165
|
-
lightCone = uLightCone[i];
|
|
1197
|
+
lightCone = uLightCone[i].xy;
|
|
1198
|
+
lightExponent = uLightCone[i].z;
|
|
1166
1199
|
iesProfile = uLightIesProfile[i];
|
|
1167
1200
|
iesAxis = uLightIesAxis[i].xyz;
|
|
1168
1201
|
lightChannels = uLightIesAxis[i].w;
|
|
@@ -1188,12 +1221,15 @@ export const MAIN_GLSL = `void main() {
|
|
|
1188
1221
|
* froxel it is binned into has no edge in the picture.
|
|
1189
1222
|
*/
|
|
1190
1223
|
if (clusteredArea) {
|
|
1191
|
-
|
|
1224
|
+
vec3 seenCentre = lightPos;
|
|
1225
|
+
vec2 seenHalf = lightCone;
|
|
1226
|
+
if (!areaBarnDoors(seenCentre, lightDir, iesAxis, seenHalf, areaDoors)) continue;
|
|
1227
|
+
float areaForm = areaSignedForm(n, seenCentre, lightDir, iesAxis, seenHalf);
|
|
1192
1228
|
float areaWindow = clamp(1.0 - pow(length(lightPos - vWorldPos) / max(lightRadius, 1e-4), 4.0), 0.0, 1.0);
|
|
1193
1229
|
areaForm = mix(max(0.0, areaForm), abs(areaForm), areaTwoSided);
|
|
1194
1230
|
if (areaForm > 0.0) {
|
|
1195
1231
|
areaLightAdd(
|
|
1196
|
-
|
|
1232
|
+
seenCentre, lightDir, iesAxis, seenHalf, lightColor * (areaWindow * areaWindow), areaForm,
|
|
1197
1233
|
1.0, vec3(1.0), n, albedo, metal, specColor, surfaceRoughness, modelled,
|
|
1198
1234
|
lampOpen, lampShadowed
|
|
1199
1235
|
);
|
|
@@ -1244,7 +1280,16 @@ export const MAIN_GLSL = `void main() {
|
|
|
1244
1280
|
* same way three.js windows its own, so the light still ends where it says it does.
|
|
1245
1281
|
*/
|
|
1246
1282
|
float falloff;
|
|
1247
|
-
|
|
1283
|
+
/*
|
|
1284
|
+
* **A light may name its own falloff, and then it is Unreal's for a light without
|
|
1285
|
+
* inverse-square falloff**: \`(1 - (d/R)^2)^n\` with no distance term, so a fill authored to
|
|
1286
|
+
* light a whole hall across a hundred metres does, where the inverse square would have it
|
|
1287
|
+
* gone a few metres out. Zero is the frame's own rule below, which every light was before.
|
|
1288
|
+
*/
|
|
1289
|
+
if (lightExponent > 0.0) {
|
|
1290
|
+
float reach = dist / max(lightRadius, 1e-4);
|
|
1291
|
+
falloff = pow(clamp(1.0 - reach * reach, 0.0, 1.0), lightExponent);
|
|
1292
|
+
} else if (uLightFalloff == 1) {
|
|
1248
1293
|
float window = clamp(1.0 - pow(dist / max(lightRadius, 1e-4), 4.0), 0.0, 1.0);
|
|
1249
1294
|
falloff = window * window / max(dist * dist, 0.01);
|
|
1250
1295
|
} else {
|
|
@@ -1507,7 +1552,11 @@ export const MAIN_GLSL = `void main() {
|
|
|
1507
1552
|
photometric = mix(1.0, iesGain, step(0.0, iesProfile));
|
|
1508
1553
|
}
|
|
1509
1554
|
|
|
1510
|
-
|
|
1555
|
+
/* A light's own exponent already is its whole curve; the frame's smooth rule squares its own. */
|
|
1556
|
+
float shape =
|
|
1557
|
+
(lightExponent > 0.0 || uLightFalloff == 1 ? falloff : falloff * falloff) *
|
|
1558
|
+
coneFalloff *
|
|
1559
|
+
photometric;
|
|
1511
1560
|
glassGlow += lightColor * backNdl * shape * lightWeight * shaded * lampGlass;
|
|
1512
1561
|
if (ndl <= 0.0 && !modelledBehind) continue;
|
|
1513
1562
|
/*
|
|
@@ -1584,16 +1633,15 @@ export const MAIN_GLSL = `void main() {
|
|
|
1584
1633
|
if (vSpecular > 0.0 || metal > 0.0) {
|
|
1585
1634
|
vec3 toEyeLamp = normalize(uCameraPos - vWorldPos);
|
|
1586
1635
|
vec3 lampHalfway = normalize(toLight / max(dist, 1e-4) + toEyeLamp);
|
|
1587
|
-
/* The same grazing whitening the sun's highlight takes, and zero at metal 0. */
|
|
1588
|
-
vec3 lampSpec =
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1636
|
+
/* The same grazing whitening the sun's highlight takes, and zero at metal 0 for the look. */
|
|
1637
|
+
vec3 lampSpec = highlightTint(specColor, max(dot(toEyeLamp, lampHalfway), 0.0), metal);
|
|
1638
|
+
/* The look's lobe, or GGX's own where the surface asks for it: see \`physicalLobe\`. */
|
|
1639
|
+
float lampNdh = max(dot(n, lampHalfway), 0.0);
|
|
1640
|
+
float lampLobe = physicalSpecular()
|
|
1641
|
+
? physicalLobe(lampNdh, ndl, dot(n, toEyeLamp), surfaceRoughness, lightSourceRadius, dist)
|
|
1642
|
+
: sphereLobe(lampNdh, surfaceRoughness, lightSourceRadius, dist);
|
|
1593
1643
|
/* Held back with the diffuse half, and shadowed by the same term it always was. */
|
|
1594
|
-
vec3 lampHighlight =
|
|
1595
|
-
lightColor * sphereLobe(max(dot(n, lampHalfway), 0.0), surfaceRoughness, lightSourceRadius, dist)
|
|
1596
|
-
* lampSpec * shape * lightWeight;
|
|
1644
|
+
vec3 lampHighlight = lightColor * lampLobe * lampSpec * shape * lightWeight;
|
|
1597
1645
|
lampOpen += lampHighlight;
|
|
1598
1646
|
lampShadowed += lampHighlight * shaded * lampGlass;
|
|
1599
1647
|
}
|
|
@@ -1637,10 +1685,18 @@ export const MAIN_GLSL = `void main() {
|
|
|
1637
1685
|
vec3 centre = uAreaLightPos[a];
|
|
1638
1686
|
vec3 right = uAreaLightRight[a];
|
|
1639
1687
|
vec3 up = uAreaLightUp[a];
|
|
1640
|
-
vec2 halfSize = uAreaLightSize[a];
|
|
1688
|
+
vec2 halfSize = uAreaLightSize[a].xy;
|
|
1689
|
+
/*
|
|
1690
|
+
* **The part of the rectangle this fragment sees past its barn doors** (\`areaBarnDoors\`),
|
|
1691
|
+
* which its light and highlight come from. Its shadow keeps the whole rectangle's centre and
|
|
1692
|
+
* size below, because that is what its map was baked from.
|
|
1693
|
+
*/
|
|
1694
|
+
vec3 seenCentre = centre;
|
|
1695
|
+
vec2 seenHalf = halfSize;
|
|
1696
|
+
if (!areaBarnDoors(seenCentre, right, up, seenHalf, uAreaLightSize[a].zw)) continue;
|
|
1641
1697
|
|
|
1642
1698
|
/* The form factor and its sign, which is the sidedness: see \`areaSignedForm\`. */
|
|
1643
|
-
float signedForm = areaSignedForm(n,
|
|
1699
|
+
float signedForm = areaSignedForm(n, seenCentre, right, up, seenHalf);
|
|
1644
1700
|
float form = mix(max(0.0, signedForm), abs(signedForm), uAreaLightTwoSided[a]);
|
|
1645
1701
|
/* The form factor is linear in the normal, so the one seen from behind is its negation. */
|
|
1646
1702
|
float backForm = glassTransmission > 0.0
|
|
@@ -1757,7 +1813,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1757
1813
|
if (form <= 0.0) continue;
|
|
1758
1814
|
/* The diffuse, the model's answer or the lobe integrated over the rectangle: see areaLight.ts. */
|
|
1759
1815
|
areaLightAdd(
|
|
1760
|
-
|
|
1816
|
+
seenCentre, right, up, seenHalf, uAreaLightColor[a], form, areaOccl, areaGlass,
|
|
1761
1817
|
n, albedo, metal, specColor, surfaceRoughness, modelled, lampOpen, lampShadowed
|
|
1762
1818
|
);
|
|
1763
1819
|
}
|
|
@@ -1905,6 +1961,9 @@ export const MAIN_GLSL = `void main() {
|
|
|
1905
1961
|
* mix(1.0, min(lightShade, sunShade), EMISSIVE_SHADOW_SHARE) * fxGlow;
|
|
1906
1962
|
/* And a lit window's glow, which the scene's lit share already times: not gated on night. */
|
|
1907
1963
|
lit += windowGlow * uEmission.x;
|
|
1964
|
+
/* And a draw's overlay: its rim, its dissolve's band and the colour laid over. Not gated on the
|
|
1965
|
+
night, as emission is: a glow the surface wears rather than light it gives off. overlay.ts. */
|
|
1966
|
+
if (SURFACE_OVERLAY) lit += overlayGlow(surfaceAt.xy, n);
|
|
1908
1967
|
|
|
1909
1968
|
#if NIGHT_EMISSIVE
|
|
1910
1969
|
/*
|
|
@@ -2103,6 +2162,10 @@ export const MAIN_GLSL = `void main() {
|
|
|
2103
2162
|
return;
|
|
2104
2163
|
}
|
|
2105
2164
|
|
|
2165
|
+
/* WebGL2's frame writes the reflection maps itself, with the fog already reckoned above. */
|
|
2166
|
+
if (REFLECTION_MAPS) {
|
|
2167
|
+
reflectionSurfaceOut(reflectedProbe, reflectedTint, reflectedRoughness, ormOcclusion, fog);
|
|
2168
|
+
}
|
|
2106
2169
|
outColor = vec4(shaded, alpha);
|
|
2107
2170
|
}
|
|
2108
2171
|
`;
|