@woosh/meep-engine 2.43.16 → 2.43.18
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/core/assert.js +3 -1
- package/core/bvh2/aabb3/aabb3_intersects_ray.js +14 -9
- package/core/bvh2/aabb3/aabb3_intersects_ray_branchless.js +52 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +2 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +214 -5
- package/core/bvh2/bvh3/bvh_query_leaves_ray.js +32 -29
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/geom/3d/aabb/compute_aabb_from_points.js +4 -3
- package/core/geom/3d/compute_triangle_normal.js +76 -0
- package/core/geom/3d/topology/samples/sampleFloodFill.js +1 -1
- package/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +1 -1
- package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +1 -1
- package/core/geom/3d/topology/struct/TopoTriangle.js +1 -57
- package/core/geom/3d/topology/tm_face_normal.js +1 -1
- package/core/geom/3d/topology/tm_vertex_compute_normal.js +1 -1
- package/core/geom/3d/triangle/computeTriangleRayIntersection.js +195 -27
- package/core/geom/Vector3.js +12 -12
- package/core/math/physics/brdf/D_GGX.js +13 -0
- package/editor/tools/v2/prototypeTransformControls.js +14 -2
- package/engine/ecs/parent/EntityNode.js +80 -7
- package/engine/ecs/parent/EntityNodeFlags.js +8 -0
- package/engine/ecs/terrain/tiles/TerrainTile.js +7 -9
- package/engine/graphics/ecs/path/PathDisplaySystem.d.ts +3 -0
- package/engine/graphics/ecs/path/PathDisplaySystem.js +10 -0
- package/engine/graphics/geometry/AttributeSpec.js +18 -3
- package/engine/graphics/geometry/VertexDataSpec.js +53 -3
- package/engine/graphics/micron/format/VirtualGeometry.js +7 -0
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +1 -1
- package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +5 -2
- package/engine/graphics/particles/particular/engine/parameter/sample/RGBA_LUT_HEATMAP_IR.js +11 -0
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -9
- package/engine/graphics/sh3/README.md +1 -0
- package/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +324 -0
- package/engine/graphics/sh3/path_tracer/PathTracedMesh.js +85 -0
- package/engine/graphics/sh3/path_tracer/PathTracer.js +469 -0
- package/engine/graphics/sh3/path_tracer/apply_texture_clamping_to_coordinate.js +22 -0
- package/engine/graphics/sh3/path_tracer/compute_triangle_group_aabb3.js +36 -0
- package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +55 -0
- package/engine/graphics/sh3/path_tracer/make_sky_hosek.js +44 -0
- package/engine/graphics/sh3/path_tracer/make_sky_rtiw.js +15 -0
- package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +619 -0
- package/engine/graphics/sh3/path_tracer/random_in_hemisphere.js +39 -0
- package/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +42 -0
- package/engine/graphics/sh3/path_tracer/ray_reflect.js +27 -0
- package/engine/graphics/sh3/path_tracer/sample_triangle_attribute.js +35 -0
- package/engine/graphics/sh3/path_tracer/vec3_uint8_to_float.js +12 -0
- package/engine/graphics/sh3/sky/hosek/README.md +4 -0
- package/engine/graphics/sh3/sky/hosek/prototype_hosek.js +71 -0
- package/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +4171 -0
- package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +2 -0
- package/package.json +1 -1
- package/view/elements/progress/SmoothProgressBar.js +1 -1
- package/view/task/TaskProgressView.js +6 -8
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
2
|
+
import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
3
|
+
import { PathTracer } from "./PathTracer.js";
|
|
4
|
+
import {
|
|
5
|
+
Box3,
|
|
6
|
+
MeshStandardMaterial,
|
|
7
|
+
OctahedronBufferGeometry,
|
|
8
|
+
PerspectiveCamera,
|
|
9
|
+
PlaneBufferGeometry,
|
|
10
|
+
Sphere,
|
|
11
|
+
SphereBufferGeometry
|
|
12
|
+
} from "three";
|
|
13
|
+
import { Sampler2D } from "../../texture/sampler/Sampler2D.js";
|
|
14
|
+
import sampler2D2Canvas from "../../texture/sampler/Sampler2D2Canvas.js";
|
|
15
|
+
import { ray3_array_compose } from "../../../../core/geom/3d/ray/ray3_array_compose.js";
|
|
16
|
+
import { Transform } from "../../../ecs/transform/Transform.js";
|
|
17
|
+
import { prettyPrint } from "../../../../core/NumberFormat.js";
|
|
18
|
+
import { float2uint8 } from "../../../../core/binary/float2uint8.js";
|
|
19
|
+
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
20
|
+
import { Camera } from "../../ecs/camera/Camera.js";
|
|
21
|
+
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
22
|
+
import { scaleSampler2D } from "../../texture/sampler/scaleSampler2D.js";
|
|
23
|
+
import { seededRandom } from "../../../../core/math/random/seededRandom.js";
|
|
24
|
+
import { mat4 } from "gl-matrix";
|
|
25
|
+
import { v3_distance } from "../../../../core/geom/v3_distance.js";
|
|
26
|
+
import ConcurrentExecutor from "../../../../core/process/executor/ConcurrentExecutor.js";
|
|
27
|
+
import Task from "../../../../core/process/task/Task.js";
|
|
28
|
+
import { TaskSignal } from "../../../../core/process/task/TaskSignal.js";
|
|
29
|
+
import Quaternion from "../../../../core/geom/Quaternion.js";
|
|
30
|
+
import TaskProgressView from "../../../../view/task/TaskProgressView.js";
|
|
31
|
+
import { Localization } from "../../../../core/Localization.js";
|
|
32
|
+
|
|
33
|
+
import '../../../../../../../css/game.scss';
|
|
34
|
+
import { MouseEvents } from "../../../input/devices/events/MouseEvents.js";
|
|
35
|
+
import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
|
|
36
|
+
import { noop } from "../../../../core/function/Functions.js";
|
|
37
|
+
import { Color } from "../../../../core/color/Color.js";
|
|
38
|
+
import { min2 } from "../../../../core/math/min2.js";
|
|
39
|
+
import { makeGeometryIndexed } from "../../geometry/buffered/makeGeometryIndexed.js";
|
|
40
|
+
|
|
41
|
+
document.body.style.margin = 0;
|
|
42
|
+
document.body.style.overflow = "hidden";
|
|
43
|
+
|
|
44
|
+
const vContainer = new EmptyView();
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const vCanvas = new CanvasView();
|
|
48
|
+
vContainer.addChild(vCanvas);
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
vContainer.size.set(window.innerWidth, window.innerHeight);
|
|
52
|
+
// vCanvas.size.set(512, 512);
|
|
53
|
+
// vCanvas.size.set(1080, 1080);
|
|
54
|
+
vCanvas.size.copy(vContainer.size);
|
|
55
|
+
|
|
56
|
+
vContainer.css({
|
|
57
|
+
position: 'absolute',
|
|
58
|
+
top: 0,
|
|
59
|
+
left: 0,
|
|
60
|
+
overflowY: "visible",
|
|
61
|
+
overflowX: "visible"
|
|
62
|
+
|
|
63
|
+
});
|
|
64
|
+
vCanvas.css({
|
|
65
|
+
overflow: "visible"
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const pt = new PathTracer();
|
|
69
|
+
|
|
70
|
+
const gltfLoader = new GLTFLoader();
|
|
71
|
+
// const gltf_url = 'data/models/LowPolyTownshipSet/Town_Hall/model.gltf';
|
|
72
|
+
// const gltf_url = 'data/models/road_bike/road_bike.gltf';
|
|
73
|
+
// const gltf_url = 'data/models/sponza-pbr/gltf/sponza.glb';
|
|
74
|
+
// const gltf_url = 'data/models/sibenik/model.gltf';
|
|
75
|
+
// gltfLoader.load(gltf_url, (gltf) => {
|
|
76
|
+
//
|
|
77
|
+
// gltf.scene.updateMatrixWorld();
|
|
78
|
+
//
|
|
79
|
+
// gltf.scene.traverse(m => {
|
|
80
|
+
//
|
|
81
|
+
// if (m.isMesh) {
|
|
82
|
+
//
|
|
83
|
+
// pt.addMesh(
|
|
84
|
+
// m.geometry,
|
|
85
|
+
// m.material,
|
|
86
|
+
// m.matrixWorld.elements
|
|
87
|
+
// );
|
|
88
|
+
//
|
|
89
|
+
// }
|
|
90
|
+
// });
|
|
91
|
+
//
|
|
92
|
+
// trace_image(vCanvas);
|
|
93
|
+
// });
|
|
94
|
+
|
|
95
|
+
//
|
|
96
|
+
// pt.addMesh(
|
|
97
|
+
// new TorusKnotBufferGeometry(1, 0.3, 128, 128),
|
|
98
|
+
// new MeshStandardMaterial({ color: '#FF0000' }),
|
|
99
|
+
// Transform.fromJSON({
|
|
100
|
+
// scale: 0.5
|
|
101
|
+
// }).matrix
|
|
102
|
+
// );
|
|
103
|
+
//
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
function prepare_scene_sphere_01(pt, camera) {
|
|
107
|
+
camera.position.set(0, 0, -2.1);
|
|
108
|
+
camera.lookAt(0, 0, 0);
|
|
109
|
+
pt.addMesh(
|
|
110
|
+
new SphereBufferGeometry(1, 16, 16),
|
|
111
|
+
new MeshStandardMaterial({ color: '#FF0000' }),
|
|
112
|
+
Transform.fromJSON({
|
|
113
|
+
scale: 0.5
|
|
114
|
+
}).matrix
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const ground_material = new MeshStandardMaterial({
|
|
118
|
+
color: '#00FF00'
|
|
119
|
+
});
|
|
120
|
+
pt.addMesh(new PlaneBufferGeometry(), ground_material, Transform.fromJSON({
|
|
121
|
+
position: new Vector3(0, -0.5, 0),
|
|
122
|
+
scale: 50,
|
|
123
|
+
rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
|
|
124
|
+
}).matrix);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function promise_ply(url) {
|
|
128
|
+
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
new PLYLoader().load(url, resolve, noop, reject);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {string} url
|
|
137
|
+
* @return {Promise<GLTF>}
|
|
138
|
+
*/
|
|
139
|
+
function promise_gltf(url) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
new GLTFLoader().load(url, resolve, noop, reject);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
*
|
|
147
|
+
* @param {PathTracer} pt
|
|
148
|
+
* @param {THREE.Camera} camera
|
|
149
|
+
* @param {string} url
|
|
150
|
+
* @return {Promise<void>}
|
|
151
|
+
*/
|
|
152
|
+
async function prepare_scene_gltf(pt, camera, url) {
|
|
153
|
+
const gltf = await promise_gltf(url);
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
const ground_material = new MeshStandardMaterial({
|
|
157
|
+
color: '#ffceae'
|
|
158
|
+
});
|
|
159
|
+
pt.addMesh(new PlaneBufferGeometry(), ground_material, Transform.fromJSON({
|
|
160
|
+
position: new Vector3(0, 0, 0),
|
|
161
|
+
scale: 5000,
|
|
162
|
+
rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
|
|
163
|
+
}).matrix);
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
gltf.scene.updateMatrixWorld();
|
|
167
|
+
|
|
168
|
+
gltf.scene.traverse((m) => {
|
|
169
|
+
if (m.isMesh) {
|
|
170
|
+
pt.addMesh(m.geometry, m.material, m.matrixWorld.elements);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const box3 = new Box3();
|
|
175
|
+
box3.setFromObject(gltf.scene);
|
|
176
|
+
|
|
177
|
+
const sphere = new Sphere();
|
|
178
|
+
|
|
179
|
+
box3.getBoundingSphere(sphere);
|
|
180
|
+
|
|
181
|
+
camera.position.set(1, 1.3, 1)
|
|
182
|
+
.normalize()
|
|
183
|
+
.multiplyScalar(sphere.radius * 2.6);
|
|
184
|
+
|
|
185
|
+
camera.lookAt(sphere.center);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
*
|
|
190
|
+
* @param {PathTracer} pt
|
|
191
|
+
* @param {THREE.Camera} camera
|
|
192
|
+
* @return {Promise<void>}
|
|
193
|
+
*/
|
|
194
|
+
async function prepare_scene_lucy(pt, camera) {
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
const lucy_geom = await promise_ply("data/models/stanford/Lucy100k.ply")
|
|
198
|
+
|
|
199
|
+
const lucy_material = new MeshStandardMaterial({
|
|
200
|
+
color: '#95c9ff'
|
|
201
|
+
});
|
|
202
|
+
pt.addMesh(lucy_geom, lucy_material, Transform.fromJSON({
|
|
203
|
+
position: new Vector3(0, 0, 0),
|
|
204
|
+
scale: 1,
|
|
205
|
+
// rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
|
|
206
|
+
}).matrix);
|
|
207
|
+
|
|
208
|
+
const ground_material = new MeshStandardMaterial({
|
|
209
|
+
color: '#ffceae'
|
|
210
|
+
});
|
|
211
|
+
pt.addMesh(new PlaneBufferGeometry(), ground_material, Transform.fromJSON({
|
|
212
|
+
position: new Vector3(0, -800, 0),
|
|
213
|
+
scale: 5000,
|
|
214
|
+
rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
|
|
215
|
+
}).matrix);
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
camera.position.set(0, 0, -2300);
|
|
219
|
+
camera.lookAt(0, 0, 0);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Ray-Tracing In One Weekend test scene
|
|
224
|
+
* @param {PathTracer} pt
|
|
225
|
+
* @param {THREE.Camera} camera
|
|
226
|
+
*/
|
|
227
|
+
async function prepare_scene_rtiow(pt, camera) {
|
|
228
|
+
const random = seededRandom();
|
|
229
|
+
|
|
230
|
+
const sphere_geo = new OctahedronBufferGeometry(1, 8);
|
|
231
|
+
makeGeometryIndexed(sphere_geo);
|
|
232
|
+
|
|
233
|
+
const ground_material = new MeshStandardMaterial({
|
|
234
|
+
color: '#ffffff'
|
|
235
|
+
});
|
|
236
|
+
pt.addMesh(new PlaneBufferGeometry(), ground_material, Transform.fromJSON({
|
|
237
|
+
position: new Vector3(0, 0, 0),
|
|
238
|
+
scale: 50,
|
|
239
|
+
rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
|
|
240
|
+
}).matrix);
|
|
241
|
+
|
|
242
|
+
const spheres = [];
|
|
243
|
+
|
|
244
|
+
function overlaps_existing(x, y, z, r) {
|
|
245
|
+
for (let i = 0; i < spheres.length; i++) {
|
|
246
|
+
const sphere = spheres[i];
|
|
247
|
+
|
|
248
|
+
const r_1 = sphere[3];
|
|
249
|
+
|
|
250
|
+
if (v3_distance(sphere[0], sphere[1], sphere[2], x, y, z) < r_1 + r) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function add_sphere(center, radius, material) {
|
|
259
|
+
|
|
260
|
+
const mat = new Float32Array(16);
|
|
261
|
+
mat4.fromRotationTranslationScale(mat, [0, 0, 0, 1], center, [radius, radius, radius])
|
|
262
|
+
|
|
263
|
+
pt.addMesh(sphere_geo, material, mat);
|
|
264
|
+
|
|
265
|
+
spheres.push([
|
|
266
|
+
center[0],
|
|
267
|
+
center[1],
|
|
268
|
+
center[2],
|
|
269
|
+
radius
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const material1 = new MeshStandardMaterial({
|
|
274
|
+
color: '#FFFFFF'
|
|
275
|
+
});
|
|
276
|
+
add_sphere([0, 1, 0], 1, material1);
|
|
277
|
+
|
|
278
|
+
const material2 = new MeshStandardMaterial({
|
|
279
|
+
color: '#FFFFFF'
|
|
280
|
+
});
|
|
281
|
+
add_sphere([-4, 1, 0], 1, material2);
|
|
282
|
+
|
|
283
|
+
const material3 = new MeshStandardMaterial({
|
|
284
|
+
color: '#FFFFFF'
|
|
285
|
+
});
|
|
286
|
+
add_sphere([4, 1, 0], 1, material3);
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
for (let a = -11; a < 11; a++) {
|
|
290
|
+
for (let b = -11; b < 11; b++) {
|
|
291
|
+
|
|
292
|
+
const choose_mat = random();
|
|
293
|
+
|
|
294
|
+
const radius = 0.2;
|
|
295
|
+
|
|
296
|
+
const center = [0, radius, 0];
|
|
297
|
+
|
|
298
|
+
do {
|
|
299
|
+
center[0] = a + 0.9 * random();
|
|
300
|
+
center[2] = b + 0.9 * random();
|
|
301
|
+
} while (overlaps_existing(center[0], center[1], center[2], radius));
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
const mat = new Float32Array(16);
|
|
305
|
+
mat4.fromRotationTranslationScale(mat, [0, 0, 0, 1], center, [radius, radius, radius])
|
|
306
|
+
|
|
307
|
+
const material = new MeshStandardMaterial({
|
|
308
|
+
color: Color.fromHSV(random(), 0.9, 0.9).toHex()
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (choose_mat < 0.8) {
|
|
312
|
+
|
|
313
|
+
// diffuse
|
|
314
|
+
add_sphere(center, radius, material);
|
|
315
|
+
} else if (choose_mat < 0.95) {
|
|
316
|
+
// metal
|
|
317
|
+
add_sphere(center, radius, material);
|
|
318
|
+
} else {
|
|
319
|
+
// glass
|
|
320
|
+
add_sphere(center, radius, material);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
camera.position.set(13, 2, 3);
|
|
329
|
+
camera.lookAt(0, 0, 0);
|
|
330
|
+
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
*
|
|
335
|
+
* @param {Sampler2D} target
|
|
336
|
+
* @param {PathTracer} pt
|
|
337
|
+
* @param {Camera} camera
|
|
338
|
+
* @param {{current:number, total:number}} progress
|
|
339
|
+
*/
|
|
340
|
+
function* render(target, pt, camera, progress = { current: 0, total: 0 }) {
|
|
341
|
+
const random = seededRandom(0);
|
|
342
|
+
|
|
343
|
+
// update camera
|
|
344
|
+
camera.updateProjectionMatrix();
|
|
345
|
+
camera.updateMatrixWorld(true);
|
|
346
|
+
|
|
347
|
+
//update world inverse matrix
|
|
348
|
+
camera.matrixWorldInverse.copy(camera.matrixWorld);
|
|
349
|
+
camera.matrixWorldInverse.invert();
|
|
350
|
+
|
|
351
|
+
const out = [];
|
|
352
|
+
const out2 = [];
|
|
353
|
+
const ray = [];
|
|
354
|
+
|
|
355
|
+
const ray_origin = new Vector3();
|
|
356
|
+
const ray_direction = new Vector3();
|
|
357
|
+
|
|
358
|
+
const width = target.width;
|
|
359
|
+
const height = target.height;
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
const t0 = performance.now();
|
|
363
|
+
let sample_count = 0;
|
|
364
|
+
|
|
365
|
+
const pixel_scale_x = 1 / (width - 1);
|
|
366
|
+
const pixel_scale_y = 1 / (height - 1);
|
|
367
|
+
|
|
368
|
+
const pixel_sample_count = 500;
|
|
369
|
+
|
|
370
|
+
progress.total = width * height;
|
|
371
|
+
|
|
372
|
+
const max_y = height - 1;
|
|
373
|
+
|
|
374
|
+
const RENDER_TILE_SIZE = 8;
|
|
375
|
+
|
|
376
|
+
const tile_count_x = width / RENDER_TILE_SIZE;
|
|
377
|
+
const tile_count_y = height / RENDER_TILE_SIZE;
|
|
378
|
+
|
|
379
|
+
// render in square tiles to get better memory exploitation, as rays are more likely to hit same things in smaller region
|
|
380
|
+
for (let tile_y = 0; tile_y < tile_count_y; tile_y++) {
|
|
381
|
+
|
|
382
|
+
const y0 = tile_y * RENDER_TILE_SIZE;
|
|
383
|
+
const y1 = min2(height, y0 + RENDER_TILE_SIZE);
|
|
384
|
+
|
|
385
|
+
for (let tile_x = 0; tile_x < tile_count_x; tile_x++) {
|
|
386
|
+
|
|
387
|
+
const x0 = tile_x * RENDER_TILE_SIZE;
|
|
388
|
+
const x1 = min2(width, x0 + RENDER_TILE_SIZE);
|
|
389
|
+
|
|
390
|
+
for (let y = y0; y < y1; y++) {
|
|
391
|
+
|
|
392
|
+
const v = y * pixel_scale_y;
|
|
393
|
+
const _y = v * 2 - 1;
|
|
394
|
+
|
|
395
|
+
for (let x = x0; x < x1; x++) {
|
|
396
|
+
|
|
397
|
+
const u = x * pixel_scale_x;
|
|
398
|
+
const _x = u * 2 - 1;
|
|
399
|
+
|
|
400
|
+
out2[0] = 0;
|
|
401
|
+
out2[1] = 0;
|
|
402
|
+
out2[2] = 0;
|
|
403
|
+
|
|
404
|
+
for (let i = 0; i < pixel_sample_count; i++) {
|
|
405
|
+
|
|
406
|
+
Camera.projectRay(camera,
|
|
407
|
+
_x + random() * pixel_scale_x * 2,
|
|
408
|
+
_y + random() * pixel_scale_y * 2,
|
|
409
|
+
ray_origin, ray_direction
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
ray3_array_compose(
|
|
413
|
+
ray,
|
|
414
|
+
ray_origin.x, ray_origin.y, ray_origin.z,
|
|
415
|
+
ray_direction.x, ray_direction.y, ray_direction.z
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
pt.path_trace(out, ray, Infinity, 4, random);
|
|
419
|
+
|
|
420
|
+
out2[0] += out[0];
|
|
421
|
+
out2[1] += out[1];
|
|
422
|
+
out2[2] += out[2];
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
sample_count++;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const pixel_address = ((max_y - y) * width + x) * 4;
|
|
429
|
+
|
|
430
|
+
target.data[pixel_address] = float2uint8(out2[0] / pixel_sample_count);
|
|
431
|
+
target.data[pixel_address + 1] = float2uint8(out2[1] / pixel_sample_count);
|
|
432
|
+
target.data[pixel_address + 2] = float2uint8(out2[2] / pixel_sample_count);
|
|
433
|
+
target.data[pixel_address + 3] = 255;
|
|
434
|
+
|
|
435
|
+
progress.current++;
|
|
436
|
+
|
|
437
|
+
yield;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
// console.profile('trace');
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
// console.profileEnd('trace');
|
|
449
|
+
|
|
450
|
+
const total_time = performance.now() - t0;
|
|
451
|
+
|
|
452
|
+
console.log(`Trace finished in ${prettyPrint(total_time)}ms. Total of ${prettyPrint(sample_count)} samples, ${prettyPrint(sample_count * 1000 / total_time)} samples per second`);
|
|
453
|
+
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const executor = new ConcurrentExecutor(1, 15);
|
|
457
|
+
|
|
458
|
+
const camera = new PerspectiveCamera();
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
*
|
|
462
|
+
* @param {THREE.Camera} camera
|
|
463
|
+
* @return {Promise<void>}
|
|
464
|
+
*/
|
|
465
|
+
async function start_renderer(camera) {
|
|
466
|
+
camera.aspect = vCanvas.size.x / vCanvas.size.y;
|
|
467
|
+
|
|
468
|
+
const path = 'data/models/LowPolyTownshipSet/Small_house/Small_house.gltf';
|
|
469
|
+
|
|
470
|
+
// await prepare_scene_lucy(pt, camera);
|
|
471
|
+
await prepare_scene_rtiow(pt, camera);
|
|
472
|
+
// await prepare_scene_sphere_01(pt, camera);
|
|
473
|
+
// await prepare_scene_gltf(pt, camera, path);
|
|
474
|
+
|
|
475
|
+
pt.build();
|
|
476
|
+
pt.optimize();
|
|
477
|
+
|
|
478
|
+
const pixelRatio = 1;
|
|
479
|
+
|
|
480
|
+
const rt = Sampler2D.uint8(4, vCanvas.size.x, vCanvas.size.y);
|
|
481
|
+
|
|
482
|
+
let scaled_rt = rt;
|
|
483
|
+
if (pixelRatio !== 1) {
|
|
484
|
+
scaled_rt = Sampler2D.uint8clamped(4, Math.ceil(rt.width * pixelRatio), Math.ceil(rt.height * pixelRatio));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function make_render_task() {
|
|
488
|
+
const progress_v = { current: 0, total: 0 };
|
|
489
|
+
|
|
490
|
+
const it = render(scaled_rt, pt, camera, progress_v);
|
|
491
|
+
|
|
492
|
+
return new Task({
|
|
493
|
+
name: 'render',
|
|
494
|
+
cycleFunction() {
|
|
495
|
+
const next = it.next();
|
|
496
|
+
|
|
497
|
+
if (!next.done) {
|
|
498
|
+
return TaskSignal.Continue;
|
|
499
|
+
} else {
|
|
500
|
+
return TaskSignal.EndSuccess;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
},
|
|
504
|
+
computeProgress() {
|
|
505
|
+
return progress_v.total > 0 ? progress_v.current / progress_v.total : 0;
|
|
506
|
+
}
|
|
507
|
+
})
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
const loc = new Localization();
|
|
512
|
+
|
|
513
|
+
async function update() {
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
const t = make_render_task();
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
const vProgress = new TaskProgressView({
|
|
520
|
+
task: t,
|
|
521
|
+
localization: loc
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
vProgress.size.set(vContainer.size.x, vContainer.size.y);
|
|
525
|
+
vProgress.css({
|
|
526
|
+
position: 'absolute',
|
|
527
|
+
top: 0,
|
|
528
|
+
left: 0,
|
|
529
|
+
pointerEvents: "none"
|
|
530
|
+
});
|
|
531
|
+
vProgress.el.querySelector('.fill').style.background = 'rgb(255,220,94)';
|
|
532
|
+
vProgress.el.querySelector('.progress-bar').style.height = '8px';
|
|
533
|
+
|
|
534
|
+
vContainer.addChild(vProgress);
|
|
535
|
+
|
|
536
|
+
const p_done = t.promise();
|
|
537
|
+
|
|
538
|
+
executor.run(t);
|
|
539
|
+
|
|
540
|
+
await p_done;
|
|
541
|
+
|
|
542
|
+
vContainer.removeChild(vProgress);
|
|
543
|
+
|
|
544
|
+
if (scaled_rt !== rt) {
|
|
545
|
+
scaleSampler2D(scaled_rt, rt);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
sampler2D2Canvas(rt, 1, 0, vCanvas.el);
|
|
549
|
+
|
|
550
|
+
requestAnimationFrame(update);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
update();
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
start_renderer(camera);
|
|
557
|
+
|
|
558
|
+
vCanvas.el.addEventListener(MouseEvents.Click, (evt) => {
|
|
559
|
+
const ray = [];
|
|
560
|
+
|
|
561
|
+
const ray_origin = new Vector3();
|
|
562
|
+
const ray_direction = new Vector3();
|
|
563
|
+
|
|
564
|
+
const pointer = getPointer(vCanvas.el, evt);
|
|
565
|
+
|
|
566
|
+
const _x = pointer.x;
|
|
567
|
+
const _y = pointer.y;
|
|
568
|
+
|
|
569
|
+
Camera.projectRay(camera,
|
|
570
|
+
_x,
|
|
571
|
+
_y,
|
|
572
|
+
ray_origin, ray_direction
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
ray3_array_compose(
|
|
576
|
+
ray,
|
|
577
|
+
ray_origin.x, ray_origin.y, ray_origin.z,
|
|
578
|
+
ray_direction.x, ray_direction.y, ray_direction.z
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const out = [];
|
|
582
|
+
|
|
583
|
+
pt.trace(out, ray, 0, Infinity);
|
|
584
|
+
|
|
585
|
+
console.log(pointer, out, ray, pt);
|
|
586
|
+
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
vCanvas.css({
|
|
590
|
+
pointerEvents: 'auto'
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
function getPointer(domElement, event) {
|
|
594
|
+
|
|
595
|
+
if (domElement.ownerDocument.pointerLockElement) {
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
x: 0,
|
|
599
|
+
y: 0,
|
|
600
|
+
button: event.button
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
} else {
|
|
604
|
+
|
|
605
|
+
const rect = domElement.getBoundingClientRect();
|
|
606
|
+
|
|
607
|
+
return {
|
|
608
|
+
x: (event.clientX - rect.left) / rect.width * 2 - 1,
|
|
609
|
+
y: -(event.clientY - rect.top) / rect.height * 2 + 1,
|
|
610
|
+
button: event.button
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// link
|
|
618
|
+
document.body.appendChild(vContainer.el);
|
|
619
|
+
vContainer.link();
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { v3_dot } from "../../../../core/geom/v3_dot.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {function} random
|
|
6
|
+
* @param {number[]} result
|
|
7
|
+
* @param {number} result_offset
|
|
8
|
+
* @param {number[]} normal
|
|
9
|
+
* @param {number} normal_offset
|
|
10
|
+
*/
|
|
11
|
+
export function random_in_hemisphere(random, result, result_offset, normal, normal_offset) {
|
|
12
|
+
const nx = normal[normal_offset + 0];
|
|
13
|
+
const ny = normal[normal_offset + 1];
|
|
14
|
+
const nz = normal[normal_offset + 2];
|
|
15
|
+
|
|
16
|
+
const phi = Math.PI * 2 * random();
|
|
17
|
+
|
|
18
|
+
const cosTheta = random() * 2 - 1;
|
|
19
|
+
|
|
20
|
+
const theta = Math.acos(cosTheta);
|
|
21
|
+
|
|
22
|
+
const sinTheta = Math.sin(theta);
|
|
23
|
+
|
|
24
|
+
//compute coordinates
|
|
25
|
+
const x = sinTheta * Math.cos(phi);
|
|
26
|
+
const y = sinTheta * Math.sin(phi);
|
|
27
|
+
const z = cosTheta;
|
|
28
|
+
|
|
29
|
+
if (v3_dot(x, y, z, nx, ny, nz) < 0) {
|
|
30
|
+
result[result_offset] = -x;
|
|
31
|
+
result[result_offset + 1] = -y;
|
|
32
|
+
result[result_offset + 2] = -z;
|
|
33
|
+
} else {
|
|
34
|
+
//write the result
|
|
35
|
+
result[result_offset] = x;
|
|
36
|
+
result[result_offset + 1] = y;
|
|
37
|
+
result[result_offset + 2] = z;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { v3_length } from "../../../../core/geom/v3_length.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number[]} output
|
|
6
|
+
* @param {number[]} hit
|
|
7
|
+
* @param {number[]} m 4x4 matrix
|
|
8
|
+
*/
|
|
9
|
+
export function ray_hit_apply_transform(output, hit, m) {
|
|
10
|
+
|
|
11
|
+
// transform position
|
|
12
|
+
const p_x = hit[0];
|
|
13
|
+
const p_y = hit[1];
|
|
14
|
+
const p_z = hit[2];
|
|
15
|
+
|
|
16
|
+
// compute perspective projection
|
|
17
|
+
const w = 1 / (m[3] * p_x + m[7] * p_y + m[11] * p_z + m[15]);
|
|
18
|
+
|
|
19
|
+
const result_p_x = (m[0] * p_x + m[4] * p_y + m[8] * p_z + m[12]) * w;
|
|
20
|
+
const result_p_y = (m[1] * p_x + m[5] * p_y + m[9] * p_z + m[13]) * w;
|
|
21
|
+
const result_p_z = (m[2] * p_x + m[6] * p_y + m[10] * p_z + m[14]) * w;
|
|
22
|
+
|
|
23
|
+
output[0] = result_p_x;
|
|
24
|
+
output[1] = result_p_y;
|
|
25
|
+
output[2] = result_p_z;
|
|
26
|
+
|
|
27
|
+
// transform normal
|
|
28
|
+
const n_x = hit[3];
|
|
29
|
+
const n_y = hit[4];
|
|
30
|
+
const n_z = hit[5];
|
|
31
|
+
|
|
32
|
+
const result_n_x = m[0] * n_x + m[4] * n_y + m[8] * n_z;
|
|
33
|
+
const result_n_y = m[1] * n_x + m[5] * n_y + m[9] * n_z;
|
|
34
|
+
const result_n_z = m[2] * n_x + m[6] * n_y + m[10] * n_z;
|
|
35
|
+
|
|
36
|
+
const normal_multiplier = 1 / v3_length(result_n_x, result_n_y, result_n_z);
|
|
37
|
+
|
|
38
|
+
output[3] = result_n_x * normal_multiplier;
|
|
39
|
+
output[4] = result_n_y * normal_multiplier;
|
|
40
|
+
output[5] = result_n_z * normal_multiplier;
|
|
41
|
+
|
|
42
|
+
}
|