@driftengine/core 4.4.1 → 4.4.2

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.
Files changed (38) hide show
  1. package/CHANGELOG.json +26 -0
  2. package/README.md +1 -1
  3. package/dist/render/backend/webgl2/renderer.d.ts +3 -0
  4. package/dist/render/backend/webgl2/renderer.js +13 -0
  5. package/dist/render/backend/webgpu/postPass.d.ts +19 -3
  6. package/dist/render/backend/webgpu/postPass.js +17 -4
  7. package/dist/render/backend/webgpu/renderer.d.ts +10 -0
  8. package/dist/render/backend/webgpu/renderer.js +67 -4
  9. package/dist/render/flameLight.js +15 -2
  10. package/dist/render/pointShadowBudget.js +51 -41
  11. package/dist/render/recon/disocclusion.d.ts +36 -3
  12. package/dist/render/recon/disocclusion.js +56 -4
  13. package/dist/render/recon/resolve.js +95 -12
  14. package/dist/render/sceneTarget.d.ts +2 -0
  15. package/dist/render/sceneTarget.js +1 -1
  16. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +31 -6
  17. package/dist/render/shaders/generated/temporalResolve.wgsl.js +31 -6
  18. package/dist/render/shaders/recon/resolve.wgsl.d.ts +1 -1
  19. package/dist/render/shaders/recon/resolve.wgsl.js +112 -8
  20. package/dist/render/shaders/temporalResolve.js +133 -5
  21. package/dist/render/temporalAa.d.ts +145 -0
  22. package/dist/render/temporalAa.js +190 -0
  23. package/dist/render/temporalPass.d.ts +16 -14
  24. package/dist/render/temporalPass.js +59 -14
  25. package/package.json +6 -6
  26. package/src/render/backend/webgl2/renderer.ts +21 -1
  27. package/src/render/backend/webgpu/postPass.ts +34 -4
  28. package/src/render/backend/webgpu/renderer.ts +70 -4
  29. package/src/render/flameLight.ts +15 -2
  30. package/src/render/pointShadowBudget.ts +49 -39
  31. package/src/render/recon/disocclusion.ts +54 -3
  32. package/src/render/recon/resolve.ts +137 -10
  33. package/src/render/sceneTarget.ts +8 -1
  34. package/src/render/shaders/generated/temporalResolve.wgsl.ts +31 -6
  35. package/src/render/shaders/recon/resolve.wgsl.ts +112 -8
  36. package/src/render/shaders/temporalResolve.ts +141 -5
  37. package/src/render/temporalAa.ts +227 -0
  38. package/src/render/temporalPass.ts +88 -12
@@ -15,6 +15,9 @@ import { TEMPORAL_RESOLVE_FRAG } from './shaders/temporalResolve.ts';
15
15
  * grade all read the scene texture, and reading the unresolved one would grade a stable picture
16
16
  * from an unstable source and put the crawl back on screen through the bloom.
17
17
  */
