@driftengine/core 4.8.5 → 4.8.6
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 +4321 -4250
- package/dist/index.d.ts +10 -2
- package/dist/index.js +11 -1
- package/dist/render/ambientHarmonics.d.ts +46 -0
- package/dist/render/ambientHarmonics.js +80 -0
- package/dist/render/areaLights.d.ts +19 -0
- package/dist/render/areaLights.js +20 -0
- package/dist/render/backend/api.d.ts +13 -2
- package/dist/render/backend/webgl2/instanced.d.ts +2 -0
- package/dist/render/backend/webgl2/instanced.js +11 -2
- package/dist/render/backend/webgl2/renderer.d.ts +74 -1
- package/dist/render/backend/webgl2/renderer.js +229 -37
- package/dist/render/backend/webgl2/skinScatter.d.ts +14 -0
- package/dist/render/backend/webgl2/skinScatter.js +88 -26
- package/dist/render/backend/webgpu/buffers.js +2 -1
- package/dist/render/backend/webgpu/clusterBinner.js +3 -2
- package/dist/render/backend/webgpu/flatPass.d.ts +7 -5
- package/dist/render/backend/webgpu/flatPass.js +15 -13
- package/dist/render/backend/webgpu/particlePass.d.ts +37 -4
- package/dist/render/backend/webgpu/particlePass.js +80 -12
- package/dist/render/backend/webgpu/postPass.d.ts +6 -1
- package/dist/render/backend/webgpu/postPass.js +7 -2
- package/dist/render/backend/webgpu/renderer.d.ts +58 -7
- package/dist/render/backend/webgpu/renderer.js +329 -78
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +41 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +40 -28
- package/dist/render/backend/webgpu/skinPaletteRing.js +69 -32
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +10 -2
- package/dist/render/backend/webgpu/skinScatterPass.js +59 -9
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +2 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +18 -4
- package/dist/render/bloomChain.d.ts +44 -0
- package/dist/render/bloomChain.js +28 -0
- package/dist/render/bloomPass.d.ts +3 -1
- package/dist/render/bloomPass.js +16 -2
- package/dist/render/clusteredLights.d.ts +55 -1
- package/dist/render/clusteredLights.js +182 -8
- package/dist/render/fixtureAtlas.js +1 -1
- package/dist/render/instanceCull.js +7 -0
- package/dist/render/instances.d.ts +32 -10
- package/dist/render/instances.js +17 -8
- package/dist/render/lightBudget.d.ts +26 -1
- package/dist/render/lightBudget.js +26 -3
- package/dist/render/lightmap.d.ts +102 -0
- package/dist/render/lightmap.js +118 -0
- package/dist/render/mesh.js +2 -1
- package/dist/render/particleBatch.d.ts +59 -3
- package/dist/render/particleBatch.js +53 -2
- package/dist/render/particleMaterial.d.ts +6 -1
- package/dist/render/particleMaterial.js +10 -2
- package/dist/render/particlePool.d.ts +11 -0
- package/dist/render/particlePool.js +2 -0
- package/dist/render/particleSort.d.ts +34 -0
- package/dist/render/particleSort.js +96 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +8 -1
- package/dist/render/shaders/bloom.d.ts +8 -4
- package/dist/render/shaders/bloom.js +20 -3
- package/dist/render/shaders/flat/areaLight.d.ts +10 -0
- package/dist/render/shaders/flat/areaLight.js +96 -0
- package/dist/render/shaders/flat/index.js +30 -4
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +107 -105
- package/dist/render/shaders/flat/models.d.ts +16 -4
- package/dist/render/shaders/flat/models.js +64 -4
- package/dist/render/shaders/flat/normalMap.d.ts +10 -0
- package/dist/render/shaders/flat/normalMap.js +25 -0
- package/dist/render/shaders/flat/preamble.js +74 -37
- package/dist/render/shaders/flat/skin.js +6 -5
- package/dist/render/shaders/generated/bloom.wgsl.d.ts +13 -3
- package/dist/render/shaders/generated/bloom.wgsl.js +13 -3
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1631 -2044
- package/dist/render/shaders/generated/flat.wgsl.js +1669 -2082
- package/dist/render/shaders/generated/particle.wgsl.d.ts +115 -1
- package/dist/render/shaders/generated/particle.wgsl.js +115 -1
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/skinBlur.wgsl.js +12 -2
- package/dist/render/shaders/particle.d.ts +17 -1
- package/dist/render/shaders/particle.js +133 -1
- package/dist/render/shaders/skinBlur.js +25 -3
- package/dist/render/skinBlur.d.ts +8 -5
- package/dist/render/skinBlur.js +8 -5
- package/dist/render/surfaceModel.d.ts +21 -1
- package/dist/render/surfaceModel.js +22 -0
- package/dist/render/surfaceTexture.d.ts +14 -1
- package/dist/render/surfaceTexture.js +15 -2
- package/package.json +6 -6
- package/src/index.ts +20 -1
- package/src/render/ambientHarmonics.ts +92 -0
- package/src/render/areaLights.ts +39 -0
- package/src/render/backend/api.ts +14 -1
- package/src/render/backend/webgl2/instanced.ts +12 -2
- package/src/render/backend/webgl2/renderer.ts +292 -35
- package/src/render/backend/webgl2/skinScatter.ts +120 -43
- package/src/render/backend/webgpu/buffers.ts +2 -1
- package/src/render/backend/webgpu/clusterBinner.ts +3 -1
- package/src/render/backend/webgpu/flatPass.ts +18 -13
- package/src/render/backend/webgpu/particlePass.ts +118 -12
- package/src/render/backend/webgpu/postPass.ts +7 -2
- package/src/render/backend/webgpu/renderer.ts +396 -95
- package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +41 -1
- package/src/render/backend/webgpu/skinPaletteRing.ts +65 -33
- package/src/render/backend/webgpu/skinScatterPass.ts +59 -9
- package/src/render/backend/webgpu/surfaceTexturePass.ts +26 -5
- package/src/render/bloomChain.ts +69 -0
- package/src/render/bloomPass.ts +26 -2
- package/src/render/clusteredLights.ts +221 -7
- package/src/render/fixtureAtlas.ts +1 -1
- package/src/render/instanceCull.ts +5 -0
- package/src/render/instances.ts +40 -11
- package/src/render/lightBudget.ts +48 -2
- package/src/render/lightmap.ts +202 -0
- package/src/render/mesh.ts +2 -1
- package/src/render/particleBatch.ts +95 -4
- package/src/render/particleMaterial.ts +11 -1
- package/src/render/particlePool.ts +13 -0
- package/src/render/particleSort.ts +133 -0
- package/src/render/sceneTarget.ts +18 -1
- package/src/render/shaders/bloom.ts +20 -3
- package/src/render/shaders/flat/areaLight.ts +96 -0
- package/src/render/shaders/flat/index.ts +30 -4
- package/src/render/shaders/flat/main.ts +107 -105
- package/src/render/shaders/flat/models.ts +73 -8
- package/src/render/shaders/flat/normalMap.ts +25 -0
- package/src/render/shaders/flat/preamble.ts +74 -37
- package/src/render/shaders/flat/skin.ts +6 -5
- package/src/render/shaders/generated/bloom.wgsl.ts +13 -3
- package/src/render/shaders/generated/flat.wgsl.ts +1669 -2082
- package/src/render/shaders/generated/particle.wgsl.ts +116 -1
- package/src/render/shaders/generated/skinBlur.wgsl.ts +12 -2
- package/src/render/shaders/particle.ts +134 -1
- package/src/render/shaders/skinBlur.ts +25 -3
- package/src/render/skinBlur.ts +8 -5
- package/src/render/surfaceModel.ts +36 -1
- package/src/render/surfaceTexture.ts +41 -3
|
@@ -63,7 +63,9 @@ import {
|
|
|
63
63
|
clusteredMode,
|
|
64
64
|
createClusterLightSet,
|
|
65
65
|
createClusterTable,
|
|
66
|
+
clusteredLightTotal,
|
|
66
67
|
fillClusterLightSet,
|
|
68
|
+
lightChannelsOf,
|
|
67
69
|
} from '../../clusteredLights.ts';
|
|
68
70
|
import type {
|
|
69
71
|
PassContext,
|
|
@@ -88,7 +90,14 @@ import { FILM_FRAG, FILM_VERT } from '../../shaders/film.ts';
|
|
|
88
90
|
import { SceneTarget } from '../../sceneTarget.ts';
|
|
89
91
|
import type { ColourGradeLut } from '../../colourGrade.ts';
|
|
90
92
|
import { FILM_LOOK_WITHOUT_COMPOSITE } from '../../shaders/filmLook.ts';
|
|
91
|
-
import {
|
|
93
|
+
import { AMBIENT_SH_FLOATS, packAmbientSH } from '../../ambientHarmonics.ts';
|
|
94
|
+
import {
|
|
95
|
+
bloomProfileWarning,
|
|
96
|
+
bloomThresholdOf,
|
|
97
|
+
defaultBloomResponse,
|
|
98
|
+
resolveBloomResponse,
|
|
99
|
+
type BloomResponse,
|
|
100
|
+
} from '../../bloomChain.ts';
|
|
92
101
|
import {
|
|
93
102
|
createEmptyTexture2D,
|
|
94
103
|
createEmptyTexture2DArray,
|
|
@@ -129,7 +138,14 @@ import {
|
|
|
129
138
|
} from '../../lightBudget.ts';
|
|
130
139
|
import { MODEL_PARAM_FLOATS, eyeAxisInWorld, packModel } from '../../surfaceModel.ts';
|
|
131
140
|
import type { SurfaceModelKind } from '../../surfaceModel.ts';
|
|
132
|
-
import { modelBound, skinHalfBound } from '../../shaders/flat/models.ts';
|
|
141
|
+
import { lightmapRegionsBound, modelBound, skinHalfBound } from '../../shaders/flat/models.ts';
|
|
142
|
+
import {
|
|
143
|
+
lightmapTexels,
|
|
144
|
+
warnRegionsWithoutPage,
|
|
145
|
+
warnUnpagedLightmap,
|
|
146
|
+
withLightmapUvs,
|
|
147
|
+
} from '../../lightmap.ts';
|
|
148
|
+
import type { LightmapPage } from '../../lightmap.ts';
|
|
133
149
|
import type { SkinHalf } from '../../shaders/flat/models.ts';
|
|
134
150
|
import { GlSkinScatter } from './skinScatter.ts';
|
|
135
151
|
import {
|
|
@@ -224,6 +240,7 @@ import {
|
|
|
224
240
|
bindAreaLights,
|
|
225
241
|
bindAreaShadows,
|
|
226
242
|
openCones,
|
|
243
|
+
PARTICLE_DEPTH_UNIT,
|
|
227
244
|
} from '../../lightBudget.ts';
|
|
228
245
|
import { resolveRenderQuality } from '../../renderQuality.ts';
|
|
229
246
|
import type { RenderQuality, RenderQualityOptions } from '../../renderQuality.ts';
|
|
@@ -430,6 +447,12 @@ export interface Environment extends Atmosphere {
|
|
|
430
447
|
lightIesAxes: Float32Array;
|
|
431
448
|
/** One per active light: a tile of the cookie atlas, or −1 for none. */
|
|
432
449
|
lightCookies: Float32Array;
|
|
450
|
+
/**
|
|
451
|
+
* One per active light: the lighting channels it lights, a mask from 1 to 255. Absent, short, or
|
|
452
|
+
* a light at 1 is the default channel every surface is on too. See `PointLightSet.lightChannels`
|
|
453
|
+
* and `SurfaceMaterial.lightChannels`.
|
|
454
|
+
*/
|
|
455
|
+
lightChannels?: Float32Array;
|
|
433
456
|
/**
|
|
434
457
|
* The rectangular emitters this frame, or null for none.
|
|
435
458
|
*
|
|
@@ -508,6 +531,8 @@ export function createEnvironment(overrides: Partial<Environment> = {}): Environ
|
|
|
508
531
|
lightIesAxes: new Float32Array(MAX_POINT_LIGHTS * 3),
|
|
509
532
|
/* −1, because tile 0 is a real cookie and no light here has asked for one. */
|
|
510
533
|
lightCookies: new Float32Array(MAX_POINT_LIGHTS).fill(-1),
|
|
534
|
+
/* Channel 1, the default every surface is on, so every light lights everything. */
|
|
535
|
+
lightChannels: new Float32Array(MAX_POINT_LIGHTS).fill(1),
|
|
511
536
|
/* None, so the shader's loop breaks before it reads anything. */
|
|
512
537
|
areaLights: null,
|
|
513
538
|
activeLightWorldIndices: new Int32Array(MAX_POINT_LIGHTS).fill(-1),
|
|
@@ -618,6 +643,9 @@ export interface SkyColors {
|
|
|
618
643
|
export { MAX_DEPTH_LAYER } from '../../depthConvention.ts';
|
|
619
644
|
|
|
620
645
|
/** The identity tint, handed back after any draw that asked for one. See `drawMesh`. */
|
|
646
|
+
/** The far corner of no highlight box: what an environment that names none reads. */
|
|
647
|
+
const NO_HIGHLIGHT: readonly number[] = [0, 0, 0];
|
|
648
|
+
|
|
621
649
|
const WHITE_TINT = new Float32Array([1, 1, 1]);
|
|
622
650
|
/** The lit stage's clip plane when there is no mirror: zero, which clips nothing. */
|
|
623
651
|
const NO_CLIP_PLANE = new Float32Array(4);
|
|
@@ -1364,6 +1392,23 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1364
1392
|
private motionBlurScale = 1;
|
|
1365
1393
|
/** How much of the bloom ceiling this frame takes. See `setBloom`. */
|
|
1366
1394
|
private bloomScale = 1;
|
|
1395
|
+
/** The draw's own ambient, as `packAmbientSH` writes it; zeros are the frame's. */
|
|
1396
|
+
private readonly ambientSH = new Float32Array(AMBIENT_SH_FLOATS);
|
|
1397
|
+
/** Scratch for a sprite's depth conversion, so a particle draw allocates nothing. */
|
|
1398
|
+
private readonly spriteInverseProjection = mat4.create();
|
|
1399
|
+
/** Said once: a sprite asked for a soft edge where no depth copy could be had. */
|
|
1400
|
+
private warnedSpriteDepth = false;
|
|
1401
|
+
/** Said once: more rectangles than the fixed arm shades, and no froxel table for the rest. */
|
|
1402
|
+
private warnedAreaOverflow = false;
|
|
1403
|
+
/**
|
|
1404
|
+
* `uEnvironmentDials` as it stands: which chain the probe holds, the reflectivity, the gain. One
|
|
1405
|
+
* vector on the device, so written whole, and kept here so a setter moving one keeps the others.
|
|
1406
|
+
*/
|
|
1407
|
+
private readonly environmentDials = new Float32Array(3);
|
|
1408
|
+
/** `uEmission` as it stands: the emissive gain and the night factor. */
|
|
1409
|
+
private readonly emission = new Float32Array([1, 0]);
|
|
1410
|
+
/** The ramp and each level's tint, as `resolveBloomResponse` writes them; the subtraction and white. */
|
|
1411
|
+
private readonly bloomResponse = defaultBloomResponse();
|
|
1367
1412
|
/** In scene units, once `setBloom` has moved it; null reads the profile's. */
|
|
1368
1413
|
private bloomThresholdSet: number | null = null;
|
|
1369
1414
|
/**
|
|
@@ -2460,9 +2505,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2460
2505
|
gl.activeTexture(gl.TEXTURE0 + FIXTURE_ATLAS_TEXTURE_UNIT);
|
|
2461
2506
|
gl.bindTexture(gl.TEXTURE_2D, this.fixtureTexture);
|
|
2462
2507
|
gl.uniform1i(u['uFixtureAtlas'] ?? null, FIXTURE_ATLAS_TEXTURE_UNIT);
|
|
2463
|
-
gl.
|
|
2464
|
-
gl.uniform1f(u['uIesPlaneCount'] ?? null, this.iesPlanes);
|
|
2465
|
-
gl.uniform1f(u['uCookieTiles'] ?? null, this.cookieTiles);
|
|
2508
|
+
gl.uniform3f(u['uFixtureShape'] ?? null, this.iesRows, this.iesPlanes, this.cookieTiles);
|
|
2466
2509
|
gl.activeTexture(gl.TEXTURE0);
|
|
2467
2510
|
}
|
|
2468
2511
|
|
|
@@ -2516,7 +2559,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2516
2559
|
gl.uniformMatrix4fv(u['uView'] ?? null, false, camera.view);
|
|
2517
2560
|
|
|
2518
2561
|
this.clusterTable ??= createClusterTable();
|
|
2519
|
-
|
|
2562
|
+
/* The rectangles past the fixed arm's go into the table. See `ClusterLightSet.areas`. */
|
|
2563
|
+
const lights = fillClusterLightSet(env, this.clusterLights, this.shadedAreaLights);
|
|
2520
2564
|
/* A slot is read only under `POINT_SHADOWS`; see `lightHasFixture`. */
|
|
2521
2565
|
const shadowSlots = this.quality.pointShadows ? this.lightBudget.maxLights : 0;
|
|
2522
2566
|
buildLightClusters(
|
|
@@ -2536,7 +2580,10 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2536
2580
|
*/
|
|
2537
2581
|
shadowSlots,
|
|
2538
2582
|
);
|
|
2539
|
-
gl.uniform1i(
|
|
2583
|
+
gl.uniform1i(
|
|
2584
|
+
u['uClustered'] ?? null,
|
|
2585
|
+
clusteredMode(lights, clusteredLightTotal(lights), shadowSlots),
|
|
2586
|
+
);
|
|
2540
2587
|
gl.texSubImage2D(
|
|
2541
2588
|
gl.TEXTURE_2D,
|
|
2542
2589
|
0,
|
|
@@ -3252,8 +3299,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3252
3299
|
* one. Measured on hardware: WebGL2 drew neither the bend nor the bulge while WebGPU drew
|
|
3253
3300
|
* both, which is the two-backend comparison doing exactly what it is for.
|
|
3254
3301
|
*/
|
|
3255
|
-
|
|
3256
|
-
|
|
3302
|
+
const drawn = withLightmapUvs(data);
|
|
3303
|
+
this.warmVariants(drawn);
|
|
3304
|
+
return new Mesh(this.gl, drawn, options.dynamic === true);
|
|
3257
3305
|
}
|
|
3258
3306
|
|
|
3259
3307
|
/**
|
|
@@ -3266,8 +3314,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3266
3314
|
* the signal that it was abandoned.
|
|
3267
3315
|
*/
|
|
3268
3316
|
createMeshIncremental(data: MeshData, options: MeshOptions = {}): IncrementalMesh {
|
|
3269
|
-
|
|
3270
|
-
|
|
3317
|
+
const drawn = withLightmapUvs(data);
|
|
3318
|
+
this.warmVariants(drawn);
|
|
3319
|
+
const { mesh, upload } = createMeshIncremental(this.gl, drawn, options.dynamic === true);
|
|
3271
3320
|
return {
|
|
3272
3321
|
mesh,
|
|
3273
3322
|
upload: {
|
|
@@ -3445,6 +3494,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3445
3494
|
return new SurfaceTexture(this.gl, sources, options, this.compressedFormats);
|
|
3446
3495
|
}
|
|
3447
3496
|
|
|
3497
|
+
/** A baked lightmap page, as a `lightmapModel` material's `modelMap`. See `RendererApi`. */
|
|
3498
|
+
createLightmap(page: LightmapPage): SurfaceTexture {
|
|
3499
|
+
return new SurfaceTexture(this.gl, lightmapTexels(page), { wrap: 'clamp', mipmap: false });
|
|
3500
|
+
}
|
|
3501
|
+
|
|
3448
3502
|
/**
|
|
3449
3503
|
* Replace a surface texture's pixels, keeping the GPU object and its sampler state.
|
|
3450
3504
|
*
|
|
@@ -3522,7 +3576,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3522
3576
|
const label = `flat.${variant}.${kind}.${half}`;
|
|
3523
3577
|
const program = compileProgram(
|
|
3524
3578
|
gl,
|
|
3525
|
-
|
|
3579
|
+
modelVertexOf(variant, kind),
|
|
3526
3580
|
skinHalfBound(modelBound(this.flatFragSource, kind), half),
|
|
3527
3581
|
label,
|
|
3528
3582
|
);
|
|
@@ -3693,6 +3747,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3693
3747
|
this.currentMaterial = material;
|
|
3694
3748
|
/* What the blur spreads this skin by: the last material to name a profile says. */
|
|
3695
3749
|
const model = material?.model;
|
|
3750
|
+
warnUnpagedLightmap(model, material?.modelMap);
|
|
3696
3751
|
if (model?.kind === 'skin' && this.skinScatter !== null) {
|
|
3697
3752
|
this.skinScatter.setProfile(
|
|
3698
3753
|
model.profile,
|
|
@@ -3738,7 +3793,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3738
3793
|
v[0] = material?.cutout ?? 0;
|
|
3739
3794
|
v[1] = CUTOUT_RESOLVE_CODE[this.cutoutResolveNow(material, translucent)];
|
|
3740
3795
|
v[2] = this.cutoutFrame;
|
|
3741
|
-
|
|
3796
|
+
/* The material's lighting channels, which the lamps' are compared with. See `uCutout`. */
|
|
3797
|
+
v[3] = lightChannelsOf(material?.lightChannels);
|
|
3742
3798
|
return v;
|
|
3743
3799
|
}
|
|
3744
3800
|
|
|
@@ -3866,6 +3922,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3866
3922
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
|
|
3867
3923
|
this.materialFlags[0] = 0;
|
|
3868
3924
|
gl.uniform4iv(u['uMaterialFlags'] ?? null, this.materialFlags);
|
|
3925
|
+
/* No image to cut, and the channels all the same: a material needs no albedo to name them. */
|
|
3926
|
+
gl.uniform4f(u['uCutout'] ?? null, 0, 0, 0, lightChannelsOf(material?.lightChannels));
|
|
3869
3927
|
return;
|
|
3870
3928
|
}
|
|
3871
3929
|
albedo.bind(gl, SURFACE_TEXTURE_UNIT);
|
|
@@ -3917,6 +3975,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3917
3975
|
* is 1 and `bindMeshPass` restores it, so it scales geometry that declared grain and
|
|
3918
3976
|
* leaves geometry that did not exactly as it is.
|
|
3919
3977
|
*/
|
|
3978
|
+
/**
|
|
3979
|
+
* The ambient the following draws take, as nine spherical-harmonic coefficients of incoming
|
|
3980
|
+
* radiance — red, green and blue of each, twenty-seven numbers — or `null` for the frame's own:
|
|
3981
|
+
* the sky's gradient, or the probes'. See `ambientHarmonics.ts` for the basis and the axes.
|
|
3982
|
+
*
|
|
3983
|
+
* **For a thing lit by where it stands**: a consumer sampling a stage's baked volume of indirect
|
|
3984
|
+
* light at a character every frame sets the result around that character's draws, and the
|
|
3985
|
+
* character takes the light of its spot rather than the frame's. It replaces the diffuse ambient
|
|
3986
|
+
* only — a glossy surface still reflects the probes — and it is pass state like the material,
|
|
3987
|
+
* which `bindMeshPass` clears, so a mirror or a probe bake drawn after does not inherit it.
|
|
3988
|
+
*/
|
|
3920
3989
|
/**
|
|
3921
3990
|
* How much of the environment the following draws mirror, 0 to 1.
|
|
3922
3991
|
*
|
|
@@ -3927,10 +3996,22 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3927
3996
|
* Defaults to zero and bindMeshPass restores it, so a scene that never calls this looks
|
|
3928
3997
|
* exactly as it did.
|
|
3929
3998
|
*/
|
|
3999
|
+
setAmbientSH(coefficients: ArrayLike<number> | null): void {
|
|
4000
|
+
if (this.contextLost) return;
|
|
4001
|
+
packAmbientSH(coefficients, this.ambientSH);
|
|
4002
|
+
this.materials.dirty();
|
|
4003
|
+
for (const target of this.flatTargets) {
|
|
4004
|
+
this.gl.useProgram(target.program);
|
|
4005
|
+
this.gl.uniform4fv(target.uniforms['uAmbientSH[0]'] ?? null, this.ambientSH);
|
|
4006
|
+
}
|
|
4007
|
+
this.useFlatProgram();
|
|
4008
|
+
}
|
|
4009
|
+
|
|
3930
4010
|
setSurfaceReflectivity(amount: number): void {
|
|
3931
4011
|
if (this.contextLost) return;
|
|
3932
4012
|
this.materials.dirty();
|
|
3933
|
-
this.
|
|
4013
|
+
this.environmentDials[1] = Math.min(1, Math.max(0, amount));
|
|
4014
|
+
this.writeFlatVector('uEnvironmentDials', this.environmentDials);
|
|
3934
4015
|
}
|
|
3935
4016
|
|
|
3936
4017
|
/**
|
|
@@ -3948,7 +4029,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3948
4029
|
setEnvironmentGain(gain: number): void {
|
|
3949
4030
|
if (this.contextLost) return;
|
|
3950
4031
|
this.materials.dirty();
|
|
3951
|
-
this.
|
|
4032
|
+
this.environmentDials[2] = Math.max(0, gain);
|
|
4033
|
+
this.writeFlatVector('uEnvironmentDials', this.environmentDials);
|
|
3952
4034
|
}
|
|
3953
4035
|
|
|
3954
4036
|
/**
|
|
@@ -4019,6 +4101,18 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4019
4101
|
this.useFlatProgram();
|
|
4020
4102
|
}
|
|
4021
4103
|
|
|
4104
|
+
/** A vector of material state, two to four floats, into every flat program. */
|
|
4105
|
+
private writeFlatVector(name: string, value: Float32Array): void {
|
|
4106
|
+
for (const target of this.flatTargets) {
|
|
4107
|
+
this.gl.useProgram(target.program);
|
|
4108
|
+
const at = target.uniforms[name] ?? null;
|
|
4109
|
+
if (value.length === 2) this.gl.uniform2fv(at, value);
|
|
4110
|
+
else if (value.length === 3) this.gl.uniform3fv(at, value);
|
|
4111
|
+
else this.gl.uniform4fv(at, value);
|
|
4112
|
+
}
|
|
4113
|
+
this.useFlatProgram();
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4022
4116
|
/** One int of material state, into every flat program, for `writeFlatFloat`'s reason. */
|
|
4023
4117
|
private writeFlatInt(name: string, value: number): void {
|
|
4024
4118
|
for (const target of this.flatTargets) {
|
|
@@ -4083,8 +4177,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4083
4177
|
setSurfaceRelief(amount: number, cyclesPerMetre = 60): void {
|
|
4084
4178
|
if (this.contextLost) return;
|
|
4085
4179
|
this.materials.dirty();
|
|
4086
|
-
|
|
4087
|
-
|
|
4180
|
+
const strength = Math.min(1, Math.max(0, amount));
|
|
4181
|
+
const cycles = Math.max(0.01, cyclesPerMetre);
|
|
4182
|
+
for (const target of this.flatTargets) {
|
|
4183
|
+
this.gl.useProgram(target.program);
|
|
4184
|
+
this.gl.uniform2f(target.uniforms['uRelief'] ?? null, strength, cycles);
|
|
4185
|
+
}
|
|
4186
|
+
this.useFlatProgram();
|
|
4088
4187
|
}
|
|
4089
4188
|
|
|
4090
4189
|
/**
|
|
@@ -4142,7 +4241,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4142
4241
|
setEmissiveGain(gain: number): void {
|
|
4143
4242
|
if (this.contextLost) return;
|
|
4144
4243
|
this.materials.dirty();
|
|
4145
|
-
this.
|
|
4244
|
+
this.emission[0] = gain;
|
|
4245
|
+
this.writeFlatVector('uEmission', this.emission);
|
|
4146
4246
|
}
|
|
4147
4247
|
|
|
4148
4248
|
/* -- Instanced meshes --------------------------------------------------------------- */
|
|
@@ -4254,6 +4354,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4254
4354
|
options: TranslucentMeshOptions,
|
|
4255
4355
|
): void {
|
|
4256
4356
|
if (this.contextLost) return;
|
|
4357
|
+
warnRegionsWithoutPage(this.currentMaterial?.model, data.lightmapRegions);
|
|
4257
4358
|
const mesh = batch.mesh;
|
|
4258
4359
|
/* Nor a batch of a mesh with nothing in it: see `Mesh.indexCount`. */
|
|
4259
4360
|
if (!mesh.complete || mesh.indexCount === 0) return;
|
|
@@ -4767,8 +4868,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4767
4868
|
const { gl } = this;
|
|
4768
4869
|
const u = batch.uniforms;
|
|
4769
4870
|
gl.useProgram(batch.program);
|
|
4770
|
-
batch.upload(gl, data);
|
|
4871
|
+
batch.upload(gl, data, camera.position);
|
|
4771
4872
|
batch.bindMaterial(gl);
|
|
4873
|
+
if (batch.material === 'sprite') this.bindSpriteFades(batch, camera);
|
|
4772
4874
|
gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, this.viewProjFor(camera));
|
|
4773
4875
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
4774
4876
|
gl.uniform1f(u['uTime'] ?? null, timeSeconds);
|
|
@@ -4800,6 +4902,48 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4800
4902
|
if (this.materialDoubleSided) gl.enable(gl.CULL_FACE);
|
|
4801
4903
|
}
|
|
4802
4904
|
|
|
4905
|
+
/**
|
|
4906
|
+
* A sprite's two fades and the depth copy the soft one reads. The copy is the frame's opaque
|
|
4907
|
+
* depth, so it is taken only in the frame's own picture: in a mirror or a probe's face it would
|
|
4908
|
+
* be another view's, and the edge stays hard there. Without a scene target there is no copy at
|
|
4909
|
+
* all, and the renderer says so once rather than drawing a hard edge that was asked to be soft.
|
|
4910
|
+
*/
|
|
4911
|
+
private bindSpriteFades(batch: ParticleBatch, camera: Camera): void {
|
|
4912
|
+
const { gl } = this;
|
|
4913
|
+
const u = batch.uniforms;
|
|
4914
|
+
const scene = this.sceneTarget;
|
|
4915
|
+
let depth: WebGLTexture | null = null;
|
|
4916
|
+
if (batch.softDepth > 0 && !this.reflectionPassActive && !this.probePassActive) {
|
|
4917
|
+
depth = scene?.snapshotDepth(true) ?? null;
|
|
4918
|
+
if (depth === null && !this.warnedSpriteDepth) {
|
|
4919
|
+
this.warnedSpriteDepth = true;
|
|
4920
|
+
console.warn(
|
|
4921
|
+
"WebGL2: a 'sprite' asked for a soft edge, which reads a copy of the frame's depth, and " +
|
|
4922
|
+
'this profile keeps none — screenEffects is off, or the driver refused the copy. The ' +
|
|
4923
|
+
'edge is hard.',
|
|
4924
|
+
);
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
gl.activeTexture(gl.TEXTURE0 + PARTICLE_DEPTH_UNIT);
|
|
4928
|
+
gl.bindTexture(gl.TEXTURE_2D, depth ?? this.emptyTexture2D);
|
|
4929
|
+
gl.uniform1i(u['uDepth'] ?? null, PARTICLE_DEPTH_UNIT);
|
|
4930
|
+
gl.uniform4f(u['uFade'] ?? null, batch.softDepth, batch.cameraFade, depth === null ? 0 : 1, 0);
|
|
4931
|
+
mat4.invert(this.spriteInverseProjection, camera.projection);
|
|
4932
|
+
const inverse = this.spriteInverseProjection;
|
|
4933
|
+
gl.uniform4f(
|
|
4934
|
+
u['uDepthToViewZ'] ?? null,
|
|
4935
|
+
inverse[10] ?? 0,
|
|
4936
|
+
inverse[14] ?? 0,
|
|
4937
|
+
inverse[11] ?? 0,
|
|
4938
|
+
inverse[15] ?? 1,
|
|
4939
|
+
);
|
|
4940
|
+
gl.uniform2f(
|
|
4941
|
+
u['uViewport'] ?? null,
|
|
4942
|
+
scene?.frameWidth ?? gl.drawingBufferWidth,
|
|
4943
|
+
scene?.frameHeight ?? gl.drawingBufferHeight,
|
|
4944
|
+
);
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4803
4947
|
/** Build a batch for electrical arcs. `capacity` is in segments, not arcs. */
|
|
4804
4948
|
createBolts(segmentCapacity: number, label = 'bolts'): BoltBatch {
|
|
4805
4949
|
return new BoltBatch(this.gl, segmentCapacity, label);
|
|
@@ -5918,7 +6062,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5918
6062
|
const label = `flat.${variant}.${kind}.${half}`;
|
|
5919
6063
|
const program = compileProgram(
|
|
5920
6064
|
gl,
|
|
5921
|
-
|
|
6065
|
+
modelVertexOf(variant, kind),
|
|
5922
6066
|
skinHalfBound(modelBound(this.flatFragSource, kind), half),
|
|
5923
6067
|
label,
|
|
5924
6068
|
);
|
|
@@ -6800,10 +6944,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6800
6944
|
* and wrong for a day whose exposure spans 2.5 to 14: a courtyard blooming at noon, or candles
|
|
6801
6945
|
* never blooming at night. A caller whose exposure moves passes what it wants on screen over the
|
|
6802
6946
|
* exposure. Omitted leaves it where it was, so a caller that never passes one keeps the profile's.
|
|
6947
|
+
*
|
|
6948
|
+
* **`response` is how a colour comes in past the threshold and what colour each octave of the
|
|
6949
|
+
* halo takes** — a ramp in place of the subtraction, and a tint a level — held until moved like
|
|
6950
|
+
* the threshold; `null` goes back to the subtraction and white. See `BloomResponse`: it is what
|
|
6951
|
+
* matches a stage built for another engine's bloom, whose tints are how a strength past 1 is
|
|
6952
|
+
* asked for.
|
|
6803
6953
|
*/
|
|
6804
|
-
setBloom(scale: number, threshold?: number): void {
|
|
6954
|
+
setBloom(scale: number, threshold?: number, response?: BloomResponse | null): void {
|
|
6805
6955
|
this.bloomScale = Math.min(Math.max(scale, 0), 1);
|
|
6806
6956
|
if (threshold !== undefined) this.bloomThresholdSet = bloomThresholdOf(threshold);
|
|
6957
|
+
if (response !== undefined) resolveBloomResponse(response, this.bloomResponse);
|
|
6807
6958
|
}
|
|
6808
6959
|
|
|
6809
6960
|
/**
|
|
@@ -7364,6 +7515,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7364
7515
|
? {
|
|
7365
7516
|
strength: bloomStrength,
|
|
7366
7517
|
threshold: this.bloomThresholdSet ?? this.quality.bloomThreshold,
|
|
7518
|
+
response: this.bloomResponse,
|
|
7367
7519
|
}
|
|
7368
7520
|
: undefined;
|
|
7369
7521
|
|
|
@@ -7699,6 +7851,19 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7699
7851
|
bindMeshPass(camera: Camera, env: Environment): void {
|
|
7700
7852
|
/* The pass's own material is reopened, so the next draw opens one. See `materialChanges.ts`. */
|
|
7701
7853
|
this.materials.dirty();
|
|
7854
|
+
/* Rectangles past the fixed arm's are the froxel table's, and without it nobody shades them. */
|
|
7855
|
+
if (
|
|
7856
|
+
!this.warnedAreaOverflow &&
|
|
7857
|
+
!this.quality.clusteredLights &&
|
|
7858
|
+
(env.areaLights?.count ?? 0) > this.shadedAreaLights
|
|
7859
|
+
) {
|
|
7860
|
+
this.warnedAreaOverflow = true;
|
|
7861
|
+
console.warn(
|
|
7862
|
+
`WebGL2: ${env.areaLights?.count ?? 0} rectangular lights and ${this.shadedAreaLights} ` +
|
|
7863
|
+
'shaded without clusteredLights: the rest are not drawn. Turn clusteredLights on, and the ' +
|
|
7864
|
+
'froxel table shades every one past the fixed ones, unshadowed.',
|
|
7865
|
+
);
|
|
7866
|
+
}
|
|
7702
7867
|
/*
|
|
7703
7868
|
* Captured here rather than taken as an argument to `endFrame`, because this is the
|
|
7704
7869
|
* camera the world was drawn with and a caller should not have to hand it over twice.
|
|
@@ -7810,6 +7975,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7810
7975
|
this.materialHasMaps = false;
|
|
7811
7976
|
this.currentMaterial = null;
|
|
7812
7977
|
this.currentSurfaceTexture = null;
|
|
7978
|
+
/* Nor an ambient of its own: the frame's, until a draw asks. See `setAmbientSH`. */
|
|
7979
|
+
this.ambientSH.fill(0);
|
|
7980
|
+
/* No reflection and an environment at its own brightness; the emission the world asks for. */
|
|
7981
|
+
this.environmentDials[1] = 0;
|
|
7982
|
+
this.environmentDials[2] = 1;
|
|
7983
|
+
this.emission[0] = env.emissiveGain;
|
|
7984
|
+
this.emission[1] = env.nightFactor;
|
|
7813
7985
|
for (const target of this.flatTargets) {
|
|
7814
7986
|
this.gl.useProgram(target.program);
|
|
7815
7987
|
this.writeMeshPassState(target.uniforms, camera, env);
|
|
@@ -8036,13 +8208,18 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8036
8208
|
this.oitWeight = 0;
|
|
8037
8209
|
this.ditherFade = 0;
|
|
8038
8210
|
gl.uniform2f(u['uWriteMode'] ?? null, 0, 0);
|
|
8039
|
-
/*
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8211
|
+
/* The draw's own ambient as it stands, which `bindMeshPass` has just cleared: a program built
|
|
8212
|
+
in the middle of a pass takes what the caller set. See `setAmbientSH`. */
|
|
8213
|
+
gl.uniform4fv(u['uAmbientSH[0]'] ?? null, this.ambientSH);
|
|
8214
|
+
/*
|
|
8215
|
+
* Which chain the probe holds, no environment reflection, and an environment at its own
|
|
8216
|
+
* brightness — the reflectivity's identity is 0 and the gain's is 1 — as `bindMeshPass` set
|
|
8217
|
+
* them, or as a draw since has: a program built in the middle of a pass takes what stands.
|
|
8218
|
+
* See `setSurfaceReflectivity` and `setEnvironmentGain`.
|
|
8219
|
+
*/
|
|
8220
|
+
gl.uniform3fv(u['uEnvironmentDials'] ?? null, this.environmentDials);
|
|
8043
8221
|
/* And no relief unless a caller asks, for the same reason. */
|
|
8044
|
-
gl.
|
|
8045
|
-
gl.uniform1f(u['uReliefCycles'] ?? null, 60);
|
|
8222
|
+
gl.uniform2f(u['uRelief'] ?? null, 0, 60);
|
|
8046
8223
|
/* And no relief read off a surface texture either, for the same reason. */
|
|
8047
8224
|
gl.uniform1f(u['uTextureRelief'] ?? null, 0);
|
|
8048
8225
|
/* The mirror's plane in a reflection pass, and zero — which clips nothing — in every other. */
|
|
@@ -8060,8 +8237,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8060
8237
|
this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0),
|
|
8061
8238
|
this.quality.underwaterAtmosphere,
|
|
8062
8239
|
);
|
|
8063
|
-
|
|
8064
|
-
gl.
|
|
8240
|
+
/* The emissive gain and the night factor, as the pass set them. See `uEmission`. */
|
|
8241
|
+
gl.uniform2fv(u['uEmission'] ?? null, this.emission);
|
|
8065
8242
|
/* Absent means zero, so a world written before this term existed adds nothing. */
|
|
8066
8243
|
gl.uniform1f(u['uNightEmissive'] ?? null, env.nightEmissive ?? 0);
|
|
8067
8244
|
/*
|
|
@@ -8083,8 +8260,16 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8083
8260
|
gl.uniform1f(u['uShadowMaxSlope'] ?? null, this.quality.directionalShadowMaxSlope);
|
|
8084
8261
|
gl.uniform1i(u['uShadowFilterTaps'] ?? null, this.quality.shadowFilterTaps);
|
|
8085
8262
|
gl.uniform3fv(u['uHighlightMin'] ?? null, env.highlightMin);
|
|
8086
|
-
|
|
8087
|
-
|
|
8263
|
+
/* The far corner, and the gain in its w. See `uHighlightMax`. */
|
|
8264
|
+
/* An environment written by hand may leave the box out; then there is none, as before. */
|
|
8265
|
+
const max = env.highlightMax ?? NO_HIGHLIGHT;
|
|
8266
|
+
gl.uniform4f(
|
|
8267
|
+
u['uHighlightMax'] ?? null,
|
|
8268
|
+
max[0] ?? 0,
|
|
8269
|
+
max[1] ?? 0,
|
|
8270
|
+
max[2] ?? 0,
|
|
8271
|
+
env.highlightGain ?? 0,
|
|
8272
|
+
);
|
|
8088
8273
|
|
|
8089
8274
|
bindPointLights(gl, u, env, this.quality.pointLightFalloff);
|
|
8090
8275
|
this.bindClusters(u, camera, env);
|
|
@@ -8184,7 +8369,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8184
8369
|
* between them; there is one array, so `RenderQuality.environmentPrefilter` decides what the
|
|
8185
8370
|
* convolution writes and a profile that changes it has to bake again.
|
|
8186
8371
|
*/
|
|
8187
|
-
|
|
8372
|
+
this.environmentDials[0] = this.quality.environmentPrefilter ? 1 : 0;
|
|
8373
|
+
gl.uniform3fv(u['uEnvironmentDials'] ?? null, this.environmentDials);
|
|
8188
8374
|
gl.uniform1f(u['uEnvironmentMaxLod'] ?? null, array?.ggxMaxLevel ?? 0);
|
|
8189
8375
|
/*
|
|
8190
8376
|
* The map's edge, which used to be `exp2(maxLod)` and is not any more: the chain stops one
|
|
@@ -8383,12 +8569,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8383
8569
|
if (this.quality.cullDraws && this.occluded(mesh.bounds, model)) return;
|
|
8384
8570
|
this.drawBudget.ask();
|
|
8385
8571
|
this.takeMaterial();
|
|
8386
|
-
/*
|
|
8572
|
+
/*
|
|
8573
|
+
* Skin under the screen-space blur draws its halves: the frame's, then at once its diffuse's
|
|
8574
|
+
* light and its colour, each into the blur's own target.
|
|
8575
|
+
*/
|
|
8387
8576
|
const splits = this.skinSplits();
|
|
8388
8577
|
this.drawMeshHalf(mesh, model, depthLayer, tint, splits ? 'scene' : 'whole');
|
|
8389
8578
|
if (splits && this.skinScatter !== null) {
|
|
8390
8579
|
this.skinScatter.begin();
|
|
8391
8580
|
this.drawMeshHalf(mesh, model, depthLayer, tint, 'diffuse');
|
|
8581
|
+
this.skinScatter.beginAlbedo();
|
|
8582
|
+
this.drawMeshHalf(mesh, model, depthLayer, tint, 'albedo');
|
|
8392
8583
|
this.sceneTarget?.bind();
|
|
8393
8584
|
}
|
|
8394
8585
|
}
|
|
@@ -8574,8 +8765,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8574
8765
|
* depth 1.0 against a buffer cleared to 1.0, and under `LESS` it would not draw at
|
|
8575
8766
|
* all. Film, caustics and text lie flush on surfaces for the same reason.
|
|
8576
8767
|
*/
|
|
8577
|
-
/* A skin's diffuse
|
|
8578
|
-
|
|
8768
|
+
/* A skin's diffuse and colour halves are the same surface again: each finds the depth its
|
|
8769
|
+
frame half wrote. */
|
|
8770
|
+
const again = half === 'diffuse' || half === 'albedo';
|
|
8579
8771
|
gl.depthFunc(again ? gl.EQUAL : this.reversedDepth ? gl.GREATER : gl.LESS);
|
|
8580
8772
|
if (again) gl.depthMask(false);
|
|
8581
8773
|
/* A dithered cutout in a multisampled frame with no temporal resolve: its share becomes the
|
|
@@ -9030,6 +9222,62 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
9030
9222
|
return true;
|
|
9031
9223
|
}
|
|
9032
9224
|
|
|
9225
|
+
/**
|
|
9226
|
+
* One layer of the declared probe grid from an image, the way `setEnvironmentImage` fills a
|
|
9227
|
+
* single probe: the same equirectangular image of linear RGB floats, projected onto the capture
|
|
9228
|
+
* cube and prefiltered into that layer, the others left as they are. Returns false — and says
|
|
9229
|
+
* why — where there is no probe, no grid, or no such layer.
|
|
9230
|
+
*
|
|
9231
|
+
* **What it is for**: a scene baked somewhere else. Another engine's reflection captures are
|
|
9232
|
+
* images taken where each one stands; a consumer fits them to a lattice — for each point, the
|
|
9233
|
+
* capture whose reach holds it — and hands each point its image here, where `bakeProbe` would
|
|
9234
|
+
* have drawn this engine's own world into it.
|
|
9235
|
+
*
|
|
9236
|
+
* `options.irradiance` decides, at grid scope as a bake's does, whether the grid also lights the
|
|
9237
|
+
* scene's diffuse ambient. A grid that crossfades writes the set being swept, as a bake does.
|
|
9238
|
+
*/
|
|
9239
|
+
setProbeLayerImage(
|
|
9240
|
+
layer: number,
|
|
9241
|
+
image: {
|
|
9242
|
+
readonly width: number;
|
|
9243
|
+
readonly height: number;
|
|
9244
|
+
readonly data: Float32Array;
|
|
9245
|
+
},
|
|
9246
|
+
options?: ProbeBakeOptions,
|
|
9247
|
+
): boolean {
|
|
9248
|
+
if (this.contextLost) return false;
|
|
9249
|
+
const probe = this.probeCapture;
|
|
9250
|
+
const array = this.probeArray;
|
|
9251
|
+
const grid = this.probes;
|
|
9252
|
+
const sweeps = this.probeSweeps;
|
|
9253
|
+
if (probe === null || array === null || grid === null || sweeps === null) {
|
|
9254
|
+
console.warn(
|
|
9255
|
+
'Renderer: setProbeLayerImage needs a reflection probe (`reflectionProbeSize`) and a grid ' +
|
|
9256
|
+
'declared with setProbeGrid; the image was ignored.',
|
|
9257
|
+
);
|
|
9258
|
+
return false;
|
|
9259
|
+
}
|
|
9260
|
+
if (!Number.isInteger(layer) || layer < 0 || layer >= grid.layers) {
|
|
9261
|
+
console.warn(
|
|
9262
|
+
`Renderer: setProbeLayerImage was given layer ${layer}, and the grid has ${grid.layers}.`,
|
|
9263
|
+
);
|
|
9264
|
+
return false;
|
|
9265
|
+
}
|
|
9266
|
+
if (!probe.upload(this.gl, equirectToCubeFaces(image, probe.size))) return false;
|
|
9267
|
+
this.probeAmbient = options?.irradiance ?? true;
|
|
9268
|
+
this.environmentPrefilter?.run(
|
|
9269
|
+
this.gl,
|
|
9270
|
+
probe,
|
|
9271
|
+
array,
|
|
9272
|
+
sweeps.writeLayer(layer),
|
|
9273
|
+
ENVIRONMENT_TEXTURE_UNIT,
|
|
9274
|
+
this.quality.environmentPrefilterSamples,
|
|
9275
|
+
this.quality.environmentPrefilter,
|
|
9276
|
+
);
|
|
9277
|
+
sweeps.baked(layer);
|
|
9278
|
+
return true;
|
|
9279
|
+
}
|
|
9280
|
+
|
|
9033
9281
|
/**
|
|
9034
9282
|
* Draw a volume of light: a beam from a lamp, a shaft through a window, the cone under a
|
|
9035
9283
|
* street light.
|
|
@@ -9420,6 +9668,15 @@ const NO_MODEL_PARAMS = new Float32Array(MODEL_PARAM_FLOATS);
|
|
|
9420
9668
|
* The lit vertex stage a program of this variant compiles: the standard programs' and the cloth's,
|
|
9421
9669
|
* which `modelProgram` pairs a model's fragment stage with.
|
|
9422
9670
|
*/
|
|
9671
|
+
/**
|
|
9672
|
+
* The vertex stage a model's program draws with: the variant's own, but for a lightmapped instanced
|
|
9673
|
+
* batch, whose tint lane is each instance's region of the page. See `lightmap.ts`.
|
|
9674
|
+
*/
|
|
9675
|
+
function modelVertexOf(variant: string, kind: SurfaceModelKind): string {
|
|
9676
|
+
const vertex = litVertexOf(variant);
|
|
9677
|
+
return kind === 'lightmap' && variant === 'instanced' ? lightmapRegionsBound(vertex) : vertex;
|
|
9678
|
+
}
|
|
9679
|
+
|
|
9423
9680
|
function litVertexOf(variant: string): string {
|
|
9424
9681
|
if (variant.startsWith('cloth')) {
|
|
9425
9682
|
const eight = variant[5] === '8';
|