@woosh/meep-engine 2.119.57 → 2.119.59
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/editor/ecs/component/createObjectEditor.js +2 -0
- package/editor/tools/TransformTool.js +6 -5
- package/editor/tools/v2/TransformMode.d.ts +7 -0
- package/editor/tools/v2/TransformMode.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/core/collection/array/array_shift_back.d.ts +9 -0
- package/src/core/collection/array/array_shift_back.d.ts.map +1 -0
- package/src/core/collection/array/array_shift_back.js +20 -0
- package/src/core/events/signal/Signal.d.ts.map +1 -1
- package/src/core/events/signal/Signal.js +55 -1
- package/src/core/events/signal/SignalHandler.d.ts +5 -0
- package/src/core/events/signal/SignalHandler.d.ts.map +1 -1
- package/src/core/events/signal/SignalHandler.js +6 -0
- package/src/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +2 -1
- package/src/engine/EngineHarness.d.ts +2 -2
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +1 -1
- package/src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +1 -1
- package/src/engine/graphics/material/manager/MaterialManager.d.ts +6 -0
- package/src/engine/graphics/material/manager/MaterialManager.d.ts.map +1 -1
- package/src/engine/graphics/material/manager/MaterialManager.js +9 -0
- package/src/engine/graphics/sh3/gi/material/common.d.ts +1 -1
- package/src/engine/graphics/sh3/gi/material/common.js +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.d.ts +7 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.js +60 -0
- package/src/engine/graphics/sh3/lpv/PathTracerProbeRenderer.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/PathTracerProbeRenderer.js +1 -0
- package/src/engine/graphics/sh3/lpv/build_probes_for_scene.d.ts +8 -0
- package/src/engine/graphics/sh3/lpv/build_probes_for_scene.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/build_probes_for_scene.js +38 -27
- package/src/engine/graphics/sh3/lpv/serialization/LightProbeVolumeSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/serialization/LightProbeVolumeSerializationAdapter.js +2 -0
- package/src/engine/graphics/sh3/lpv/util/lpv_visualise_probes.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/util/lpv_visualise_probes.js +6 -2
- package/src/engine/graphics/sh3/lpv_build_editor.d.ts +9 -0
- package/src/engine/graphics/sh3/lpv_build_editor.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lpv_build_editor.js +695 -0
- package/src/engine/graphics/sh3/prototypeSH3Probe.js +14 -1
- package/src/engine/graphics/sh3/shader/SH3VisualisationMaterial.d.ts +1 -0
- package/src/engine/graphics/sh3/shader/SH3VisualisationMaterial.d.ts.map +1 -1
- package/src/engine/graphics/sh3/shader/SH3VisualisationMaterial.js +9 -0
- package/src/engine/graphics/sh3/visualise_spherical_harmonic_sphere.d.ts +1 -1
- package/src/engine/graphics/sh3/visualise_spherical_harmonic_sphere.d.ts.map +1 -1
- package/src/engine/graphics/sh3/visualise_spherical_harmonic_sphere.js +2 -5
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +23 -1
- package/editor/tools/SelectionTool.d.ts +0 -27
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
import { OctahedronBufferGeometry } from "three";
|
|
2
|
+
import { TransformControls } from "../../../../editor/tools/v2/TransformControls.js";
|
|
3
|
+
import { TransformMode } from "../../../../editor/tools/v2/TransformMode.js";
|
|
4
|
+
import { assert } from "../../../core/assert.js";
|
|
5
|
+
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
6
|
+
import { downloadAsFile } from "../../../core/binary/downloadAsFile.js";
|
|
7
|
+
import { EndianType } from "../../../core/binary/EndianType.js";
|
|
8
|
+
import { SignalBinding } from "../../../core/events/signal/SignalBinding.js";
|
|
9
|
+
import { SimpleStateMachine } from "../../../core/fsm/simple/SimpleStateMachine.js";
|
|
10
|
+
import { SimpleStateMachineDescription } from "../../../core/fsm/simple/SimpleStateMachineDescription.js";
|
|
11
|
+
import { SurfacePoint3 } from "../../../core/geom/3d/SurfacePoint3.js";
|
|
12
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
13
|
+
import { Action } from "../../../core/process/undo/Action.js";
|
|
14
|
+
import { ActionProcessor } from "../../../core/process/undo/ActionProcessor.js";
|
|
15
|
+
import { ArrayBufferLoader } from "../../asset/loaders/ArrayBufferLoader.js";
|
|
16
|
+
import Tag from "../../ecs/components/Tag.js";
|
|
17
|
+
import Entity from "../../ecs/Entity.js";
|
|
18
|
+
import { Transform } from "../../ecs/transform/Transform.js";
|
|
19
|
+
import { EngineHarness } from "../../EngineHarness.js";
|
|
20
|
+
import Highlight from "../ecs/highlight/Highlight.js";
|
|
21
|
+
import { ShadedGeometryHighlightSystem } from "../ecs/highlight/system/ShadedGeometryHighlightSystem.js";
|
|
22
|
+
import { ShadedGeometry } from "../ecs/mesh-v2/ShadedGeometry.js";
|
|
23
|
+
import { ShadedGeometrySystem } from "../ecs/mesh-v2/ShadedGeometrySystem.js";
|
|
24
|
+
import { make_ray_from_viewport_position } from "../make_ray_from_viewport_position.js";
|
|
25
|
+
import { MaterialTransformer } from "./gi/material/MaterialTransformer.js";
|
|
26
|
+
import { lpv_volume_bake_via_task } from "./lpv/build_probes_for_scene.js";
|
|
27
|
+
import { LightProbeVolumeSerializationAdapter } from "./lpv/serialization/LightProbeVolumeSerializationAdapter.js";
|
|
28
|
+
import { sh3_make_shaded_geometry } from "./visualise_spherical_harmonic_sphere.js";
|
|
29
|
+
|
|
30
|
+
const DEFAULT_SH_DATA = new Float32Array(27);
|
|
31
|
+
DEFAULT_SH_DATA.fill(1);
|
|
32
|
+
|
|
33
|
+
class ActionProbeRemove extends Action {
|
|
34
|
+
|
|
35
|
+
entity = -1;
|
|
36
|
+
|
|
37
|
+
_index = -1;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @type {Entity}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
_destroyed;
|
|
44
|
+
|
|
45
|
+
static from(entity) {
|
|
46
|
+
const r = new ActionProbeRemove();
|
|
47
|
+
|
|
48
|
+
r.entity = entity;
|
|
49
|
+
|
|
50
|
+
return r;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {EditorState} context
|
|
56
|
+
* @return {Promise<void>}
|
|
57
|
+
*/
|
|
58
|
+
async apply(context) {
|
|
59
|
+
|
|
60
|
+
const probe_index = context.getProbeIndex(this.entity);
|
|
61
|
+
|
|
62
|
+
this._index = probe_index;
|
|
63
|
+
|
|
64
|
+
this._destroyed = context.removeProbe(probe_index);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
* @param {EditorState} context
|
|
70
|
+
* @return {Promise<void>}
|
|
71
|
+
*/
|
|
72
|
+
async revert(context) {
|
|
73
|
+
|
|
74
|
+
this.entity = this._destroyed.id;
|
|
75
|
+
|
|
76
|
+
context.createProbe(this._destroyed);
|
|
77
|
+
|
|
78
|
+
this._destroyed = null;
|
|
79
|
+
this._index = -1;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class EditorState {
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @type {Entity[]}
|
|
89
|
+
*/
|
|
90
|
+
probes = [];
|
|
91
|
+
/**
|
|
92
|
+
*
|
|
93
|
+
* @type {LightProbeVolume|null}
|
|
94
|
+
*/
|
|
95
|
+
volume = null
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @type {Engine}
|
|
99
|
+
*/
|
|
100
|
+
engine
|
|
101
|
+
|
|
102
|
+
mesh_needs_rebuilding = false;
|
|
103
|
+
|
|
104
|
+
ensureMesh() {
|
|
105
|
+
if (this.mesh_needs_rebuilding) {
|
|
106
|
+
this.volume.build_mesh();
|
|
107
|
+
this.mesh_needs_rebuilding = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
* @return {EntityComponentDataset}
|
|
114
|
+
*/
|
|
115
|
+
get ecd() {
|
|
116
|
+
return this.engine.entityManager.dataset;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
* @param {Entity} entity
|
|
122
|
+
*/
|
|
123
|
+
createProbe(entity) {
|
|
124
|
+
|
|
125
|
+
entity.build(this.ecd);
|
|
126
|
+
|
|
127
|
+
this.probes.push(entity);
|
|
128
|
+
|
|
129
|
+
const p = entity.getComponent(Transform).position;
|
|
130
|
+
|
|
131
|
+
const index = this.volume.add_point(...p);
|
|
132
|
+
|
|
133
|
+
assert.equal(index, this.probes.length - 1);
|
|
134
|
+
|
|
135
|
+
this.mesh_needs_rebuilding = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
*
|
|
140
|
+
* @param {number} index
|
|
141
|
+
* @return {Entity}
|
|
142
|
+
*/
|
|
143
|
+
removeProbe(index) {
|
|
144
|
+
const [probe] = this.probes.splice(index, 1);
|
|
145
|
+
|
|
146
|
+
probe.destroy();
|
|
147
|
+
|
|
148
|
+
this.volume.remove_point(index);
|
|
149
|
+
|
|
150
|
+
this.mesh_needs_rebuilding = true;
|
|
151
|
+
|
|
152
|
+
return probe;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
probeCoefficientsFromVolume(index) {
|
|
156
|
+
const probe = this.probes[index];
|
|
157
|
+
|
|
158
|
+
const sg = probe.getComponent(ShadedGeometry);
|
|
159
|
+
|
|
160
|
+
sg.material.fromArray(this.volume.harmonics, index * 27);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
*
|
|
165
|
+
* @param {number} index
|
|
166
|
+
*/
|
|
167
|
+
probeToVolume(index) {
|
|
168
|
+
|
|
169
|
+
const probe = this.probes[index];
|
|
170
|
+
const t = probe.getComponent(Transform);
|
|
171
|
+
|
|
172
|
+
const existing_position = new Vector3();
|
|
173
|
+
existing_position.fromArray(this.volume.points, index * 3);
|
|
174
|
+
|
|
175
|
+
if (existing_position.equals(t.position)) {
|
|
176
|
+
// all good
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
t.position.toArray(this.volume.points, index * 3);
|
|
181
|
+
this.volume.incrementVersion();
|
|
182
|
+
|
|
183
|
+
this.mesh_needs_rebuilding = true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
*
|
|
188
|
+
* @param {number} entity_id
|
|
189
|
+
* @return {number}
|
|
190
|
+
*/
|
|
191
|
+
getProbeIndex(entity_id) {
|
|
192
|
+
return this.probes.findIndex(p => p.id === entity_id);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
*
|
|
198
|
+
* @param {Engine} engine
|
|
199
|
+
* @param {LightProbeVolume} volume
|
|
200
|
+
* @param {string} [path_key]
|
|
201
|
+
* @param {number} [placement_surface_offset] How far to place new probes away from the surface
|
|
202
|
+
*/
|
|
203
|
+
export async function lpv_build_editor({
|
|
204
|
+
engine,
|
|
205
|
+
volume,
|
|
206
|
+
path_key = "lpv",
|
|
207
|
+
placement_surface_offset = 1
|
|
208
|
+
}) {
|
|
209
|
+
|
|
210
|
+
engine.assetManager.registerLoader('binary', new ArrayBufferLoader());
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
let build_in_progress = false;
|
|
214
|
+
|
|
215
|
+
async function bake() {
|
|
216
|
+
if (build_in_progress) {
|
|
217
|
+
console.warn('build in progress');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
build_in_progress = true;
|
|
221
|
+
|
|
222
|
+
ctx.probes.forEach(p => p.destroy());
|
|
223
|
+
|
|
224
|
+
volume.build_mesh();
|
|
225
|
+
|
|
226
|
+
await lpv_volume_bake_via_task(volume, ecd, engine);
|
|
227
|
+
|
|
228
|
+
for (let i = 0; i < ctx.probes.length; i++) {
|
|
229
|
+
ctx.probeCoefficientsFromVolume(i);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
ctx.probes.forEach(p => p.build(ecd));
|
|
233
|
+
|
|
234
|
+
update_volume_visual();
|
|
235
|
+
|
|
236
|
+
build_in_progress = false;
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// create drop handle
|
|
241
|
+
document.body.addEventListener('dragover', (ev) => {
|
|
242
|
+
ev.preventDefault();
|
|
243
|
+
});
|
|
244
|
+
document.body.addEventListener("drop",
|
|
245
|
+
/**
|
|
246
|
+
*
|
|
247
|
+
* @param {DragEvent} ev
|
|
248
|
+
*/
|
|
249
|
+
(ev) => {
|
|
250
|
+
ev.preventDefault();
|
|
251
|
+
|
|
252
|
+
let processed = false;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
*
|
|
256
|
+
* @param {File} file
|
|
257
|
+
*/
|
|
258
|
+
function processFile(file) {
|
|
259
|
+
if (processed) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// URL @ Mozilla, webkitURL @ Chrome
|
|
264
|
+
const url = (window.webkitURL ? webkitURL : URL).createObjectURL(file);
|
|
265
|
+
|
|
266
|
+
engine.assetManager.promise(url, "binary").then(asset => {
|
|
267
|
+
|
|
268
|
+
const data = asset.create();
|
|
269
|
+
|
|
270
|
+
const buffer = BinaryBuffer.fromArrayBuffer(data);
|
|
271
|
+
buffer.endianness = EndianType.LittleEndian;
|
|
272
|
+
|
|
273
|
+
const adapter = new LightProbeVolumeSerializationAdapter();
|
|
274
|
+
|
|
275
|
+
adapter.deserialize(buffer, volume);
|
|
276
|
+
|
|
277
|
+
// assume mesh is invalid just in case
|
|
278
|
+
ctx.mesh_needs_rebuilding = true;
|
|
279
|
+
|
|
280
|
+
// reinit
|
|
281
|
+
reinit();
|
|
282
|
+
update_volume_visual();
|
|
283
|
+
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
processed = true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (ev.dataTransfer.items) {
|
|
291
|
+
// Use DataTransferItemList interface to access the file(s)
|
|
292
|
+
for (var i = 0; i < ev.dataTransfer.items.length; i++) {
|
|
293
|
+
// If dropped items aren't files, reject them
|
|
294
|
+
if (ev.dataTransfer.items[i].kind === 'file') {
|
|
295
|
+
var file = ev.dataTransfer.items[i].getAsFile();
|
|
296
|
+
|
|
297
|
+
processFile(file);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
// Use DataTransfer interface to access the file(s)
|
|
302
|
+
for (var i = 0; i < ev.dataTransfer.files.length; i++) {
|
|
303
|
+
const file = ev.dataTransfer.files[i];
|
|
304
|
+
|
|
305
|
+
processFile(file);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
const camera_controller = await EngineHarness.buildOrbitalCameraController({
|
|
311
|
+
engine
|
|
312
|
+
});
|
|
313
|
+
camera_controller.destroy();
|
|
314
|
+
|
|
315
|
+
const probe_size = 1;
|
|
316
|
+
|
|
317
|
+
const em = engine.entityManager;
|
|
318
|
+
const ecd = em.dataset;
|
|
319
|
+
|
|
320
|
+
em.addSystem(new ShadedGeometryHighlightSystem(engine));
|
|
321
|
+
|
|
322
|
+
ecd.registerComponentType(Highlight);
|
|
323
|
+
|
|
324
|
+
const PROBE_TAG_STRING = 'PLV/probe';
|
|
325
|
+
|
|
326
|
+
const geometry = new OctahedronBufferGeometry(1, 5);
|
|
327
|
+
|
|
328
|
+
const ctx = new EditorState();
|
|
329
|
+
ctx.probes = [];
|
|
330
|
+
ctx.volume = volume;
|
|
331
|
+
ctx.engine = engine;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
*
|
|
335
|
+
* @type {number[]}
|
|
336
|
+
*/
|
|
337
|
+
const selected = [];
|
|
338
|
+
|
|
339
|
+
const actions = new ActionProcessor(ctx);
|
|
340
|
+
|
|
341
|
+
const controls = new TransformControls(engine.graphics.camera, engine.viewStack.el);
|
|
342
|
+
controls.setMode(TransformMode.Translate);
|
|
343
|
+
controls.build(ecd);
|
|
344
|
+
controls.detach();
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
function unselect() {
|
|
348
|
+
if (selected.length === 0) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for (let i = 0; i < selected.length; i++) {
|
|
353
|
+
|
|
354
|
+
ecd.removeComponentFromEntity(selected[i], Highlight);
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
selected.splice(0, selected.length);
|
|
359
|
+
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
*
|
|
364
|
+
* @param {number[]} entities
|
|
365
|
+
*/
|
|
366
|
+
function set_selection(entities) {
|
|
367
|
+
unselect();
|
|
368
|
+
|
|
369
|
+
for (let i = 0; i < entities.length; i++) {
|
|
370
|
+
const entity = entities[i];
|
|
371
|
+
|
|
372
|
+
ecd.addComponentToEntity(entity, Highlight.fromOne(1, 1, 0));
|
|
373
|
+
selected.push(entity);
|
|
374
|
+
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function create_probe_entity(volume_index = -1) {
|
|
380
|
+
|
|
381
|
+
const entity = new Entity();
|
|
382
|
+
|
|
383
|
+
const transform = new Transform();
|
|
384
|
+
|
|
385
|
+
transform.scale.setScalar(probe_size);
|
|
386
|
+
|
|
387
|
+
entity.add(Tag.fromOne(PROBE_TAG_STRING));
|
|
388
|
+
entity.add(transform);
|
|
389
|
+
|
|
390
|
+
let sg;
|
|
391
|
+
if (volume_index >= 0) {
|
|
392
|
+
|
|
393
|
+
sg = sh3_make_shaded_geometry(
|
|
394
|
+
ctx.volume.harmonics, 27 * volume_index
|
|
395
|
+
);
|
|
396
|
+
} else {
|
|
397
|
+
sg = sh3_make_shaded_geometry(DEFAULT_SH_DATA, 0);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
entity.add(sg);
|
|
401
|
+
|
|
402
|
+
return entity;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const smd = new SimpleStateMachineDescription();
|
|
406
|
+
const STATE_NAVIGATION = smd.createState();
|
|
407
|
+
const STATE_TRANSFORM = smd.createState();
|
|
408
|
+
|
|
409
|
+
smd.createEdge(STATE_NAVIGATION, STATE_TRANSFORM);
|
|
410
|
+
smd.createEdge(STATE_TRANSFORM, STATE_NAVIGATION);
|
|
411
|
+
|
|
412
|
+
const transform_proxy = new Entity().add(new Transform());
|
|
413
|
+
transform_proxy.build(ecd);
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
*
|
|
417
|
+
* @param {number[]} entities
|
|
418
|
+
*/
|
|
419
|
+
function attach_transform(entities) {
|
|
420
|
+
const entities_copy = entities.slice();
|
|
421
|
+
|
|
422
|
+
// figure out center mass
|
|
423
|
+
const center = new Vector3();
|
|
424
|
+
for (let i = 0; i < entities.length; i++) {
|
|
425
|
+
const entity = entities[i];
|
|
426
|
+
|
|
427
|
+
center.add(
|
|
428
|
+
ecd.getComponent(entity, Transform).position
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
center.multiplyScalar(1 / entities.length);
|
|
432
|
+
transform_proxy.getComponent(Transform).position.copy(center);
|
|
433
|
+
|
|
434
|
+
const last_position = new Vector3();
|
|
435
|
+
last_position.copy(center);
|
|
436
|
+
|
|
437
|
+
controls.attach(transform_proxy.id);
|
|
438
|
+
controls.entity.addEventListener("change", () => {
|
|
439
|
+
if (entities_copy.length === 0) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const new_position = transform_proxy.getComponent(Transform).position.clone();
|
|
444
|
+
const displacement = new_position.clone();
|
|
445
|
+
displacement.sub(last_position);
|
|
446
|
+
|
|
447
|
+
last_position.copy(new_position);
|
|
448
|
+
|
|
449
|
+
for (let i = 0; i < entities.length; i++) {
|
|
450
|
+
const entity = entities[i];
|
|
451
|
+
const index = ctx.getProbeIndex(entity);
|
|
452
|
+
|
|
453
|
+
const probe = ctx.probes[index];
|
|
454
|
+
|
|
455
|
+
probe.getComponent(Transform).position.add(displacement);
|
|
456
|
+
|
|
457
|
+
ctx.probeToVolume(index);
|
|
458
|
+
}
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const sm = new SimpleStateMachine(smd);
|
|
463
|
+
|
|
464
|
+
const keys = engine.devices.keyboard.keys;
|
|
465
|
+
|
|
466
|
+
function register_shortcuts_common() {
|
|
467
|
+
|
|
468
|
+
const ctrl = keys.ctrl;
|
|
469
|
+
|
|
470
|
+
keys.l.down.add(reinit);
|
|
471
|
+
keys.b.down.add(bake);
|
|
472
|
+
|
|
473
|
+
keys.z.down.add(() => {
|
|
474
|
+
|
|
475
|
+
if (ctrl.is_down) {
|
|
476
|
+
actions.undo();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
keys.y.down.add(() => {
|
|
482
|
+
|
|
483
|
+
if (ctrl.is_down) {
|
|
484
|
+
actions.redo();
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
keys.s.down.add(() => {
|
|
490
|
+
|
|
491
|
+
if (ctrl.is_down) {
|
|
492
|
+
|
|
493
|
+
const buffer = BinaryBuffer.fromEndianness(EndianType.LittleEndian);
|
|
494
|
+
|
|
495
|
+
const adapter = new LightProbeVolumeSerializationAdapter();
|
|
496
|
+
|
|
497
|
+
adapter.serialize(buffer, volume);
|
|
498
|
+
|
|
499
|
+
buffer.trim();
|
|
500
|
+
|
|
501
|
+
engine.storage.promiseStoreBinary(`lpv:${path_key}`, buffer.data);
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
const date = new Date();
|
|
505
|
+
|
|
506
|
+
downloadAsFile(buffer.data, `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}_${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}.lpv`)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
const state_bindings_nav = [
|
|
514
|
+
new SignalBinding(engine.devices.pointer.on.tap, () => {
|
|
515
|
+
const ray = make_ray_from_viewport_position(engine, engine.devices.pointer.position);
|
|
516
|
+
|
|
517
|
+
const sgm = em.getSystem(ShadedGeometrySystem);
|
|
518
|
+
|
|
519
|
+
const contact = new SurfacePoint3();
|
|
520
|
+
|
|
521
|
+
if (keys.ctrl.is_down) {
|
|
522
|
+
// create new entity
|
|
523
|
+
const entity = sgm.raycastNearest(
|
|
524
|
+
contact,
|
|
525
|
+
...ray.origin,
|
|
526
|
+
...ray.direction,
|
|
527
|
+
(entity) => {
|
|
528
|
+
return !(ecd.getComponent(entity, Tag)?.contains(PROBE_TAG_STRING));
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
if (entity !== undefined) {
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
const probe = create_probe_entity();
|
|
536
|
+
|
|
537
|
+
const p = new Vector3();
|
|
538
|
+
p.copy(contact.normal);
|
|
539
|
+
p.multiplyScalar(0.01);
|
|
540
|
+
p.add(contact.position);
|
|
541
|
+
|
|
542
|
+
const p2 = new SurfacePoint3();
|
|
543
|
+
|
|
544
|
+
// do raycast in opposite direction
|
|
545
|
+
const entity_2 = sgm.raycastNearest(
|
|
546
|
+
p2,
|
|
547
|
+
...p,
|
|
548
|
+
...contact.normal,
|
|
549
|
+
(entity) => {
|
|
550
|
+
return !(ecd.getComponent(entity, Tag)?.contains(PROBE_TAG_STRING));
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
if (entity_2 !== undefined && p2.position.distanceTo(p) < placement_surface_offset * 2) {
|
|
555
|
+
|
|
556
|
+
p.lerpVectors(p, p2.position, 0.5);
|
|
557
|
+
|
|
558
|
+
} else {
|
|
559
|
+
p.copy(contact.normal);
|
|
560
|
+
p.multiplyScalar(placement_surface_offset);
|
|
561
|
+
p.add(contact.position);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
probe.getComponent(Transform).position.copy(p);
|
|
565
|
+
|
|
566
|
+
ctx.createProbe(probe);
|
|
567
|
+
|
|
568
|
+
set_selection([probe.id]);
|
|
569
|
+
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
} else {
|
|
573
|
+
// do select
|
|
574
|
+
const entity = sgm.raycastNearest(
|
|
575
|
+
contact,
|
|
576
|
+
...ray.origin,
|
|
577
|
+
...ray.direction,
|
|
578
|
+
(entity) => {
|
|
579
|
+
return ecd.getComponent(entity, Tag)?.contains(PROBE_TAG_STRING);
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
|
|
583
|
+
if (entity !== undefined) {
|
|
584
|
+
|
|
585
|
+
const entity_id = entity.entity;
|
|
586
|
+
|
|
587
|
+
if (keys.shift.is_down) {
|
|
588
|
+
if (selected.includes(entity_id)) {
|
|
589
|
+
set_selection(selected.filter(e => e !== entity_id));
|
|
590
|
+
} else {
|
|
591
|
+
set_selection(selected.slice().concat(entity_id));
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
set_selection([entity_id]);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}),
|
|
599
|
+
new SignalBinding(keys.x.down, () => {
|
|
600
|
+
|
|
601
|
+
if (selected.length === 0) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const entities = selected.slice();
|
|
606
|
+
|
|
607
|
+
unselect();
|
|
608
|
+
|
|
609
|
+
actions.mark('Delete');
|
|
610
|
+
for (let i = 0; i < entities.length; i++) {
|
|
611
|
+
actions.do(ActionProbeRemove.from(entities[i]));
|
|
612
|
+
}
|
|
613
|
+
}),
|
|
614
|
+
new SignalBinding(keys.e.down, () => {
|
|
615
|
+
if (selected.length === 0) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
sm.navigateTo(STATE_TRANSFORM);
|
|
620
|
+
}),
|
|
621
|
+
new SignalBinding(keys.a.down, () => {
|
|
622
|
+
if (keys.ctrl.is_down) {
|
|
623
|
+
// select all
|
|
624
|
+
set_selection(ctx.probes.map(e => e.id));
|
|
625
|
+
}
|
|
626
|
+
})
|
|
627
|
+
];
|
|
628
|
+
|
|
629
|
+
sm.addEventHandlerStateEntry(STATE_NAVIGATION, () => {
|
|
630
|
+
camera_controller.build(ecd);
|
|
631
|
+
|
|
632
|
+
state_bindings_nav.forEach(b => b.link());
|
|
633
|
+
});
|
|
634
|
+
sm.addEventHandlerStateExit(STATE_NAVIGATION, () => {
|
|
635
|
+
camera_controller.destroy();
|
|
636
|
+
|
|
637
|
+
state_bindings_nav.forEach(b => b.unlink())
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
const state_bindings_transform = [
|
|
641
|
+
|
|
642
|
+
new SignalBinding(keys.e.down, () => {
|
|
643
|
+
sm.navigateTo(STATE_NAVIGATION);
|
|
644
|
+
}),
|
|
645
|
+
];
|
|
646
|
+
|
|
647
|
+
sm.addEventHandlerStateEntry(STATE_TRANSFORM, () => {
|
|
648
|
+
state_bindings_transform.forEach(b => b.link());
|
|
649
|
+
|
|
650
|
+
attach_transform(selected);
|
|
651
|
+
});
|
|
652
|
+
sm.addEventHandlerStateExit(STATE_TRANSFORM, () => {
|
|
653
|
+
state_bindings_transform.forEach(b => b.unlink());
|
|
654
|
+
|
|
655
|
+
controls.detach();
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
sm.setState(STATE_NAVIGATION);
|
|
659
|
+
|
|
660
|
+
function initialize_from_volume() {
|
|
661
|
+
|
|
662
|
+
for (let i = 0; i < volume.count; i++) {
|
|
663
|
+
|
|
664
|
+
const entity = create_probe_entity(i);
|
|
665
|
+
|
|
666
|
+
entity.getComponent(Transform).position.fromArray(volume.points, i * 3);
|
|
667
|
+
|
|
668
|
+
ctx.probes.push(entity);
|
|
669
|
+
|
|
670
|
+
entity.build(ecd);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function update_volume_visual() {
|
|
676
|
+
const transformers = engine.graphics.getMaterialManager().getCompilationSteps(MaterialTransformer);
|
|
677
|
+
|
|
678
|
+
ctx.ensureMesh();
|
|
679
|
+
|
|
680
|
+
transformers.forEach(t => t.update());
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function reinit() {
|
|
684
|
+
unselect();
|
|
685
|
+
ctx.probes.forEach(p => p.destroy());
|
|
686
|
+
ctx.probes.splice(0, ctx.probes.length);
|
|
687
|
+
initialize_from_volume();
|
|
688
|
+
|
|
689
|
+
console.log(volume);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
initialize_from_volume();
|
|
694
|
+
register_shortcuts_common();
|
|
695
|
+
}
|