@woosh/meep-engine 3.18.0 → 3.19.0
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/build/bundle-worker-image-decoder.js +1 -1
- package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleCurveEditorView.js +303 -120
- package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleGradientEditorView.js +108 -63
- package/editor/view/particles/effect/ParticleGraphEditorView.js +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.js +3 -1
- package/editor/view/particles/effect/particle-editor.css +60 -30
- package/package.json +1 -2
- package/samples/engine/README.md +1 -1
- package/src/core/binary/compression/decompress_bytes.d.ts +13 -0
- package/src/core/binary/compression/decompress_bytes.d.ts.map +1 -0
- package/src/core/binary/compression/decompress_bytes.js +28 -0
- package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +67 -22
- package/src/engine/asset/loaders/image/ImageDecoderWorker.js +12 -27
- package/src/engine/asset/loaders/image/prototypePNG.js +8 -7
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +266 -0
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -0
- package/src/engine/graphics/ecs/particles/ParticleEffect.js +455 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +58 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +219 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +178 -25
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +809 -310
- package/src/format/image/png/PNGReader.d.ts +7 -6
- package/src/format/image/png/PNGReader.d.ts.map +1 -1
- package/src/format/image/png/PNGReader.js +13 -12
- package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts +3 -2
- package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -1
- package/src/format/image/png/chunk/png_chunk_decode_iTXt.js +5 -4
- package/src/format/image/png/chunk/png_chunk_decode_zTXt.d.ts +3 -2
- package/src/format/image/png/chunk/png_chunk_decode_zTXt.d.ts.map +1 -1
- package/src/format/image/png/chunk/png_chunk_decode_zTXt.js +5 -4
- package/src/format/image/png/png_inflate.d.ts +3 -3
- package/src/format/image/png/png_inflate.d.ts.map +1 -1
- package/src/format/image/png/png_inflate.js +29 -39
- package/src/format/texture/ktx2/ktx2_read.d.ts +4 -4
- package/src/format/texture/ktx2/ktx2_read.d.ts.map +1 -1
- package/src/format/texture/ktx2/ktx2_read.js +18 -21
- package/src/shade/playground/particle_ecs/README.md +203 -0
- package/src/shade/playground/particle_ecs/bonfire_editor.d.ts +39 -0
- package/src/shade/playground/particle_ecs/bonfire_editor.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/bonfire_editor.js +315 -0
- package/src/shade/playground/particle_ecs/bonfire_effects.d.ts +145 -0
- package/src/shade/playground/particle_ecs/bonfire_effects.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/bonfire_effects.js +202 -0
- package/src/shade/playground/particle_ecs/bonfire_sprites.d.ts +23 -0
- package/src/shade/playground/particle_ecs/bonfire_sprites.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/bonfire_sprites.js +315 -0
- package/src/shade/playground/particle_ecs/bonfire_world.d.ts +86 -0
- package/src/shade/playground/particle_ecs/bonfire_world.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/bonfire_world.js +303 -0
- package/src/shade/playground/particle_ecs/effects/embers.json +1634 -0
- package/src/shade/playground/particle_ecs/effects/flame.json +1882 -0
- package/src/shade/playground/particle_ecs/effects/smoke.json +1860 -0
- package/src/shade/playground/particle_ecs/effects/soot.json +1606 -0
- package/src/shade/playground/particle_ecs/index.html +330 -0
- package/src/shade/playground/particle_ecs/main.d.ts +2 -0
- package/src/shade/playground/particle_ecs/main.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/main.js +566 -0
- package/src/shade/playground/particle_ecs/moonlit_environment.d.ts +16 -0
- package/src/shade/playground/particle_ecs/moonlit_environment.d.ts.map +1 -0
- package/src/shade/playground/particle_ecs/moonlit_environment.js +144 -0
- package/src/shade/playground/particle_editor/README.md +5 -4
- package/src/shade/playground/profile_hotkey.d.ts +58 -0
- package/src/shade/playground/profile_hotkey.d.ts.map +1 -0
- package/src/shade/playground/profile_hotkey.js +325 -0
- package/src/shade/playground/ssr_variance/README.md +105 -0
- package/src/shade/playground/ssr_variance/capture.d.ts +16 -0
- package/src/shade/playground/ssr_variance/capture.d.ts.map +1 -0
- package/src/shade/playground/ssr_variance/capture.js +96 -0
- package/src/shade/playground/ssr_variance/index.html +22 -0
- package/src/shade/playground/ssr_variance/main.d.ts +2 -0
- package/src/shade/playground/ssr_variance/main.d.ts.map +1 -0
- package/src/shade/playground/ssr_variance/main.js +246 -0
- package/src/shade/playground/ssr_variance/reference.d.ts +18 -0
- package/src/shade/playground/ssr_variance/reference.d.ts.map +1 -0
- package/src/shade/playground/ssr_variance/reference.js +78 -0
- package/src/shade/playground/ssr_variance/scene.d.ts +11 -0
- package/src/shade/playground/ssr_variance/scene.d.ts.map +1 -0
- package/src/shade/playground/ssr_variance/scene.js +61 -0
- package/src/shade/playground/ssr_variance/statistics.d.ts +44 -0
- package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -0
- package/src/shade/playground/ssr_variance/statistics.js +51 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.js +9 -3
- package/src/shade/renderer/loader/usd/usd_decode_image.d.ts +4 -4
- package/src/shade/renderer/loader/usd/usd_decode_image.d.ts.map +1 -1
- package/src/shade/renderer/loader/usd/usd_decode_image.js +4 -4
- package/src/shade/renderer/particles/DESIGN.md +748 -703
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +11 -4
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +431 -424
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.js +2 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js +0 -6
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.js +19 -5
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts +4 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +133 -0
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +0 -8
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +16 -113
- package/src/shade/renderer/texture/source/texel_data_from_ktx2.d.ts +2 -2
- package/src/shade/renderer/texture/source/texel_data_from_ktx2.d.ts.map +1 -1
- package/src/shade/renderer/texture/source/texel_data_from_ktx2.js +3 -3
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts +0 -20
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts +0 -14
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts +0 -50
- package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts +0 -17
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts.map +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} BonfireWorld
|
|
3
|
+
* @property {number} flame entity
|
|
4
|
+
* @property {number} smoke entity
|
|
5
|
+
* @property {number} embers entity
|
|
6
|
+
* @property {number} soot entity
|
|
7
|
+
* @property {import("../../../engine/graphics/ecs/particles/ParticleEffect.js").ParticleEffect[]} effects
|
|
8
|
+
* the four components, in flame / smoke / embers / soot order
|
|
9
|
+
* @property {Light} firelight the point light at the fire, for {@link animate_bonfire} to flicker
|
|
10
|
+
* @property {number[]} entities everything built, for teardown
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Build the whole set.
|
|
14
|
+
*
|
|
15
|
+
* Async because the meshlet builder runs on a WASM instance that instantiates asynchronously at
|
|
16
|
+
* import; building geometry before it is ready reads an instance that is not there yet.
|
|
17
|
+
*
|
|
18
|
+
* @param {import("../../../engine/ecs/EntityComponentDataset.js").EntityComponentDataset} dataset
|
|
19
|
+
* @param {object} [options]
|
|
20
|
+
* @param {import("./bonfire_sprites.js").BonfireSprites} [options.sprites] image URLs for the four
|
|
21
|
+
* effects; omitted, they draw as untextured quads, which is what the headless tests use
|
|
22
|
+
* @returns {Promise<BonfireWorld>}
|
|
23
|
+
*/
|
|
24
|
+
export function build_bonfire_world(dataset: import("../../../engine/ecs/EntityComponentDataset.js").EntityComponentDataset, { sprites }?: {
|
|
25
|
+
sprites?: import("./bonfire_sprites.js").BonfireSprites;
|
|
26
|
+
}): Promise<BonfireWorld>;
|
|
27
|
+
/**
|
|
28
|
+
* Flicker the firelight.
|
|
29
|
+
*
|
|
30
|
+
* Three sine waves with no common period, so it never repeats audibly — the classic cheap fire
|
|
31
|
+
* flicker, and it is here rather than in the effects because it is the *light* that flickers: the
|
|
32
|
+
* particles already flicker on their own, and a light that held still while they did would read as
|
|
33
|
+
* a lamp with a fire drawn in front of it.
|
|
34
|
+
*
|
|
35
|
+
* @param {BonfireWorld} world
|
|
36
|
+
* @param {number} time seconds since start
|
|
37
|
+
*/
|
|
38
|
+
export function animate_bonfire(world: BonfireWorld, time: number): void;
|
|
39
|
+
/**
|
|
40
|
+
* The scene the page shows, built as entities.
|
|
41
|
+
*
|
|
42
|
+
* **Every visible thing here is a `Transform64` and one more component**, which is the whole point
|
|
43
|
+
* of the page: the ground and the logs are `ShadedGeometry`, the moon and the firelight are `Light`,
|
|
44
|
+
* and the flame, smoke, embers and soot are `ParticleEffect`. Four systems observe those pairs and
|
|
45
|
+
* put rows in one `Scene`. Nothing in this file touches the scene graph, and nothing about placing
|
|
46
|
+
* a fire is different from placing a rock.
|
|
47
|
+
*
|
|
48
|
+
* That is what the rework bought. Before it, the particle system observed the scene's emitter nodes
|
|
49
|
+
* directly, so an effect was the one thing in a level that could not be spawned, moved, parented or
|
|
50
|
+
* destroyed by the machinery everything else uses.
|
|
51
|
+
*/
|
|
52
|
+
/** Where the fire is. Everything else in the set is arranged around it. */
|
|
53
|
+
export const FIRE_POSITION: Vector3;
|
|
54
|
+
export type BonfireWorld = {
|
|
55
|
+
/**
|
|
56
|
+
* entity
|
|
57
|
+
*/
|
|
58
|
+
flame: number;
|
|
59
|
+
/**
|
|
60
|
+
* entity
|
|
61
|
+
*/
|
|
62
|
+
smoke: number;
|
|
63
|
+
/**
|
|
64
|
+
* entity
|
|
65
|
+
*/
|
|
66
|
+
embers: number;
|
|
67
|
+
/**
|
|
68
|
+
* entity
|
|
69
|
+
*/
|
|
70
|
+
soot: number;
|
|
71
|
+
/**
|
|
72
|
+
* the four components, in flame / smoke / embers / soot order
|
|
73
|
+
*/
|
|
74
|
+
effects: import("../../../engine/graphics/ecs/particles/ParticleEffect.js").ParticleEffect[];
|
|
75
|
+
/**
|
|
76
|
+
* the point light at the fire, for {@link animate_bonfire } to flicker
|
|
77
|
+
*/
|
|
78
|
+
firelight: Light;
|
|
79
|
+
/**
|
|
80
|
+
* everything built, for teardown
|
|
81
|
+
*/
|
|
82
|
+
entities: number[];
|
|
83
|
+
};
|
|
84
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
85
|
+
import { Light } from "../../../engine/graphics/ecs/light/Light.js";
|
|
86
|
+
//# sourceMappingURL=bonfire_world.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bonfire_world.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/particle_ecs/bonfire_world.js"],"names":[],"mappings":"AA8CA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;GAWG;AACH,6CANW,OAAO,+CAA+C,EAAE,sBAAsB;IAEtB,OAAO,GAA/D,OAAO,sBAAsB,EAAE,cAAc;IAE3C,QAAQ,YAAY,CAAC,CAuIjC;AAED;;;;;;;;;;GAUG;AACH,uCAHW,YAAY,QACZ,MAAM,QAShB;AA3MD;;;;;;;;;;;;GAYG;AAEH,2EAA2E;AAC3E,oCAAkD;;;;;WAapC,MAAM;;;;WACN,MAAM;;;;YACN,MAAM;;;;UACN,MAAM;;;;aACN,OAAO,0DAA0D,EAAE,cAAc,EAAE;;;;eAEnF,KAAK;;;;cACL,MAAM,EAAE;;oBArDF,+BAA+B;sBAG7B,6CAA6C"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { Color } from "../../../core/color/Color.js";
|
|
2
|
+
import Quaternion from "../../../core/geom/Quaternion.js";
|
|
3
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
4
|
+
import { Entity } from "../../../engine/ecs/Entity.js";
|
|
5
|
+
import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
|
|
6
|
+
import { Light } from "../../../engine/graphics/ecs/light/Light.js";
|
|
7
|
+
import { LightType } from "../../../engine/graphics/ecs/light/LightType.js";
|
|
8
|
+
import { ShadedGeometry } from "../../../engine/graphics/ecs/mesh-v2/ShadedGeometry.js";
|
|
9
|
+
import { MeshletGeometry } from "../../renderer/geometry/MeshletGeometry.js";
|
|
10
|
+
import { MeshoptClusterizer } from "../../renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js";
|
|
11
|
+
import { meshlet_geometry_build_from_geometry } from "../../renderer/geometry/meshlet_geometry_build_from_geometry.js";
|
|
12
|
+
import { make_box_geometry } from "../../renderer/geometry/primitives/make_box_geometry.js";
|
|
13
|
+
import { make_cylinder_geometry } from "../../renderer/geometry/primitives/make_cylinder_geometry.js";
|
|
14
|
+
import { make_plane_geometry } from "../../renderer/geometry/primitives/make_plane_geometry.js";
|
|
15
|
+
import { ShadeDrawSide } from "../../renderer/material/ShadeDrawSide.js";
|
|
16
|
+
import { StandardShadeMaterial } from "../../renderer/material/StandardShadeMaterial.js";
|
|
17
|
+
import { TransparencyMode } from "../../renderer/material/TransparencyMode.js";
|
|
18
|
+
import { bonfire_effects } from "./bonfire_effects.js";
|
|
19
|
+
import { MOON_DIRECTION } from "./moonlit_environment.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The scene the page shows, built as entities.
|
|
23
|
+
*
|
|
24
|
+
* **Every visible thing here is a `Transform64` and one more component**, which is the whole point
|
|
25
|
+
* of the page: the ground and the logs are `ShadedGeometry`, the moon and the firelight are `Light`,
|
|
26
|
+
* and the flame, smoke, embers and soot are `ParticleEffect`. Four systems observe those pairs and
|
|
27
|
+
* put rows in one `Scene`. Nothing in this file touches the scene graph, and nothing about placing
|
|
28
|
+
* a fire is different from placing a rock.
|
|
29
|
+
*
|
|
30
|
+
* That is what the rework bought. Before it, the particle system observed the scene's emitter nodes
|
|
31
|
+
* directly, so an effect was the one thing in a level that could not be spawned, moved, parented or
|
|
32
|
+
* destroyed by the machinery everything else uses.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** Where the fire is. Everything else in the set is arranged around it. */
|
|
36
|
+
export const FIRE_POSITION = new Vector3(0, 0, 0);
|
|
37
|
+
|
|
38
|
+
/** Radius of the ring of stones, in metres. */
|
|
39
|
+
const PIT_RADIUS = 0.85;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Baseline intensity of the firelight, before the flicker.
|
|
43
|
+
* @type {number}
|
|
44
|
+
*/
|
|
45
|
+
const FIRELIGHT_INTENSITY = 3.5;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {object} BonfireWorld
|
|
49
|
+
* @property {number} flame entity
|
|
50
|
+
* @property {number} smoke entity
|
|
51
|
+
* @property {number} embers entity
|
|
52
|
+
* @property {number} soot entity
|
|
53
|
+
* @property {import("../../../engine/graphics/ecs/particles/ParticleEffect.js").ParticleEffect[]} effects
|
|
54
|
+
* the four components, in flame / smoke / embers / soot order
|
|
55
|
+
* @property {Light} firelight the point light at the fire, for {@link animate_bonfire} to flicker
|
|
56
|
+
* @property {number[]} entities everything built, for teardown
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Build the whole set.
|
|
61
|
+
*
|
|
62
|
+
* Async because the meshlet builder runs on a WASM instance that instantiates asynchronously at
|
|
63
|
+
* import; building geometry before it is ready reads an instance that is not there yet.
|
|
64
|
+
*
|
|
65
|
+
* @param {import("../../../engine/ecs/EntityComponentDataset.js").EntityComponentDataset} dataset
|
|
66
|
+
* @param {object} [options]
|
|
67
|
+
* @param {import("./bonfire_sprites.js").BonfireSprites} [options.sprites] image URLs for the four
|
|
68
|
+
* effects; omitted, they draw as untextured quads, which is what the headless tests use
|
|
69
|
+
* @returns {Promise<BonfireWorld>}
|
|
70
|
+
*/
|
|
71
|
+
export async function build_bonfire_world(dataset, { sprites = {} } = {}) {
|
|
72
|
+
await MeshoptClusterizer.ready;
|
|
73
|
+
|
|
74
|
+
/** @type {number[]} */
|
|
75
|
+
const entities = [];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {Entity} builder
|
|
79
|
+
* @returns {number}
|
|
80
|
+
*/
|
|
81
|
+
const build = builder => {
|
|
82
|
+
builder.build(dataset);
|
|
83
|
+
entities.push(builder.id);
|
|
84
|
+
|
|
85
|
+
return builder.id;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// --- the ground, the pit and the fuel ------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
const ground_material = material(new Color(0.12, 0.113, 0.10, 1), { roughness: 0.95 });
|
|
91
|
+
const stone_material = material(new Color(0.14, 0.14, 0.15, 1), { roughness: 0.8 });
|
|
92
|
+
const log_material = material(new Color(0.17, 0.10, 0.065, 1), { roughness: 0.85 });
|
|
93
|
+
|
|
94
|
+
build(new Entity()
|
|
95
|
+
.add(placed(new Vector3(0, 0, 0), Quaternion.fromAxisAngle(Vector3.right, -Math.PI / 2)))
|
|
96
|
+
.add(shaded(meshlets(make_plane_geometry(200, 200, 1, 1)), ground_material)));
|
|
97
|
+
|
|
98
|
+
const stone = meshlets(make_box_geometry(0.34, 0.26, 0.28));
|
|
99
|
+
|
|
100
|
+
for (let i = 0; i < 11; i++) {
|
|
101
|
+
const angle = (i / 11) * Math.PI * 2;
|
|
102
|
+
const wobble = 0.9 + ((i * 37) % 7) / 24;
|
|
103
|
+
|
|
104
|
+
build(new Entity()
|
|
105
|
+
.add(placed(
|
|
106
|
+
new Vector3(
|
|
107
|
+
FIRE_POSITION.x + Math.cos(angle) * PIT_RADIUS * wobble,
|
|
108
|
+
0.1,
|
|
109
|
+
FIRE_POSITION.z + Math.sin(angle) * PIT_RADIUS * wobble
|
|
110
|
+
),
|
|
111
|
+
Quaternion.fromAxisAngle(Vector3.up, angle + wobble)
|
|
112
|
+
))
|
|
113
|
+
.add(shaded(stone, stone_material)));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Logs leaning into a teepee, which is where the flame's pinch comes from visually: the fire is
|
|
117
|
+
// widest at the fuel and narrows above it.
|
|
118
|
+
const log = meshlets(make_cylinder_geometry(0.075, 0.1, 1.5, 8, 1));
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < 5; i++) {
|
|
121
|
+
const angle = (i / 5) * Math.PI * 2 + 0.4;
|
|
122
|
+
const lean = 0.42;
|
|
123
|
+
|
|
124
|
+
build(new Entity()
|
|
125
|
+
.add(placed(
|
|
126
|
+
new Vector3(
|
|
127
|
+
FIRE_POSITION.x + Math.cos(angle) * 0.34,
|
|
128
|
+
0.62,
|
|
129
|
+
FIRE_POSITION.z + Math.sin(angle) * 0.34
|
|
130
|
+
),
|
|
131
|
+
// rotate +Y toward the outward lean: the axis is up x outward
|
|
132
|
+
Quaternion.fromAxisAngle(
|
|
133
|
+
new Vector3(Math.sin(angle), 0, -Math.cos(angle)),
|
|
134
|
+
lean
|
|
135
|
+
)
|
|
136
|
+
))
|
|
137
|
+
.add(shaded(log, log_material)));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// two spent logs lying across the pit
|
|
141
|
+
for (const [offset, angle] of [[new Vector3(0.1, 0.09, -0.55), 0.7], [new Vector3(-0.35, 0.09, 0.4), 2.3]]) {
|
|
142
|
+
build(new Entity()
|
|
143
|
+
.add(placed(
|
|
144
|
+
new Vector3(FIRE_POSITION.x + offset.x, offset.y, FIRE_POSITION.z + offset.z),
|
|
145
|
+
Quaternion.fromAxisAngle(new Vector3(Math.sin(angle), 0, -Math.cos(angle)), Math.PI / 2)
|
|
146
|
+
))
|
|
147
|
+
.add(shaded(log, log_material)));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// --- the lights ----------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
const moon = new Light();
|
|
153
|
+
|
|
154
|
+
moon.type.set(LightType.DIRECTION);
|
|
155
|
+
moon.color.setRGB(0.62, 0.72, 1.0);
|
|
156
|
+
moon.intensity.set(1.1);
|
|
157
|
+
// an angular radius, for a directional source: the moon's is about half a degree, and a source
|
|
158
|
+
// with some size is what softens the terminator and the shadow's edge
|
|
159
|
+
moon.radius.set(0.0087);
|
|
160
|
+
moon.castShadow.set(true);
|
|
161
|
+
|
|
162
|
+
build(new Entity()
|
|
163
|
+
.add(placed(new Vector3(0, 12, 0), look_along(MOON_DIRECTION.clone().negate())))
|
|
164
|
+
.add(moon));
|
|
165
|
+
|
|
166
|
+
// The fire's own light, and the thing that makes the set look lit by the fire rather than lit
|
|
167
|
+
// near it: a warm point source inside the flame, flickered by {@link animate_bonfire}.
|
|
168
|
+
const firelight = new Light();
|
|
169
|
+
|
|
170
|
+
firelight.type.set(LightType.POINT);
|
|
171
|
+
firelight.color.setRGB(1.0, 0.52, 0.19);
|
|
172
|
+
firelight.intensity.set(FIRELIGHT_INTENSITY);
|
|
173
|
+
firelight.distance.set(18);
|
|
174
|
+
// the flame is roughly a third of a metre across, and a source with size is what keeps the
|
|
175
|
+
// stones from each carrying one mirror-sharp highlight
|
|
176
|
+
firelight.radius.set(0.35);
|
|
177
|
+
|
|
178
|
+
build(new Entity()
|
|
179
|
+
.add(placed(new Vector3(FIRE_POSITION.x, 0.55, FIRE_POSITION.z)))
|
|
180
|
+
.add(firelight));
|
|
181
|
+
|
|
182
|
+
// --- the fire ------------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
const effects = bonfire_effects(sprites);
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {import("../../../engine/graphics/ecs/particles/ParticleEffect.js").ParticleEffect} effect
|
|
188
|
+
* @param {number} height
|
|
189
|
+
* @returns {number}
|
|
190
|
+
*/
|
|
191
|
+
const emitter = (effect, height) => build(new Entity()
|
|
192
|
+
.add(placed(new Vector3(FIRE_POSITION.x, FIRE_POSITION.y + height, FIRE_POSITION.z)))
|
|
193
|
+
.add(effect));
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
flame: emitter(effects.flame, 0.16),
|
|
197
|
+
smoke: emitter(effects.smoke, 0.16),
|
|
198
|
+
embers: emitter(effects.embers, 0.16),
|
|
199
|
+
soot: emitter(effects.soot, 0.16),
|
|
200
|
+
effects: [effects.flame, effects.smoke, effects.embers, effects.soot],
|
|
201
|
+
firelight,
|
|
202
|
+
entities,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Flicker the firelight.
|
|
208
|
+
*
|
|
209
|
+
* Three sine waves with no common period, so it never repeats audibly — the classic cheap fire
|
|
210
|
+
* flicker, and it is here rather than in the effects because it is the *light* that flickers: the
|
|
211
|
+
* particles already flicker on their own, and a light that held still while they did would read as
|
|
212
|
+
* a lamp with a fire drawn in front of it.
|
|
213
|
+
*
|
|
214
|
+
* @param {BonfireWorld} world
|
|
215
|
+
* @param {number} time seconds since start
|
|
216
|
+
*/
|
|
217
|
+
export function animate_bonfire(world, time) {
|
|
218
|
+
const wobble =
|
|
219
|
+
Math.sin(time * 8.7) * 0.13
|
|
220
|
+
+ Math.sin(time * 3.1 + 1.7) * 0.09
|
|
221
|
+
+ Math.sin(time * 17.3 + 0.4) * 0.05;
|
|
222
|
+
|
|
223
|
+
world.firelight.intensity.set(FIRELIGHT_INTENSITY * (1 + wobble));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// -------------------------------------------------------------------------------------------
|
|
227
|
+
// Helpers
|
|
228
|
+
// -------------------------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {Vector3} position
|
|
232
|
+
* @param {Quaternion} [rotation]
|
|
233
|
+
* @returns {Transform64}
|
|
234
|
+
*/
|
|
235
|
+
function placed(position, rotation = new Quaternion()) {
|
|
236
|
+
const transform = new Transform64();
|
|
237
|
+
|
|
238
|
+
transform.setTranslation(position.x, position.y, position.z);
|
|
239
|
+
transform.setRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
240
|
+
transform.updateMatrix();
|
|
241
|
+
|
|
242
|
+
return transform;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* A rotation that points local **forward** along `direction`, which is how a `DirectionalLight`
|
|
247
|
+
* takes its direction — it has no direction field, only a transform.
|
|
248
|
+
*
|
|
249
|
+
* @param {Vector3} direction unit
|
|
250
|
+
* @returns {Quaternion}
|
|
251
|
+
*/
|
|
252
|
+
function look_along(direction) {
|
|
253
|
+
const q = new Quaternion();
|
|
254
|
+
|
|
255
|
+
q.fromUnitVectors(Vector3.forward, direction);
|
|
256
|
+
q.normalize();
|
|
257
|
+
|
|
258
|
+
return q;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @param {MeshletGeometry} geometry
|
|
263
|
+
* @param {StandardShadeMaterial} material_instance
|
|
264
|
+
* @returns {ShadedGeometry}
|
|
265
|
+
*/
|
|
266
|
+
function shaded(geometry, material_instance) {
|
|
267
|
+
const component = new ShadedGeometry();
|
|
268
|
+
|
|
269
|
+
component.geometry = geometry;
|
|
270
|
+
component.material = material_instance;
|
|
271
|
+
|
|
272
|
+
return component;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @param {object} geometry
|
|
277
|
+
* @returns {MeshletGeometry}
|
|
278
|
+
*/
|
|
279
|
+
function meshlets(geometry) {
|
|
280
|
+
const built = new MeshletGeometry();
|
|
281
|
+
|
|
282
|
+
meshlet_geometry_build_from_geometry(geometry, built);
|
|
283
|
+
|
|
284
|
+
return built;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @param {Color} diffuse
|
|
289
|
+
* @param {object} [options]
|
|
290
|
+
* @param {number} [options.roughness]
|
|
291
|
+
* @returns {StandardShadeMaterial}
|
|
292
|
+
*/
|
|
293
|
+
function material(diffuse, { roughness = 0.8 } = {}) {
|
|
294
|
+
const result = new StandardShadeMaterial();
|
|
295
|
+
|
|
296
|
+
result.diffuse_color.copy(diffuse);
|
|
297
|
+
result.roughness_factor = roughness;
|
|
298
|
+
result.metallic_factor = 0;
|
|
299
|
+
result.transparency_mode = TransparencyMode.Opaque;
|
|
300
|
+
result.draw_side = ShadeDrawSide.Double;
|
|
301
|
+
|
|
302
|
+
return result;
|
|
303
|
+
}
|