@driftengine/core 4.9.0 → 4.11.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 +133 -11
- package/README.md +43 -38
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -4
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/backend/api.d.ts +10 -3
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +189 -4
- package/dist/render/backend/webgl2/renderer.js +614 -66
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +24 -4
- package/dist/render/backend/webgpu/buffers.js +116 -59
- package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
- package/dist/render/backend/webgpu/clothKernels.js +76 -0
- package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
- package/dist/render/backend/webgpu/clothOps.js +78 -0
- package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
- package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
- package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
- package/dist/render/backend/webgpu/clothSetPack.js +144 -0
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/drawCommand.d.ts +20 -4
- package/dist/render/backend/webgpu/drawCommand.js +11 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
- package/dist/render/backend/webgpu/flatPass.js +137 -20
- package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
- package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/latePass.js +1 -0
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/motionPass.js +15 -6
- package/dist/render/backend/webgpu/pipelineCache.d.ts +28 -1
- package/dist/render/backend/webgpu/pipelineCache.js +46 -1
- package/dist/render/backend/webgpu/postPass.d.ts +1 -1
- package/dist/render/backend/webgpu/renderer.d.ts +200 -35
- package/dist/render/backend/webgpu/renderer.js +993 -168
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +242 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/backend/webgpu/vertexFormats.d.ts +22 -0
- package/dist/render/backend/webgpu/vertexFormats.js +97 -0
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/globalMediumPass.d.ts +2 -0
- package/dist/render/globalMediumPass.js +1 -0
- package/dist/render/indexWidth.d.ts +17 -0
- package/dist/render/indexWidth.js +23 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightMatrix.d.ts +11 -0
- package/dist/render/lightMatrix.js +14 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +14 -0
- package/dist/render/mesh.js +44 -14
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/renderQuality.d.ts +30 -0
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.d.ts +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/screenSpaceReflection.d.ts +2 -1
- package/dist/render/shader.d.ts +15 -0
- package/dist/render/shader.js +41 -0
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/flat/directionalShadow.js +84 -10
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +3 -0
- package/dist/render/shaders/flat/index.d.ts +21 -0
- package/dist/render/shaders/flat/index.js +42 -7
- package/dist/render/shaders/flat/layered.d.ts +19 -0
- package/dist/render/shaders/flat/layered.js +115 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +58 -21
- package/dist/render/shaders/flat/mapReads.d.ts +10 -0
- package/dist/render/shaders/flat/mapReads.js +38 -0
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/movingSun.d.ts +21 -0
- package/dist/render/shaders/flat/movingSun.js +46 -0
- package/dist/render/shaders/flat/normalMap.d.ts +6 -2
- package/dist/render/shaders/flat/normalMap.js +14 -3
- package/dist/render/shaders/flat/overlay.d.ts +3 -2
- package/dist/render/shaders/flat/overlay.js +42 -20
- package/dist/render/shaders/flat/pointShadow.js +2 -2
- package/dist/render/shaders/flat/preamble.js +59 -27
- package/dist/render/shaders/flat/worldUv.d.ts +22 -0
- package/dist/render/shaders/flat/worldUv.js +113 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3616 -3042
- package/dist/render/shaders/generated/flat.wgsl.js +3688 -3113
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
- package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
- package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
- package/dist/render/shaders/globalMedium.js +9 -1
- package/dist/render/shaders/lightVolume.js +9 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/tangentFrame.d.ts +1 -1
- package/dist/render/shaders/tangentFrame.js +16 -3
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/skinnedClothRun.d.ts +28 -0
- package/dist/render/skinnedClothRun.js +103 -35
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceLayers.d.ts +39 -0
- package/dist/render/surfaceLayers.js +26 -0
- package/dist/render/surfaceOverlay.d.ts +16 -3
- package/dist/render/surfaceOverlay.js +11 -6
- package/dist/render/surfaceProjection.d.ts +34 -0
- package/dist/render/surfaceProjection.js +30 -0
- package/dist/render/surfaceTexture.d.ts +68 -7
- package/dist/render/surfaceTexture.js +56 -17
- package/dist/render/vertexPacking.d.ts +48 -0
- package/dist/render/vertexPacking.js +68 -0
- package/package.json +6 -6
- package/src/index.ts +12 -4
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/backend/api.ts +13 -3
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +723 -79
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +195 -70
- package/src/render/backend/webgpu/clothKernels.ts +86 -0
- package/src/render/backend/webgpu/clothOps.ts +86 -0
- package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
- package/src/render/backend/webgpu/clothSetPack.ts +197 -0
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/drawCommand.ts +25 -4
- package/src/render/backend/webgpu/flatPass.ts +212 -41
- package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/latePass.ts +1 -0
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/motionPass.ts +18 -7
- package/src/render/backend/webgpu/pipelineCache.ts +53 -7
- package/src/render/backend/webgpu/renderer.ts +1201 -202
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +364 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/backend/webgpu/vertexFormats.ts +113 -0
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/glCompressed.ts +83 -0
- package/src/render/globalMediumPass.ts +7 -0
- package/src/render/indexWidth.ts +27 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightMatrix.ts +15 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +72 -14
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/renderQuality.ts +38 -0
- package/src/render/rendererHarness.ts +15 -0
- package/src/render/screenSpaceReflection.ts +2 -1
- package/src/render/shader.ts +59 -0
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/flat/directionalShadow.ts +84 -10
- package/src/render/shaders/flat/glassTint.ts +7 -1
- package/src/render/shaders/flat/index.ts +63 -7
- package/src/render/shaders/flat/layered.ts +115 -0
- package/src/render/shaders/flat/main.ts +58 -21
- package/src/render/shaders/flat/mapReads.ts +38 -0
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/movingSun.ts +46 -0
- package/src/render/shaders/flat/normalMap.ts +14 -3
- package/src/render/shaders/flat/overlay.ts +42 -20
- package/src/render/shaders/flat/pointShadow.ts +2 -2
- package/src/render/shaders/flat/preamble.ts +59 -27
- package/src/render/shaders/flat/worldUv.ts +113 -0
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/flat.wgsl.ts +3688 -3113
- package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
- package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
- package/src/render/shaders/globalMedium.ts +9 -1
- package/src/render/shaders/lightVolume.ts +9 -1
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/tangentFrame.ts +16 -3
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/skinnedClothRun.ts +138 -38
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceLayers.ts +57 -0
- package/src/render/surfaceOverlay.ts +24 -7
- package/src/render/surfaceProjection.ts +57 -0
- package/src/render/surfaceTexture.ts +124 -27
- package/src/render/vertexPacking.ts +109 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* array samples exactly as a 2D texture does. A mesh names its layer per vertex (`MeshData.layers`),
|
|
9
9
|
* so a merged block wearing forty facades is one draw.
|
|
10
10
|
*/
|
|
11
|
+
import type { SurfaceLayers } from './surfaceLayers.ts';
|
|
12
|
+
import type { SurfaceProjection } from './surfaceProjection.ts';
|
|
11
13
|
import type { SurfaceModel } from './surfaceModel.ts';
|
|
12
|
-
import type { CompressedTextureFormat, SurfaceSource } from './compressedSource.ts';
|
|
14
|
+
import type { CompressedTextureFormat, CompressedTextureSource, SurfaceSource } from './compressedSource.ts';
|
|
13
15
|
import type { SurfaceLayerEffect } from './surfaceEffects.ts';
|
|
14
16
|
import type { CutoutMode } from './cutoutDither.ts';
|
|
15
17
|
import type { LightmapTexels } from './lightmap.ts';
|
|
@@ -107,7 +109,7 @@ export interface SurfaceMaterial<Texture = SurfaceTexture> {
|
|
|
107
109
|
* which is every light's default too, so a scene that names no channel is lit as it always was.
|
|
108
110
|
*
|
|
109
111
|
* A point or spot light shades this surface only where its `PointLightSet.lightChannels` and this
|
|
110
|
-
* share a bit —
|
|
112
|
+
* share a bit — lighting channels. A character's own key and rim lights on channel 2,
|
|
111
113
|
* and the character's materials on 3, light the character and leave the floor around it as the
|
|
112
114
|
* stage's lights alone have it. **What it does not reach**: the sun, the sky and the probes, area
|
|
113
115
|
* lights, DriftLight's volume and the GPU-driven pipeline light every surface whatever its mask.
|
|
@@ -141,6 +143,22 @@ export interface SurfaceMaterial<Texture = SurfaceTexture> {
|
|
|
141
143
|
* which is the opposite of what the caller asked for.
|
|
142
144
|
*/
|
|
143
145
|
occlusionStrength?: number;
|
|
146
|
+
/**
|
|
147
|
+
* How much of the environment this material's draws mirror, 0 to 1: the number
|
|
148
|
+
* `setSurfaceReflectivity` sets for every draw, stated by the material for its own. Absent, its
|
|
149
|
+
* draws wear the setter's, as every material's did before this existed.
|
|
150
|
+
*
|
|
151
|
+
* **Here so a static list can carry it.** A list keeps each entry's material and none of the
|
|
152
|
+
* renderer's state between draws (`createStaticDraws`), so a stage whose batches each mirror their
|
|
153
|
+
* own share of a baked reflection says so in the material it records. What it gives up is nothing a
|
|
154
|
+
* setter could do: one called after this material is set is ignored for the material's draws.
|
|
155
|
+
*/
|
|
156
|
+
reflectivity?: number;
|
|
157
|
+
/**
|
|
158
|
+
* How bright the environment this material's draws reflect is: `setEnvironmentGain`'s number,
|
|
159
|
+
* stated by the material for its own, and absent the setter's. Held non-negative.
|
|
160
|
+
*/
|
|
161
|
+
environmentGain?: number;
|
|
144
162
|
/**
|
|
145
163
|
* Scales the emissive map, per channel. Default 1.
|
|
146
164
|
*
|
|
@@ -164,14 +182,14 @@ export interface SurfaceMaterial<Texture = SurfaceTexture> {
|
|
|
164
182
|
modelMap?: Texture | null;
|
|
165
183
|
/**
|
|
166
184
|
* Whether a lamp's and the sun's highlight on this surface is GGX's own, `π · D · Vis · F · N·L`,
|
|
167
|
-
* as
|
|
168
|
-
* peak of one. **False by default**, every surface as it was.
|
|
185
|
+
* as physically based renderers and this engine's skin and eye shade it, rather than the engine's
|
|
186
|
+
* lobe scaled to a peak of one. **False by default**, every surface as it was.
|
|
169
187
|
*
|
|
170
188
|
* The peak-normalised lobe is a look control: the specular attribute says how strong a highlight
|
|
171
189
|
* is and roughness how wide, apart. Physical, they are entangled as they are in a real surface —
|
|
172
190
|
* the peak is `1 / (4 α²)` of the light head-on, so a polished surface's highlight is many times
|
|
173
191
|
* the look's and a rough one's lower and broader — and the specular attribute is read as the
|
|
174
|
-
* reflectance at normal incidence, F0:
|
|
192
|
+
* reflectance at normal incidence, F0: `0.08 × Specular`, 0.04 at its default. Fresnel
|
|
175
193
|
* then brightens every surface toward grazing, not only a metal. A rectangle's highlight is the
|
|
176
194
|
* lobe integrated over it with the attribute as F0 already, so it is unchanged either way.
|
|
177
195
|
*
|
|
@@ -180,6 +198,34 @@ export interface SurfaceMaterial<Texture = SurfaceTexture> {
|
|
|
180
198
|
* and an 8-bit frame clips the brighter peak without `hdrScene`.
|
|
181
199
|
*/
|
|
182
200
|
physicalSpecular?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Texture coordinates from where a point is in the world rather than from the mesh: `'planar'`
|
|
203
|
+
* across the horizontal axes for ground, `'triplanar'` on three planes for walls and rock, at so
|
|
204
|
+
* many repeats a metre. Absent, the mesh's, as every material's were. **A lit switch**, compiled in
|
|
205
|
+
* the first time a material asks, so a scene that never asks pays nothing. See
|
|
206
|
+
* `surfaceProjection.ts` for what it gives up.
|
|
207
|
+
*/
|
|
208
|
+
projection?: SurfaceProjection | null;
|
|
209
|
+
/**
|
|
210
|
+
* How much light from behind a thin surface lets through, 0 to 1: a banner lit from behind, a
|
|
211
|
+
* leaf against the sun, a lampshade. The light falling on the far side — the sun, lamps, area
|
|
212
|
+
* lights, DriftLight — reaches the eye through the surface, coloured by its own colour; a metal
|
|
213
|
+
* lets none through. 0, the default, is every material as it was. Two-sided or not: a one-sided
|
|
214
|
+
* surface seen from its front shows the light behind it as well.
|
|
215
|
+
*
|
|
216
|
+
* **What it gives up**: a thin surface, not a volume, so a thick one lets through as much as a
|
|
217
|
+
* sheet; the light behind is not blurred by the surface; and none of it on glass, which lets
|
|
218
|
+
* light through by its own rule (`TranslucentMeshOptions.glass`).
|
|
219
|
+
*/
|
|
220
|
+
diffuseTransmission?: number;
|
|
221
|
+
/**
|
|
222
|
+
* Up to five layers blended by a mask, each at its own repeat: `albedo`, `normal` and `orm` arrays
|
|
223
|
+
* whose layers are the material's, and a mask laying each over the ones before it. Absent, the
|
|
224
|
+
* material is one layer, as every material was. **A lit switch**, compiled in the first time a
|
|
225
|
+
* material asks. The mask is read where `modelMap` goes, so a material carries one or the other.
|
|
226
|
+
* See `surfaceLayers.ts` for what it gives up.
|
|
227
|
+
*/
|
|
228
|
+
layers?: SurfaceLayers<Texture> | null;
|
|
183
229
|
}
|
|
184
230
|
export interface SurfaceTextureOptions {
|
|
185
231
|
/**
|
|
@@ -275,7 +321,9 @@ export declare class SurfaceTexture {
|
|
|
275
321
|
/** The per-layer effects table, or null for a texture given none. See `surfaceEffects.ts`. */
|
|
276
322
|
private effectsTable;
|
|
277
323
|
/** The block format a compressed texture holds, or null for one uploaded from images. */
|
|
278
|
-
private
|
|
324
|
+
private blockFormat;
|
|
325
|
+
/** How the texture is sampled, kept so blocks swapped in by `update` are sampled the same way. */
|
|
326
|
+
private readonly sampling;
|
|
279
327
|
/** Level 0's size, which `flatLayer` copies; kept as `update` changes it. */
|
|
280
328
|
private width;
|
|
281
329
|
private height;
|
|
@@ -303,7 +351,20 @@ export declare class SurfaceTexture {
|
|
|
303
351
|
* Not a hot path: it re-uploads the whole image and regenerates the chain. A caller
|
|
304
352
|
* doing this every frame at any size wants to know that it costs what it costs.
|
|
305
353
|
*/
|
|
306
|
-
update(gl: WebGL2RenderingContext, source: TexImageSource): void;
|
|
354
|
+
update(gl: WebGL2RenderingContext, source: TexImageSource | CompressedTextureSource, compressed?: readonly CompressedTextureFormat[]): void;
|
|
355
|
+
/**
|
|
356
|
+
* Blocks in place of the image, behind the same handle: **a new GL object** rather than the
|
|
357
|
+
* image's levels respecified, because a chain shorter than the image's would leave the levels
|
|
358
|
+
* past it allocated, and immutable storage could not be respecified at all. Sampled as the image
|
|
359
|
+
* was, and refused before anything changes where the context does not take the format.
|
|
360
|
+
*/
|
|
361
|
+
private swapToBlocks;
|
|
362
|
+
/**
|
|
363
|
+
* Wrap, filters and anisotropy on the bound texture. Nearest where the caller said their pixels
|
|
364
|
+
* are the subject; see `filter`. The mip chain is still blended between levels, because that is
|
|
365
|
+
* minification and this option is about magnification.
|
|
366
|
+
*/
|
|
367
|
+
private applySampling;
|
|
307
368
|
/**
|
|
308
369
|
* Attach the only layer as the bound framebuffer's colour: a scene capture's target, drawn into
|
|
309
370
|
* by `captureScene`. Engine-internal, as `bind` is.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { layerSize, refuseArrayUpdate, sourceSize } from './textureSource.js';
|
|
2
|
-
import { compressedLayers, planBlocks, refuseBlockUpdate } from './compressedSource.js';
|
|
2
|
+
import { compressedLayers, isCompressedSource, planBlocks, refuseBlockUpdate, } from './compressedSource.js';
|
|
3
3
|
import { uploadCompressedArray } from './glCompressed.js';
|
|
4
4
|
import { SURFACE_EFFECT_TEXELS, packSurfaceEffects } from './surfaceEffects.js';
|
|
5
5
|
import { isLightmapTexels } from './lightmap.js';
|
|
@@ -25,6 +25,8 @@ export class SurfaceTexture {
|
|
|
25
25
|
effectsTable = null;
|
|
26
26
|
/** The block format a compressed texture holds, or null for one uploaded from images. */
|
|
27
27
|
blockFormat;
|
|
28
|
+
/** How the texture is sampled, kept so blocks swapped in by `update` are sampled the same way. */
|
|
29
|
+
sampling;
|
|
28
30
|
/** Level 0's size, which `flatLayer` copies; kept as `update` changes it. */
|
|
29
31
|
width = 0;
|
|
30
32
|
height = 0;
|
|
@@ -101,23 +103,14 @@ export class SurfaceTexture {
|
|
|
101
103
|
this.storage = this.srgb ? gl.SRGB8_ALPHA8 : gl.RGBA8;
|
|
102
104
|
uploadImages(gl, sources, this.srgb);
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, nearest ? gl.NEAREST : gl.LINEAR);
|
|
111
|
-
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, this.mipmapped
|
|
112
|
-
? nearest
|
|
113
|
-
? gl.NEAREST_MIPMAP_LINEAR
|
|
114
|
-
: gl.LINEAR_MIPMAP_LINEAR
|
|
115
|
-
: nearest
|
|
116
|
-
? gl.NEAREST
|
|
117
|
-
: gl.LINEAR);
|
|
106
|
+
this.sampling = {
|
|
107
|
+
wrap,
|
|
108
|
+
nearest: options.filter === 'nearest',
|
|
109
|
+
anisotropy: options.anisotropy ?? DEFAULT_ANISOTROPY,
|
|
110
|
+
};
|
|
111
|
+
this.applySampling(gl);
|
|
118
112
|
if (this.mipmapped && this.blockFormat === null)
|
|
119
113
|
gl.generateMipmap(gl.TEXTURE_2D_ARRAY);
|
|
120
|
-
applyAnisotropy(gl, options.anisotropy ?? DEFAULT_ANISOTROPY);
|
|
121
114
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
122
115
|
/* Half floats, nearest, clamped: a table read by texelFetch, whose every whole number is under
|
|
123
116
|
what a half holds exactly. */
|
|
@@ -155,10 +148,14 @@ export class SurfaceTexture {
|
|
|
155
148
|
* Not a hot path: it re-uploads the whole image and regenerates the chain. A caller
|
|
156
149
|
* doing this every frame at any size wants to know that it costs what it costs.
|
|
157
150
|
*/
|
|
158
|
-
update(gl, source) {
|
|
151
|
+
update(gl, source, compressed = []) {
|
|
159
152
|
if (this.texture === null)
|
|
160
153
|
return;
|
|
161
154
|
refuseArrayUpdate(this.layers);
|
|
155
|
+
if (isCompressedSource(source)) {
|
|
156
|
+
this.swapToBlocks(gl, source, compressed);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
162
159
|
refuseBlockUpdate(this.blockFormat);
|
|
163
160
|
const { width, height } = sourceSize(source);
|
|
164
161
|
this.width = width;
|
|
@@ -171,6 +168,48 @@ export class SurfaceTexture {
|
|
|
171
168
|
gl.generateMipmap(gl.TEXTURE_2D_ARRAY);
|
|
172
169
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
173
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Blocks in place of the image, behind the same handle: **a new GL object** rather than the
|
|
173
|
+
* image's levels respecified, because a chain shorter than the image's would leave the levels
|
|
174
|
+
* past it allocated, and immutable storage could not be respecified at all. Sampled as the image
|
|
175
|
+
* was, and refused before anything changes where the context does not take the format.
|
|
176
|
+
*/
|
|
177
|
+
swapToBlocks(gl, source, compressed) {
|
|
178
|
+
const plan = planBlocks([source], this.srgb, compressed);
|
|
179
|
+
const texture = gl.createTexture();
|
|
180
|
+
if (texture === null)
|
|
181
|
+
throw new Error('SurfaceTexture: createTexture failed');
|
|
182
|
+
this.dropFlat(gl);
|
|
183
|
+
if (this.texture !== null)
|
|
184
|
+
gl.deleteTexture(this.texture);
|
|
185
|
+
this.texture = texture;
|
|
186
|
+
this.blockFormat = source.format;
|
|
187
|
+
this.width = source.width;
|
|
188
|
+
this.height = source.height;
|
|
189
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, texture);
|
|
190
|
+
uploadCompressedArray(gl, plan.name, [source], this.mipmapped ? plan.levels : 1);
|
|
191
|
+
this.applySampling(gl);
|
|
192
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Wrap, filters and anisotropy on the bound texture. Nearest where the caller said their pixels
|
|
196
|
+
* are the subject; see `filter`. The mip chain is still blended between levels, because that is
|
|
197
|
+
* minification and this option is about magnification.
|
|
198
|
+
*/
|
|
199
|
+
applySampling(gl) {
|
|
200
|
+
const { wrap, nearest, anisotropy } = this.sampling;
|
|
201
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, wrap);
|
|
202
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, wrap);
|
|
203
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, nearest ? gl.NEAREST : gl.LINEAR);
|
|
204
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, this.mipmapped
|
|
205
|
+
? nearest
|
|
206
|
+
? gl.NEAREST_MIPMAP_LINEAR
|
|
207
|
+
: gl.LINEAR_MIPMAP_LINEAR
|
|
208
|
+
: nearest
|
|
209
|
+
? gl.NEAREST
|
|
210
|
+
: gl.LINEAR);
|
|
211
|
+
applyAnisotropy(gl, anisotropy);
|
|
212
|
+
}
|
|
174
213
|
/**
|
|
175
214
|
* Attach the only layer as the bound framebuffer's colour: a scene capture's target, drawn into
|
|
176
215
|
* by `captureScene`. Engine-internal, as `bind` is.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { MeshData } from '@driftengine/drft';
|
|
2
|
+
/**
|
|
3
|
+
* How each of a mesh's vertex attributes travels to the device, decided once from its data and
|
|
4
|
+
* bound by each backend: as floats, as sixteen-bit fixed point, or as one value every vertex
|
|
5
|
+
* shares.
|
|
6
|
+
*
|
|
7
|
+
* **Only what reads back as it went, or near enough that no picture can tell.** One value every
|
|
8
|
+
* vertex shares is exact, and is a constant rather than a stream: a colour or an emissive naming
|
|
9
|
+
* no difference between vertices costs nothing a vertex, where both were always stored per vertex.
|
|
10
|
+
* A unit direction — a normal, a tangent and its handedness — in sixteen-bit signed fixed point is
|
|
11
|
+
* within 1/32767 a component, a few thousandths of a degree: measured against floats, 12 pixels of
|
|
12
|
+
* 921,600 moved in one published scene, by 2 of 255 on average, and none in the other eight.
|
|
13
|
+
* Colours and skin weights inside [0, 1] in sixteen-bit unsigned fixed point are within 1/65535. A
|
|
14
|
+
* textured vertex with a tangent frame, white and not glowing, goes from 64 bytes to 36 on WebGPU.
|
|
15
|
+
*
|
|
16
|
+
* **What it gives up.** Eight-bit normals would save four bytes more and are not taken: a normal in
|
|
17
|
+
* steps of 1/127 can band a highlight. **Texture coordinates stay floats**, in any range: a
|
|
18
|
+
* coordinate on a tile's far edge rounds past it in sixteen-bit fixed point, by 1/131,070, and a
|
|
19
|
+
* pixel there samples the neighbouring tile of an atlas — measured as 29 pixels moved by 62 of 255
|
|
20
|
+
* in the voxel scene, every one at a face's edge — and a half float, which steps by a 2048th near
|
|
21
|
+
* 1.0, is worse. A dynamic mesh's normals stay floats, because each rewrite would have to be packed
|
|
22
|
+
* on the CPU. What would make this wrong is a value outside its range, which the range check sends
|
|
23
|
+
* to floats rather than clamping, or a shader reading an attribute as something other than the
|
|
24
|
+
* value it carries.
|
|
25
|
+
*/
|
|
26
|
+
/** Floats; sixteen-bit fixed point, signed or not; or one value for every vertex. */
|
|
27
|
+
export type AttributePacking = 'float' | 'snorm16' | 'unorm16' | 'constant';
|
|
28
|
+
/** The attributes this decides for. Every other one travels as floats. */
|
|
29
|
+
export declare const PACKED_ATTRIBUTES: readonly ['normals', 'tangents', 'colors', 'emissive', 'weights', 'weights2'];
|
|
30
|
+
export type PackedAttribute = (typeof PACKED_ATTRIBUTES)[number];
|
|
31
|
+
export type VertexPacking = Readonly<Record<PackedAttribute, AttributePacking>>;
|
|
32
|
+
/** The choice for this mesh. `dynamic` is a mesh whose positions and normals are rewritten. */
|
|
33
|
+
export declare function vertexPackingOf(data: MeshData, dynamic: boolean): VertexPacking;
|
|
34
|
+
/**
|
|
35
|
+
* What 1 is in each fixed point, the values WebGPU's `snorm16` and `unorm16` and WebGL2's
|
|
36
|
+
* normalised `SHORT` and `UNSIGNED_SHORT` divide by. A value is stored rounded to nearest, so 1, 0
|
|
37
|
+
* and -1 come back exactly.
|
|
38
|
+
*/
|
|
39
|
+
export declare const SNORM16_ONE = 32767;
|
|
40
|
+
export declare const UNORM16_ONE = 65535;
|
|
41
|
+
/** One value in the fixed point whose 1 is `one`, rounded to nearest: the only place it is. */
|
|
42
|
+
export declare function toFixed16(value: number, one: number): number;
|
|
43
|
+
/** An attribute's values in its fixed point, tightly, for a backend reading separate arrays. */
|
|
44
|
+
export declare function fixedArray(values: Float32Array, packing: 'snorm16' | 'unorm16'): Int16Array | Uint16Array;
|
|
45
|
+
/** How `name` travels under this packing: floats for an attribute it does not decide for. */
|
|
46
|
+
export declare function packingFor(packing: VertexPacking, name: string): AttributePacking;
|
|
47
|
+
/** The value every vertex shares, for an attribute packed as `'constant'`. */
|
|
48
|
+
export declare function sharedValue(values: Float32Array, width: number): number[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** The attributes this decides for. Every other one travels as floats. */
|
|
2
|
+
export const PACKED_ATTRIBUTES = [
|
|
3
|
+
'normals',
|
|
4
|
+
'tangents',
|
|
5
|
+
'colors',
|
|
6
|
+
'emissive',
|
|
7
|
+
'weights',
|
|
8
|
+
'weights2',
|
|
9
|
+
];
|
|
10
|
+
/** The choice for this mesh. `dynamic` is a mesh whose positions and normals are rewritten. */
|
|
11
|
+
export function vertexPackingOf(data, dynamic) {
|
|
12
|
+
return {
|
|
13
|
+
normals: dynamic ? 'float' : fixedOrFloat(data.normals, -1),
|
|
14
|
+
tangents: fixedOrFloat(data.tangents, -1),
|
|
15
|
+
colors: shared(data.colors, 3) ? 'constant' : fixedOrFloat(data.colors, 0),
|
|
16
|
+
emissive: shared(data.emissive, 1) ? 'constant' : 'float',
|
|
17
|
+
weights: fixedOrFloat(data.weights, 0),
|
|
18
|
+
weights2: fixedOrFloat(data.weights2, 0),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* What 1 is in each fixed point, the values WebGPU's `snorm16` and `unorm16` and WebGL2's
|
|
23
|
+
* normalised `SHORT` and `UNSIGNED_SHORT` divide by. A value is stored rounded to nearest, so 1, 0
|
|
24
|
+
* and -1 come back exactly.
|
|
25
|
+
*/
|
|
26
|
+
export const SNORM16_ONE = 32767;
|
|
27
|
+
export const UNORM16_ONE = 65535;
|
|
28
|
+
/** One value in the fixed point whose 1 is `one`, rounded to nearest: the only place it is. */
|
|
29
|
+
export function toFixed16(value, one) {
|
|
30
|
+
return Math.round(value * one);
|
|
31
|
+
}
|
|
32
|
+
/** An attribute's values in its fixed point, tightly, for a backend reading separate arrays. */
|
|
33
|
+
export function fixedArray(values, packing) {
|
|
34
|
+
const out = packing === 'snorm16' ? new Int16Array(values.length) : new Uint16Array(values.length);
|
|
35
|
+
const one = packing === 'snorm16' ? SNORM16_ONE : UNORM16_ONE;
|
|
36
|
+
for (let at = 0; at < values.length; at++)
|
|
37
|
+
out[at] = toFixed16(values[at], one);
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** How `name` travels under this packing: floats for an attribute it does not decide for. */
|
|
41
|
+
export function packingFor(packing, name) {
|
|
42
|
+
return packing[name] ?? 'float';
|
|
43
|
+
}
|
|
44
|
+
/** The value every vertex shares, for an attribute packed as `'constant'`. */
|
|
45
|
+
export function sharedValue(values, width) {
|
|
46
|
+
return Array.from(values.subarray(0, width));
|
|
47
|
+
}
|
|
48
|
+
/** Fixed point where every value lies in [low, 1]; floats otherwise, and for a NaN. */
|
|
49
|
+
function fixedOrFloat(values, low) {
|
|
50
|
+
if (values === undefined)
|
|
51
|
+
return 'float';
|
|
52
|
+
for (let at = 0; at < values.length; at++) {
|
|
53
|
+
const value = values[at];
|
|
54
|
+
if (!(value >= low && value <= 1))
|
|
55
|
+
return 'float';
|
|
56
|
+
}
|
|
57
|
+
return low < 0 ? 'snorm16' : 'unorm16';
|
|
58
|
+
}
|
|
59
|
+
/** Whether every vertex holds the first vertex's value. Not for a mesh of none. */
|
|
60
|
+
function shared(values, width) {
|
|
61
|
+
if (values.length < width)
|
|
62
|
+
return false;
|
|
63
|
+
for (let at = width; at < values.length; at++) {
|
|
64
|
+
if (values[at] !== values[at % width])
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftengine/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "The runtime of DriftEngine, a WebGPU game engine with a WebGL2 fallback: renderer, loop, input, cameras, scene graph and physics",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@driftengine/drft": "4.
|
|
33
|
-
"@driftengine/physics": "4.
|
|
32
|
+
"@driftengine/drft": "4.11.0",
|
|
33
|
+
"@driftengine/physics": "4.11.0",
|
|
34
34
|
"gl-matrix": "^3.4.3"
|
|
35
35
|
},
|
|
36
36
|
"author": "Drift Technologies",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"prepack": "node ../../scripts/build.mjs @driftengine/core"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@driftengine/nav": "4.
|
|
71
|
-
"@driftengine/network": "4.
|
|
72
|
-
"@driftengine/texture": "4.
|
|
70
|
+
"@driftengine/nav": "4.11.0",
|
|
71
|
+
"@driftengine/network": "4.11.0",
|
|
72
|
+
"@driftengine/texture": "4.11.0"
|
|
73
73
|
}
|
|
74
74
|
}
|
package/src/index.ts
CHANGED
|
@@ -539,8 +539,8 @@ export type { LightmapPage, LightmapRegion } from './render/lightmap.ts';
|
|
|
539
539
|
* A skinned cloth solved where the renderer can: compute on WebGPU, the CPU under WebGL2. A function
|
|
540
540
|
* rather than a renderer method so only a game that imports it carries the solver.
|
|
541
541
|
*/
|
|
542
|
-
export { createSkinnedCloth } from './render/skinnedClothRun.ts';
|
|
543
|
-
export type { SkinnedClothSolver } from './render/skinnedClothRun.ts';
|
|
542
|
+
export { createSkinnedCloth, createSkinnedClothSet } from './render/skinnedClothRun.ts';
|
|
543
|
+
export type { SkinnedClothSet, SkinnedClothSolver } from './render/skinnedClothRun.ts';
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
546
|
* What a frame asked of a backend, against the ceilings that backend imposes.
|
|
@@ -568,6 +568,10 @@ export type {
|
|
|
568
568
|
ShadowCasterSink,
|
|
569
569
|
ShadowCasters,
|
|
570
570
|
} from './render/shadowCasters.ts';
|
|
571
|
+
/* What `createStaticDraws` hands back, so a consumer can hold one in a field it declares. */
|
|
572
|
+
export type { StaticDrawsHandle } from './render/staticDraws.ts';
|
|
573
|
+
/* A bone animation's clip as a caller hands it over, and the handle `createBoneAnimation` returns. */
|
|
574
|
+
export type { BoneAnimationClip, BoneAnimationHandle } from './render/boneAnimation.ts';
|
|
571
575
|
export type { Atmosphere, UnderwaterAtmosphere } from './render/atmosphere.ts';
|
|
572
576
|
/*
|
|
573
577
|
* Reading an image's texels back exactly, which no canvas and no `VideoFrame` will do.
|
|
@@ -648,6 +652,7 @@ export type {
|
|
|
648
652
|
DirectionalShadowDepthLayers,
|
|
649
653
|
GlassShadows,
|
|
650
654
|
OutputTransform,
|
|
655
|
+
PipelineCompile,
|
|
651
656
|
RenderQuality,
|
|
652
657
|
RenderQualityOptions,
|
|
653
658
|
ShadowFilterTaps,
|
|
@@ -659,13 +664,16 @@ export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.ts'
|
|
|
659
664
|
export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.ts';
|
|
660
665
|
export { SurfaceTexture } from './render/surfaceTexture.ts';
|
|
661
666
|
export type { SurfaceMaterial, SurfaceTextureOptions } from './render/surfaceTexture.ts';
|
|
667
|
+
export type { SurfaceProjection } from './render/surfaceProjection.ts';
|
|
662
668
|
/*
|
|
663
|
-
* BC
|
|
664
|
-
* ask before handing one over — whether this device takes its format
|
|
669
|
+
* Compressed textures — BC, ETC2 and EAC, ASTC: the source `createSurfaceTexture` takes as blocks,
|
|
670
|
+
* the one question to ask before handing one over — whether this device takes its format
|
|
671
|
+
* (`renderer.compressedFormats`) — and the bytes a level of it holds, for a reader checking a file.
|
|
665
672
|
*/
|
|
666
673
|
export {
|
|
667
674
|
compressedFormatName,
|
|
668
675
|
isCompressedSource,
|
|
676
|
+
levelBytes,
|
|
669
677
|
uploadsCompressed,
|
|
670
678
|
} from './render/compressedSource.ts';
|
|
671
679
|
export type {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* **Why a draw needs its own.** The engine's diffuse ambient is one answer for a whole frame — the
|
|
6
6
|
* sky-and-ground gradient, or the probe grid's irradiance — so everything standing in one place is
|
|
7
|
-
* lit alike. A stage with a baked volume of indirect light (
|
|
7
|
+
* lit alike. A stage with a baked volume of indirect light (a volumetric lightmap) lights a
|
|
8
8
|
* character by sampling that volume where the character stands; a consumer that samples it each
|
|
9
9
|
* frame hands the result here, around that character's draws, and the character takes the light of
|
|
10
10
|
* the spot it is in rather than the frame's average.
|
package/src/render/areaLights.ts
CHANGED
|
@@ -94,14 +94,14 @@ export interface AreaLightSource {
|
|
|
94
94
|
* others. **Read only where the rectangle is shaded through the froxel table** — the ones past
|
|
95
95
|
* `maxAreaLights` with `clusteredLights` on; the fixed four light everything they face, as they
|
|
96
96
|
* always have. Absent, it is where the rectangle's irradiance on its axis falls to a thousandth
|
|
97
|
-
* of a scene unit, and never inside the rectangle itself.
|
|
97
|
+
* of a scene unit, and never inside the rectangle itself. An attenuation radius, in metres.
|
|
98
98
|
*/
|
|
99
99
|
range?: number;
|
|
100
100
|
/**
|
|
101
101
|
* Barn doors: a flap hinged at each of the rectangle's four edges, standing this many degrees from
|
|
102
102
|
* its normal. 90, or absent, folds them flat and they hide nothing; smaller closes them, so the
|
|
103
103
|
* light narrows to the opening they leave — a rectangle at 50° throws a beam rather than filling
|
|
104
|
-
* its hemisphere.
|
|
104
|
+
* its hemisphere. 88° is the usual default, nearly flat.
|
|
105
105
|
*
|
|
106
106
|
* What a fragment sees past the doors is the part of the rectangle no door's tip hides, one axis
|
|
107
107
|
* at a time, and the rectangle then shades as that smaller rectangle, its highlight included.
|
|
@@ -111,7 +111,7 @@ export interface AreaLightSource {
|
|
|
111
111
|
* rectangle's back face has none.
|
|
112
112
|
*/
|
|
113
113
|
barnDoorAngle?: number;
|
|
114
|
-
/** The barn doors' length in metres. Absent, 0.2:
|
|
114
|
+
/** The barn doors' length in metres. Absent, 0.2: the usual default of 20 cm. */
|
|
115
115
|
barnDoorLength?: number;
|
|
116
116
|
}
|
|
117
117
|
|
|
@@ -150,7 +150,7 @@ export function createAreaLightBuffer(capacity: number = MAX_AREA_LIGHTS): AreaL
|
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
/**
|
|
153
|
+
/** The usual default barn door length, in metres. See `AreaLightSource.barnDoorLength`. */
|
|
154
154
|
export const DEFAULT_BARN_DOOR_LENGTH = 0.2;
|
|
155
155
|
|
|
156
156
|
/**
|
|
@@ -8,7 +8,7 @@ import type { Renderer, TranslucentMeshOptions } from './webgl2/renderer.ts';
|
|
|
8
8
|
import type { InstancedOptions, MeshInstances } from '../instances.ts';
|
|
9
9
|
import type { SurfaceMaterial } from '../surfaceTexture.ts';
|
|
10
10
|
import type { SurfaceOverlay } from '../surfaceOverlay.ts';
|
|
11
|
-
import type { SurfaceSource } from '../compressedSource.ts';
|
|
11
|
+
import type { CompressedTextureSource, SurfaceSource } from '../compressedSource.ts';
|
|
12
12
|
import type { LightmapPage } from '../lightmap.ts';
|
|
13
13
|
import type { DeviceParticles } from '../particlePool.ts';
|
|
14
14
|
import type { ClothBindingData } from '../clothBindingData.ts';
|
|
@@ -415,12 +415,22 @@ export type RendererApi = Omit<
|
|
|
415
415
|
): boolean;
|
|
416
416
|
|
|
417
417
|
/**
|
|
418
|
-
* Replace a texture's pixels, keeping the
|
|
418
|
+
* Replace a texture's pixels, keeping the handle and its sampler state.
|
|
419
419
|
*
|
|
420
420
|
* The binding a draw loop already holds stays valid, so the swap is a swap rather than a
|
|
421
421
|
* rebuild. Not a hot path: it re-uploads the whole image and rebuilds the mip chain.
|
|
422
|
+
*
|
|
423
|
+
* **Blocks may replace an image**, at the format's own size and with the chain they carry: the
|
|
424
|
+
* same picture at a fraction of the memory, which is how a loader that first showed a decoded
|
|
425
|
+
* image hands the device the blocks it encoded afterwards. Read in the colour space the texture
|
|
426
|
+
* was made with, and refused as `createSurfaceTexture` refuses them where the device does not take
|
|
427
|
+
* that format (`compressedFormats`). **The way back is refused**: a texture holding blocks takes
|
|
428
|
+
* no image, since nothing could say what its chain should become.
|
|
422
429
|
*/
|
|
423
|
-
updateSurfaceTexture(
|
|
430
|
+
updateSurfaceTexture(
|
|
431
|
+
texture: SurfaceTextureHandle,
|
|
432
|
+
source: TexImageSource | CompressedTextureSource,
|
|
433
|
+
): void;
|
|
424
434
|
|
|
425
435
|
disposeSurfaceTexture(texture: SurfaceTextureHandle): void;
|
|
426
436
|
|
|
@@ -248,12 +248,17 @@ async function acquireWebGpu(
|
|
|
248
248
|
features.push('timestamp-query');
|
|
249
249
|
}
|
|
250
250
|
/*
|
|
251
|
-
*
|
|
252
|
-
* a device without
|
|
253
|
-
* texture at a byte a texel instead of four.
|
|
251
|
+
* The three block families, on the same terms: each asked for wherever the adapter offers it,
|
|
252
|
+
* because a device without one still draws — the loader decodes, or encodes ETC2, for it — and
|
|
253
|
+
* one with it samples a texture at a byte a texel or half of one instead of four. Desktops
|
|
254
|
+
* offer BC; phones ETC2 and ASTC. See `compressedUpload.ts`.
|
|
254
255
|
*/
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
for (const family of [
|
|
257
|
+
'texture-compression-bc',
|
|
258
|
+
'texture-compression-etc2',
|
|
259
|
+
'texture-compression-astc',
|
|
260
|
+
] as const) {
|
|
261
|
+
if (adapter.features?.has(family) === true) features.push(family);
|
|
257
262
|
}
|
|
258
263
|
const descriptor: GPUDeviceDescriptor = {};
|
|
259
264
|
if (Object.keys(required).length > 0) descriptor.requiredLimits = required;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bone animation's textures on this backend, and a batch's clocks: what
|
|
3
|
+
* `shaders/boneAnimation.ts` reads with `texelFetch`, made once and never filtered. The twin of
|
|
4
|
+
* `webgpu/boneAnimations.ts`, at the same formats for the same reason: a turn in half floats jitters
|
|
5
|
+
* a crowd's hands at the frame's rate.
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
CLOCK_TEXTURE_WIDTH,
|
|
9
|
+
type BoneAnimationHandle,
|
|
10
|
+
type BoneAnimationTexels,
|
|
11
|
+
} from '../../boneAnimation.ts';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A float texture read by index: one level, nearest, clamped. Bound on unit 0, chosen rather than
|
|
15
|
+
* inherited, for the reason `oitPass.ts` gives: `bindTexture` binds to whatever unit is active, and
|
|
16
|
+
* a frame leaves that wherever its last pass finished.
|
|
17
|
+
*/
|
|
18
|
+
function floatTexture(
|
|
19
|
+
gl: WebGL2RenderingContext,
|
|
20
|
+
internal: number,
|
|
21
|
+
width: number,
|
|
22
|
+
height: number,
|
|
23
|
+
): WebGLTexture {
|
|
24
|
+
const texture = gl.createTexture();
|
|
25
|
+
if (texture === null) throw new Error('boneAnimations: createTexture failed');
|
|
26
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
27
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
28
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, internal, width, height);
|
|
29
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
30
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
31
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
32
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
33
|
+
return texture;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A clip on the device, from `createBoneAnimation`. */
|
|
37
|
+
export class GlBoneAnimation implements BoneAnimationHandle {
|
|
38
|
+
readonly bones: number;
|
|
39
|
+
readonly frames: number;
|
|
40
|
+
readonly framesPerSecond: number;
|
|
41
|
+
readonly boneScale: number;
|
|
42
|
+
readonly places: WebGLTexture;
|
|
43
|
+
readonly turns: WebGLTexture;
|
|
44
|
+
disposed = false;
|
|
45
|
+
|
|
46
|
+
constructor(gl: WebGL2RenderingContext, texels: BoneAnimationTexels) {
|
|
47
|
+
this.bones = texels.bones;
|
|
48
|
+
this.frames = texels.frames;
|
|
49
|
+
this.framesPerSecond = texels.framesPerSecond;
|
|
50
|
+
this.boneScale = texels.boneScale;
|
|
51
|
+
const make = (data: Float32Array): WebGLTexture => {
|
|
52
|
+
const texture = floatTexture(gl, gl.RGBA32F, texels.bones, texels.frames);
|
|
53
|
+
gl.texSubImage2D(
|
|
54
|
+
gl.TEXTURE_2D,
|
|
55
|
+
0,
|
|
56
|
+
0,
|
|
57
|
+
0,
|
|
58
|
+
texels.bones,
|
|
59
|
+
texels.frames,
|
|
60
|
+
gl.RGBA,
|
|
61
|
+
gl.FLOAT,
|
|
62
|
+
data,
|
|
63
|
+
);
|
|
64
|
+
return texture;
|
|
65
|
+
};
|
|
66
|
+
this.places = make(texels.places);
|
|
67
|
+
this.turns = make(texels.turns);
|
|
68
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
dispose(gl: WebGL2RenderingContext): void {
|
|
72
|
+
this.disposed = true;
|
|
73
|
+
gl.deleteTexture(this.places);
|
|
74
|
+
gl.deleteTexture(this.turns);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A batch's clocks: two floats an instance, wrapped onto rows `CLOCK_TEXTURE_WIDTH` wide. */
|
|
79
|
+
export class GlInstanceClocks {
|
|
80
|
+
readonly texture: WebGLTexture;
|
|
81
|
+
readonly staging: Float32Array;
|
|
82
|
+
private readonly width: number;
|
|
83
|
+
|
|
84
|
+
constructor(gl: WebGL2RenderingContext, capacity: number) {
|
|
85
|
+
this.width = Math.max(1, Math.min(capacity, CLOCK_TEXTURE_WIDTH));
|
|
86
|
+
const rows = Math.max(1, Math.ceil(capacity / this.width));
|
|
87
|
+
this.staging = new Float32Array(this.width * rows * 2);
|
|
88
|
+
this.texture = floatTexture(gl, gl.RG32F, this.width, rows);
|
|
89
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The rows that hold the first `count` instances, from `staging`. */
|
|
93
|
+
upload(gl: WebGL2RenderingContext, count: number): void {
|
|
94
|
+
if (count <= 0) return;
|
|
95
|
+
const rows = Math.ceil(count / this.width);
|
|
96
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
97
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
98
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, rows, gl.RG, gl.FLOAT, this.staging);
|
|
99
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
dispose(gl: WebGL2RenderingContext): void {
|
|
103
|
+
gl.deleteTexture(this.texture);
|
|
104
|
+
}
|
|
105
|
+
}
|