@woosh/meep-engine 2.138.1 → 2.138.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.
- package/package.json +1 -1
- package/src/core/process/worker/WorkerProxy.d.ts +39 -1
- package/src/core/process/worker/WorkerProxy.d.ts.map +1 -1
- package/src/core/process/worker/WorkerProxy.js +93 -13
- package/src/engine/graphics/impostors/octahedral/prototypeBaker.js +3 -3
- package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.d.ts.map +1 -1
- package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +128 -223
- package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js +4 -2
- package/src/engine/graphics/sh3/path_tracer/PathTracedScene.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/PathTracedScene.js +4 -2
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +2 -2
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"description": "Pure JavaScript game engine. Fully featured and production ready.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Alexander Goldring",
|
|
8
|
-
"version": "2.138.
|
|
8
|
+
"version": "2.138.2",
|
|
9
9
|
"main": "build/meep.module.js",
|
|
10
10
|
"module": "build/meep.module.js",
|
|
11
11
|
"exports": {
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
export type WorkerStatus = string;
|
|
2
|
+
/**
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export const WorkerStatus: Readonly<{
|
|
6
|
+
STOPPED: "STOPPED";
|
|
7
|
+
RUNNING: "RUNNING";
|
|
8
|
+
FAILED: "FAILED";
|
|
9
|
+
}>;
|
|
1
10
|
export default WorkerProxy;
|
|
2
11
|
declare class WorkerProxy {
|
|
3
12
|
/**
|
|
@@ -12,7 +21,17 @@ declare class WorkerProxy {
|
|
|
12
21
|
* @private
|
|
13
22
|
*/
|
|
14
23
|
private __pending;
|
|
15
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @type {WorkerStatus}
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
private __status;
|
|
29
|
+
/**
|
|
30
|
+
* Error captured when the worker transitions to FAILED. Used to reject any subsequent requests.
|
|
31
|
+
* @type {Error|null}
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
private __failure;
|
|
16
35
|
/**
|
|
17
36
|
*
|
|
18
37
|
* @type {Worker|null}
|
|
@@ -60,9 +79,14 @@ declare class WorkerProxy {
|
|
|
60
79
|
*/
|
|
61
80
|
private __handleMessage;
|
|
62
81
|
isRunning(): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* @returns {WorkerStatus}
|
|
84
|
+
*/
|
|
85
|
+
getStatus(): WorkerStatus;
|
|
63
86
|
/**
|
|
64
87
|
* Stop the worker.
|
|
65
88
|
* If the worker is not running, this method does nothing.
|
|
89
|
+
* A worker in FAILED state cannot be stopped (it has already been terminated).
|
|
66
90
|
*/
|
|
67
91
|
stop(): void;
|
|
68
92
|
/**
|
|
@@ -81,5 +105,19 @@ declare class WorkerProxy {
|
|
|
81
105
|
*
|
|
82
106
|
*/
|
|
83
107
|
start(): void;
|
|
108
|
+
/**
|
|
109
|
+
* Worker-level error handler. Fires when the worker script itself fails
|
|
110
|
+
* (e.g. importScripts 404) or when an uncaught error escapes a handler.
|
|
111
|
+
* Treats the worker as permanently failed: rejects all pending and future requests.
|
|
112
|
+
*
|
|
113
|
+
* @param {ErrorEvent} errorEvent
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
private __handleError;
|
|
117
|
+
/**
|
|
118
|
+
* @param {Error} err
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
private __failAllPending;
|
|
84
122
|
}
|
|
85
123
|
//# sourceMappingURL=WorkerProxy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerProxy.d.ts","sourceRoot":"","sources":["../../../../../src/core/process/worker/WorkerProxy.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"WorkerProxy.d.ts","sourceRoot":"","sources":["../../../../../src/core/process/worker/WorkerProxy.js"],"names":[],"mappings":"2BAIU,MAAM;AADhB;;GAEG;AACH;;;;GAIG;;AAqCH;IA4CI;;;;OAIG;IACH,iBAHW,MAAM,gBAQhB;IApDD;;;;OAIG;IACH,kBAAe;IAEf;;;OAGG;IACH,iBAAgC;IAEhC;;;;OAIG;IACH,kBAAiB;IAEjB;;;;OAIG;IACH,iBAAgB;IAEhB;;;;OAIG;IACH,qBAAiB;IAEjB;;;;;OAKG;IACH,eAAiB;IAQb,YAAc;IACd,aAAsB;IAK1B;;;;;;OAMG;IACH,wBAJW,MAAM,2BAsDhB;IAED;;;;OAIG;IACH,qBAgBC;IAED;;;OAGG;IACH,sBAQC;IAED;;;;OAIG;IACH,wBAqCC;IAED,qBAEC;IAED;;OAEG;IACH,aAFa,YAAY,CAIxB;IAED;;;;OAIG;IACH,aAMC;IAED;;;;;OAKG;IACH,kBAJW,MAAM,eACN,MAAM,GACJ,OAAO,CAkCnB;IAED,4BAmBC;IAED;;;;;;OAMG;IACH,cAqBC;IAED;;;;;;;OAOG;IACH,sBAmBC;IAED;;;OAGG;IACH,yBAaC;CACJ"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
2
|
import { array_remove_first } from "../../collection/array/array_remove_first.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @enum {string}
|
|
6
|
+
*/
|
|
7
|
+
export const WorkerStatus = Object.freeze({
|
|
8
|
+
STOPPED: 'STOPPED',
|
|
9
|
+
RUNNING: 'RUNNING',
|
|
10
|
+
FAILED: 'FAILED',
|
|
11
|
+
});
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
*
|
|
6
15
|
* @param {Worker} worker
|
|
@@ -45,7 +54,18 @@ class WorkerProxy {
|
|
|
45
54
|
*/
|
|
46
55
|
__pending = {};
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
/**
|
|
58
|
+
* @type {WorkerStatus}
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
__status = WorkerStatus.STOPPED;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Error captured when the worker transitions to FAILED. Used to reject any subsequent requests.
|
|
65
|
+
* @type {Error|null}
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
__failure = null;
|
|
49
69
|
|
|
50
70
|
/**
|
|
51
71
|
*
|
|
@@ -91,6 +111,10 @@ class WorkerProxy {
|
|
|
91
111
|
$submitRequest(name, args) {
|
|
92
112
|
assert.isString(name, "name");
|
|
93
113
|
|
|
114
|
+
if (this.__status === WorkerStatus.FAILED) {
|
|
115
|
+
return Promise.reject(this.__failure);
|
|
116
|
+
}
|
|
117
|
+
|
|
94
118
|
const pending = this.__pending[name];
|
|
95
119
|
|
|
96
120
|
const argumentCount = args.length;
|
|
@@ -218,20 +242,27 @@ class WorkerProxy {
|
|
|
218
242
|
}
|
|
219
243
|
|
|
220
244
|
isRunning() {
|
|
221
|
-
return this.
|
|
245
|
+
return this.__status === WorkerStatus.RUNNING;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @returns {WorkerStatus}
|
|
250
|
+
*/
|
|
251
|
+
getStatus() {
|
|
252
|
+
return this.__status;
|
|
222
253
|
}
|
|
223
254
|
|
|
224
255
|
/**
|
|
225
256
|
* Stop the worker.
|
|
226
257
|
* If the worker is not running, this method does nothing.
|
|
258
|
+
* A worker in FAILED state cannot be stopped (it has already been terminated).
|
|
227
259
|
*/
|
|
228
260
|
stop() {
|
|
229
|
-
if (
|
|
230
|
-
//not running
|
|
261
|
+
if (this.__status !== WorkerStatus.RUNNING) {
|
|
231
262
|
return;
|
|
232
263
|
}
|
|
233
264
|
this.__worker.terminate();
|
|
234
|
-
this.
|
|
265
|
+
this.__status = WorkerStatus.STOPPED;
|
|
235
266
|
}
|
|
236
267
|
|
|
237
268
|
/**
|
|
@@ -258,7 +289,7 @@ class WorkerProxy {
|
|
|
258
289
|
if (request.id === id) {
|
|
259
290
|
|
|
260
291
|
|
|
261
|
-
if (
|
|
292
|
+
if (this.__status !== WorkerStatus.RUNNING) {
|
|
262
293
|
// not running, simply cut from the queue
|
|
263
294
|
|
|
264
295
|
requestQueue.splice(i, 1);
|
|
@@ -303,26 +334,75 @@ class WorkerProxy {
|
|
|
303
334
|
*
|
|
304
335
|
*/
|
|
305
336
|
start() {
|
|
306
|
-
if (this.
|
|
337
|
+
if (this.__status === WorkerStatus.RUNNING) {
|
|
307
338
|
//already running
|
|
308
339
|
return;
|
|
309
340
|
}
|
|
310
341
|
|
|
342
|
+
if (this.__status === WorkerStatus.FAILED) {
|
|
343
|
+
// FAILED is terminal — refuse to restart. A re-spawn on the same URL would just hit the same load error.
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
311
347
|
this.__worker = new Worker(this.url,{
|
|
312
348
|
name: this.__name
|
|
313
349
|
});
|
|
314
350
|
|
|
315
351
|
this.__worker.onmessage = this.__handleMessage;
|
|
352
|
+
this.__worker.onerror = this.__handleError;
|
|
316
353
|
|
|
317
|
-
|
|
318
|
-
this.__worker.onerror = (errorEvent) => {
|
|
319
|
-
console.error('Worker error:', errorEvent);
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
this.__isRunning = true;
|
|
354
|
+
this.__status = WorkerStatus.RUNNING;
|
|
323
355
|
|
|
324
356
|
this.sendPendingRequests();
|
|
325
357
|
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Worker-level error handler. Fires when the worker script itself fails
|
|
361
|
+
* (e.g. importScripts 404) or when an uncaught error escapes a handler.
|
|
362
|
+
* Treats the worker as permanently failed: rejects all pending and future requests.
|
|
363
|
+
*
|
|
364
|
+
* @param {ErrorEvent} errorEvent
|
|
365
|
+
* @private
|
|
366
|
+
*/
|
|
367
|
+
__handleError = (errorEvent) => {
|
|
368
|
+
const message = errorEvent.message || 'unknown error';
|
|
369
|
+
const filename = errorEvent.filename || this.url;
|
|
370
|
+
const lineno = errorEvent.lineno || 0;
|
|
371
|
+
|
|
372
|
+
const err = new Error(`Worker '${this.__name}' failed: ${message} (${filename}:${lineno})`);
|
|
373
|
+
|
|
374
|
+
// Set status BEFORE rejecting requests so any synchronous resubmission in a rejection
|
|
375
|
+
// handler immediately fails fast instead of being queued against a dead worker.
|
|
376
|
+
this.__status = WorkerStatus.FAILED;
|
|
377
|
+
this.__failure = err;
|
|
378
|
+
|
|
379
|
+
if (this.__worker !== null) {
|
|
380
|
+
this.__worker.terminate();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
this.__failAllPending(err);
|
|
384
|
+
|
|
385
|
+
console.error('Worker error:', errorEvent);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @param {Error} err
|
|
390
|
+
* @private
|
|
391
|
+
*/
|
|
392
|
+
__failAllPending(err) {
|
|
393
|
+
for (const methodName in this.__pending) {
|
|
394
|
+
if (!this.__pending.hasOwnProperty(methodName)) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const queue = this.__pending[methodName];
|
|
399
|
+
const requests = queue.splice(0, queue.length);
|
|
400
|
+
|
|
401
|
+
for (const request of requests) {
|
|
402
|
+
request.reject(err);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
326
406
|
}
|
|
327
407
|
|
|
328
408
|
export default WorkerProxy;
|
|
@@ -54,10 +54,10 @@ async function main(engine) {
|
|
|
54
54
|
const renderer = engine.graphics.renderer;
|
|
55
55
|
baker.renderer = renderer;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const path = 'data/models/LowPolyTownshipSet/Small_house/Small_house.gltf';
|
|
58
58
|
// const path = 'data/models/samples/textured_unit_cube.gltf';
|
|
59
59
|
// const path = 'data/models/samples/teapot.gltf';
|
|
60
|
-
const path = 'data/models/samples/just_a_girl/scene.gltf';
|
|
60
|
+
// const path = 'data/models/samples/just_a_girl/scene.gltf';
|
|
61
61
|
// const path = 'data/models/road_bike/road_bike.gltf'; //large CAD-type model
|
|
62
62
|
// const path = 'data/models/LowPolyTownshipSet/Barrel/model.gltf';
|
|
63
63
|
// const path = 'data/models/LowPolyTownshipSet/Town_Hall/model.gltf';
|
|
@@ -96,7 +96,7 @@ async function main(engine) {
|
|
|
96
96
|
offset: new Vector2(0, 0)
|
|
97
97
|
}))
|
|
98
98
|
.add(GUIElement.fromView(ctrl))
|
|
99
|
-
.build(ecd);
|
|
99
|
+
// .build(ecd);
|
|
100
100
|
|
|
101
101
|
// build out preview scene with impostor and the original
|
|
102
102
|
const t0 = Transform.fromJSON({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImpostorShaderV0.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ImpostorShaderV0.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js"],"names":[],"mappings":"AAgNA;IACI,cA2DC;IAHG,4CAAyB;CAIhC;kCArQM,OAAO"}
|
|
@@ -13,34 +13,87 @@ import {
|
|
|
13
13
|
* For ray projection using projection matrix : https://encreative.blogspot.com/2019/05/computing-ray-origin-and-direction-from.html
|
|
14
14
|
*/
|
|
15
15
|
const shader_vx = `
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
in vec2 uv;
|
|
18
18
|
in vec3 position;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
out vec2 vUv;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
|
|
22
|
+
// Octahedral atlas frame indices and triangle interpolation weights are
|
|
23
|
+
// chosen once per-impostor — the pivot-to-camera direction is constant
|
|
24
|
+
// for all vertices of the card, so every vertex computes the same answer.
|
|
25
|
+
// Forwarded as flat varyings so every fragment samples the same 3 atlas
|
|
26
|
+
// frames; otherwise a perspective camera would flip the chosen frame
|
|
27
|
+
// across the card and produce visible seams.
|
|
28
|
+
flat out vec2 vGridFloor;
|
|
29
|
+
flat out vec4 vWeights;
|
|
28
30
|
|
|
29
31
|
uniform mat4 modelViewMatrix;
|
|
30
32
|
uniform mat4 projectionMatrix;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
|
|
33
34
|
uniform vec3 uOffset;
|
|
34
35
|
uniform float uRadius;
|
|
35
36
|
uniform float uFrames;
|
|
36
|
-
|
|
37
|
+
uniform bool uIsFullSphere;
|
|
38
|
+
|
|
39
|
+
vec2 VecToSphereOct(vec3 pivotToCamera)
|
|
40
|
+
{
|
|
41
|
+
vec3 octant = sign(pivotToCamera);
|
|
42
|
+
float sum = dot(pivotToCamera, octant);
|
|
43
|
+
vec3 octahedron = pivotToCamera / sum;
|
|
44
|
+
if (octahedron.y < 0.0) {
|
|
45
|
+
vec3 absolute = abs(octahedron);
|
|
46
|
+
octahedron.xz = octant.xz * vec2(1.0 - absolute.z, 1.0 - absolute.x);
|
|
47
|
+
}
|
|
48
|
+
return octahedron.xz;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
vec2 VecToHemiSphereOct(vec3 v)
|
|
52
|
+
{
|
|
53
|
+
v.y = max(v.y, 0.001);
|
|
54
|
+
v = normalize(v);
|
|
55
|
+
vec3 octant = sign(v);
|
|
56
|
+
float sum = dot(v, octant);
|
|
57
|
+
vec3 octahedron = v / sum;
|
|
58
|
+
return vec2(
|
|
59
|
+
octahedron.x + octahedron.z,
|
|
60
|
+
octahedron.z - octahedron.x
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
vec2 VectorToGrid(vec3 v)
|
|
65
|
+
{
|
|
66
|
+
if (uIsFullSphere) {
|
|
67
|
+
return VecToSphereOct(v);
|
|
68
|
+
} else {
|
|
69
|
+
return VecToHemiSphereOct(v);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
vec4 TriangleInterpolate(vec2 frac_uv)
|
|
74
|
+
{
|
|
75
|
+
vec2 omuv = vec2(1.0) - frac_uv;
|
|
76
|
+
vec4 res;
|
|
77
|
+
// frame 0 weight (corner (0,0) of the quad)
|
|
78
|
+
res.x = min(omuv.x, omuv.y);
|
|
79
|
+
// frame 1 weight (off-diagonal corner — picked by res.w)
|
|
80
|
+
res.y = abs(frac_uv.x - frac_uv.y);
|
|
81
|
+
// frame 2 weight (corner (1,1) of the quad)
|
|
82
|
+
res.z = min(frac_uv.x, frac_uv.y);
|
|
83
|
+
// triangle-half mask: 1 in the lower-right half, 0 in the upper-left
|
|
84
|
+
res.w = clamp(ceil(frac_uv.x - frac_uv.y), 0.0, 1.0);
|
|
85
|
+
return res;
|
|
86
|
+
}
|
|
87
|
+
|
|
37
88
|
void main() {
|
|
38
89
|
vUv = uv;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
90
|
+
|
|
91
|
+
// View-aligned billboard: strip the rotation out of modelViewMatrix,
|
|
92
|
+
// keeping only its translation column. The card always faces the
|
|
93
|
+
// camera in screen space. (Step 3 will replace this with a card
|
|
94
|
+
// oriented to the bake direction.)
|
|
42
95
|
mat4 m4 = modelViewMatrix;
|
|
43
|
-
|
|
96
|
+
|
|
44
97
|
m4[0][0] = 1.0;
|
|
45
98
|
m4[0][1] = 0.0;
|
|
46
99
|
m4[0][2] = 0.0;
|
|
@@ -52,252 +105,104 @@ const shader_vx = `
|
|
|
52
105
|
m4[2][0] = 0.0;
|
|
53
106
|
m4[2][1] = 0.0;
|
|
54
107
|
m4[2][2] = 1.0;
|
|
55
|
-
|
|
108
|
+
|
|
56
109
|
vec3 object_scale = vec3(
|
|
57
110
|
length(modelViewMatrix[0].xyz),
|
|
58
111
|
length(modelViewMatrix[1].xyz),
|
|
59
112
|
length(modelViewMatrix[2].xyz)
|
|
60
|
-
);
|
|
61
|
-
|
|
113
|
+
);
|
|
114
|
+
|
|
62
115
|
// scale by object's baking bounding sphere's radius
|
|
63
|
-
float card_diameter = uRadius*2.0;
|
|
116
|
+
float card_diameter = uRadius * 2.0;
|
|
64
117
|
object_scale *= card_diameter;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
vec4 mvPosition = m4 * vec4( object_scale*(position+uOffset/card_diameter), 1.0 );
|
|
69
|
-
|
|
118
|
+
|
|
119
|
+
vec4 mvPosition = m4 * vec4(object_scale * (position + uOffset / card_diameter), 1.0);
|
|
70
120
|
gl_Position = projectionMatrix * mvPosition;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
local_ray_near = near_4.xyz / near_4.w;
|
|
84
|
-
local_ray_far = far_4.xyz/ far_4.w;
|
|
121
|
+
|
|
122
|
+
// Pivot-to-camera direction in the impostor's object-local space —
|
|
123
|
+
// the same frame the atlas was baked in. The camera sits at the
|
|
124
|
+
// origin in view space; inverting modelViewMatrix takes that back
|
|
125
|
+
// into object-local space. Constant across all vertices of the card.
|
|
126
|
+
vec3 cameraPos_OS = (inverse(modelViewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
127
|
+
vec3 pivotToCameraRay = normalize(cameraPos_OS);
|
|
128
|
+
|
|
129
|
+
vec2 octahedral_uv = clamp(VectorToGrid(pivotToCameraRay) * 0.5 + 0.5, 0.0, 1.0);
|
|
130
|
+
vec2 grid = octahedral_uv * (uFrames - 1.0);
|
|
131
|
+
vGridFloor = floor(grid);
|
|
132
|
+
vWeights = TriangleInterpolate(fract(grid));
|
|
85
133
|
}
|
|
86
134
|
`;
|
|
87
135
|
const shader_fg = `
|
|
88
136
|
precision highp float;
|
|
89
137
|
precision highp int;
|
|
90
|
-
|
|
138
|
+
|
|
91
139
|
const float depth_scale = 0.5;
|
|
92
140
|
|
|
93
141
|
in vec2 vUv;
|
|
94
|
-
|
|
95
|
-
in
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
in
|
|
100
|
-
|
|
101
|
-
|
|
142
|
+
|
|
143
|
+
// Frame indices + triangle weights are computed per-impostor in the
|
|
144
|
+
// vertex shader. flat = no interpolation; every fragment sees the same
|
|
145
|
+
// values and samples the same 3 atlas frames.
|
|
146
|
+
flat in vec2 vGridFloor;
|
|
147
|
+
flat in vec4 vWeights;
|
|
148
|
+
|
|
102
149
|
out vec4 color_out;
|
|
103
|
-
|
|
150
|
+
|
|
104
151
|
uniform sampler2D tBase;
|
|
105
152
|
uniform sampler2D tGeometry;
|
|
106
153
|
uniform float uFrames;
|
|
107
154
|
uniform float uDepthScale;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
in vec3 local_ray_near;
|
|
112
|
-
in vec3 local_ray_far;
|
|
113
|
-
|
|
114
|
-
struct Material{
|
|
115
|
-
vec3 diffuse;
|
|
116
|
-
vec3 normal;
|
|
117
|
-
float depth;
|
|
118
|
-
float occlusion;
|
|
119
|
-
float roughness;
|
|
120
|
-
float metalness;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
vec2 VecToSphereOct(vec3 pivotToCamera)
|
|
124
|
-
{
|
|
125
|
-
vec3 octant = sign(pivotToCamera);
|
|
126
|
-
|
|
127
|
-
// |x| + |y| + |z| = 1
|
|
128
|
-
float sum = dot(pivotToCamera, octant);
|
|
129
|
-
vec3 octahedron = pivotToCamera / sum;
|
|
130
|
-
|
|
131
|
-
if (octahedron.y < 0.0){
|
|
132
|
-
vec3 absolute = abs(octahedron);
|
|
133
|
-
octahedron.xz = octant.xz * vec2(1.0 - absolute.z, 1.0 - absolute.x);
|
|
134
|
-
}
|
|
135
|
-
return octahedron.xz;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
//for hemisphere
|
|
139
|
-
vec2 VecToHemiSphereOct(vec3 vec)
|
|
140
|
-
{
|
|
141
|
-
vec.y = max(vec.y, 0.001);
|
|
142
|
-
vec = normalize(vec);
|
|
143
|
-
vec3 octant = sign(vec);
|
|
144
|
-
|
|
145
|
-
// |x| + |y| + |z| = 1
|
|
146
|
-
float sum = dot(vec, octant);
|
|
147
|
-
vec3 octahedron = vec / sum;
|
|
148
|
-
|
|
149
|
-
return vec2(
|
|
150
|
-
octahedron.x + octahedron.z,
|
|
151
|
-
octahedron.z - octahedron.x
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
vec2 VectorToGrid(vec3 vec)
|
|
156
|
-
{
|
|
157
|
-
if (uIsFullSphere)
|
|
158
|
-
{
|
|
159
|
-
return VecToSphereOct(vec);
|
|
160
|
-
}
|
|
161
|
-
else
|
|
162
|
-
{
|
|
163
|
-
return VecToHemiSphereOct(vec);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
vec4 TriangleInterpolate(vec2 uv){
|
|
168
|
-
uv = fract(uv);
|
|
169
|
-
|
|
170
|
-
vec2 omuv = vec2(1.0, 1.0) - uv.xy;
|
|
171
|
-
|
|
172
|
-
vec4 res = vec4(0, 0, 0, 0);
|
|
173
|
-
//frame 0
|
|
174
|
-
res.x = min(omuv.x, omuv.y);
|
|
175
|
-
//frame 1
|
|
176
|
-
res.y = abs(dot(uv, vec2(1.0, -1.0)));
|
|
177
|
-
//frame 2
|
|
178
|
-
res.z = min(uv.x, uv.y);
|
|
179
|
-
//mask
|
|
180
|
-
res.w = clamp(ceil(uv.x-uv.y),0.0, 1.0);
|
|
181
|
-
|
|
182
|
-
return res;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
vec4 ImposterBlendWeights(sampler2D tex, vec2 frame0, vec2 frame1, vec2 frame2, vec4 weights, vec4 ddxy)
|
|
187
|
-
{
|
|
188
|
-
vec4 samp0 = textureGrad(tex, frame0, ddxy.xy, ddxy.zw);
|
|
189
|
-
vec4 samp1 = textureGrad(tex, frame1, ddxy.xy, ddxy.zw);
|
|
190
|
-
vec4 samp2 = textureGrad(tex, frame2, ddxy.xy, ddxy.zw);
|
|
191
|
-
|
|
192
|
-
vec4 result = samp0*weights.x + samp1*weights.y + samp2*weights.z;
|
|
193
|
-
|
|
194
|
-
return result;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
vec4 ImposterBlendWeightsNearest(sampler2D tex, vec2 frame0, vec2 frame1, vec2 frame2, vec4 weights, vec4 ddxy)
|
|
198
|
-
{
|
|
199
|
-
vec4 samp0 = textureGrad(tex, frame0, ddxy.xy, ddxy.zw);
|
|
200
|
-
vec4 samp1 = textureGrad(tex, frame1, ddxy.xy, ddxy.zw);
|
|
201
|
-
vec4 samp2 = textureGrad(tex, frame2, ddxy.xy, ddxy.zw);
|
|
202
|
-
|
|
203
|
-
vec4 result;
|
|
204
|
-
|
|
205
|
-
if(weights.x > weights.y && weights.x > weights.z){
|
|
206
|
-
result = samp0;
|
|
207
|
-
}if(weights.y > weights.z){
|
|
208
|
-
result = samp1;
|
|
209
|
-
}else{
|
|
210
|
-
result = samp2;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return result;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
void calcuateXYbasis(vec3 plane_normal, out vec3 plane_x, out vec3 plane_y)
|
|
155
|
+
|
|
156
|
+
vec4 ImposterBlendWeights(sampler2D tex, vec2 uv0, vec2 uv1, vec2 uv2, vec4 weights, vec4 ddxy)
|
|
218
157
|
{
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
plane_x = normalize(cross(plane_normal, up));
|
|
226
|
-
plane_y = normalize(cross(plane_x, plane_normal));
|
|
158
|
+
vec4 samp0 = textureGrad(tex, uv0, ddxy.xy, ddxy.zw);
|
|
159
|
+
vec4 samp1 = textureGrad(tex, uv1, ddxy.xy, ddxy.zw);
|
|
160
|
+
vec4 samp2 = textureGrad(tex, uv2, ddxy.xy, ddxy.zw);
|
|
161
|
+
|
|
162
|
+
return samp0 * weights.x + samp1 * weights.y + samp2 * weights.z;
|
|
227
163
|
}
|
|
228
164
|
|
|
229
|
-
|
|
165
|
+
vec2 recompute_uv(vec2 frame, vec2 frame_uv, sampler2D gBuffer)
|
|
230
166
|
{
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
dot(plane_x,ray),
|
|
234
|
-
dot(plane_y,ray),
|
|
235
|
-
dot(plane_normal,ray)
|
|
236
|
-
));
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
vec2 recompute_uv(vec2 frame, vec2 frame_uv, sampler2D gBuffer){
|
|
240
|
-
vec2 frame_size = vec2(1.0/ uFrames);
|
|
241
|
-
|
|
242
|
-
vec2 source_uv = (frame + frame_uv)*frame_size;
|
|
243
|
-
|
|
167
|
+
vec2 frame_size = vec2(1.0 / uFrames);
|
|
168
|
+
vec2 source_uv = (frame + frame_uv) * frame_size;
|
|
244
169
|
float n_depth = texture(gBuffer, source_uv).a;
|
|
245
|
-
|
|
246
|
-
vec2 offset =
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
uv_f = ( frame + uv_f)*frame_size;
|
|
251
|
-
|
|
252
|
-
return clamp(uv_f,0.0, 1.0);
|
|
253
|
-
// return source_uv;
|
|
170
|
+
|
|
171
|
+
vec2 offset = (frame_uv * 2.0 - 1.0) * (0.5 - n_depth) * depth_scale;
|
|
172
|
+
vec2 uv_f = clamp(frame_uv + offset, 0.0, 1.0);
|
|
173
|
+
uv_f = (frame + uv_f) * frame_size;
|
|
174
|
+
return clamp(uv_f, 0.0, 1.0);
|
|
254
175
|
}
|
|
255
|
-
|
|
256
|
-
void main(){
|
|
257
|
-
vec3 view_direction = normalize(local_ray_near-local_ray_far);
|
|
258
|
-
|
|
259
|
-
vec2 octahedral_uv = clamp(VectorToGrid(view_direction)*0.5 + 0.5, 0.0, 1.0);
|
|
260
|
-
vec2 grid = octahedral_uv * vec2(uFrames - 1.0);
|
|
261
|
-
|
|
262
|
-
vec2 gridFrac = fract(grid);
|
|
263
|
-
vec2 gridFloor = floor(grid);
|
|
264
|
-
|
|
265
|
-
vec4 weights = TriangleInterpolate( gridFrac );
|
|
266
|
-
|
|
176
|
+
|
|
177
|
+
void main() {
|
|
267
178
|
vec2 frame_uv = vUv;
|
|
268
|
-
|
|
269
|
-
//3 nearest frames
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
vec2
|
|
273
|
-
|
|
179
|
+
|
|
180
|
+
// 3 nearest frames — chosen in the vertex shader (vGridFloor +
|
|
181
|
+
// vWeights are flat, so frame0/1/2 are identical for every fragment
|
|
182
|
+
// of this impostor card).
|
|
183
|
+
vec2 frame0 = vGridFloor;
|
|
184
|
+
vec2 frame1 = vGridFloor + mix(vec2(0.0, 1.0), vec2(1.0, 0.0), vWeights.w);
|
|
185
|
+
vec2 frame2 = vGridFloor + vec2(1.0, 1.0);
|
|
186
|
+
|
|
274
187
|
vec2 uv0 = recompute_uv(frame0, frame_uv, tGeometry);
|
|
275
188
|
vec2 uv1 = recompute_uv(frame1, frame_uv, tGeometry);
|
|
276
189
|
vec2 uv2 = recompute_uv(frame2, frame_uv, tGeometry);
|
|
277
|
-
|
|
278
|
-
vec4 ddxy = vec4(
|
|
279
|
-
|
|
280
|
-
vec2 frame_size = vec2(1.0/ uFrames);
|
|
281
|
-
|
|
190
|
+
|
|
191
|
+
vec4 ddxy = vec4(dFdx(vUv.xy), dFdy(vUv.xy));
|
|
192
|
+
|
|
282
193
|
vec4 texel_color = ImposterBlendWeights(
|
|
283
|
-
// vec4 texel_color = ImposterBlendWeightsNearest(
|
|
284
194
|
tBase,
|
|
285
195
|
uv0,
|
|
286
196
|
uv1,
|
|
287
197
|
uv2,
|
|
288
|
-
|
|
198
|
+
vWeights, ddxy
|
|
289
199
|
);
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// texel_color = vec4(texel_color.aaa, 1.0);
|
|
293
|
-
|
|
294
|
-
if(texel_color.a <= 0.5){
|
|
295
|
-
texel_color.r = 1.0;
|
|
200
|
+
|
|
201
|
+
if (texel_color.a <= 0.5) {
|
|
296
202
|
discard;
|
|
297
203
|
}
|
|
298
|
-
|
|
204
|
+
|
|
299
205
|
color_out = texel_color;
|
|
300
|
-
// color_out = vec4( snapped_oct_uv, 1.0, 1.0);
|
|
301
206
|
}
|
|
302
207
|
`;
|
|
303
208
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BufferedGeometryBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js"],"names":[],"mappings":"AAwCA;IAkBI;;;OAGG;IACH,eAFW,KAAK,GAAC,MAAM,EAAE,QAIxB;IAIG;;;;OAIG;IACH,mBAAsB;IAEtB;;;;OAIG;IACH,yBAA4B;IAE5B;;;;OAIG;IACH,6BAAgC;IAGhC;;;;OAIG;IACH,yBAAyB;IAG7B;;;OAGG;IACH,WAFW,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"BufferedGeometryBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js"],"names":[],"mappings":"AAwCA;IAkBI;;;OAGG;IACH,eAFW,KAAK,GAAC,MAAM,EAAE,QAIxB;IAIG;;;;OAIG;IACH,mBAAsB;IAEtB;;;;OAIG;IACH,yBAA4B;IAE5B;;;;OAIG;IACH,6BAAgC;IAGhC;;;;OAIG;IACH,yBAAyB;IAG7B;;;OAGG;IACH,WAFW,MAAM,cAAc,QAgD9B;IAED;;;;;OAKG;IACH,qBAFa,OAAO,CAmHnB;IAED;;;;;;;OAOG;IACH,4BANW,aAAa,KACb,MAAM,KACN,MAAM,KACN,MAAM,GACJ,OAAO,CAUnB;IAGD;;;;;;OAMG;IACH,iBAJW,MAAM,EAAE,OACR,MAAM,EAAE,OAAK,GACX,MAAM,CAoIlB;IAED;;;;;OAKG;IACH,gBAJW,MAAM,EAAE,OACR,MAAM,EAAE,OAAK,GACX,MAAM,CA2ElB;;CACJ;sBAhfqB,wCAAwC;8BAGhC,2CAA2C"}
|
|
@@ -129,10 +129,12 @@ export class BufferedGeometryBVH {
|
|
|
129
129
|
array_positions,
|
|
130
130
|
this.#morton_codes,
|
|
131
131
|
this.#bounds,
|
|
132
|
-
|
|
132
|
+
2
|
|
133
133
|
);
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
for (let i = 0; i < 3; i++) {
|
|
136
|
+
ebvh_optimize_treelet(bvh);
|
|
137
|
+
}
|
|
136
138
|
|
|
137
139
|
//
|
|
138
140
|
// ebvh_build_for_geometry_incremental(bvh, index_array, array_positions, 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PathTracedScene.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/PathTracedScene.js"],"names":[],"mappings":"AAoDA;IAGI;;;OAGG;IACH,eAFU,GAAG,CAEa;IAG1B;;;OAGG;IACH,QAFU,IAAI,MAAM,EAAE,cAAc,CAAC,CAElB;IAEnB;;;OAGG;IACH,UAFU,aAAa,EAAE,CAEX;IAEd;;;OAGG;IACH,WAFU,IAAI,MAAM,cAAc,EAAE,mBAAmB,CAAC,CAElC;IAmBtB;;;;OAIG;IACH,6BAA6C;
|
|
1
|
+
{"version":3,"file":"PathTracedScene.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/PathTracedScene.js"],"names":[],"mappings":"AAoDA;IAGI;;;OAGG;IACH,eAFU,GAAG,CAEa;IAG1B;;;OAGG;IACH,QAFU,IAAI,MAAM,EAAE,cAAc,CAAC,CAElB;IAEnB;;;OAGG;IACH,UAFU,aAAa,EAAE,CAEX;IAEd;;;OAGG;IACH,WAFU,IAAI,MAAM,cAAc,EAAE,mBAAmB,CAAC,CAElC;IAmBtB;;;;OAIG;IACH,6BAA6C;IAoF7C,iBAOC;IAED;;;;OAIG;IACH,uBAHW,MAAM,cAAc,GACnB,mBAAmB,CAmB9B;IAED;;;OAGG;IACH,gBAFW,aAAa,QAMvB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACZ,OAAO,CAInB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACZ,OAAO,CAiCnB;IAED;;;;OAIG;IACH,iBAHW,cAAc,GACZ,OAAO,CAgBnB;IAED;;;;OAIG;IACH,yBAHW,MAAM,QAAQ,oBAKxB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,cAAc,YACpB,MAAM,QAAQ,aACd,OAAK,MAAM,EAAE,QAavB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,EAAE,OACR,MAAM,EAAE,gBACR,IAAI,QA0Cd;IAED;;;;OAIG;IACH,cAHW,IAAI,GACF,OAAO,CAsCnB;IAED;;;;;OAKG;IACH,WAJW,MAAM,EAAE,OACR,MAAM,EAAE,GAAC,IAAI,GACZ,MAAM,CA+CjB;IAED;;;;;;OAMG;IACH,uBALW,MAAM,EAAE,cACR,MAAM,aACN,MAAM,EAAE,oBACR,MAAM,QAIhB;IAED;;;;;OAKG;IACH,mBAJW,MAAM,EAAE,cACR,MAAM,OACN,MAAM,EAAE,QAwHlB;;CACJ;oBA5lB8B,mCAAmC;+BAqBnC,qBAAqB;8BAJtB,kDAAkD;oCAC5C,0BAA0B;qBARzC,sCAAsC"}
|
|
@@ -177,9 +177,11 @@ export class PathTracedScene {
|
|
|
177
177
|
array_copy(nodes, 0, unprocessed_nodes, 0, node_leaf_count);
|
|
178
178
|
|
|
179
179
|
// assign root
|
|
180
|
-
bvh.__root = ebvh_build_hierarchy(bvh, unprocessed_nodes, node_leaf_count, nodes, node_leaf_count,
|
|
180
|
+
bvh.__root = ebvh_build_hierarchy(bvh, unprocessed_nodes, node_leaf_count, nodes, node_leaf_count, 3);
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
for (let i = 0; i < 3; i++) {
|
|
183
|
+
ebvh_optimize_treelet(bvh);
|
|
184
|
+
}
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
optimize() {
|
|
@@ -67,8 +67,8 @@ vCanvas.css({
|
|
|
67
67
|
* How many rays to use per-pixel
|
|
68
68
|
* @type {number}
|
|
69
69
|
*/
|
|
70
|
-
const PIXEL_SAMPLE_COUNT =
|
|
71
|
-
const PIXEL_RENDER_RATIO =
|
|
70
|
+
const PIXEL_SAMPLE_COUNT = 16;
|
|
71
|
+
const PIXEL_RENDER_RATIO = 1;
|
|
72
72
|
|
|
73
73
|
const scene = new PathTracedScene();
|
|
74
74
|
const pt = new PathTracer();
|