@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,469 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExplicitBinaryBoundingVolumeHierarchy
|
|
3
|
+
} from "../../../../core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js";
|
|
4
|
+
import { bvh_query_leaves_ray } from "../../../../core/bvh2/bvh3/bvh_query_leaves_ray.js";
|
|
5
|
+
import { aabb3_matrix4_project } from "../../../../core/geom/3d/aabb/aabb3_matrix4_project.js";
|
|
6
|
+
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
7
|
+
import { mat4, vec3 } from "gl-matrix";
|
|
8
|
+
import { ensureGeometryBoundingBox } from "../../util/ensureGeometryBoundingBox.js";
|
|
9
|
+
import { GeometryBVHBatched } from "./GeometryBVHBatched.js";
|
|
10
|
+
import { PathTracedMesh } from "./PathTracedMesh.js";
|
|
11
|
+
import { TextureAttachmentsByMaterialType } from "../../../asset/loaders/material/TextureAttachmensByMaterialType.js";
|
|
12
|
+
import { convertTexture2Sampler2D } from "../../texture/sampler/convertTexture2Sampler2D.js";
|
|
13
|
+
import {
|
|
14
|
+
LinearEncoding,
|
|
15
|
+
LinearFilter,
|
|
16
|
+
LinearMipmapLinearFilter,
|
|
17
|
+
NearestFilter,
|
|
18
|
+
NearestMipMapLinearFilter,
|
|
19
|
+
sRGBEncoding,
|
|
20
|
+
UnsignedByteType
|
|
21
|
+
} from "three";
|
|
22
|
+
import { linear_to_sRGB } from "../../../../core/color/linear_to_sRGB.js";
|
|
23
|
+
import { random_in_hemisphere } from "./random_in_hemisphere.js";
|
|
24
|
+
import { sample_triangle_attribute } from "./sample_triangle_attribute.js";
|
|
25
|
+
import { vec3_uint8_to_float } from "./vec3_uint8_to_float.js";
|
|
26
|
+
import { make_sky_rtiw } from "./make_sky_rtiw.js";
|
|
27
|
+
import { apply_texture_clamping_to_coordinate } from "./apply_texture_clamping_to_coordinate.js";
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
Ray hit data layout:
|
|
31
|
+
position: v3
|
|
32
|
+
normal: v3
|
|
33
|
+
t: float
|
|
34
|
+
u: float
|
|
35
|
+
v: float
|
|
36
|
+
primitive_index: uint
|
|
37
|
+
instance_id: uint
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const temp_ray_results = [];
|
|
41
|
+
|
|
42
|
+
const texture_uv = [0, 0];
|
|
43
|
+
const color = [];
|
|
44
|
+
|
|
45
|
+
const irradiance = [0, 0, 0];
|
|
46
|
+
const trace_result = [];
|
|
47
|
+
|
|
48
|
+
const _ray = [];
|
|
49
|
+
|
|
50
|
+
const tmp = [];
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export class PathTracer {
|
|
54
|
+
constructor() {
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @type {ExplicitBinaryBoundingVolumeHierarchy}
|
|
59
|
+
*/
|
|
60
|
+
this.bvh_top_level = new ExplicitBinaryBoundingVolumeHierarchy();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @type {Map<number, PathTracedMesh>}
|
|
65
|
+
*/
|
|
66
|
+
this.meshes = new Map();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @type {Map<number, Light>}
|
|
71
|
+
*/
|
|
72
|
+
this.lights = new Map();
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @type {Map<THREE.BufferGeometry, GeometryBVHBatched>}
|
|
77
|
+
*/
|
|
78
|
+
this.geo_cache = new Map();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @type {Map<THREE.Texture, Sampler2D>}
|
|
83
|
+
*/
|
|
84
|
+
this.textures = new Map();
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @type {function}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
this.__background_sampler = make_sky_rtiw();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
*
|
|
96
|
+
* @param {THREE.BufferGeometry} geo
|
|
97
|
+
* @return {GeometryBVHBatched}
|
|
98
|
+
*/
|
|
99
|
+
obtainGeometryBVH(geo) {
|
|
100
|
+
const cached = this.geo_cache.get(geo);
|
|
101
|
+
|
|
102
|
+
if (cached !== undefined) {
|
|
103
|
+
return cached;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const bvh8 = new GeometryBVHBatched();
|
|
107
|
+
|
|
108
|
+
bvh8.build(geo);
|
|
109
|
+
|
|
110
|
+
this.geo_cache.set(geo, bvh8);
|
|
111
|
+
|
|
112
|
+
return bvh8;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
optimize() {
|
|
116
|
+
this.bvh_top_level.trim();
|
|
117
|
+
this.bvh_top_level.sort_for_traversal_depth_first();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async build() {
|
|
121
|
+
for (const [id, mesh] of this.meshes) {
|
|
122
|
+
const material = mesh.material;
|
|
123
|
+
|
|
124
|
+
//patch textures
|
|
125
|
+
const materialType = material.type;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
*
|
|
129
|
+
* @type {TextureAttachment[]}
|
|
130
|
+
*/
|
|
131
|
+
const attachments = TextureAttachmentsByMaterialType[materialType];
|
|
132
|
+
|
|
133
|
+
if (attachments === undefined) {
|
|
134
|
+
// unsupported
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
139
|
+
const attachment = attachments[i];
|
|
140
|
+
|
|
141
|
+
const texture = attachment.read(material);
|
|
142
|
+
|
|
143
|
+
if (texture === undefined || texture === null) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (this.textures.has(texture.id)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const sampler2D = convertTexture2Sampler2D(texture, undefined, undefined, false);
|
|
152
|
+
|
|
153
|
+
this.textures.set(texture.id, sampler2D);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
* @param {THREE.BufferGeometry} geo
|
|
161
|
+
* @param {THREE.Material} material
|
|
162
|
+
* @param {mat4|number[]} transform
|
|
163
|
+
*/
|
|
164
|
+
addMesh(geo, material, transform) {
|
|
165
|
+
//meshopt_optimizeVertexCache(geo.getIndex().array, geo.getIndex().array, geo.getIndex().array.length, geo.getAttribute('position').count);
|
|
166
|
+
|
|
167
|
+
const mesh = new PathTracedMesh();
|
|
168
|
+
mesh.geometry = geo;
|
|
169
|
+
mesh.material = material;
|
|
170
|
+
mesh.transform = transform;
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
mesh.geo_bvh = this.obtainGeometryBVH(geo);
|
|
174
|
+
|
|
175
|
+
const bvh = this.bvh_top_level;
|
|
176
|
+
|
|
177
|
+
const bvh_node_id = bvh.allocate_node();
|
|
178
|
+
|
|
179
|
+
mesh.__bvh_node_id = bvh_node_id;
|
|
180
|
+
|
|
181
|
+
ensureGeometryBoundingBox(geo);
|
|
182
|
+
|
|
183
|
+
const aabb = [
|
|
184
|
+
geo.boundingBox.min.x,
|
|
185
|
+
geo.boundingBox.min.y,
|
|
186
|
+
geo.boundingBox.min.z,
|
|
187
|
+
geo.boundingBox.max.x,
|
|
188
|
+
geo.boundingBox.max.y,
|
|
189
|
+
geo.boundingBox.max.z,
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
const aabb_t = [];
|
|
193
|
+
|
|
194
|
+
aabb3_matrix4_project(aabb_t, aabb, transform);
|
|
195
|
+
|
|
196
|
+
bvh.node_set_aabb(
|
|
197
|
+
bvh_node_id,
|
|
198
|
+
aabb_t
|
|
199
|
+
);
|
|
200
|
+
bvh.node_set_user_data(
|
|
201
|
+
bvh_node_id,
|
|
202
|
+
mesh.id
|
|
203
|
+
);
|
|
204
|
+
bvh.insert_leaf(bvh_node_id);
|
|
205
|
+
|
|
206
|
+
this.meshes.set(mesh.id, mesh);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
*
|
|
211
|
+
* @param {number[]} out
|
|
212
|
+
* @param {Texture} texture
|
|
213
|
+
* @param {number} u
|
|
214
|
+
* @param {number} v
|
|
215
|
+
*/
|
|
216
|
+
sample_texture(out, texture, u, v) {
|
|
217
|
+
if (texture === undefined || texture == null) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const sampler = this.textures.get(texture.id);
|
|
222
|
+
|
|
223
|
+
if (sampler === undefined) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// TODO apply texture matrix transform
|
|
228
|
+
|
|
229
|
+
const _u = apply_texture_clamping_to_coordinate(texture.wrapS, u);
|
|
230
|
+
const _v = apply_texture_clamping_to_coordinate(texture.wrapT, v);
|
|
231
|
+
|
|
232
|
+
const magFilter = texture.magFilter;
|
|
233
|
+
|
|
234
|
+
switch (magFilter) {
|
|
235
|
+
default:
|
|
236
|
+
case NearestFilter:
|
|
237
|
+
case NearestMipMapLinearFilter:
|
|
238
|
+
sampler.sampleNearestUV(_u, _v, out);
|
|
239
|
+
break;
|
|
240
|
+
|
|
241
|
+
case LinearFilter:
|
|
242
|
+
case LinearMipmapLinearFilter:
|
|
243
|
+
|
|
244
|
+
sampler.sampleBicubicUV(_u, _v, out);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (texture.type === UnsignedByteType) {
|
|
249
|
+
vec3_uint8_to_float(out, out);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const texture_encoding = texture.encoding;
|
|
253
|
+
|
|
254
|
+
if (texture_encoding === LinearEncoding) {
|
|
255
|
+
// nothing
|
|
256
|
+
} else if (texture_encoding === sRGBEncoding) {
|
|
257
|
+
// convert value to sRGB
|
|
258
|
+
linear_to_sRGB(out, 0, out, 0);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
*
|
|
265
|
+
* @param {number[]} out
|
|
266
|
+
* @param {number[]} hit
|
|
267
|
+
*/
|
|
268
|
+
sample_material(out, hit) {
|
|
269
|
+
const primitive_id = hit[9];
|
|
270
|
+
const instance_id = hit[10];
|
|
271
|
+
const u = hit[7];
|
|
272
|
+
const v = hit[8];
|
|
273
|
+
|
|
274
|
+
out[0] = 1;
|
|
275
|
+
out[1] = 1;
|
|
276
|
+
out[2] = 1;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
*
|
|
280
|
+
* @type {PathTracedMesh}
|
|
281
|
+
*/
|
|
282
|
+
const mesh = this.meshes.get(instance_id);
|
|
283
|
+
|
|
284
|
+
if (mesh === undefined) {
|
|
285
|
+
// instance not found
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const geometry = mesh.geometry;
|
|
290
|
+
const index_attribute = geometry.getIndex();
|
|
291
|
+
const index_array = index_attribute.array;
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
// sample surface normal
|
|
295
|
+
const index_offset = primitive_id * 3;
|
|
296
|
+
|
|
297
|
+
const index_0 = index_array[index_offset];
|
|
298
|
+
const index_1 = index_array[index_offset + 1];
|
|
299
|
+
const index_2 = index_array[index_offset + 2];
|
|
300
|
+
|
|
301
|
+
const normal_attribute = geometry.getAttribute('normal');
|
|
302
|
+
|
|
303
|
+
if (normal_attribute !== undefined) {
|
|
304
|
+
// vertex normals are present, use those
|
|
305
|
+
const normal_array = normal_attribute.array;
|
|
306
|
+
|
|
307
|
+
sample_triangle_attribute(out, 3, index_0, index_1, index_2, normal_array, 3, u, v);
|
|
308
|
+
} else {
|
|
309
|
+
// copy hit normal
|
|
310
|
+
array_copy(hit, 3, out, 3, 3);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
const uv_attribute = geometry.getAttribute('uv');
|
|
315
|
+
|
|
316
|
+
if (uv_attribute !== undefined) {
|
|
317
|
+
const uv_array = uv_attribute.array;
|
|
318
|
+
sample_triangle_attribute(texture_uv, 0, index_0, index_1, index_2, uv_array, 2, u, v);
|
|
319
|
+
} else {
|
|
320
|
+
// default texture uv
|
|
321
|
+
texture_uv[0] = 0;
|
|
322
|
+
texture_uv[1] = 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const material = mesh.material;
|
|
326
|
+
|
|
327
|
+
if (material.isMeshStandardMaterial) {
|
|
328
|
+
out[0] *= material.color.r;
|
|
329
|
+
out[1] *= material.color.g;
|
|
330
|
+
out[2] *= material.color.b;
|
|
331
|
+
|
|
332
|
+
const diffuse_map = material.map;
|
|
333
|
+
|
|
334
|
+
if (diffuse_map !== null) {
|
|
335
|
+
this.sample_texture(color, diffuse_map, texture_uv[0], texture_uv[1]);
|
|
336
|
+
|
|
337
|
+
vec3.multiply(out, out, color);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
} else {
|
|
341
|
+
// unsupported
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
*
|
|
348
|
+
* @param {number[]} out
|
|
349
|
+
* @param {number[]} ray
|
|
350
|
+
* @param {number} min_distance
|
|
351
|
+
* @param {number} max_distance
|
|
352
|
+
* @return {number}
|
|
353
|
+
*/
|
|
354
|
+
trace(out, ray, min_distance, max_distance) {
|
|
355
|
+
const bvh = this.bvh_top_level;
|
|
356
|
+
const hit_count = bvh_query_leaves_ray(bvh, temp_ray_results, 0, ray[0], ray[1], ray[2], ray[3], ray[4], ray[5]);
|
|
357
|
+
|
|
358
|
+
let nearest_hit_distance = max_distance;
|
|
359
|
+
let nearest_mesh = null;
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
for (let i = 0; i < hit_count; i++) {
|
|
363
|
+
const node_id = temp_ray_results[i];
|
|
364
|
+
|
|
365
|
+
const node_user_data = bvh.node_get_user_data(node_id);
|
|
366
|
+
|
|
367
|
+
const mesh = this.meshes.get(node_user_data);
|
|
368
|
+
|
|
369
|
+
const distance_to_hit = mesh.hit(tmp, ray, min_distance, nearest_hit_distance);
|
|
370
|
+
|
|
371
|
+
if (distance_to_hit >= 0) {
|
|
372
|
+
// since raycast in leaf nodes is already bound by maximum distance, any hit we get is necessarily a closer hit than before
|
|
373
|
+
nearest_hit_distance = distance_to_hit;
|
|
374
|
+
nearest_mesh = mesh;
|
|
375
|
+
|
|
376
|
+
array_copy(tmp, 0, out, 0, 11);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (nearest_hit_distance !== max_distance) {
|
|
381
|
+
|
|
382
|
+
// out[6] = nearest_mesh;
|
|
383
|
+
|
|
384
|
+
return nearest_hit_distance;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return -1;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
*
|
|
392
|
+
* @param {number[]} out
|
|
393
|
+
* @param {number} out_offset
|
|
394
|
+
* @param {number[]} direction
|
|
395
|
+
* @param {number} direction_offset
|
|
396
|
+
*/
|
|
397
|
+
sample_background(out, out_offset, direction, direction_offset) {
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
this.__background_sampler(out, out_offset, direction, direction_offset);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
path_trace(out, ray, max_distance, max_bounce, random = Math.random) {
|
|
404
|
+
//TODO add importance sampling, see https://raytracing.github.io/books/RayTracingTheRestOfYourLife.html#lightscattering/thescatteringpdf
|
|
405
|
+
|
|
406
|
+
array_copy(ray, 0, _ray, 0, 6);
|
|
407
|
+
|
|
408
|
+
irradiance[0] = 1;
|
|
409
|
+
irradiance[1] = 1;
|
|
410
|
+
irradiance[2] = 1;
|
|
411
|
+
|
|
412
|
+
let got_emission = false;
|
|
413
|
+
|
|
414
|
+
let i;
|
|
415
|
+
for (i = 0; i < max_bounce; i++) {
|
|
416
|
+
|
|
417
|
+
const hit_distance = this.trace(trace_result, _ray, 0.0001, max_distance);
|
|
418
|
+
|
|
419
|
+
if (hit_distance < 0) {
|
|
420
|
+
// ray didn't hit anything
|
|
421
|
+
|
|
422
|
+
// sample "environment" and terminate path as there is nothing to reflect off of
|
|
423
|
+
|
|
424
|
+
this.sample_background(tmp, 0, _ray, 3);
|
|
425
|
+
|
|
426
|
+
vec3.multiply(irradiance, irradiance, tmp);
|
|
427
|
+
|
|
428
|
+
got_emission = true;
|
|
429
|
+
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
// irradiance[0] += m;
|
|
435
|
+
// irradiance[1] += m;
|
|
436
|
+
// irradiance[2] += m;
|
|
437
|
+
this.sample_material(tmp, trace_result);
|
|
438
|
+
|
|
439
|
+
// reflect ray
|
|
440
|
+
array_copy(trace_result, 0, _ray, 0, 3);
|
|
441
|
+
|
|
442
|
+
// getBiasedNormalSample(_ray, 3, tmp, 3, 1, random);
|
|
443
|
+
random_in_hemisphere(random, _ray, 3, tmp, 3);
|
|
444
|
+
|
|
445
|
+
vec3.multiply(irradiance, irradiance, tmp);
|
|
446
|
+
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (got_emission === false) {
|
|
450
|
+
// no light source was hit, propagate shadow(darkness) along the ray
|
|
451
|
+
irradiance[0] = 0;
|
|
452
|
+
irradiance[1] = 0;
|
|
453
|
+
irradiance[2] = 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
array_copy(irradiance, 0, out, 0, 3);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
*
|
|
462
|
+
* @param {number} material
|
|
463
|
+
* @param {number} hit
|
|
464
|
+
*/
|
|
465
|
+
function compute_hit_reaction_standard_material(material, hit) {
|
|
466
|
+
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ClampToEdgeWrapping, RepeatWrapping } from "three";
|
|
2
|
+
import { clamp01 } from "../../../../core/math/clamp01.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {number} clamping
|
|
7
|
+
* @param {number} v
|
|
8
|
+
* @return {number}
|
|
9
|
+
*/
|
|
10
|
+
export function apply_texture_clamping_to_coordinate(clamping, v) {
|
|
11
|
+
|
|
12
|
+
switch (clamping) {
|
|
13
|
+
case RepeatWrapping:
|
|
14
|
+
return v % 1;
|
|
15
|
+
case ClampToEdgeWrapping:
|
|
16
|
+
return clamp01(v);
|
|
17
|
+
default:
|
|
18
|
+
// unsupported?
|
|
19
|
+
return v;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { min2 } from "../../../../core/math/min2.js";
|
|
2
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compute AABB for a group of triangles based on index-buffer
|
|
6
|
+
* @param {number[]} output
|
|
7
|
+
* @param {number} output_offset
|
|
8
|
+
* @param {number[]|ArrayLike<number>} indices
|
|
9
|
+
* @param {number[]|ArrayLike<number>} positions
|
|
10
|
+
* @param {number} index_offset
|
|
11
|
+
* @param {number} index_count
|
|
12
|
+
* @param {number} d
|
|
13
|
+
*/
|
|
14
|
+
export function compute_triangle_group_aabb3(output, output_offset, indices, positions, index_offset, index_count, d) {
|
|
15
|
+
|
|
16
|
+
let i = 0;
|
|
17
|
+
for (; i < d; i++) {
|
|
18
|
+
output[output_offset + i] = Infinity;
|
|
19
|
+
output[output_offset + i + d] = -Infinity;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (i = 0; i < index_count; i++) {
|
|
23
|
+
for (let j = 0; j < 3; j++) {
|
|
24
|
+
const index = indices[index_offset + i * 3 + j];
|
|
25
|
+
|
|
26
|
+
const i3 = index * d;
|
|
27
|
+
|
|
28
|
+
for (let k = 0; k < d; k++) {
|
|
29
|
+
const v = positions[i3 + k];
|
|
30
|
+
|
|
31
|
+
output[output_offset + k] = min2(output[output_offset + k], v);
|
|
32
|
+
output[output_offset + k + d] = max2(output[output_offset + k + d], v);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see 2003 "Global Illumination Compendium" by Philip Dutré (equation 36)
|
|
3
|
+
* @see http://blog.hvidtfeldts.net/index.php/2015/01/path-tracing-3d-fractals/
|
|
4
|
+
* @param {number[]} out
|
|
5
|
+
* @param {number} out_offset
|
|
6
|
+
* @param {number[]} normal
|
|
7
|
+
* @param {number} normal_offset
|
|
8
|
+
* @param {number} power
|
|
9
|
+
* @param {function():number} random
|
|
10
|
+
*/
|
|
11
|
+
function getBiasedNormalSample(out, out_offset, normal, normal_offset, power, random) {
|
|
12
|
+
const dir_x = normal[normal_offset];
|
|
13
|
+
const dir_y = normal[normal_offset + 1];
|
|
14
|
+
const dir_z = normal[normal_offset + 2];
|
|
15
|
+
|
|
16
|
+
// we build orthonormal vectors with respect to the direction vector
|
|
17
|
+
let o1_x, o1_y, o1_z;
|
|
18
|
+
|
|
19
|
+
if (Math.abs(dir_x) > Math.abs(dir_z)) {
|
|
20
|
+
o1_x = -dir_y;
|
|
21
|
+
o1_y = dir_x;
|
|
22
|
+
o1_z = 0;
|
|
23
|
+
} else {
|
|
24
|
+
o1_x = 0;
|
|
25
|
+
o1_y = -dir_z;
|
|
26
|
+
o1_z = dir_y;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// normalize orthonormal vector
|
|
30
|
+
const o1_norm = 1 / Math.hypot(o1_x, o1_y, o1_z);
|
|
31
|
+
|
|
32
|
+
o1_x *= o1_norm;
|
|
33
|
+
o1_y *= o1_norm;
|
|
34
|
+
o1_z *= o1_norm;
|
|
35
|
+
|
|
36
|
+
const o2_x = dir_y * o1_z - dir_z * o1_y;
|
|
37
|
+
const o2_y = dir_z * o1_x - dir_x * o1_z;
|
|
38
|
+
const o2_z = dir_x * o1_y - dir_y * o1_x;
|
|
39
|
+
|
|
40
|
+
// we can skip normalizing second orthonormal vector, as it will be guaranteed to be unit length already
|
|
41
|
+
// for explanation, see https://math.stackexchange.com/questions/23259/is-the-cross-product-of-two-unit-vectors-itself-a-unit-vector#:~:text=If%20you%20know%20that%20the,(a%20length%20of%20one).
|
|
42
|
+
|
|
43
|
+
const r_x = (random()) * 2 * Math.PI;
|
|
44
|
+
const r_y = Math.pow((random()), 1 / (power + 1));
|
|
45
|
+
|
|
46
|
+
const oneminus = Math.sqrt(1.0 - r_y * r_y);
|
|
47
|
+
|
|
48
|
+
const k0 = Math.cos(r_x) * oneminus;
|
|
49
|
+
const k1 = Math.sin(r_x) * oneminus;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
out[out_offset] = k0 * o1_x + k1 * o2_x + r_y * dir_x;
|
|
53
|
+
out[out_offset + 1] = k0 * o1_y + k1 * o2_y + r_y * dir_y;
|
|
54
|
+
out[out_offset + 2] = k0 * o1_z + k1 * o2_z + r_y * dir_z;
|
|
55
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sky_hosek_compute_irradiance_by_direction,
|
|
3
|
+
sky_hosek_precompute
|
|
4
|
+
} from "../sky/hosek/sky_hosek_compute_irradiance_by_direction.js";
|
|
5
|
+
import { vec3 } from "gl-matrix";
|
|
6
|
+
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
7
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
8
|
+
|
|
9
|
+
export function make_sky_hosek(sun = [0, 1, 0], turbidity = 1, overcast = 0, albedo = [0, 0, 0]) {
|
|
10
|
+
const coeffs = new Float32Array(27);
|
|
11
|
+
const rad = new Float32Array([1, 1, 1]);
|
|
12
|
+
const sun_position = new Float32Array([sun[0], sun[2], sun[1]]);
|
|
13
|
+
|
|
14
|
+
vec3.normalize(sun_position, sun_position);
|
|
15
|
+
|
|
16
|
+
sky_hosek_precompute(coeffs, rad, sun_position, turbidity, albedo, overcast);
|
|
17
|
+
|
|
18
|
+
const v3 = [];
|
|
19
|
+
|
|
20
|
+
const value_scale = 8e-5;
|
|
21
|
+
|
|
22
|
+
return (result, result_offset, direction, direction_offset) => {
|
|
23
|
+
const d_x = direction[direction_offset];
|
|
24
|
+
const d_z = direction[direction_offset + 2];
|
|
25
|
+
const d_y = direction[direction_offset + 1];
|
|
26
|
+
|
|
27
|
+
sky_hosek_compute_irradiance_by_direction(
|
|
28
|
+
v3, coeffs, rad, sun_position,
|
|
29
|
+
d_z ,
|
|
30
|
+
d_x ,
|
|
31
|
+
d_y ,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
vec3.scale(v3, v3, value_scale);
|
|
35
|
+
|
|
36
|
+
// clamp sky contribution
|
|
37
|
+
v3[0] = max2(0, v3[0]);
|
|
38
|
+
v3[1] = max2(0, v3[1]);
|
|
39
|
+
v3[2] = max2(0, v3[2]);
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
array_copy(v3, 0, result, result_offset, 3);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { lerp } from "../../../../core/math/lerp.js";
|
|
2
|
+
|
|
3
|
+
export function make_sky_rtiw() {
|
|
4
|
+
// see https://raytracing.github.io/books/RayTracingInOneWeekend.html
|
|
5
|
+
|
|
6
|
+
return (out, out_offset, direction, direction_offset) => {
|
|
7
|
+
|
|
8
|
+
const dir_y = direction[direction_offset + 1];
|
|
9
|
+
const t = 0.5 * (dir_y + 1);
|
|
10
|
+
|
|
11
|
+
out[out_offset] = lerp(0.5, 1, t);
|
|
12
|
+
out[out_offset + 1] = lerp(0.7, 1, t);
|
|
13
|
+
out[out_offset + 2] = lerp(1, 1, t);
|
|
14
|
+
}
|
|
15
|
+
}
|