18
+ /** The resolve's three outputs: the picture and the two halves of the flicker record. */
19
+ const DRAW_ALL = [0x8ce0, 0x8ce1, 0x8ce2]; // COLOR_ATTACHMENT0, 1, 2
20
+
18
21
  export class TemporalPass {
19
22
  private readonly program: WebGLProgram;
20
23
  private readonly uniforms: Record<string, WebGLUniformLocation | null>;
@@ -22,6 +25,21 @@ export class TemporalPass {
22
25
 
23
26
  /** The pair, and which of them the next resolve writes into. */
24
27
  private textures: (WebGLTexture | null)[] = [null, null];
28
+ /**
29
+ * Each pixel's flicker record, a pair beside the history's and swapped with it: see the
30
+ * anti-flicker in `temporalAa.ts`. In the history's own format, which holds what the record does —
31
+ * a change and a sample are colours' luma, and eight bits hold them wherever eight bits hold the
32
+ * colour.
33
+ */
34
+ private records: (WebGLTexture | null)[] = [null, null];
35
+ /** The rest of each pixel's record — depth, pull and recent swing — beside the first. */
36
+ private motions: (WebGLTexture | null)[] = [null, null];
37
+ /**
38
+ * Whether the records can be half float, which the depth in them needs. Asked of the context
39
+ * rather than taken from the scene's format, since a record of an eight-bit scene still holds
40
+ * metres. Without it the anti-flicker is off and the resolve is the one before it existed.
41
+ */
42
+ private readonly recordFloat: boolean;
25
43
  private framebuffers: (WebGLFramebuffer | null)[] = [null, null];
26
44
  private write = 0;
27
45
 
@@ -40,6 +58,7 @@ export class TemporalPass {
40
58
  */
41
59
  private readonly floatColor: boolean,
42
60
  ) {
61
+ this.recordFloat = gl.getExtension('EXT_color_buffer_float') !== null;
43
62
  this.program = compileProgram(gl, FULLSCREEN_VERT, TEMPORAL_RESOLVE_FRAG, 'temporalResolve');
44
63
  this.uniforms = uniformLocations(gl, this.program, 'temporalPass');
45
64
  const vao = gl.createVertexArray();
@@ -55,19 +74,45 @@ export class TemporalPass {
55
74
 
56
75
  for (let i = 0; i < 2; i++) {
57
76
  if (this.textures[i] === null) this.textures[i] = gl.createTexture();
58
- gl.bindTexture(gl.TEXTURE_2D, this.textures[i]);
59
- if (this.floatColor) {
60
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);
61
- } else {
62
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
77
+ if (this.records[i] === null) this.records[i] = gl.createTexture();
78
+ if (this.motions[i] === null) this.motions[i] = gl.createTexture();
79
+ for (const texture of [this.textures[i], this.records[i], this.motions[i]]) {
80
+ gl.bindTexture(gl.TEXTURE_2D, texture);
81
+ if (texture === this.textures[i] ? this.floatColor : this.recordFloat) {
82
+ /* The depth record is two numbers a pixel: metres, and how far they swing. */
83
+ const pair = texture === this.motions[i];
84
+ gl.texImage2D(
85
+ gl.TEXTURE_2D,
86
+ 0,
87
+ pair ? gl.RG16F : gl.RGBA16F,
88
+ width,
89
+ height,
90
+ 0,
91
+ pair ? gl.RG : gl.RGBA,
92
+ gl.HALF_FLOAT,
93
+ null,
94
+ );
95
+ } else {
96
+ gl.texImage2D(
97
+ gl.TEXTURE_2D,
98
+ 0,
99
+ gl.RGBA,
100
+ width,
101
+ height,
102
+ 0,
103
+ gl.RGBA,
104
+ gl.UNSIGNED_BYTE,
105
+ null,
106
+ );
107
+ }
108
+ /* Linear, because the history is sampled between texels wherever the reprojection lands;
109
+ clamped, because a sample that wrapped would pull the far edge of the screen into the
110
+ corner — and the shader rejects an off-screen reprojection before it can anyway. */
111
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
112
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
113
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
114
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
63
115
  }
64
- /* Linear, because the history is sampled between texels wherever the reprojection lands;
65
- clamped, because a sample that wrapped would pull the far edge of the screen into the
66
- corner — and the shader rejects an off-screen reprojection before it can anyway. */
67
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
68
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
69
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
70
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
71
116
 
72
117
  if (this.framebuffers[i] === null) this.framebuffers[i] = gl.createFramebuffer();
73
118
  gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[i]);
@@ -78,6 +123,22 @@ export class TemporalPass {
78
123
  this.textures[i],
79
124
  0,
80
125
  );
126
+ gl.framebufferTexture2D(
127
+ gl.FRAMEBUFFER,
128
+ gl.COLOR_ATTACHMENT1,
129
+ gl.TEXTURE_2D,
130
+ this.records[i],
131
+ 0,
132
+ );
133
+ gl.framebufferTexture2D(
134
+ gl.FRAMEBUFFER,
135
+ gl.COLOR_ATTACHMENT2,
136
+ gl.TEXTURE_2D,
137
+ this.motions[i],
138
+ 0,
139
+ );
140
+ /* Per framebuffer, so set once here: the resolve writes the picture and the record. */
141
+ gl.drawBuffers(DRAW_ALL);
81
142
  }
82
143
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
83
144
  }
@@ -96,6 +157,8 @@ export class TemporalPass {
96
157
  width: number,
97
158
  height: number,
98
159
  blend: number,
160
+ periodStart: boolean,
161
+ depthToViewZ: Float32Array,
99
162
  ): WebGLTexture {
100
163
  const { gl } = this;
101
164
  this.ensureSize(width, height);
@@ -120,10 +183,19 @@ export class TemporalPass {
120
183
  gl.activeTexture(gl.TEXTURE2);
121
184
  gl.bindTexture(gl.TEXTURE_2D, depth);
122
185
  gl.uniform1i(this.uniforms['uDepth'] ?? null, 2);
186
+ gl.activeTexture(gl.TEXTURE3);
187
+ gl.bindTexture(gl.TEXTURE_2D, this.records[history]);
188
+ gl.uniform1i(this.uniforms['uFlicker'] ?? null, 3);
189
+ gl.activeTexture(gl.TEXTURE4);
190
+ gl.bindTexture(gl.TEXTURE_2D, this.motions[history]);
191
+ gl.uniform1i(this.uniforms['uFlickerMotion'] ?? null, 4);
192
+ gl.uniform4fv(this.uniforms['uDepthToViewZ'] ?? null, depthToViewZ);
193
+ gl.uniform1f(this.uniforms['uAntiFlicker'] ?? null, this.recordFloat ? 1 : 0);
123
194
 
124
195
  gl.uniformMatrix4fv(this.uniforms['uReprojection'] ?? null, false, reprojection);
125
196
  gl.uniform2f(this.uniforms['uTexel'] ?? null, 1 / width, 1 / height);
126
197
  gl.uniform1f(this.uniforms['uHistoryBlend'] ?? null, blend);
198
+ gl.uniform1f(this.uniforms['uPeriodStart'] ?? null, periodStart ? 1 : 0);
127
199
 
128
200
  gl.bindVertexArray(this.vao);
129
201
  gl.drawArrays(gl.TRIANGLES, 0, 3);
@@ -141,8 +213,12 @@ export class TemporalPass {
141
213
  const { gl } = this;
142
214
  for (let i = 0; i < 2; i++) {
143
215
  if (this.textures[i] !== null) gl.deleteTexture(this.textures[i]);
216
+ if (this.records[i] !== null) gl.deleteTexture(this.records[i]);
217
+ if (this.motions[i] !== null) gl.deleteTexture(this.motions[i]);
144
218
  if (this.framebuffers[i] !== null) gl.deleteFramebuffer(this.framebuffers[i]);
145
219
  this.textures[i] = null;
220
+ this.records[i] = null;
221
+ this.motions[i] = null;
146
222
  this.framebuffers[i] = null;
147
223
  }
148
224
  gl.deleteProgram(this.program);