minerender 2.1.0-alpha.42 → 2.1.0-alpha.43

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.
@@ -3100,6 +3100,10 @@ var SceneObject = class _SceneObject extends Object3D2 {
3100
3100
  this.setMatrixAt(index, new Matrix43());
3101
3101
  return reference;
3102
3102
  }
3103
+ /** Returns the live reference for a raycast hit on this object's instance mesh. */
3104
+ getInstanceReference(mesh, index) {
3105
+ return mesh === this.instanceMesh ? this.instanceReferences.get(index) : void 0;
3106
+ }
3103
3107
  isInstanceActive(index, reference) {
3104
3108
  return this.instanceReferences.get(index) === reference;
3105
3109
  }
@@ -3182,9 +3186,9 @@ var SceneObject = class _SceneObject extends Object3D2 {
3182
3186
  }
3183
3187
  getRotationAt(index, euler = new Euler3()) {
3184
3188
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3185
- const matrix = this.getMatrixAt(index);
3186
- euler.setFromRotationMatrix(matrix);
3187
- return euler;
3189
+ const rotation = new Quaternion3();
3190
+ this.getMatrixAt(index).decompose(new Vector35(), rotation, new Vector35());
3191
+ return euler.setFromQuaternion(rotation);
3188
3192
  }
3189
3193
  setScaleAt(index, scale) {
3190
3194
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
@@ -3434,11 +3438,12 @@ var GuiObject = class extends SceneObject {
3434
3438
  // src/inspector/SceneInspector.ts
3435
3439
  import { Raycaster, Vector2 as Vector22 } from "three";
3436
3440
  var p7 = prefix("SceneInspector");
3437
- var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3441
+ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
3438
3442
  var SceneInspector = class {
3439
3443
  constructor(renderer) {
3440
3444
  this.renderer = renderer;
3441
3445
  this.mouse = new Vector22();
3446
+ this.listeners = new AbortController();
3442
3447
  this.objectInfoContainer = document.createElement("div");
3443
3448
  this.objectControlsContainer = document.createElement("div");
3444
3449
  this.raycaster = new Raycaster();
@@ -3448,13 +3453,44 @@ var SceneInspector = class {
3448
3453
  this.objectInfoContainer.classList.add("minerender-inspector", "minerender-object-info");
3449
3454
  this.objectControlsContainer.classList.add("minerender-inspector", "minerender-object-controls");
3450
3455
  this.objectInfoContainer.innerHTML = help;
3451
- document.addEventListener("click", this.onClick.bind(this), {
3452
- passive: true
3453
- });
3456
+ const canvas = this.renderer.renderer.domElement;
3457
+ const options = { signal: this.listeners.signal };
3458
+ canvas.addEventListener("pointerdown", (event) => {
3459
+ this.pointer = event.button === 0 && (event.ctrlKey || event.metaKey) ? event : void 0;
3460
+ }, options);
3461
+ canvas.addEventListener("pointermove", (event) => {
3462
+ if (this.pointer?.pointerId === event.pointerId && Math.hypot(event.clientX - this.pointer.clientX, event.clientY - this.pointer.clientY) > 5) {
3463
+ this.pointer = void 0;
3464
+ }
3465
+ }, options);
3466
+ canvas.addEventListener("pointerup", (event) => {
3467
+ const start = this.pointer;
3468
+ this.pointer = void 0;
3469
+ if (start?.pointerId === event.pointerId && Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) <= 5) {
3470
+ this.onClick(event);
3471
+ }
3472
+ }, options);
3473
+ canvas.addEventListener("pointercancel", () => {
3474
+ this.pointer = void 0;
3475
+ }, options);
3476
+ canvas.addEventListener("pointerleave", () => {
3477
+ this.pointer = void 0;
3478
+ }, options);
3479
+ canvas.addEventListener("contextmenu", (event) => {
3480
+ if (this.pointer?.ctrlKey) event.preventDefault();
3481
+ }, options);
3482
+ }
3483
+ dispose() {
3484
+ this.listeners.abort();
3485
+ this.pointer = void 0;
3486
+ this.selectedObject = void 0;
3487
+ this.objectInfoContainer.remove();
3488
+ this.objectControlsContainer.remove();
3454
3489
  }
3455
3490
  findMeshChildren(from, out = []) {
3491
+ if (!from.visible) return out;
3456
3492
  for (let c of from.children) {
3457
- if (isMesh(c)) {
3493
+ if (c.visible && isMesh(c)) {
3458
3494
  out.push(c);
3459
3495
  }
3460
3496
  this.findMeshChildren(c, out);
@@ -3462,50 +3498,43 @@ var SceneInspector = class {
3462
3498
  return out;
3463
3499
  }
3464
3500
  onClick(event) {
3465
- if (event.target?.nodeName !== "CANVAS") return;
3466
- if (!event.ctrlKey) return;
3467
- setTimeout(() => {
3468
- this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
3469
- this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
3470
- this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3471
- let start = Date.now();
3472
- let targets = this.findMeshChildren(this.renderer.scene);
3473
- const intersects = this.raycaster.intersectObjects(targets, false);
3474
- console.debug("Raycast took " + (Date.now() - start) + "ms for " + targets.length + " possible targets with " + intersects.length + " results");
3475
- if (intersects.length > 0) {
3476
- this.handleRaycasterObjects(intersects);
3477
- }
3478
- });
3501
+ const canvas = this.renderer.renderer.domElement;
3502
+ if (event.target !== canvas || event.button !== 0 || !(event.ctrlKey || event.metaKey)) return;
3503
+ const rect = canvas.getBoundingClientRect();
3504
+ const x = event.clientX - rect.left, y = event.clientY - rect.top;
3505
+ if (rect.width <= 0 || rect.height <= 0 || x < 0 || y < 0 || x >= rect.width || y >= rect.height) return;
3506
+ this.mouse.set(x / rect.width * 2 - 1, 1 - y / rect.height * 2);
3507
+ this.renderer.camera.updateWorldMatrix(true, false);
3508
+ this.renderer.scene.updateMatrixWorld(true);
3509
+ this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3510
+ this.handleRaycasterObjects(this.raycaster.intersectObjects(this.findMeshChildren(this.renderer.scene), false));
3479
3511
  }
3480
3512
  appendTo(el) {
3481
3513
  el.append(this.objectInfoContainer);
3482
3514
  el.append(this.objectControlsContainer);
3483
3515
  }
3484
3516
  handleRaycasterObjects(intersections) {
3485
- console.debug(intersections);
3486
- const firstIntersection = intersections[0];
3487
- if (firstIntersection && firstIntersection.object) {
3488
- const firstObject = firstIntersection.object;
3489
- let targetIntersection = void 0;
3490
- let targetObject = void 0;
3491
- const firstSceneObjectIntersection = intersections.find((i) => i.object && i.object.parent && isSceneObject(i.object.parent));
3492
- if (firstSceneObjectIntersection && firstSceneObjectIntersection.object) {
3493
- targetIntersection = firstSceneObjectIntersection;
3494
- targetObject = firstSceneObjectIntersection.object;
3495
- } else {
3496
- targetIntersection = firstIntersection;
3497
- targetObject = firstObject;
3517
+ const hit = intersections[0];
3518
+ if (!hit) return;
3519
+ const instance = this.getIntersectionInstance(hit);
3520
+ this.selectObject(instance?.instanceable ?? hit.object, hit, instance);
3521
+ }
3522
+ getIntersectionInstance(hit) {
3523
+ if (hit?.instanceId === void 0) return void 0;
3524
+ for (let parent = hit.object.parent; parent; parent = parent.parent) {
3525
+ if (isSceneObject(parent)) {
3526
+ const instance = parent.getInstanceReference(hit.object, hit.instanceId);
3527
+ if (instance) return instance;
3498
3528
  }
3499
- if (!targetIntersection || !targetObject) return;
3500
- this.selectObject(targetObject, targetIntersection);
3501
3529
  }
3530
+ return void 0;
3502
3531
  }
3503
- selectObject(targetObject, targetIntersection) {
3532
+ selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
3504
3533
  this.selectedObject = targetObject;
3505
3534
  console.log(p7, "selected", targetObject);
3506
- this.redraw(targetObject, targetIntersection);
3535
+ this.redraw(targetObject, targetIntersection, instance);
3507
3536
  }
3508
- redraw(targetObject, targetIntersection) {
3537
+ redraw(targetObject, targetIntersection, instance) {
3509
3538
  this.objectInfoContainer.innerHTML = help;
3510
3539
  if (targetIntersection) {
3511
3540
  this.addInfoLine("Distance", "D", targetIntersection.distance);
@@ -3518,8 +3547,8 @@ var SceneInspector = class {
3518
3547
  if (isSceneObject(targetObject.parent)) {
3519
3548
  }
3520
3549
  }
3521
- if ("atlas" in targetObject) {
3522
- const atlas = targetObject["atlas"];
3550
+ const atlas = "atlas" in targetObject ? targetObject["atlas"] : void 0;
3551
+ if (atlas?.image.canvas) {
3523
3552
  const img = atlas.image.canvas;
3524
3553
  img.style.width = "100px";
3525
3554
  img.style.height = "100px";
@@ -3528,28 +3557,31 @@ var SceneInspector = class {
3528
3557
  this.objectInfoContainer.prepend(img);
3529
3558
  }
3530
3559
  this.objectControlsContainer.innerHTML = "";
3531
- this.addControls(targetObject, targetIntersection);
3560
+ this.addControls(targetObject, targetIntersection, instance);
3532
3561
  }
3533
- addControls(object, intersection) {
3562
+ addControls(object, intersection, instance) {
3534
3563
  const container = document.createElement("div");
3535
3564
  container.append(this.separator("Select Parent/Child"));
3536
3565
  if (object.parent) {
3537
3566
  container.append(this.buttonControl("Select Parent " + object.parent.constructor.name + " " + object.parent.name, "P", () => {
3538
- this.selectObject(object.parent, intersection);
3567
+ this.selectObject(object.parent, intersection, instance);
3539
3568
  }));
3540
3569
  }
3541
3570
  if (object.children.length > 0) {
3542
3571
  let i = 1;
3543
3572
  for (let child of object.children) {
3544
3573
  container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
3545
- this.selectObject(child, intersection);
3574
+ this.selectObject(child, intersection, instance);
3546
3575
  }));
3547
3576
  }
3548
3577
  }
3549
3578
  container.append(this.separator());
3550
- container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3579
+ const selectedInstance = instance && (object === instance.instanceable || object === intersection?.object) ? instance : void 0;
3580
+ if (!selectedInstance) {
3581
+ container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3582
+ }
3551
3583
  container.append(this.separator("Mesh"));
3552
- this.addObjectControls(object, intersection, container);
3584
+ this.addObjectControls(object, intersection, container, selectedInstance);
3553
3585
  container.append(this.separator());
3554
3586
  this.objectControlsContainer.append(container);
3555
3587
  }
@@ -3561,78 +3593,26 @@ var SceneInspector = class {
3561
3593
  this.objectInfoContainer.append(document.createElement("br"));
3562
3594
  return el;
3563
3595
  }
3564
- addObjectControls(target, intersection, container) {
3596
+ addObjectControls(target, intersection, container, instance) {
3565
3597
  const posRange = 16 * 16;
3566
3598
  const rotRange = 360;
3567
3599
  const scaleRange = 4;
3568
- if (typeof intersection !== "undefined" && typeof intersection.instanceId !== "undefined" && isSceneObject(target) && target.isInstanced) {
3569
- const scObj = target;
3570
- container.append(this.separator("Position"));
3571
- let pos = scObj.getPositionAt(intersection.instanceId);
3572
- container.append(this.rangeControl("X Position", "X", -posRange + pos.x, posRange + pos.x, pos.x, 1, (v) => {
3573
- pos = scObj.getPositionAt(intersection.instanceId);
3574
- pos.x = v;
3575
- scObj.setPositionAt(intersection.instanceId, pos);
3576
- }));
3577
- container.append(this.rangeControl("Y Position", "Y", -posRange + pos.y, posRange + pos.y, pos.y, 1, (v) => {
3578
- pos = scObj.getPositionAt(intersection.instanceId);
3579
- pos.y = v;
3580
- scObj.setPositionAt(intersection.instanceId, pos);
3581
- }));
3582
- container.append(this.rangeControl("Z Position", "Z", -posRange + pos.z, posRange + pos.z, pos.z, 1, (v) => {
3583
- pos = scObj.getPositionAt(intersection.instanceId);
3584
- pos.z = v;
3585
- scObj.setPositionAt(intersection.instanceId, pos);
3586
- }));
3587
- container.append(this.separator("Rotation"));
3588
- let rot = scObj.getRotationAt(intersection.instanceId);
3589
- container.append(this.rangeControl("X Rotation", "X", 0, rotRange, Math.round(toDegrees(rot.x)), 1, (v) => {
3590
- rot = scObj.getRotationAt(intersection.instanceId);
3591
- rot.x = toRadians(v);
3592
- scObj.setRotationAt(intersection.instanceId, rot);
3593
- }));
3594
- container.append(this.rangeControl("Y Rotation", "Y", 0, rotRange, Math.round(toDegrees(rot.y)), 1, (v) => {
3595
- rot = scObj.getRotationAt(intersection.instanceId);
3596
- rot.y = toRadians(v);
3597
- scObj.setRotationAt(intersection.instanceId, rot);
3598
- }));
3599
- container.append(this.rangeControl("Z Rotation", "Z", 0, rotRange, Math.round(toDegrees(rot.z)), 1, (v) => {
3600
- rot = scObj.getRotationAt(intersection.instanceId);
3601
- rot.z = toRadians(v);
3602
- scObj.setRotationAt(intersection.instanceId, rot);
3603
- }));
3604
- container.append(this.separator("Scale"));
3605
- let scl = scObj.getScale();
3606
- container.append(this.rangeControl("X Scale", "X", 0, scaleRange, scl.x, 0.1, (v) => {
3607
- scl = scObj.getScaleAt(intersection.instanceId);
3608
- scl.x = v;
3609
- scObj.setScaleAt(intersection.instanceId, scl);
3610
- }));
3611
- container.append(this.rangeControl("Y Scale", "Y", 0, scaleRange, scl.y, 0.1, (v) => {
3612
- scl = scObj.getScaleAt(intersection.instanceId);
3613
- scl.y = v;
3614
- scObj.setScaleAt(intersection.instanceId, scl);
3615
- }));
3616
- container.append(this.rangeControl("Z Scale", "Z", 0, scaleRange, scl.z, 0.1, (v) => {
3617
- scl = scObj.getScaleAt(intersection.instanceId);
3618
- scl.z = v;
3619
- scObj.setScaleAt(intersection.instanceId, scl);
3620
- }));
3621
- } else if (isTransformable(target)) {
3622
- const parent = target;
3600
+ const transform = instance ?? (isTransformable(target) ? target : void 0);
3601
+ if (transform) {
3602
+ const parent = transform;
3623
3603
  container.append(this.separator("Position"));
3624
3604
  let pos = parent.getPosition();
3625
- container.append(this.rangeControl("X Position", "X", -posRange, posRange, pos.x, 1, (v) => {
3605
+ container.append(this.rangeControl("X Position", "X", pos.x - posRange, pos.x + posRange, pos.x, 1, (v) => {
3626
3606
  pos = parent.getPosition();
3627
3607
  pos.x = v;
3628
3608
  parent.setPosition(pos);
3629
3609
  }));
3630
- container.append(this.rangeControl("Y Position", "Y", -posRange, posRange, pos.y, 1, (v) => {
3610
+ container.append(this.rangeControl("Y Position", "Y", pos.y - posRange, pos.y + posRange, pos.y, 1, (v) => {
3631
3611
  pos = parent.getPosition();
3632
3612
  pos.y = v;
3633
3613
  parent.setPosition(pos);
3634
3614
  }));
3635
- container.append(this.rangeControl("Z Position", "Z", -posRange, posRange, pos.z, 1, (v) => {
3615
+ container.append(this.rangeControl("Z Position", "Z", pos.z - posRange, pos.z + posRange, pos.z, 1, (v) => {
3636
3616
  pos = parent.getPosition();
3637
3617
  pos.z = v;
3638
3618
  parent.setPosition(pos);
@@ -3721,6 +3701,7 @@ var SceneInspector = class {
3721
3701
  toggle.checked = val;
3722
3702
  toggle.addEventListener("change", (e) => {
3723
3703
  change(toggle.checked);
3704
+ this.renderer.scene.dirty = true;
3724
3705
  });
3725
3706
  label.append(toggle);
3726
3707
  label.append(document.createElement("br"));
@@ -3733,7 +3714,6 @@ var SceneInspector = class {
3733
3714
  label.setAttribute("title", name);
3734
3715
  labelText.style.width = "18%";
3735
3716
  labelText.style.display = "inline-block";
3736
- labelText.innerText = `${id} (${val})`;
3737
3717
  const range = document.createElement("input");
3738
3718
  range.setAttribute("type", "range");
3739
3719
  range.style.width = "80%";
@@ -3741,8 +3721,10 @@ var SceneInspector = class {
3741
3721
  range.min = `${min}`;
3742
3722
  range.step = `${step}`;
3743
3723
  range.value = `${val}`;
3724
+ labelText.innerText = `${id} (${range.value})`;
3744
3725
  const onChange = () => {
3745
3726
  change(parseFloat(range.value));
3727
+ this.renderer.scene.dirty = true;
3746
3728
  labelText.innerText = `${id} (${range.value})`;
3747
3729
  };
3748
3730
  range.addEventListener("input", onChange);