@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.
Files changed (53) hide show
  1. package/core/assert.js +3 -1
  2. package/core/bvh2/aabb3/aabb3_intersects_ray.js +14 -9
  3. package/core/bvh2/aabb3/aabb3_intersects_ray_branchless.js +52 -0
  4. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +2 -0
  5. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +214 -5
  6. package/core/bvh2/bvh3/bvh_query_leaves_ray.js +32 -29
  7. package/core/collection/array/typed/typed_array_copy.js +2 -2
  8. package/core/geom/3d/aabb/compute_aabb_from_points.js +4 -3
  9. package/core/geom/3d/compute_triangle_normal.js +76 -0
  10. package/core/geom/3d/topology/samples/sampleFloodFill.js +1 -1
  11. package/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +1 -1
  12. package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +1 -1
  13. package/core/geom/3d/topology/struct/TopoTriangle.js +1 -57
  14. package/core/geom/3d/topology/tm_face_normal.js +1 -1
  15. package/core/geom/3d/topology/tm_vertex_compute_normal.js +1 -1
  16. package/core/geom/3d/triangle/computeTriangleRayIntersection.js +195 -27
  17. package/core/geom/Vector3.js +12 -12
  18. package/core/math/physics/brdf/D_GGX.js +13 -0
  19. package/editor/tools/v2/prototypeTransformControls.js +14 -2
  20. package/engine/ecs/parent/EntityNode.js +80 -7
  21. package/engine/ecs/parent/EntityNodeFlags.js +8 -0
  22. package/engine/ecs/terrain/tiles/TerrainTile.js +7 -9
  23. package/engine/graphics/ecs/path/PathDisplaySystem.d.ts +3 -0
  24. package/engine/graphics/ecs/path/PathDisplaySystem.js +10 -0
  25. package/engine/graphics/geometry/AttributeSpec.js +18 -3
  26. package/engine/graphics/geometry/VertexDataSpec.js +53 -3
  27. package/engine/graphics/micron/format/VirtualGeometry.js +7 -0
  28. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +1 -1
  29. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +5 -2
  30. package/engine/graphics/particles/particular/engine/parameter/sample/RGBA_LUT_HEATMAP_IR.js +11 -0
  31. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -9
  32. package/engine/graphics/sh3/README.md +1 -0
  33. package/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +324 -0
  34. package/engine/graphics/sh3/path_tracer/PathTracedMesh.js +85 -0
  35. package/engine/graphics/sh3/path_tracer/PathTracer.js +469 -0
  36. package/engine/graphics/sh3/path_tracer/apply_texture_clamping_to_coordinate.js +22 -0
  37. package/engine/graphics/sh3/path_tracer/compute_triangle_group_aabb3.js +36 -0
  38. package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +55 -0
  39. package/engine/graphics/sh3/path_tracer/make_sky_hosek.js +44 -0
  40. package/engine/graphics/sh3/path_tracer/make_sky_rtiw.js +15 -0
  41. package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +619 -0
  42. package/engine/graphics/sh3/path_tracer/random_in_hemisphere.js +39 -0
  43. package/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +42 -0
  44. package/engine/graphics/sh3/path_tracer/ray_reflect.js +27 -0
  45. package/engine/graphics/sh3/path_tracer/sample_triangle_attribute.js +35 -0
  46. package/engine/graphics/sh3/path_tracer/vec3_uint8_to_float.js +12 -0
  47. package/engine/graphics/sh3/sky/hosek/README.md +4 -0
  48. package/engine/graphics/sh3/sky/hosek/prototype_hosek.js +71 -0
  49. package/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +4171 -0
  50. package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +2 -0
  51. package/package.json +1 -1
  52. package/view/elements/progress/SmoothProgressBar.js +1 -1
  53. 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
+ }