@woosh/meep-engine 3.19.0 → 3.20.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-terrain.js +1 -1
- package/editor/view/particles/effect/ParticleGraphEditorView.js +2 -2
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.js +7 -48
- package/package.json +1 -1
- package/src/core/collection/array/array_group_by.d.ts.map +1 -1
- package/src/core/collection/array/array_group_by.js +2 -11
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +4 -9
- package/src/core/model/object/optional_clone.d.ts +7 -0
- package/src/core/model/object/optional_clone.d.ts.map +1 -0
- package/src/core/model/object/optional_equality.d.ts +10 -0
- package/src/core/model/object/optional_equality.d.ts.map +1 -0
- package/src/{shade/descriptor/util → core/model/object}/optional_equality.js +2 -2
- package/src/core/model/object/optional_hash.d.ts +9 -0
- package/src/core/model/object/optional_hash.d.ts.map +1 -0
- package/src/{shade/descriptor/util → core/model/object}/optional_hash.js +3 -3
- package/src/engine/asset/Asset.d.ts +1 -1
- package/src/engine/asset/Asset.d.ts.map +1 -1
- package/src/engine/asset/Asset.js +3 -1
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.d.ts.map +1 -1
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +9 -10
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
- package/src/engine/graphics/ecs/particles/ParticleEffect.js +6 -22
- package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +1 -1
- package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +3 -3
- package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +1 -1
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +1 -1
- package/src/shade/descriptor/pipeline/render/ColorTargetState.js +3 -3
- package/src/shade/descriptor/pipeline/render/FragmentState.js +1 -1
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +3 -3
- package/src/shade/playground/particle_editor/README.md +1 -1
- package/src/shade/playground/particle_system/particle_prototype.d.ts +7 -9
- package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_prototype.js +7 -9
- package/src/shade/playground/ssr_motion/README.md +22 -0
- package/src/shade/playground/ssr_motion/index.html +18 -0
- package/src/shade/playground/ssr_motion/main.d.ts +2 -0
- package/src/shade/playground/ssr_motion/main.d.ts.map +1 -0
- package/src/shade/playground/ssr_motion/main.js +149 -0
- package/src/shade/playground/ssr_variance/index.html +1 -0
- package/src/shade/renderer/geometry/Geometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/Geometry.js +4 -7
- package/src/shade/renderer/material/StandardShadeMaterial.js +2 -2
- package/src/shade/renderer/particles/DESIGN.md +9 -11
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +3 -1
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +1 -1
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +9 -15
- package/src/shade/renderer/particles/graph/particle_group_library.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_group_library.js +8 -3
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +0 -2
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_parameters.js +0 -9
- package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_presentation.js +0 -10
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts +2 -8
- package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_ramp.js +2 -8
- package/src/shade/renderer/particles/graph/validate_particle_graph.js +0 -6
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +13 -4
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +1 -12
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/InstructionStream.js +1 -12
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +54 -60
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleVMISA.js +9 -17
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts +0 -1
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/particle_assembly.js +2 -16
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +1 -1
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +1 -1
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +0 -14
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +3 -17
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +15 -36
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +1 -5
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +1 -8
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +2 -11
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +2 -11
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +13 -0
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts +3 -6
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +49 -17
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +0 -2
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +0 -2
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +1 -5
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +0 -2
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +1 -3
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +4 -20
- package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +2 -5
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts.map +1 -1
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js +0 -2
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts.map +1 -1
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js +0 -2
- 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 +21 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -0
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +2 -1
- package/src/shade/renderer/scene/Mesh.js +1 -1
- package/src/shade/renderer/texture/ShadeTexture.js +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts +0 -19
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +0 -30
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts +0 -11
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts.map +0 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.js +0 -13
- /package/src/{shade/descriptor/util → core/model/object}/optional_clone.js +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
3
|
+
<title>SSR cross · camera motion</title><style>
|
|
4
|
+
body{margin:24px;background:#14161a;color:#e7e9ee;font:14px/1.5 system-ui}h1{font-size:24px;margin-bottom:8px}p{color:#acb5c5;max-width:900px}main{display:grid;grid-template-columns:minmax(0,800px) 260px;gap:24px}canvas{display:block;width:100%;height:auto;background:#08090a;touch-action:none;outline:none}canvas:focus{outline:1px solid #749ac4}label{display:block;margin:0 0 14px}input[type=range],select{width:100%}button,select{font:inherit;padding:8px;background:#29313e;color:inherit;border:1px solid #4b586d;border-radius:4px}button{margin:0 4px 8px 0}output{float:right;font-variant-numeric:tabular-nums}a{color:#9ac9ff}#status{white-space:pre-wrap}.error{color:#ff9a9a}@media(max-width:900px){main{grid-template-columns:1fr}}
|
|
5
|
+
</style></head><body tabindex="0">
|
|
6
|
+
<h1>SSR cross · camera motion</h1>
|
|
7
|
+
<p>The same glowing cross and colored markers as the variance lab. Fixed exposure; final-image TAA defaults off. Drag to orbit, right-drag to pan, scroll to zoom, or focus the scene and use WASD.</p>
|
|
8
|
+
<main><section><canvas id="view" width="800" height="500" tabindex="0" aria-label="Interactive reflection scene"></canvas><p id="status" role="status">Initializing…</p><p><a href="../ssr_variance/">Exact variance and convergence measurements</a></p></section><aside>
|
|
9
|
+
<label>Floor roughness <output id="roughness-value">0.30</output><input id="roughness" aria-label="Floor roughness" type="range" min="0.01" max="1" step="0.01" value="0.3"></label>
|
|
10
|
+
<label>Camera <select id="motion"><option value="free">Free camera</option><option value="lateral">Lateral movement</option><option value="forward">Forward movement</option><option value="orbit">Orbit movement</option><option value="still">Still camera</option></select></label>
|
|
11
|
+
<label>Motion speed <output id="speed-value">1.0×</output><input id="speed" aria-label="Motion speed" type="range" min="0.1" max="3" step="0.1" value="1"></label>
|
|
12
|
+
<label>SSR history <select id="temporal"><option value="0">Parallax</option><option value="1">Surface only</option><option value="2">No temporal history</option></select></label>
|
|
13
|
+
<label><input id="spatial" type="checkbox" checked> Spatial denoising</label>
|
|
14
|
+
<label><input id="taa" type="checkbox"> Final-image TAA</label>
|
|
15
|
+
<label><input id="jitter" type="checkbox"> Raster jitter</label>
|
|
16
|
+
<button id="motion-pause">Pause motion</button><button id="render-pause">Pause rendering</button><button id="step">Step frame</button><button id="restart">Reset camera</button><button id="reset">Reset SSR history</button>
|
|
17
|
+
<p>Pausing motion keeps sampling. Pausing rendering freezes the displayed frame. Ordinary camera movement preserves history; resets and material changes clear it.</p>
|
|
18
|
+
</aside></main><script type="module" src="./main.js"></script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/ssr_motion/main.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
2
|
+
import { PerspectiveCamera } from "../../renderer/camera/PerspectiveCamera.js";
|
|
3
|
+
import { OrbitalCameraController } from "../../renderer/camera/OrbitalCameraController.js";
|
|
4
|
+
import { Renderer } from "../../renderer/Renderer.js";
|
|
5
|
+
import { ShadeIndirectLightingMode } from "../../renderer/ShadeIndirectLightingMode.js";
|
|
6
|
+
import { FixedProjection } from "../ssr_variance/capture.js";
|
|
7
|
+
import { create_scene } from "../ssr_variance/scene.js";
|
|
8
|
+
|
|
9
|
+
const element = id => document.getElementById(id);
|
|
10
|
+
const params = new URLSearchParams(location.search);
|
|
11
|
+
const number = (name, fallback, min, max) => {
|
|
12
|
+
const value = Number(params.get(name) ?? fallback);
|
|
13
|
+
return Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : fallback;
|
|
14
|
+
};
|
|
15
|
+
element('roughness').value = number('roughness', 0.3, 0.01, 1);
|
|
16
|
+
element('speed').value = number('speed', 1, 0.1, 3);
|
|
17
|
+
if (['free', 'lateral', 'forward', 'orbit', 'still'].includes(params.get('motion'))) { element('motion').value = params.get('motion'); }
|
|
18
|
+
if (['0', '1', '2'].includes(params.get('temporal'))) { element('temporal').value = params.get('temporal'); }
|
|
19
|
+
element('spatial').checked = params.get('spatial') !== 'off';
|
|
20
|
+
for (const name of ['taa', 'jitter']) { element(name).checked = params.get(name) === 'on'; }
|
|
21
|
+
|
|
22
|
+
async function start() {
|
|
23
|
+
const canvas = element('view'), renderer = new Renderer();
|
|
24
|
+
await renderer.initialize({ context: canvas.getContext('webgpu'), pixelRatio: 1 });
|
|
25
|
+
renderer.feature_ssr_enabled = true;
|
|
26
|
+
renderer.indirect_lighting_mode = ShadeIndirectLightingMode.IBL;
|
|
27
|
+
for (const name of ['ssao', 'bloom', 'sharpening', 'motion_blur', 'automatic_exposure']) { renderer[`feature_${name}_enabled`] = false; }
|
|
28
|
+
renderer.exposure_compensation = 1;
|
|
29
|
+
renderer.internal_resolution_scale = 1;
|
|
30
|
+
renderer.feature_taa_enabled = element('taa').checked;
|
|
31
|
+
renderer.ssr.spatial_denoising_enabled = element('spatial').checked;
|
|
32
|
+
renderer.ssr.reprojection_mode = Number(element('temporal').value);
|
|
33
|
+
const world = await create_scene();
|
|
34
|
+
world.ground_material.roughness_factor = Number(element('roughness').value);
|
|
35
|
+
const floor_materials = new Map([[world.ground_material.roughness_factor, world.ground_material]]);
|
|
36
|
+
const camera = new PerspectiveCamera();
|
|
37
|
+
camera.near = 0.1; camera.far = 50; camera.fov = 50 * Math.PI / 180;
|
|
38
|
+
camera.aspect = canvas.width / canvas.height;
|
|
39
|
+
const controller = new OrbitalCameraController(camera, canvas);
|
|
40
|
+
controller.movement_speed_scale = 2;
|
|
41
|
+
renderer.resize(canvas.width, canvas.height);
|
|
42
|
+
class ProjectionControl extends FixedProjection {
|
|
43
|
+
record(frame) { if (!element('jitter').checked) { super.record(frame); } }
|
|
44
|
+
}
|
|
45
|
+
renderer.add_extension(new ProjectionControl());
|
|
46
|
+
let phase = 0, frame_count = 0, motion_paused = false;
|
|
47
|
+
let rendering_paused = params.has('manual'), stopped = false, request, last_time, last_status = 0;
|
|
48
|
+
const pose = (position, target) => {
|
|
49
|
+
camera.transform.setTranslation(...position);
|
|
50
|
+
camera.transform.lookAt(new Vector3(...target));
|
|
51
|
+
camera.transform.updateMatrix();
|
|
52
|
+
controller.look(new Vector3(...position), new Vector3(...target));
|
|
53
|
+
};
|
|
54
|
+
function status() {
|
|
55
|
+
element('status').textContent = `Frame ${frame_count} · roughness ${world.ground_material.roughness_factor.toFixed(2)}\n${rendering_paused ? 'Rendering paused' : motion_paused ? 'Motion paused · sampling continues' : 'Running'} · final TAA ${renderer.feature_taa_enabled ? 'on' : 'off'}`;
|
|
56
|
+
element('render-pause').textContent = rendering_paused ? 'Resume rendering' : 'Pause rendering';
|
|
57
|
+
}
|
|
58
|
+
function fail(error) {
|
|
59
|
+
stopped = true; cancelAnimationFrame(request);
|
|
60
|
+
element('status').textContent = error.message ?? String(error);
|
|
61
|
+
element('status').classList.add('error'); console.error(error);
|
|
62
|
+
}
|
|
63
|
+
function reset_camera() {
|
|
64
|
+
phase = 0; pose([0, 3.2, 7], [0, 0.2, -2]);
|
|
65
|
+
renderer.indicate_view_change(); status();
|
|
66
|
+
}
|
|
67
|
+
function set_roughness() {
|
|
68
|
+
const roughness = Number(element('roughness').value);
|
|
69
|
+
// GPU material contexts are immutable after upload. Reuse at most one
|
|
70
|
+
// material per slider value, and refresh the scene's material membership.
|
|
71
|
+
let material = floor_materials.get(roughness);
|
|
72
|
+
if (!material) {
|
|
73
|
+
material = world.ground_material.clone();
|
|
74
|
+
material.roughness_factor = roughness;
|
|
75
|
+
floor_materials.set(roughness, material);
|
|
76
|
+
}
|
|
77
|
+
if (material !== world.ground_material) {
|
|
78
|
+
world.scene.remove(world.ground);
|
|
79
|
+
world.ground.material = world.ground_material = material;
|
|
80
|
+
world.ground.updateMatrices();
|
|
81
|
+
renderer.graphics.materials.obtain(material);
|
|
82
|
+
world.scene.add(world.ground);
|
|
83
|
+
}
|
|
84
|
+
element('roughness-value').textContent = world.ground_material.roughness_factor.toFixed(2);
|
|
85
|
+
renderer.indicate_view_change(); status();
|
|
86
|
+
}
|
|
87
|
+
function frame(dt = 1 / 60, advance = true) {
|
|
88
|
+
if (stopped) { throw new Error('Renderer stopped after an error'); }
|
|
89
|
+
const mode = element('motion').value;
|
|
90
|
+
if (advance && !motion_paused) {
|
|
91
|
+
phase += dt * Number(element('speed').value) * 0.7;
|
|
92
|
+
const t = Math.sin(phase);
|
|
93
|
+
if (mode === 'free') { controller.update(dt); }
|
|
94
|
+
else if (mode === 'lateral') { pose([2 * t, 3.2, 7], [2 * t, 0.2, -2]); }
|
|
95
|
+
else if (mode === 'forward') { pose([0, 3.2, 7 + 1.6 * t], [0, 0.2, -2 + 1.6 * t]); }
|
|
96
|
+
else if (mode === 'orbit') { pose([4 * t, 3.2, 7 - 0.7 * t * t], [0, 0.2, -2]); }
|
|
97
|
+
}
|
|
98
|
+
if (renderer.render(camera, world.scene, dt) === false) { throw new Error('Renderer did not submit the frame'); }
|
|
99
|
+
frame_count++;
|
|
100
|
+
if (performance.now() - last_status > 250 || rendering_paused) { status(); last_status = performance.now(); }
|
|
101
|
+
return frame_count;
|
|
102
|
+
}
|
|
103
|
+
function tick(time) {
|
|
104
|
+
if (stopped) { return; }
|
|
105
|
+
const dt = last_time === undefined ? 1 / 60 : Math.min((time - last_time) / 1000, 0.05);
|
|
106
|
+
last_time = time;
|
|
107
|
+
try { if (!rendering_paused) { frame(dt); } }
|
|
108
|
+
catch (error) { fail(error); return; }
|
|
109
|
+
request = requestAnimationFrame(tick);
|
|
110
|
+
}
|
|
111
|
+
element('roughness').oninput = set_roughness;
|
|
112
|
+
element('speed').oninput = () => { element('speed-value').textContent = `${Number(element('speed').value).toFixed(1)}×`; };
|
|
113
|
+
element('speed').oninput();
|
|
114
|
+
element('motion').onchange = () => {
|
|
115
|
+
if (element('motion').value !== 'free') { reset_camera(); }
|
|
116
|
+
};
|
|
117
|
+
canvas.addEventListener('pointerdown', () => { canvas.focus(); element('motion').value = 'free'; motion_paused = false; element('motion-pause').textContent = 'Pause motion'; });
|
|
118
|
+
canvas.addEventListener('contextmenu', event => event.preventDefault());
|
|
119
|
+
element('temporal').onchange = () => { renderer.ssr.reprojection_mode = Number(element('temporal').value); };
|
|
120
|
+
element('spatial').onchange = () => { renderer.ssr.spatial_denoising_enabled = element('spatial').checked; };
|
|
121
|
+
element('taa').onchange = () => { renderer.feature_taa_enabled = element('taa').checked; renderer.indicate_view_change(); status(); };
|
|
122
|
+
element('jitter').onchange = () => renderer.indicate_view_change();
|
|
123
|
+
element('motion-pause').onclick = () => { motion_paused = !motion_paused; element('motion-pause').textContent = motion_paused ? 'Resume motion' : 'Pause motion'; status(); };
|
|
124
|
+
element('render-pause').onclick = () => { rendering_paused = !rendering_paused; status(); };
|
|
125
|
+
element('step').onclick = () => { rendering_paused = true; try { frame(); } catch (error) { fail(error); } };
|
|
126
|
+
element('restart').onclick = reset_camera;
|
|
127
|
+
element('reset').onclick = () => { renderer.ssr.reset_history = true; };
|
|
128
|
+
const device = renderer.graphics.device;
|
|
129
|
+
device.addEventListener('uncapturederror', event => fail(event.error));
|
|
130
|
+
device.lost.then(info => { if (!stopped) { fail(new Error(`GPU device lost: ${info.message}`)); } });
|
|
131
|
+
addEventListener('pagehide', () => { stopped = true; cancelAnimationFrame(request); controller.pointer.stop(); controller.keyboard.stop(); renderer.destroy(); device.destroy(); });
|
|
132
|
+
addEventListener('pageshow', event => { if (event.persisted) { location.reload(); } });
|
|
133
|
+
reset_camera(); set_roughness();
|
|
134
|
+
const lab = globalThis.ssr_motion_lab = {
|
|
135
|
+
renderer, camera, world, frame, pose,
|
|
136
|
+
step(n = 1, advance = true) {
|
|
137
|
+
if (!rendering_paused) { throw new Error('Pause rendering before exact stepping'); }
|
|
138
|
+
if (!Number.isSafeInteger(n) || n < 1) { throw new Error('Step count must be a positive integer'); }
|
|
139
|
+
for (let i = 0; i < n; i++) { frame(1 / 60, advance); }
|
|
140
|
+
return frame_count;
|
|
141
|
+
},
|
|
142
|
+
get frame_count() { return frame_count; },
|
|
143
|
+
};
|
|
144
|
+
request = requestAnimationFrame(tick);
|
|
145
|
+
return lab;
|
|
146
|
+
}
|
|
147
|
+
globalThis.ssr_motion_ready = start().catch(error => {
|
|
148
|
+
element('status').textContent = error.message ?? String(error); console.error(error); throw error;
|
|
149
|
+
});
|
|
@@ -5,6 +5,7 @@ body{margin:24px;background:#14161a;color:#e7e9ee;font:14px system-ui}h1{font-si
|
|
|
5
5
|
</style></head><body>
|
|
6
6
|
<h1>SSR variance lab</h1>
|
|
7
7
|
<p>One ground plane · roughness 0.30 · metallic 1 · textured emissive card · fixed camera and exposure. Starts at frame zero. Rendering advances only when requested.</p>
|
|
8
|
+
<p><a href="../ssr_motion/">Move the camera and adjust floor roughness</a></p>
|
|
8
9
|
<label>Spatial <select id="spatial"><option value="on">On</option><option value="off">Off</option></select></label>
|
|
9
10
|
<label>Temporal <select id="temporal"><option value="on">On</option><option value="off">Off</option></select></label>
|
|
10
11
|
<label>Raster jitter <select id="jitter"><option value="off">Off</option><option value="on">On</option></select></label>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Geometry.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/geometry/Geometry.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Geometry.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/geometry/Geometry.js"],"names":[],"mappings":"4BA4BU,MAAM;;;;AAQhB;;GAEG;AACH;IAQI;;;;OAIG;IACH,iBAEC;IAED;;;OAGG;IACH,MAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,YAFU,SAAS,EAAE,CAEL;IAEhB;;;OAGG;IACH,OAFU,SAAS,GAAC,IAAI,CAEX;IAEb;;;OAGG;IACH,cAFU,YAAY,CAEa;IACnC;;;OAGG;IACH,iBAFU,YAAY,CAEgB;IAEtC;;;OAGG;IACH,OAFU,MAAM,CAEM;IAOtB;;;;;;;;;;OAUG;IACH,sBAEC;IAED;;OAEG;IACH,8BAIC;IAGD;;;;OAIG;IACH,cAHW,MAAM,GAAC,aAAa,GAClB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,aAAa,GAClB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,aAAa,SACpB,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,aAAa,GAClB,OAAO,CAInB;IAED;;;;OAIG;IACH,cAHW,QAAQ,GACN,OAAO,CAYnB;IAED,eAQC;IAED;;;;OAIG;IACH,mBAHW,MAAM,GACL,SAAS,GAAC,SAAS,CAkB9B;IAED;;;;OAIG;IACH,mBAHW,MAAM,GACJ,OAAO,CAMnB;IAED;;;OAGG;IACH,wBAFW,SAAS,QAQnB;IAED;;;OAGG;IACH,wBAFW,SAAS,QASnB;IAED;;;;OAIG;IACH,sBAHW,MAAM,GACL,SAAS,GAAC,SAAS,CAiB9B;IAED;;;OAGG;IACH,kBAFY,MAAM,CAWjB;IAED;;;OAGG;IACH,iBAFY,MAAM,CAYjB;IAED;;;;OAIG;IACH,qBAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,oBAIC;IAED;;OAEG;IACH,mBASC;IAED,qBAIC;IAED;;OAEG;IACH,qCAoBC;IAED,8BAaC;IAED,8BAKC;IAED,2BAeC;IAED,sBAOC;IAED,uBA4BC;IAoFD,uBAOC;IAED,wBAWC;IAED;;;OAGG;IACH,YAFW,QAAQ,QAelB;IAED;;;OAGG;IACH,SAFY,QAAQ,CAQnB;IAED,eAEC;IAED;;;OAGG;IACH,iCAYC;IAGL;;;OAGG;IACH,qBAFU,OAAO,CAEY;;CAN5B;0BAnkByB,gBAAgB"}
|
|
@@ -14,8 +14,9 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
geometry_compute_vertex_normals_unindexed
|
|
16
16
|
} from "../../../engine/graphics/geometry/buffered/geometry_compute_vertex_normals_unindexed.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { optional_clone } from "../../../core/model/object/optional_clone.js";
|
|
18
|
+
import { optional_equality } from "../../../core/model/object/optional_equality.js";
|
|
19
|
+
import { optional_hash } from "../../../core/model/object/optional_hash.js";
|
|
19
20
|
import { Attribute } from "./Attribute.js";
|
|
20
21
|
import { build_tangent_from_normal } from "./normals/build_tangent_from_normal.js";
|
|
21
22
|
import { geometry_build_tangents } from "./normals/geometry_build_tangents.js";
|
|
@@ -551,11 +552,7 @@ export class Geometry {
|
|
|
551
552
|
|
|
552
553
|
this.name = other.name;
|
|
553
554
|
|
|
554
|
-
|
|
555
|
-
this.index = other.index.clone();
|
|
556
|
-
} else {
|
|
557
|
-
this.index = null;
|
|
558
|
-
}
|
|
555
|
+
this.index = optional_clone(other.index);
|
|
559
556
|
|
|
560
557
|
this.attributes = other.attributes.map(a => a.clone());
|
|
561
558
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { combine_hash } from "../../../core/collection/array/combine_hash.js";
|
|
2
2
|
import { Color } from "../../../core/color/Color.js";
|
|
3
3
|
import LinearModifier from "../../../core/model/stat/LinearModifier.js";
|
|
4
|
-
import { optional_equality } from "
|
|
5
|
-
import { optional_hash } from "
|
|
4
|
+
import { optional_equality } from "../../../core/model/object/optional_equality.js";
|
|
5
|
+
import { optional_hash } from "../../../core/model/object/optional_hash.js";
|
|
6
6
|
import { ShadeMaterial } from "./ShadeMaterial.js";
|
|
7
7
|
|
|
8
8
|
export class StandardShadeMaterial extends ShadeMaterial {
|
|
@@ -22,7 +22,7 @@ the decision to spawn is the GPU's.
|
|
|
22
22
|
- Distinct per-particle lifecycle: **no** built-in age/position — the schema + program define state.
|
|
23
23
|
- Billboard renderer reuses engine shader chunks incl. lighting (forward-shaded, optional per emitter).
|
|
24
24
|
- Blend modes (alpha + additive) via a **single** premultiplied blend setup.
|
|
25
|
-
-
|
|
25
|
+
- Authored curves and RGB/RGBA gradients compiled into arithmetic for simulation.
|
|
26
26
|
- Spawning decided on the GPU, per emitter, with the CPU able to ask for bursts through the same path.
|
|
27
27
|
- No per-frame allocation on the CPU beyond the frame graph's own records.
|
|
28
28
|
|
|
@@ -159,7 +159,7 @@ recursion, no data-dependent jumps — conditionals are predicated via CMP/SELEC
|
|
|
159
159
|
Word 0 packs the opcode (bits 0..7), the lane count (8..10), each source's `VM_KIND` (two bits per
|
|
160
160
|
slot at 16..21) and the destination slot (24..31). A source word means what its kind says: `REG`
|
|
161
161
|
is a base slot plus a swizzle, `IMM` is an `f32` bit pattern read in every lane, and `NONE` is a
|
|
162
|
-
raw field the opcode reads for itself (attribute word-offset+comp /
|
|
162
|
+
raw field the opcode reads for itself (attribute word-offset+comp / builtin id /
|
|
163
163
|
pool index).
|
|
164
164
|
- Constant pool: `array<vec4f>` per program, referenced by `LOAD_CONST`.
|
|
165
165
|
- Two entry sections per program: **INIT** and **UPDATE** (offsets in the emitter record). INIT
|
|
@@ -167,8 +167,6 @@ recursion, no data-dependent jumps — conditionals are predicated via CMP/SELEC
|
|
|
167
167
|
- Builtins (`LOAD_BUILTIN`): DT, EMITTER_AGE, EMITTER_POSITION, EMITTER_DIRECTION, EMITTER_UP,
|
|
168
168
|
PARTICLE_INDEX, SPAWN_FRACTION, TIME … assembled per-invocation by the host shader. The emitter's
|
|
169
169
|
position and axes are its node's `global` out of the scene database.
|
|
170
|
-
- `CURVE dst, handle, s0`: `dst.x = animation_curve_evaluate(curves[handle], s0.x)` — reuses the
|
|
171
|
-
engine's GPU AnimationCurve chunk + database.
|
|
172
170
|
|
|
173
171
|
#### Two interpreters
|
|
174
172
|
|
|
@@ -212,11 +210,13 @@ A core `NodeGraph` holds particle nodes (ports + parameters) for INIT and UPDATE
|
|
|
212
210
|
2. lowers each node to VM ops (nodes emit via a small builder that allocates result registers),
|
|
213
211
|
3. linear-scan register allocation with liveness,
|
|
214
212
|
4. interns constants into the pool,
|
|
215
|
-
5. resolves
|
|
216
|
-
6. emits `Program { init, update, constants, reg_count, attributes
|
|
213
|
+
5. resolves attribute references,
|
|
214
|
+
6. emits `Program { init, update, constants, reg_count, attributes }`.
|
|
217
215
|
|
|
218
216
|
Standard node library: constants, attribute get/set, arithmetic/vector/math, random (uniform/sphere/
|
|
219
|
-
disk/cone),
|
|
217
|
+
disk/cone), authored curves and RGB/RGBA gradients, noise (curl), integrate, gravity, emit-shapes,
|
|
218
|
+
compare/select, kill-if. Curves and gradients expand into graph nodes that emit ordinary VM
|
|
219
|
+
arithmetic; no animation-table binding or sampling opcode is needed.
|
|
220
220
|
|
|
221
221
|
### Emitters are scene nodes
|
|
222
222
|
|
|
@@ -684,7 +684,6 @@ src/shade/renderer/particles/
|
|
|
684
684
|
warmup/chunk_particle_warmup_step.js one particle's advance: per-lane decode, jittered tick
|
|
685
685
|
warmup/shader_particle_warmup_advance.js the advance over the fast file (+ _wide.js)
|
|
686
686
|
warmup/graph_particle_warmup.js the loop, recorded on a frame that registered a pre-warm
|
|
687
|
-
shaders/chunk_particle_curve_disabled.js the no-curves-bound CURVE provider
|
|
688
687
|
shaders/chunk_particle_billboard_vertex.js the billboard vertex stage, shared by every draw
|
|
689
688
|
shaders/shader_particle_avboit_*.js occupancy / splat / draw through AVBOIT
|
|
690
689
|
bounds/* the measured emitter box: accumulate, publish
|
|
@@ -743,6 +742,5 @@ was seeded.
|
|
|
743
742
|
Done: `Renderer.feature_particles_enabled` (off by default), `Renderer.particles(scene_ctx)` creating
|
|
744
743
|
one system per scene context on first use, `simulate` recorded before the transparency pass and the
|
|
745
744
|
system passed to the AVBOIT orchestrator as its side channel. Remaining:
|
|
746
|
-
1. For lit emitters, compile a
|
|
747
|
-
|
|
748
|
-
shading-chunk-backed lighting hook (+ the `SHADING_LIGHT_RESOURCE_GROUP`).
|
|
745
|
+
1. For lit emitters, compile a render variant that swaps the disabled lighting hook for a
|
|
746
|
+
shading-chunk-backed lighting hook (+ the `SHADING_LIGHT_RESOURCE_GROUP`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH;IAmLI;;;;;;OAMG;IACH,sBANW,MAAM,iBACN,OAAO,6BAA6B,EAAE,eAAe;QAEpC,QAAQ,GAAzB,MAAM;QACW,sBAAsB,GAAvC,MAAM;OAoBhB;IA1MD;;;OAGG;IACH,UAFU,MAAM,CAEP;IAET;;;OAGG;IACH,eAFU,OAAO,6BAA6B,EAAE,eAAe,CAEjD;IAEd;;;OAGG;IACH,UAFU,MAAM,CAEP;IAET;;OAEG;IACH,UAFU,eAAe,CAEhB;IAET;;;OAGG;IACH,OAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,MAFU,MAAM,CAEP;IAET;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;;OAIG;IACH,kBAFU,YAAY,CAE0B;IAEhD;;;;OAIG;IACH,sBAAM;IAEN,yBAAyB;IACzB,0BAAc;IAEd;;;;;;OAMG;IACH,SAFU,MAAM,CAEH;IA2Ib;;;OAGG;IACH,kCAEC;IAED;;;OAGG;IACH,yEAEC;IAED;;;;;;;;;;;;OAYG;IACH,eAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,gCAEC;IAED;;;;;;;OAOG;IACH,eAHW,OAAO,8BAA8B,EAAE,eAAe,SACtD,MAAM,QAwBhB;IAwED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH;QAZkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;QAC/D,MAAM,EAArB,MAAM;QACS,cAAc,EAA7B,MAAM;QAES,EAAE,EAAjB,MAAM;QACsB,IAAI,GAAhC,kBAAkB;QACF,KAAK,GAArB,MAAM;QAEU,KAAK,GAArB,MAAM;QAEJ,MAAM,GAAC,SAAS,CA8D5B;IAiBD;;;;;;;;;OASG;IACH;QANgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACjE,MAAM,EAAnB,MAAM;QACkB,kBAAkB,EAA1C,UAAU,MAAM,CAAC;QACJ,SAAS,EAAtB,MAAM;QACJ,MAAM,CAalB;IAED;;;;;;;;;;OAUG;IACH;QAPgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACjE,MAAM,EAAnB,MAAM;QACO,IAAI,EAAjB,MAAM;QACO,aAAa,EAA1B,MAAM;QACsD,MAAM,EAAlE;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC;QACnD;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAkBjE;IAED;;;;;;;;;;;;;;OAcG;IACH;QAXgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACrB,QAAQ,EAAjE,OAAO,2BAA2B,EAAE,cAAc;QACrC,MAAM,EAAnB,MAAM;QACO,aAAa,EAA1B,MAAM;QACO,IAAI,EAAjB,MAAM;QACO,QAAQ,EAArB,MAAM;QACO,eAAe,EAA5B,MAAM;QACO,oBAAoB,EAAjC,MAAM;QACoE,YAAY,EAAtF;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAC;QACjE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAsB/E;IAED;;;;;;;;;OASG;IACH,mBAFa,IAAI,CA2DhB;IAoYD;;;OAGG;IACH;YAFoB,MAAM,GAAE,MAAM;MAcjC;IAED,gBA4BC;;CACJ;gCAlnC+B,8BAA8B;mCAD3B,yBAAyB"}
|
|
@@ -41,6 +41,8 @@ const WORD = Uint32Array.BYTES_PER_ELEMENT;
|
|
|
41
41
|
const STORAGE = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;
|
|
42
42
|
const INDIRECT = GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC;
|
|
43
43
|
|
|
44
|
+
const DEFAULT_CAPACITY = 524288;
|
|
45
|
+
|
|
44
46
|
/**
|
|
45
47
|
* The GPU particle system: a feature of a scene, in the mould of `ReSTIRDI` — construct once
|
|
46
48
|
* against a {@link GPUSceneContext}, and contribute the frame's passes through
|
|
@@ -299,7 +301,7 @@ export class GPUParticleSystem {
|
|
|
299
301
|
* @param {number} [options.capacity] max simultaneous particles
|
|
300
302
|
* @param {number} [options.spawn_command_capacity] most {@link spawn} calls one frame keeps
|
|
301
303
|
*/
|
|
302
|
-
constructor(graphics, scene_context, { capacity =
|
|
304
|
+
constructor(graphics, scene_context, { capacity = DEFAULT_CAPACITY, spawn_command_capacity = 256 } = {}) {
|
|
303
305
|
assert.defined(graphics, "graphics");
|
|
304
306
|
assert.defined(scene_context, "scene_context");
|
|
305
307
|
assert.equal(scene_context.isGPUSceneContext, true, "scene_context.isGPUSceneContext !== true");
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Every stock operation that takes no parameters of its own is a method here, taken from the library
|
|
11
11
|
* rather than listed — a type added to it is callable the same day. The rest — `const`, `swizzle`,
|
|
12
|
-
* `random`, `
|
|
12
|
+
* `random`, `curveLiteral` and the attribute nodes — need a parameter and are reached through
|
|
13
13
|
* {@link #op}, or through the shorthands below where there is an obvious one.
|
|
14
14
|
*
|
|
15
15
|
* A number where a value is expected becomes a literal, so `g.mul(v, 0.5)` is what it looks like.
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
*
|
|
18
18
|
* Every stock operation that takes no parameters of its own is a method here, taken from the library
|
|
19
19
|
* rather than listed — a type added to it is callable the same day. The rest — `const`, `swizzle`,
|
|
20
|
-
* `random`, `
|
|
20
|
+
* `random`, `curveLiteral` and the attribute nodes — need a parameter and are reached through
|
|
21
21
|
* {@link #op}, or through the shorthands below where there is an obvious one.
|
|
22
22
|
*
|
|
23
23
|
* A number where a value is expected becomes a literal, so `g.mul(v, 0.5)` is what it looks like.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticleNodeRegistry.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/ParticleNodeRegistry.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ParticleNodeRegistry.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/ParticleNodeRegistry.js"],"names":[],"mappings":"AA+qBA;;;;;;;GAOG;AACH,8CAFa,uBAAuB,EAAE,CAIrC;AAED;;;;;GAKG;AACH,oDAJW,MAAM,GACJ,uBAAuB,CAWnC;AA1qBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;;;;GASG;AACH,kCAFU,QAAQ,CAE2C;AAE7D;;;GAGG;AACH,wCAFU,MAAM,CAE+B;AAE/C;;GAEG;AACH,qCAFU,YAAY,CAEmC;wCAhEjB,8BAA8B;yBAZ7C,oDAAoD;6BAFhD,wDAAwD"}
|
|
@@ -90,12 +90,14 @@ for (const type of PARTICLE_ALL_VALUE_TYPES) {
|
|
|
90
90
|
*
|
|
91
91
|
* IDs are handed out in declaration order rather than by {@link NodeDescription}'s global counter,
|
|
92
92
|
* so they do not drift with unrelated node usage elsewhere in the engine. Appending new node types
|
|
93
|
-
* at the end of the library is therefore safe
|
|
94
|
-
*
|
|
93
|
+
* at the end of the library is therefore safe. Removed types leave their IDs unused so existing
|
|
94
|
+
* serialized graphs retain the same IDs for every remaining type.
|
|
95
95
|
*
|
|
96
96
|
* @type {Map<string, ParticleNodeDescription>}
|
|
97
97
|
*/
|
|
98
|
-
const descriptions_by_name = new Map();
|
|
98
|
+
const descriptions_by_name = new Map();
|
|
99
|
+
|
|
100
|
+
let next_description_id = 0;
|
|
99
101
|
|
|
100
102
|
/**
|
|
101
103
|
* @param {string} name
|
|
@@ -123,7 +125,7 @@ function define(name, inputs, emit, {
|
|
|
123
125
|
const description = new ParticleNodeDescription();
|
|
124
126
|
|
|
125
127
|
description.name = name;
|
|
126
|
-
description.id =
|
|
128
|
+
description.id = next_description_id++;
|
|
127
129
|
|
|
128
130
|
// what an author reads is decided in one table, away from the lowering; see
|
|
129
131
|
// ./particle_node_presentation.js
|
|
@@ -572,14 +574,8 @@ define("compare", ["a", "b"], (s, c) => {
|
|
|
572
574
|
}, MASK_RESULT);
|
|
573
575
|
define("select", ["a", "b", "condition"], (s, c) => s.emit(VM_OP.SELECT, c.out, c.in("a"), c.in("b"), c.in("condition"), c.width), blend_controlled_by("condition"));
|
|
574
576
|
|
|
575
|
-
//
|
|
576
|
-
|
|
577
|
-
// a curve read wider than a scalar is the broadcast for free.
|
|
578
|
-
define("curve", ["t"], (s, c) => s.curve(c.out, c.parameters.handle, c.in("t"), c.width), {
|
|
579
|
-
infer_types: () => ({ output: PARTICLE_TYPE_F32, inputs: { t: PARTICLE_TYPE_F32 } }),
|
|
580
|
-
operation_width: ({ demand }) => demand,
|
|
581
|
-
input_widths: () => ({ t: 1 }),
|
|
582
|
-
});
|
|
577
|
+
// ID 39 belonged to the removed animation-table sampler. Keep it unused.
|
|
578
|
+
next_description_id++;
|
|
583
579
|
|
|
584
580
|
// --- semantic sources ---
|
|
585
581
|
// Appended rather than filed with the other sources, because a node type's id is its position in
|
|
@@ -665,9 +661,7 @@ function expanding(name, inputs, output, body) {
|
|
|
665
661
|
return description;
|
|
666
662
|
}
|
|
667
663
|
|
|
668
|
-
// One curve, written into the program
|
|
669
|
-
// host's animation-curve table and this one *is* the curve, the way `color` is a colour rather than
|
|
670
|
-
// the name of one.
|
|
664
|
+
// One authored curve, written into the program as arithmetic.
|
|
671
665
|
expanding(
|
|
672
666
|
"curveLiteral",
|
|
673
667
|
[{ name: "t", type: PARTICLE_TYPE_F32 }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particle_group_library.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_group_library.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;GAUG;AACH,+CAHW,OAAO,wBAAwB,EAAE,iBAAiB,GAChD,OAAO,wBAAwB,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"particle_group_library.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_group_library.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;GAUG;AACH,+CAHW,OAAO,wBAAwB,EAAE,iBAAiB,GAChD,OAAO,wBAAwB,EAAE,iBAAiB,CAqB9D;AAED;;;;GAIG;AACH,mCAFa,OAAO,wBAAwB,EAAE,iBAAiB,EAAE,CAIhE;AAED;;;;;GAKG;AACH,yCAHW,MAAM,GACJ,OAAO,wBAAwB,EAAE,iBAAiB,GAAC,SAAS,CAIxE;AAED;;;;;GAKG;AACH,6CAHW,MAAM,GACJ,OAAO,CAInB"}
|
|
@@ -38,9 +38,14 @@ export function register_particle_group(group) {
|
|
|
38
38
|
|
|
39
39
|
// The group node itself, and the two boundary blocks its body is wired to: a view that opens the
|
|
40
40
|
// group draws those, and everything drawn needs a box generated for it.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
// Stock types leave holes when removed. Allocate after their highest ID rather than relying
|
|
42
|
+
// on NodeDescription's global counter, which counts constructions, not reserved IDs.
|
|
43
|
+
let id = Math.max(...PARTICLE_NODE_REGISTRY.nodes.keys()) + 1;
|
|
44
|
+
|
|
45
|
+
for (const description of [group.description, group.inputNode.description, group.outputNode.description]) {
|
|
46
|
+
description.id = id++;
|
|
47
|
+
PARTICLE_NODE_REGISTRY.addNode(description);
|
|
48
|
+
}
|
|
44
49
|
|
|
45
50
|
return group;
|
|
46
51
|
}
|
|
@@ -91,8 +91,6 @@ export const PARTICLE_PARAMETER_KIND: Readonly<{
|
|
|
91
91
|
ENUM: "enum";
|
|
92
92
|
/** one to four lane selectors in `[0, 4)`, one per output lane */
|
|
93
93
|
SWIZZLE: "swizzle";
|
|
94
|
-
/** a non-negative integer — a curve handle */
|
|
95
|
-
INTEGER: "integer";
|
|
96
94
|
/**
|
|
97
95
|
* an {@link ../../../../engine/animation/curve/AnimationCurve.js AnimationCurve}, as the
|
|
98
96
|
* `{keys: [...]}` record that class writes and reads
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particle_node_parameters.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_node_parameters.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"particle_node_parameters.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_node_parameters.js"],"names":[],"mappings":"AA+LA;;;;;;;;;;;;;;;;;GAiBG;AACH,sDAHW,MAAM,GACJ,MAAM,CAIlB;AAwBD;;;;;;GAMG;AACH,+CAJW,MAAM,GACJ,qBAAqB,EAAE,CAcnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,uDANW,MAAM;IAEyD,MAAM,GAArE,OAAO,6BAA6B,EAAE,cAAc;IAElD,MAAM,CAmBlB;AAED;;;;GAIG;AACH,2CAFa,MAAM;IAAC,WAAW,EAAE,OAAO,8BAA8B,EAAE,uBAAuB,CAAC;IAAC,UAAU,EAAE,qBAAqB,EAAE,CAAA;CAAC,CAAC,CAOrI;;;;sCApRS,MAAM;AApBhB;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH;IACI,0FAA0F;;IAE1F,kFAAkF;;IAElF,mFAAmF;;IAEnF,2EAA2E;;IAE3E,kEAAkE;;IAElE;;;OAGG;;IAEH;;;OAGG;;GAEJ;AAEH;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;GASG;AACH,gDAFU,MAAM,EAAE,CAWf;AAEH;;;;;GAKG;AACH;QAFiB,MAAM,GAAE,MAAM;EAI7B;AAEF;;;;;GAKG;AACH;QAFiB,MAAM,GAAE,qBAAqB,EAAE;EAuF7C;;;;;;;;UAtIW,MAAM;;;;UACN,MAAM;;;;;;;;;;YAGC,MAAM;;;;;;;;YACb,OAAO;;;;kBAIP,MAAM"}
|
|
@@ -37,8 +37,6 @@ export const PARTICLE_PARAMETER_KIND = Object.freeze({
|
|
|
37
37
|
ENUM: "enum",
|
|
38
38
|
/** one to four lane selectors in `[0, 4)`, one per output lane */
|
|
39
39
|
SWIZZLE: "swizzle",
|
|
40
|
-
/** a non-negative integer — a curve handle */
|
|
41
|
-
INTEGER: "integer",
|
|
42
40
|
/**
|
|
43
41
|
* an {@link ../../../../engine/animation/curve/AnimationCurve.js AnimationCurve}, as the
|
|
44
42
|
* `{keys: [...]}` record that class writes and reads
|
|
@@ -172,13 +170,6 @@ export const PARTICLE_NODE_PARAMETER_SCHEMA = Object.freeze({
|
|
|
172
170
|
description: "Which input lane each output lane reads; one to four of them, and that count is the result's width.",
|
|
173
171
|
}],
|
|
174
172
|
|
|
175
|
-
curve: [{
|
|
176
|
-
name: "handle",
|
|
177
|
-
kind: PARTICLE_PARAMETER_KIND.INTEGER,
|
|
178
|
-
default: 0,
|
|
179
|
-
description: "Row of the animation-curve table to sample.",
|
|
180
|
-
}],
|
|
181
|
-
|
|
182
173
|
curveLiteral: [{
|
|
183
174
|
name: "curve",
|
|
184
175
|
kind: PARTICLE_PARAMETER_KIND.CURVE,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particle_node_presentation.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_node_presentation.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"particle_node_presentation.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_node_presentation.js"],"names":[],"mappings":"AAiUA;;;;;;;GAOG;AACH,iDAHW,MAAM,GACJ;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAIvD;AAjSD;;;;;;;;GAQG;AACH;QAFiB,MAAM,GAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC;EA8QjE"}
|
|
@@ -301,17 +301,7 @@ export const PARTICLE_NODE_PRESENTATION = Object.freeze({
|
|
|
301
301
|
},
|
|
302
302
|
|
|
303
303
|
// --- ramps ---
|
|
304
|
-
// Two ways to have a curve, and the labels say which is which. The table one came first and was
|
|
305
|
-
// called just "Curve"; it is renamed here rather than leaving the new one to explain itself,
|
|
306
|
-
// because "the one that samples the host's table" is the surprising half of the pair and the
|
|
307
|
-
// one an author has to have decided to want.
|
|
308
|
-
curve: {
|
|
309
|
-
label: "Curve Table",
|
|
310
|
-
icon: `M5 18C10 18 9 6 19 6 ${dot(5, 18, 1.6)} ${dot(19, 6, 1.6)}`,
|
|
311
|
-
help: "sample a row of the host's animation-curve table at t",
|
|
312
|
-
},
|
|
313
304
|
curveLiteral: {
|
|
314
|
-
// the same curve with its keys on it: this one is the curve rather than a handle to one
|
|
315
305
|
label: "Curve",
|
|
316
306
|
icon: `M4 19C10 19 8 5 20 5 ${dot(4, 19, 1.8)} ${dot(12, 12, 1.8)} ${dot(20, 5, 1.8)}`,
|
|
317
307
|
help: "a curve of your own, written into the program: t in, its value out",
|
|
@@ -128,14 +128,8 @@ export function roll_out_particle_gradient(g: import("./ParticleGroupBuilder.js"
|
|
|
128
128
|
* {@link ./ParticleNodeDescription.js ParticleNodeDescription#expand}), and this is what they expand
|
|
129
129
|
* *into*: stock nodes, which is to say VM instructions, with the curve rolled out along them.
|
|
130
130
|
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* There is a `CURVE` opcode, and it is not this. That one samples a row of the animation-curve table
|
|
134
|
-
* a host uploads, which is the right answer for a curve an author is dragging around at runtime and
|
|
135
|
-
* the wrong one for a curve that is part of the effect: it costs a table, a row, a handle to keep in
|
|
136
|
-
* step with it, and a texture fetch. A ramp with four stops rolls out to about twenty instructions
|
|
137
|
-
* of pure arithmetic, needs nothing from the host, and constant-folds where an author has left a
|
|
138
|
-
* segment flat.
|
|
131
|
+
* A ramp with four stops rolls out to about twenty instructions of pure arithmetic, needs nothing
|
|
132
|
+
* from the host, and constant-folds where an author has left a segment flat.
|
|
139
133
|
*
|
|
140
134
|
* ## How a piecewise function becomes straight-line code
|
|
141
135
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particle_ramp.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_ramp.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"particle_ramp.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/particle_ramp.js"],"names":[],"mappings":"AAqFA;;;;;;;;GAQG;AACH,0CAFa,sBAAsB,CASlC;AAED;;;;GAIG;AACH,6CAFa,oBAAoB,EAAE,CAOlC;AAUD;;;;;;;;;GASG;AACH,+CAFa,OAAO,CAanB;AAED;;;;;GAKG;AACH,kDAFa,OAAO,CAanB;AAED;;;;;;;;;GASG;AACH,2CAHW,sBAAsB,GACpB,gBAAgB,EAAE,CAI9B;AAED;;;;;;GAMG;AACH,gDAHW,sBAAsB,GACpB,cAAc,CAQ1B;AAED;;;;;GAKG;AACH,qDAHW,cAAc,GACZ,sBAAsB,CAWlC;AAED;;;;;GAKG;AACH,+CAHW,oBAAoB,EAAE,GACpB,oBAAoB,EAAE,CAMlC;AAED;;;;;;;GAOG;AACH,gDAJW,oBAAoB,EAAE,KACtB,MAAM,GACJ,MAAM,EAAE,CAsBpB;AA8BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CALW,OAAO,2BAA2B,EAAE,oBAAoB,iBAExD,sBAAsB,OA+ChC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,8CANW,OAAO,2BAA2B,EAAE,oBAAoB,iBAExD,oBAAoB,EAAE,cACtB,MAAM,OA8BhB;AAzYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH;;;;;;GAMG;AAEH;;;GAGG;AACH,iDAFU,MAAM,CAEoC;;;;;;UAxBtC,MAAM;WACN,MAAM;eACN,MAAM;gBACN,MAAM;;;;;qCAMP;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAA;CAAC;;;;;;mCAQ1B;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC;+BA5EjB,sDAAsD"}
|
|
@@ -11,14 +11,8 @@ import { AnimationCurve } from "../../../../engine/animation/curve/AnimationCurv
|
|
|
11
11
|
* {@link ./ParticleNodeDescription.js ParticleNodeDescription#expand}), and this is what they expand
|
|
12
12
|
* *into*: stock nodes, which is to say VM instructions, with the curve rolled out along them.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* There is a `CURVE` opcode, and it is not this. That one samples a row of the animation-curve table
|
|
17
|
-
* a host uploads, which is the right answer for a curve an author is dragging around at runtime and
|
|
18
|
-
* the wrong one for a curve that is part of the effect: it costs a table, a row, a handle to keep in
|
|
19
|
-
* step with it, and a texture fetch. A ramp with four stops rolls out to about twenty instructions
|
|
20
|
-
* of pure arithmetic, needs nothing from the host, and constant-folds where an author has left a
|
|
21
|
-
* segment flat.
|
|
14
|
+
* A ramp with four stops rolls out to about twenty instructions of pure arithmetic, needs nothing
|
|
15
|
+
* from the host, and constant-folds where an author has left a segment flat.
|
|
22
16
|
*
|
|
23
17
|
* ## How a piecewise function becomes straight-line code
|
|
24
18
|
*
|
|
@@ -231,12 +231,6 @@ function check_parameters(node, description, layout, error) {
|
|
|
231
231
|
}
|
|
232
232
|
break;
|
|
233
233
|
|
|
234
|
-
case PARTICLE_PARAMETER_KIND.INTEGER:
|
|
235
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
236
|
-
error(node.id, `Parameter '${parameter.name}' must be a non-negative whole number.`);
|
|
237
|
-
}
|
|
238
|
-
break;
|
|
239
|
-
|
|
240
234
|
// A curve and a gradient are the only parameters with a shape underneath them, and both
|
|
241
235
|
// are written out into instructions rather than read at runtime — so a malformed one is
|
|
242
236
|
// a compile that throws rather than a value that misbehaves, and it is worth catching
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph_particles_avboit.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/graph_particles_avboit.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graph_particles_avboit.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/graph_particles_avboit.js"],"names":[],"mappings":"AAuCA;;;;;;;;;;;;;;;GAeG;AACH;IARkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACoB,kBAAkB,EAA5C,UAAU,MAAM,CAAC;IACF,SAAS,EAAxB,MAAM;IACS,gBAAgB,EAA/B,MAAM;IACS,mBAAmB,EAAlC,MAAM;IACJ,MAAM,CA8ClB;AAED;;;;;;;;;;;;;;;GAeG;AACH;IAZkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IAC/D,MAAM,EAArB,MAAM;IACS,IAAI,EAAnB,MAAM;IACwD,MAAM,EAApE;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC;IAC9B,KAAK;IACT,aAAa;IACjB,IAAI,EAAnB,MAAM;IACS,KAAK,EAApB,MAAM;IACS,gBAAgB,EAA/B,MAAM;IACS,SAAS,EAAxB,MAAM;IACJ;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CA8EjE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAjBkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;IACnB,QAAQ,EAAnE,OAAO,2BAA2B,EAAE,cAAc;IACnC,MAAM,EAArB,MAAM;IACS,aAAa,EAA5B,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,eAAe,EAA9B,MAAM;IACS,oBAAoB,EAAnC,MAAM;IACsE,YAAY,EAAxF;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC;IAC5C,KAAK;IACT,aAAa;IACjB,IAAI,EAAnB,MAAM;IACS,KAAK,EAApB,MAAM;IACS,gBAAgB,EAA/B,MAAM;IACS,SAAS,EAAxB,MAAM;IACJ;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CA2G/E"}
|
|
@@ -6,7 +6,9 @@ import { AVBOIT_OCCUPANCY_SETTINGS_STRUCT } from "../rasterize/native/avboit/sha
|
|
|
6
6
|
import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
|
|
7
7
|
import { shader_particle_avboit_occupancy } from "./shaders/shader_particle_avboit_occupancy.js";
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
PARTICLE_AVBOIT_DRAW_ALPHA_PIPELINE,
|
|
10
|
+
PARTICLE_AVBOIT_DRAW_ADDITIVE_PIPELINE,
|
|
11
|
+
PARTICLE_AVBOIT_DRAW_GENERAL_PIPELINE,
|
|
10
12
|
PARTICLE_AVBOIT_DRAW_RESOURCES,
|
|
11
13
|
} from "./shaders/shader_particle_avboit_draw.js";
|
|
12
14
|
import {
|
|
@@ -268,7 +270,7 @@ export function graph_particle_avboit_draw({
|
|
|
268
270
|
// allowed because the attachment is read-only.
|
|
269
271
|
const pass_encoder = encoder.constructRenderPass({
|
|
270
272
|
label: "Particle AVBOIT Draw",
|
|
271
|
-
pipeline:
|
|
273
|
+
pipeline: PARTICLE_AVBOIT_DRAW_ALPHA_PIPELINE,
|
|
272
274
|
bindings,
|
|
273
275
|
colorAttachments: [
|
|
274
276
|
attachment(data.color),
|
|
@@ -281,8 +283,15 @@ export function graph_particle_avboit_draw({
|
|
|
281
283
|
depthReadOnly: true,
|
|
282
284
|
},
|
|
283
285
|
});
|
|
284
|
-
|
|
285
|
-
|
|
286
|
+
// All three use the alive list; their vertex stages select disjoint particle groups.
|
|
287
|
+
// Premultiplied particles can both cover and emit, so they retain the general pipeline.
|
|
288
|
+
const args = resources.get(data.draw_args);
|
|
289
|
+
pass_encoder.drawIndirect(args, 0);
|
|
290
|
+
pass_encoder.setPipeline(graphics.render_pipelines.obtain(PARTICLE_AVBOIT_DRAW_ADDITIVE_PIPELINE));
|
|
291
|
+
pass_encoder.drawIndirect(args, 0);
|
|
292
|
+
pass_encoder.setPipeline(graphics.render_pipelines.obtain(PARTICLE_AVBOIT_DRAW_GENERAL_PIPELINE));
|
|
293
|
+
pass_encoder.drawIndirect(args, 0);
|
|
294
|
+
pass_encoder.end();
|
|
286
295
|
}
|
|
287
296
|
|
|
288
297
|
const pass_data = {};
|