@woosh/meep-engine 2.163.1 → 2.163.3
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/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +12 -0
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -0
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +18 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +14 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +24 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +368 -290
- package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts +11 -0
- package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_uniform_sample_cone.js +21 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts +13 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts.map +1 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.js +28 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.d.ts +18 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.d.ts.map +1 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.js +48 -0
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +52 -0
- package/src/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +306 -226
- package/src/engine/graphics/ecs/path/tube/build/make_cap.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/make_cap.js +26 -17
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts +26 -0
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.js +49 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts +26 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +70 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts +24 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.js +51 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts +9 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts.map +1 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.js +15 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts +44 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts.map +1 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js +189 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts +25 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts.map +1 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js +51 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts +15 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts.map +1 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js +63 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts +27 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts.map +1 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.js +323 -0
- package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
- package/src/engine/navigation/mesh/build/navmesh_build_topology.js +223 -226
- package/src/engine/.fuse_hidden0000001500000001 +0 -581
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataTexture,
|
|
3
|
+
EquirectangularReflectionMapping,
|
|
4
|
+
FloatType,
|
|
5
|
+
LinearFilter,
|
|
6
|
+
RGBAFormat
|
|
7
|
+
} from "three";
|
|
8
|
+
import { render_hosek_sky_to_equirectangular } from "./render_hosek_sky_to_equirectangular.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build an environment map from the Hosek sky model as a single equirectangular
|
|
12
|
+
* {@link DataTexture} (three.js' native sky representation,
|
|
13
|
+
* EquirectangularReflectionMapping).
|
|
14
|
+
*
|
|
15
|
+
* This returns the raw (sharp) sky; prefiltering for IBL is done by
|
|
16
|
+
* `GraphicsEngine.set_environment_texture`, which PMREMs it. The texture can be
|
|
17
|
+
* used directly as `scene.background`.
|
|
18
|
+
*
|
|
19
|
+
* @param {object} options
|
|
20
|
+
* @param {number[]|Float32Array} options.sun direction towards the sun (engine frame, +Y up); need not be unit length
|
|
21
|
+
* @param {number} [options.resolution=256] width of the equirectangular map; height is resolution/2
|
|
22
|
+
* @param {number} [options.turbidity=2] atmospheric turbidity, 1..10
|
|
23
|
+
* @param {number} [options.overcast=0] 0 = clear, 1 = fully overcast
|
|
24
|
+
* @param {number[]|Float32Array} [options.albedo=[0,0,0]] linear ground albedo
|
|
25
|
+
* @returns {THREE.DataTexture}
|
|
26
|
+
*/
|
|
27
|
+
export function make_environment_sky_hosek(
|
|
28
|
+
{
|
|
29
|
+
sun,
|
|
30
|
+
resolution = 256,
|
|
31
|
+
turbidity = 2,
|
|
32
|
+
overcast = 0,
|
|
33
|
+
albedo = [0, 0, 0]
|
|
34
|
+
}
|
|
35
|
+
) {
|
|
36
|
+
const width = Math.max(2, resolution | 0);
|
|
37
|
+
const height = Math.max(1, width >> 1);
|
|
38
|
+
|
|
39
|
+
const data = render_hosek_sky_to_equirectangular(sun, width, height, { turbidity, overcast, albedo });
|
|
40
|
+
|
|
41
|
+
const texture = new DataTexture(data, width, height, RGBAFormat, FloatType);
|
|
42
|
+
texture.mapping = EquirectangularReflectionMapping;
|
|
43
|
+
texture.magFilter = LinearFilter;
|
|
44
|
+
texture.minFilter = LinearFilter;
|
|
45
|
+
texture.generateMipmaps = false;
|
|
46
|
+
texture.needsUpdate = true;
|
|
47
|
+
|
|
48
|
+
return texture;
|
|
49
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render the Hosek sky into an equirectangular RGBA float buffer.
|
|
3
|
+
*
|
|
4
|
+
* The layout matches three.js' `equirectUv` (so the result can be used directly
|
|
5
|
+
* as an EquirectangularReflectionMapping texture or fed to PMREMGenerator):
|
|
6
|
+
* u = atan2(z, x) / (2pi) + 0.5
|
|
7
|
+
* v = asin(y) / pi + 0.5
|
|
8
|
+
* with +Y up, matching the engine convention.
|
|
9
|
+
*
|
|
10
|
+
* @param {number[]|Float32Array} sun direction towards the sun (engine frame, +Y up); need not be unit length
|
|
11
|
+
* @param {number} width number of horizontal (longitude) samples
|
|
12
|
+
* @param {number} height number of vertical (latitude) samples
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
* @param {number} [options.turbidity=2] atmospheric turbidity, 1..10
|
|
15
|
+
* @param {number} [options.overcast=0] 0 = clear, 1 = fully overcast
|
|
16
|
+
* @param {number[]|Float32Array} [options.albedo=[0,0,0]] linear ground albedo
|
|
17
|
+
* @param {Float32Array} [options.target] optional pre-allocated buffer of length width*height*4
|
|
18
|
+
* @returns {Float32Array} RGBA, row 0 = bottom (-Y), length width*height*4
|
|
19
|
+
*/
|
|
20
|
+
export function render_hosek_sky_to_equirectangular(sun: number[] | Float32Array, width: number, height: number, options?: {
|
|
21
|
+
turbidity?: number;
|
|
22
|
+
overcast?: number;
|
|
23
|
+
albedo?: number[] | Float32Array;
|
|
24
|
+
target?: Float32Array;
|
|
25
|
+
}): Float32Array;
|
|
26
|
+
//# sourceMappingURL=render_hosek_sky_to_equirectangular.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render_hosek_sky_to_equirectangular.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AACH,yDAVW,MAAM,EAAE,GAAC,YAAY,SACrB,MAAM,UACN,MAAM;IAEW,SAAS,GAA1B,MAAM;IACW,QAAQ,GAAzB,MAAM;IAC0B,MAAM,GAAtC,MAAM,EAAE,GAAC,YAAY;IACE,MAAM,GAA7B,YAAY;IACV,YAAY,CAgDxB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { make_sky_hosek } from "../../path_tracer/make_sky_hosek.js";
|
|
2
|
+
|
|
3
|
+
const TWO_PI = Math.PI * 2;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Render the Hosek sky into an equirectangular RGBA float buffer.
|
|
7
|
+
*
|
|
8
|
+
* The layout matches three.js' `equirectUv` (so the result can be used directly
|
|
9
|
+
* as an EquirectangularReflectionMapping texture or fed to PMREMGenerator):
|
|
10
|
+
* u = atan2(z, x) / (2pi) + 0.5
|
|
11
|
+
* v = asin(y) / pi + 0.5
|
|
12
|
+
* with +Y up, matching the engine convention.
|
|
13
|
+
*
|
|
14
|
+
* @param {number[]|Float32Array} sun direction towards the sun (engine frame, +Y up); need not be unit length
|
|
15
|
+
* @param {number} width number of horizontal (longitude) samples
|
|
16
|
+
* @param {number} height number of vertical (latitude) samples
|
|
17
|
+
* @param {object} [options]
|
|
18
|
+
* @param {number} [options.turbidity=2] atmospheric turbidity, 1..10
|
|
19
|
+
* @param {number} [options.overcast=0] 0 = clear, 1 = fully overcast
|
|
20
|
+
* @param {number[]|Float32Array} [options.albedo=[0,0,0]] linear ground albedo
|
|
21
|
+
* @param {Float32Array} [options.target] optional pre-allocated buffer of length width*height*4
|
|
22
|
+
* @returns {Float32Array} RGBA, row 0 = bottom (-Y), length width*height*4
|
|
23
|
+
*/
|
|
24
|
+
export function render_hosek_sky_to_equirectangular(sun, width, height, options = {}) {
|
|
25
|
+
const {
|
|
26
|
+
turbidity = 2,
|
|
27
|
+
overcast = 0,
|
|
28
|
+
albedo = [0, 0, 0],
|
|
29
|
+
target
|
|
30
|
+
} = options;
|
|
31
|
+
|
|
32
|
+
const sky = make_sky_hosek(sun, turbidity, overcast, albedo);
|
|
33
|
+
|
|
34
|
+
const data = target !== undefined ? target : new Float32Array(width * height * 4);
|
|
35
|
+
|
|
36
|
+
const direction = [0, 0, 0];
|
|
37
|
+
|
|
38
|
+
let p = 0;
|
|
39
|
+
|
|
40
|
+
for (let j = 0; j < height; j++) {
|
|
41
|
+
const v = (j + 0.5) / height;
|
|
42
|
+
|
|
43
|
+
// v = asin(y)/pi + 0.5 => y = sin((v - 0.5) * pi)
|
|
44
|
+
const latitude = (v - 0.5) * Math.PI;
|
|
45
|
+
const y = Math.sin(latitude);
|
|
46
|
+
const cos_latitude = Math.cos(latitude);
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < width; i++) {
|
|
49
|
+
const u = (i + 0.5) / width;
|
|
50
|
+
|
|
51
|
+
// u = atan2(z, x)/(2pi) + 0.5 => atan2(z, x) = (u - 0.5) * 2pi
|
|
52
|
+
const longitude = (u - 0.5) * TWO_PI;
|
|
53
|
+
|
|
54
|
+
direction[0] = cos_latitude * Math.cos(longitude);
|
|
55
|
+
direction[1] = y;
|
|
56
|
+
direction[2] = cos_latitude * Math.sin(longitude);
|
|
57
|
+
|
|
58
|
+
const offset = p * 4;
|
|
59
|
+
|
|
60
|
+
// writes linear RGB into data[offset .. offset + 2]
|
|
61
|
+
sky(data, offset, direction, 0);
|
|
62
|
+
|
|
63
|
+
data[offset + 3] = 1;
|
|
64
|
+
|
|
65
|
+
p++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a Hosek sky environment and apply it to a graphics scene, deriving the
|
|
3
|
+
* sun direction from the dataset's directional light.
|
|
4
|
+
*
|
|
5
|
+
* Delegates to {@link GraphicsEngine#set_environment_texture}, which PMREMs the
|
|
6
|
+
* equirectangular sky and assigns it as both the IBL source
|
|
7
|
+
* (`scene.environment`) and the skybox (`scene.background`).
|
|
8
|
+
*
|
|
9
|
+
* @param {GraphicsEngine} graphics
|
|
10
|
+
* @param {EntityComponentDataset} ecd source of the {@link DirectionalLight} that defines the sun
|
|
11
|
+
* @param {object} [options]
|
|
12
|
+
* @param {number} [options.resolution=256] width of the equirectangular map; height is resolution/2
|
|
13
|
+
* @param {number} [options.turbidity=2] atmospheric turbidity, 1..10
|
|
14
|
+
* @param {number} [options.overcast=0] 0 = clear, 1 = fully overcast
|
|
15
|
+
* @param {number[]|Float32Array} [options.albedo=[0,0,0]] linear ground albedo
|
|
16
|
+
* @returns {THREE.DataTexture} the equirectangular sky texture that was applied
|
|
17
|
+
*/
|
|
18
|
+
export function setup_environment_sky_from_ecd(graphics: GraphicsEngine, ecd: EntityComponentDataset, options?: {
|
|
19
|
+
resolution?: number;
|
|
20
|
+
turbidity?: number;
|
|
21
|
+
overcast?: number;
|
|
22
|
+
albedo?: number[] | Float32Array;
|
|
23
|
+
}): THREE.DataTexture;
|
|
24
|
+
//# sourceMappingURL=setup_environment_sky_from_ecd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup_environment_sky_from_ecd.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AACH;IAN4B,UAAU,GAA3B,MAAM;IACW,SAAS,GAA1B,MAAM;IACW,QAAQ,GAAzB,MAAM;IAC0B,MAAM,GAAtC,MAAM,EAAE,GAAC,YAAY;IACnB,MAAM,WAAW,CA+B7B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DirectionalLight } from "../../../render/forward_plus/model/DirectionalLight.js";
|
|
2
|
+
import { EnvironmentTextureProjection } from "../../../texture/EnvironmentTextureProjection.js";
|
|
3
|
+
import { make_environment_sky_hosek } from "./make_environment_sky_hosek.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a Hosek sky environment and apply it to a graphics scene, deriving the
|
|
7
|
+
* sun direction from the dataset's directional light.
|
|
8
|
+
*
|
|
9
|
+
* Delegates to {@link GraphicsEngine#set_environment_texture}, which PMREMs the
|
|
10
|
+
* equirectangular sky and assigns it as both the IBL source
|
|
11
|
+
* (`scene.environment`) and the skybox (`scene.background`).
|
|
12
|
+
*
|
|
13
|
+
* @param {GraphicsEngine} graphics
|
|
14
|
+
* @param {EntityComponentDataset} ecd source of the {@link DirectionalLight} that defines the sun
|
|
15
|
+
* @param {object} [options]
|
|
16
|
+
* @param {number} [options.resolution=256] width of the equirectangular map; height is resolution/2
|
|
17
|
+
* @param {number} [options.turbidity=2] atmospheric turbidity, 1..10
|
|
18
|
+
* @param {number} [options.overcast=0] 0 = clear, 1 = fully overcast
|
|
19
|
+
* @param {number[]|Float32Array} [options.albedo=[0,0,0]] linear ground albedo
|
|
20
|
+
* @returns {THREE.DataTexture} the equirectangular sky texture that was applied
|
|
21
|
+
*/
|
|
22
|
+
export function setup_environment_sky_from_ecd(graphics, ecd, options = {}) {
|
|
23
|
+
const {
|
|
24
|
+
resolution = 256,
|
|
25
|
+
turbidity = 2,
|
|
26
|
+
overcast = 0,
|
|
27
|
+
albedo = [0, 0, 0]
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
const { component: light } = ecd.getAnyComponent(DirectionalLight);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Direction *towards* the sun = negated light travel direction.
|
|
34
|
+
* Falls back to an overhead sun when the dataset has no directional light.
|
|
35
|
+
* @type {number[]}
|
|
36
|
+
*/
|
|
37
|
+
let sun;
|
|
38
|
+
|
|
39
|
+
if (light !== null) {
|
|
40
|
+
const d = light.direction;
|
|
41
|
+
sun = [-d.x, -d.y, -d.z];
|
|
42
|
+
} else {
|
|
43
|
+
sun = [0, 1, 0];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const texture = make_environment_sky_hosek({ sun, resolution, turbidity, overcast, albedo });
|
|
47
|
+
|
|
48
|
+
graphics.set_environment_texture(texture, EnvironmentTextureProjection.Equirectangular);
|
|
49
|
+
|
|
50
|
+
return texture;
|
|
51
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How an environment-map texture is projected onto the sphere.
|
|
3
|
+
*/
|
|
4
|
+
export type EnvironmentTextureProjection = number;
|
|
5
|
+
export namespace EnvironmentTextureProjection {
|
|
6
|
+
let Equirectangular: number;
|
|
7
|
+
let Cube: number;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=EnvironmentTextureProjection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvironmentTextureProjection.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics/texture/EnvironmentTextureProjection.js"],"names":[],"mappings":";;;2CAEU,MAAM"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How an environment-map texture is projected onto the sphere.
|
|
3
|
+
* @enum {number}
|
|
4
|
+
*/
|
|
5
|
+
export const EnvironmentTextureProjection = {
|
|
6
|
+
/**
|
|
7
|
+
* Lat-long / equirectangular projection. This is the default and the
|
|
8
|
+
* representation three.js uses for sky textures.
|
|
9
|
+
*/
|
|
10
|
+
Equirectangular: 0,
|
|
11
|
+
/**
|
|
12
|
+
* Cube map (six faces packed as a CubeTexture).
|
|
13
|
+
*/
|
|
14
|
+
Cube: 1
|
|
15
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convolve an equirectangular radiance map for a single output direction,
|
|
3
|
+
* importance-sampling a cone around it with a spherical-gaussian GGX weight.
|
|
4
|
+
* This is the per-texel core of the prefilter (extracted for testing).
|
|
5
|
+
*
|
|
6
|
+
* @param {Sampler2D} input equirectangular radiance (the previous, sharper mip)
|
|
7
|
+
* @param {number} out_x output (reflection) direction, unit length, +Y up
|
|
8
|
+
* @param {number} out_y
|
|
9
|
+
* @param {number} out_z
|
|
10
|
+
* @param {number} roughness perceptual roughness for this convolution step
|
|
11
|
+
* @param {number} sample_count number of cone samples
|
|
12
|
+
* @param {number[]|Float32Array} result
|
|
13
|
+
* @param {number} [result_offset=0]
|
|
14
|
+
*/
|
|
15
|
+
export function convolve_equirectangular_reflection_direction(input: Sampler2D, out_x: number, out_y: number, out_z: number, roughness: number, sample_count: number, result: number[] | Float32Array, result_offset?: number): void;
|
|
16
|
+
/**
|
|
17
|
+
* Convolve a whole equirectangular level into `output`.
|
|
18
|
+
*
|
|
19
|
+
* @param {Sampler2D} input source radiance (previous mip)
|
|
20
|
+
* @param {Sampler2D} output destination (this mip)
|
|
21
|
+
* @param {number} roughness convolution roughness for this step
|
|
22
|
+
* @param {number} sample_count
|
|
23
|
+
*/
|
|
24
|
+
export function convolve_equirectangular_reflection_level(input: Sampler2D, output: Sampler2D, roughness: number, sample_count: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* Build a prefiltered reflection mip chain from a base equirectangular radiance
|
|
27
|
+
* map. Mip 0 is the (sharp) base; each subsequent mip is half resolution and
|
|
28
|
+
* convolved from the previous one, so roughness increases with mip level. This
|
|
29
|
+
* is the CPU replacement for THREE's PMREMGenerator, decoupled from three.js.
|
|
30
|
+
*
|
|
31
|
+
* @param {Sampler2D} base equirectangular RGBA radiance (mip 0)
|
|
32
|
+
* @param {object} [options]
|
|
33
|
+
* @param {number} [options.sample_count=32] cone samples per texel (the sky is low frequency)
|
|
34
|
+
* @param {number} [options.mip_levels] number of levels; defaults to the full chain
|
|
35
|
+
* @param {number} [options.max_roughness=0.7] roughness reached at the last mip
|
|
36
|
+
* @returns {Sampler2D[]} mip chain, index 0 = base
|
|
37
|
+
*/
|
|
38
|
+
export function build_equirectangular_reflection_mip_chain(base: Sampler2D, options?: {
|
|
39
|
+
sample_count?: number;
|
|
40
|
+
mip_levels?: number;
|
|
41
|
+
max_roughness?: number;
|
|
42
|
+
}): Sampler2D[];
|
|
43
|
+
import { Sampler2D } from "../sampler/Sampler2D.js";
|
|
44
|
+
//# sourceMappingURL=convolve_equirectangular_reflection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convolve_equirectangular_reflection.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;GAaG;AACH,qEATW,SAAS,SACT,MAAM,SACN,MAAM,SACN,MAAM,aACN,MAAM,gBACN,MAAM,UACN,MAAM,EAAE,GAAC,YAAY,kBACrB,MAAM,QAiEhB;AAED;;;;;;;GAOG;AACH,iEALW,SAAS,UACT,SAAS,aACT,MAAM,gBACN,MAAM,QA6BhB;AAED;;;;;;;;;;;;GAYG;AACH,iEAPW,SAAS;IAEQ,YAAY,GAA7B,MAAM;IACW,UAAU,GAA3B,MAAM;IACW,aAAa,GAA9B,MAAM;IACJ,SAAS,EAAE,CAoCvB;0BArLyB,yBAAyB"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { hammersley_sequence_2d } from "../../../../core/math/statistics/hammersley_sequence_2d.js";
|
|
2
|
+
import { v3_orthonormal_matrix_from_normal } from "../../../../core/geom/vec3/v3_orthonormal_matrix_from_normal.js";
|
|
3
|
+
import { v3_uniform_sample_cone } from "../../../../core/geom/vec3/v3_uniform_sample_cone.js";
|
|
4
|
+
import { reflection_sample_weight } from "../../../../core/math/physics/brdf/reflection_sample_weight.js";
|
|
5
|
+
import { cone_cosine_from_roughness } from "../../../../core/math/physics/brdf/cone_cosine_from_roughness.js";
|
|
6
|
+
import { equirectangular_uv_to_direction } from "../../../../core/geom/3d/equirectangular/equirectangular_uv_to_direction.js";
|
|
7
|
+
import { sampler2d_sample_equirectangular_direction } from "../sampler/sampler2d_sample_equirectangular_direction.js";
|
|
8
|
+
import { Sampler2D } from "../sampler/Sampler2D.js";
|
|
9
|
+
import {
|
|
10
|
+
equirectangular_reflection_lod_to_roughness,
|
|
11
|
+
roughness_from_relative_mip
|
|
12
|
+
} from "./equirectangular_reflection_roughness.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Below this we treat the surface as a perfect mirror.
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
18
|
+
const BSDF_ROUGHNESS_MINIMUM = 0.02;
|
|
19
|
+
|
|
20
|
+
// scratch state (single-threaded, non-reentrant)
|
|
21
|
+
const _basis = new Float32Array(9);
|
|
22
|
+
const _rand = [0, 0];
|
|
23
|
+
const _local = [0, 0, 0];
|
|
24
|
+
const _radiance = [0, 0, 0, 0];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convolve an equirectangular radiance map for a single output direction,
|
|
28
|
+
* importance-sampling a cone around it with a spherical-gaussian GGX weight.
|
|
29
|
+
* This is the per-texel core of the prefilter (extracted for testing).
|
|
30
|
+
*
|
|
31
|
+
* @param {Sampler2D} input equirectangular radiance (the previous, sharper mip)
|
|
32
|
+
* @param {number} out_x output (reflection) direction, unit length, +Y up
|
|
33
|
+
* @param {number} out_y
|
|
34
|
+
* @param {number} out_z
|
|
35
|
+
* @param {number} roughness perceptual roughness for this convolution step
|
|
36
|
+
* @param {number} sample_count number of cone samples
|
|
37
|
+
* @param {number[]|Float32Array} result
|
|
38
|
+
* @param {number} [result_offset=0]
|
|
39
|
+
*/
|
|
40
|
+
export function convolve_equirectangular_reflection_direction(
|
|
41
|
+
input,
|
|
42
|
+
out_x, out_y, out_z,
|
|
43
|
+
roughness,
|
|
44
|
+
sample_count,
|
|
45
|
+
result,
|
|
46
|
+
result_offset = 0
|
|
47
|
+
) {
|
|
48
|
+
const cone_cos = cone_cosine_from_roughness(roughness);
|
|
49
|
+
|
|
50
|
+
v3_orthonormal_matrix_from_normal(_basis, 0, out_x, out_y, out_z);
|
|
51
|
+
|
|
52
|
+
const t_x = _basis[0], t_y = _basis[1], t_z = _basis[2];
|
|
53
|
+
const b_x = _basis[3], b_y = _basis[4], b_z = _basis[5];
|
|
54
|
+
const n_x = _basis[6], n_y = _basis[7], n_z = _basis[8];
|
|
55
|
+
|
|
56
|
+
const itemSize = input.itemSize;
|
|
57
|
+
|
|
58
|
+
let weight_accum = 0;
|
|
59
|
+
let r0 = 0, r1 = 0, r2 = 0, r3 = 0;
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < sample_count; i++) {
|
|
62
|
+
hammersley_sequence_2d(_rand, 0, i, sample_count);
|
|
63
|
+
|
|
64
|
+
v3_uniform_sample_cone(_local, 0, _rand[0], _rand[1], cone_cos);
|
|
65
|
+
|
|
66
|
+
const lx = _local[0], ly = _local[1], lz = _local[2];
|
|
67
|
+
|
|
68
|
+
// world direction = lx * T + ly * B + lz * N
|
|
69
|
+
let in_x = lx * t_x + ly * b_x + lz * n_x;
|
|
70
|
+
let in_y = lx * t_y + ly * b_y + lz * n_y;
|
|
71
|
+
let in_z = lx * t_z + ly * b_z + lz * n_z;
|
|
72
|
+
|
|
73
|
+
const len = Math.sqrt(in_x * in_x + in_y * in_y + in_z * in_z);
|
|
74
|
+
if (len > 0) {
|
|
75
|
+
const inv_len = 1.0 / len;
|
|
76
|
+
in_x *= inv_len;
|
|
77
|
+
in_y *= inv_len;
|
|
78
|
+
in_z *= inv_len;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
sampler2d_sample_equirectangular_direction(input, in_x, in_y, in_z, _radiance, 0);
|
|
82
|
+
|
|
83
|
+
const weight = reflection_sample_weight(out_x, out_y, out_z, in_x, in_y, in_z, roughness);
|
|
84
|
+
|
|
85
|
+
r0 += _radiance[0] * weight;
|
|
86
|
+
r1 += _radiance[1] * weight;
|
|
87
|
+
r2 += _radiance[2] * weight;
|
|
88
|
+
if (itemSize > 3) {
|
|
89
|
+
r3 += _radiance[3] * weight;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
weight_accum += weight;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const inv = weight_accum === 0 ? 0 : 1.0 / weight_accum;
|
|
96
|
+
|
|
97
|
+
result[result_offset] = r0 * inv;
|
|
98
|
+
result[result_offset + 1] = r1 * inv;
|
|
99
|
+
result[result_offset + 2] = r2 * inv;
|
|
100
|
+
if (itemSize > 3) {
|
|
101
|
+
result[result_offset + 3] = r3 * inv;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Convolve a whole equirectangular level into `output`.
|
|
107
|
+
*
|
|
108
|
+
* @param {Sampler2D} input source radiance (previous mip)
|
|
109
|
+
* @param {Sampler2D} output destination (this mip)
|
|
110
|
+
* @param {number} roughness convolution roughness for this step
|
|
111
|
+
* @param {number} sample_count
|
|
112
|
+
*/
|
|
113
|
+
export function convolve_equirectangular_reflection_level(input, output, roughness, sample_count) {
|
|
114
|
+
const width = output.width;
|
|
115
|
+
const height = output.height;
|
|
116
|
+
|
|
117
|
+
const direction = [0, 0, 0];
|
|
118
|
+
const texel = new Float32Array(output.itemSize);
|
|
119
|
+
|
|
120
|
+
for (let j = 0; j < height; j++) {
|
|
121
|
+
const v = (j + 0.5) / height;
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < width; i++) {
|
|
124
|
+
const u = (i + 0.5) / width;
|
|
125
|
+
|
|
126
|
+
equirectangular_uv_to_direction(u, v, direction, 0);
|
|
127
|
+
|
|
128
|
+
convolve_equirectangular_reflection_direction(
|
|
129
|
+
input,
|
|
130
|
+
direction[0], direction[1], direction[2],
|
|
131
|
+
roughness,
|
|
132
|
+
sample_count,
|
|
133
|
+
texel,
|
|
134
|
+
0
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
output.write(i, j, texel);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build a prefiltered reflection mip chain from a base equirectangular radiance
|
|
144
|
+
* map. Mip 0 is the (sharp) base; each subsequent mip is half resolution and
|
|
145
|
+
* convolved from the previous one, so roughness increases with mip level. This
|
|
146
|
+
* is the CPU replacement for THREE's PMREMGenerator, decoupled from three.js.
|
|
147
|
+
*
|
|
148
|
+
* @param {Sampler2D} base equirectangular RGBA radiance (mip 0)
|
|
149
|
+
* @param {object} [options]
|
|
150
|
+
* @param {number} [options.sample_count=32] cone samples per texel (the sky is low frequency)
|
|
151
|
+
* @param {number} [options.mip_levels] number of levels; defaults to the full chain
|
|
152
|
+
* @param {number} [options.max_roughness=0.7] roughness reached at the last mip
|
|
153
|
+
* @returns {Sampler2D[]} mip chain, index 0 = base
|
|
154
|
+
*/
|
|
155
|
+
export function build_equirectangular_reflection_mip_chain(base, options = {}) {
|
|
156
|
+
const {
|
|
157
|
+
sample_count = 32,
|
|
158
|
+
mip_levels,
|
|
159
|
+
max_roughness = 0.7
|
|
160
|
+
} = options;
|
|
161
|
+
|
|
162
|
+
const full_levels = Math.floor(Math.log2(Math.max(1, Math.min(base.width, base.height)))) + 1;
|
|
163
|
+
const levels = mip_levels !== undefined ? Math.min(mip_levels, full_levels) : full_levels;
|
|
164
|
+
|
|
165
|
+
const mips = [base];
|
|
166
|
+
|
|
167
|
+
for (let i = 1; i < levels; i++) {
|
|
168
|
+
const previous = mips[i - 1];
|
|
169
|
+
|
|
170
|
+
const width = Math.max(1, previous.width >> 1);
|
|
171
|
+
const height = Math.max(1, previous.height >> 1);
|
|
172
|
+
|
|
173
|
+
const level = Sampler2D.float32(base.itemSize, width, height);
|
|
174
|
+
|
|
175
|
+
const prev_roughness = equirectangular_reflection_lod_to_roughness(i - 1, levels, max_roughness);
|
|
176
|
+
const curr_roughness = equirectangular_reflection_lod_to_roughness(i, levels, max_roughness);
|
|
177
|
+
|
|
178
|
+
const step_roughness = Math.max(
|
|
179
|
+
BSDF_ROUGHNESS_MINIMUM,
|
|
180
|
+
roughness_from_relative_mip(prev_roughness, curr_roughness)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
convolve_equirectangular_reflection_level(previous, level, step_roughness, sample_count);
|
|
184
|
+
|
|
185
|
+
mips.push(level);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return mips;
|
|
189
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roughness schedule for a prefiltered reflection mip chain, ported from the
|
|
3
|
+
* EEVEE "sphere probe" convolution (generalised to an arbitrary mip count).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Map a mip level to the perceptual roughness it represents.
|
|
7
|
+
*
|
|
8
|
+
* @param {number} lod mip level, 0 = sharpest
|
|
9
|
+
* @param {number} mip_levels total number of mip levels
|
|
10
|
+
* @param {number} [max_roughness=0.7] roughness reached at the last mip
|
|
11
|
+
* @returns {number}
|
|
12
|
+
*/
|
|
13
|
+
export function equirectangular_reflection_lod_to_roughness(lod: number, mip_levels: number, max_roughness?: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Given that the previous mip is already convolved to `prev_mip_roughness`,
|
|
16
|
+
* derive the additional roughness to apply when convolving it into the current
|
|
17
|
+
* mip, so the result matches `curr_mip_roughness`. Uses the gaussian
|
|
18
|
+
* convolution composition rule G(a) x G(b) = G(a+b).
|
|
19
|
+
*
|
|
20
|
+
* @param {number} prev_mip_roughness
|
|
21
|
+
* @param {number} curr_mip_roughness
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
export function roughness_from_relative_mip(prev_mip_roughness: number, curr_mip_roughness: number): number;
|
|
25
|
+
//# sourceMappingURL=equirectangular_reflection_roughness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"equirectangular_reflection_roughness.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AACH,iEALW,MAAM,cACN,MAAM,kBACN,MAAM,GACJ,MAAM,CAiBlB;AAED;;;;;;;;;GASG;AACH,gEAJW,MAAM,sBACN,MAAM,GACJ,MAAM,CAYlB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roughness schedule for a prefiltered reflection mip chain, ported from the
|
|
3
|
+
* EEVEE "sphere probe" convolution (generalised to an arbitrary mip count).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Map a mip level to the perceptual roughness it represents.
|
|
8
|
+
*
|
|
9
|
+
* @param {number} lod mip level, 0 = sharpest
|
|
10
|
+
* @param {number} mip_levels total number of mip levels
|
|
11
|
+
* @param {number} [max_roughness=0.7] roughness reached at the last mip
|
|
12
|
+
* @returns {number}
|
|
13
|
+
*/
|
|
14
|
+
export function equirectangular_reflection_lod_to_roughness(lod, mip_levels, max_roughness = 0.7) {
|
|
15
|
+
const mip_ratio = mip_levels > 1 ? lod / (mip_levels - 1) : 0;
|
|
16
|
+
|
|
17
|
+
const a = mip_ratio;
|
|
18
|
+
const b = 0.6; // factor of ratio
|
|
19
|
+
const c = 0.4; // factor of ratio_sqrt
|
|
20
|
+
|
|
21
|
+
const b2 = b * b;
|
|
22
|
+
const c2 = c * c;
|
|
23
|
+
const c4 = c2 * c2;
|
|
24
|
+
|
|
25
|
+
// inverse of the roughness->lod mapping (a quadratic)
|
|
26
|
+
const ratio = (-Math.sqrt(4.0 * a * b * c2 + c4) + 2.0 * a * b + c2) / (2.0 * b2);
|
|
27
|
+
|
|
28
|
+
return ratio * max_roughness;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Given that the previous mip is already convolved to `prev_mip_roughness`,
|
|
33
|
+
* derive the additional roughness to apply when convolving it into the current
|
|
34
|
+
* mip, so the result matches `curr_mip_roughness`. Uses the gaussian
|
|
35
|
+
* convolution composition rule G(a) x G(b) = G(a+b).
|
|
36
|
+
*
|
|
37
|
+
* @param {number} prev_mip_roughness
|
|
38
|
+
* @param {number} curr_mip_roughness
|
|
39
|
+
* @returns {number}
|
|
40
|
+
*/
|
|
41
|
+
export function roughness_from_relative_mip(prev_mip_roughness, curr_mip_roughness) {
|
|
42
|
+
// the exponent should be 2 but 3 is a bit less blurry than expected in practice
|
|
43
|
+
const exponent = 3.0;
|
|
44
|
+
|
|
45
|
+
const m_prev = Math.pow(prev_mip_roughness, exponent);
|
|
46
|
+
const m_curr = Math.pow(curr_mip_roughness, exponent);
|
|
47
|
+
|
|
48
|
+
const m_target = Math.max(0.0, m_curr - m_prev);
|
|
49
|
+
|
|
50
|
+
return Math.pow(m_target, 1.0 / exponent);
|
|
51
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bilinearly sample a Sampler2D that holds an equirectangular image, by world
|
|
3
|
+
* direction (+Y up). The longitude axis (U) wraps and the latitude axis (V) is
|
|
4
|
+
* clamped, so there is no seam at longitude +/-pi (unlike Sampler2D's own
|
|
5
|
+
* bilinear sampling, which clamps both axes).
|
|
6
|
+
*
|
|
7
|
+
* @param {Sampler2D} sampler equirectangular source
|
|
8
|
+
* @param {number} dir_x
|
|
9
|
+
* @param {number} dir_y
|
|
10
|
+
* @param {number} dir_z
|
|
11
|
+
* @param {number[]|Float32Array} result
|
|
12
|
+
* @param {number} [result_offset=0]
|
|
13
|
+
*/
|
|
14
|
+
export function sampler2d_sample_equirectangular_direction(sampler: Sampler2D, dir_x: number, dir_y: number, dir_z: number, result: number[] | Float32Array, result_offset?: number): void;
|
|
15
|
+
//# sourceMappingURL=sampler2d_sample_equirectangular_direction.d.ts.map
|
package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler2d_sample_equirectangular_direction.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,sFANW,MAAM,SACN,MAAM,SACN,MAAM,UACN,MAAM,EAAE,GAAC,YAAY,kBACrB,MAAM,QA+ChB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { equirectangular_direction_to_uv } from "../../../../core/geom/3d/equirectangular/equirectangular_direction_to_uv.js";
|
|
2
|
+
|
|
3
|
+
const _uv = [0, 0];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bilinearly sample a Sampler2D that holds an equirectangular image, by world
|
|
7
|
+
* direction (+Y up). The longitude axis (U) wraps and the latitude axis (V) is
|
|
8
|
+
* clamped, so there is no seam at longitude +/-pi (unlike Sampler2D's own
|
|
9
|
+
* bilinear sampling, which clamps both axes).
|
|
10
|
+
*
|
|
11
|
+
* @param {Sampler2D} sampler equirectangular source
|
|
12
|
+
* @param {number} dir_x
|
|
13
|
+
* @param {number} dir_y
|
|
14
|
+
* @param {number} dir_z
|
|
15
|
+
* @param {number[]|Float32Array} result
|
|
16
|
+
* @param {number} [result_offset=0]
|
|
17
|
+
*/
|
|
18
|
+
export function sampler2d_sample_equirectangular_direction(sampler, dir_x, dir_y, dir_z, result, result_offset = 0) {
|
|
19
|
+
equirectangular_direction_to_uv(dir_x, dir_y, dir_z, _uv, 0);
|
|
20
|
+
|
|
21
|
+
const width = sampler.width;
|
|
22
|
+
const height = sampler.height;
|
|
23
|
+
const itemSize = sampler.itemSize;
|
|
24
|
+
const data = sampler.data;
|
|
25
|
+
|
|
26
|
+
// texel-space coordinates with texel centers at integer + 0.5
|
|
27
|
+
const fx = _uv[0] * width - 0.5;
|
|
28
|
+
const fy = _uv[1] * height - 0.5;
|
|
29
|
+
|
|
30
|
+
const x0i = Math.floor(fx);
|
|
31
|
+
const y0i = Math.floor(fy);
|
|
32
|
+
|
|
33
|
+
const tx = fx - x0i;
|
|
34
|
+
const ty = fy - y0i;
|
|
35
|
+
|
|
36
|
+
// longitude wraps, latitude clamps
|
|
37
|
+
const x0 = ((x0i % width) + width) % width;
|
|
38
|
+
const x1 = ((x0i + 1) % width + width) % width;
|
|
39
|
+
const y0 = y0i < 0 ? 0 : (y0i >= height ? height - 1 : y0i);
|
|
40
|
+
const y1i = y0i + 1;
|
|
41
|
+
const y1 = y1i < 0 ? 0 : (y1i >= height ? height - 1 : y1i);
|
|
42
|
+
|
|
43
|
+
const w00 = (1 - tx) * (1 - ty);
|
|
44
|
+
const w10 = tx * (1 - ty);
|
|
45
|
+
const w01 = (1 - tx) * ty;
|
|
46
|
+
const w11 = tx * ty;
|
|
47
|
+
|
|
48
|
+
const row0 = y0 * width;
|
|
49
|
+
const row1 = y1 * width;
|
|
50
|
+
|
|
51
|
+
const o00 = (row0 + x0) * itemSize;
|
|
52
|
+
const o10 = (row0 + x1) * itemSize;
|
|
53
|
+
const o01 = (row1 + x0) * itemSize;
|
|
54
|
+
const o11 = (row1 + x1) * itemSize;
|
|
55
|
+
|
|
56
|
+
for (let c = 0; c < itemSize; c++) {
|
|
57
|
+
result[result_offset + c] =
|
|
58
|
+
data[o00 + c] * w00 +
|
|
59
|
+
data[o10 + c] * w10 +
|
|
60
|
+
data[o01 + c] * w01 +
|
|
61
|
+
data[o11 + c] * w11;
|
|
62
|
+
}
|
|
63
|
+
}
|