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.
@@ -3048,6 +3048,10 @@ var _SceneObject = class _SceneObject extends Object3D2 {
3048
3048
  this.setMatrixAt(index, new Matrix43());
3049
3049
  return reference;
3050
3050
  }
3051
+ /** Returns the live reference for a raycast hit on this object's instance mesh. */
3052
+ getInstanceReference(mesh, index) {
3053
+ return mesh === this.instanceMesh ? this.instanceReferences.get(index) : void 0;
3054
+ }
3051
3055
  isInstanceActive(index, reference) {
3052
3056
  return this.instanceReferences.get(index) === reference;
3053
3057
  }
@@ -3130,9 +3134,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
3130
3134
  }
3131
3135
  getRotationAt(index, euler = new Euler3()) {
3132
3136
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3133
- const matrix = this.getMatrixAt(index);
3134
- euler.setFromRotationMatrix(matrix);
3135
- return euler;
3137
+ const rotation = new Quaternion3();
3138
+ this.getMatrixAt(index).decompose(new Vector35(), rotation, new Vector35());
3139
+ return euler.setFromQuaternion(rotation);
3136
3140
  }
3137
3141
  setScaleAt(index, scale) {
3138
3142
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
@@ -3388,11 +3392,12 @@ var GuiObject = class extends SceneObject {
3388
3392
  // src/inspector/SceneInspector.ts
3389
3393
  import { Raycaster, Vector2 as Vector22 } from "three";
3390
3394
  var p7 = prefix("SceneInspector");
3391
- var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3395
+ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
3392
3396
  var SceneInspector = class {
3393
3397
  constructor(renderer) {
3394
3398
  this.renderer = renderer;
3395
3399
  this.mouse = new Vector22();
3400
+ this.listeners = new AbortController();
3396
3401
  this.objectInfoContainer = document.createElement("div");
3397
3402
  this.objectControlsContainer = document.createElement("div");
3398
3403
  this.raycaster = new Raycaster();
@@ -3402,13 +3407,44 @@ var SceneInspector = class {
3402
3407
  this.objectInfoContainer.classList.add("minerender-inspector", "minerender-object-info");
3403
3408
  this.objectControlsContainer.classList.add("minerender-inspector", "minerender-object-controls");
3404
3409
  this.objectInfoContainer.innerHTML = help;
3405
- document.addEventListener("click", this.onClick.bind(this), {
3406
- passive: true
3407
- });
3410
+ const canvas = this.renderer.renderer.domElement;
3411
+ const options = { signal: this.listeners.signal };
3412
+ canvas.addEventListener("pointerdown", (event) => {
3413
+ this.pointer = event.button === 0 && (event.ctrlKey || event.metaKey) ? event : void 0;
3414
+ }, options);
3415
+ canvas.addEventListener("pointermove", (event) => {
3416
+ if (this.pointer?.pointerId === event.pointerId && Math.hypot(event.clientX - this.pointer.clientX, event.clientY - this.pointer.clientY) > 5) {
3417
+ this.pointer = void 0;
3418
+ }
3419
+ }, options);
3420
+ canvas.addEventListener("pointerup", (event) => {
3421
+ const start = this.pointer;
3422
+ this.pointer = void 0;
3423
+ if (start?.pointerId === event.pointerId && Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) <= 5) {
3424
+ this.onClick(event);
3425
+ }
3426
+ }, options);
3427
+ canvas.addEventListener("pointercancel", () => {
3428
+ this.pointer = void 0;
3429
+ }, options);
3430
+ canvas.addEventListener("pointerleave", () => {
3431
+ this.pointer = void 0;
3432
+ }, options);
3433
+ canvas.addEventListener("contextmenu", (event) => {
3434
+ if (this.pointer?.ctrlKey) event.preventDefault();
3435
+ }, options);
3436
+ }
3437
+ dispose() {
3438
+ this.listeners.abort();
3439
+ this.pointer = void 0;
3440
+ this.selectedObject = void 0;
3441
+ this.objectInfoContainer.remove();
3442
+ this.objectControlsContainer.remove();
3408
3443
  }
3409
3444
  findMeshChildren(from, out = []) {
3445
+ if (!from.visible) return out;
3410
3446
  for (let c of from.children) {
3411
- if (isMesh(c)) {
3447
+ if (c.visible && isMesh(c)) {
3412
3448
  out.push(c);
3413
3449
  }
3414
3450
  this.findMeshChildren(c, out);
@@ -3416,50 +3452,43 @@ var SceneInspector = class {
3416
3452
  return out;
3417
3453
  }
3418
3454
  onClick(event) {
3419
- if (event.target?.nodeName !== "CANVAS") return;
3420
- if (!event.ctrlKey) return;
3421
- setTimeout(() => {
3422
- this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
3423
- this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
3424
- this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3425
- let start = Date.now();
3426
- let targets = this.findMeshChildren(this.renderer.scene);
3427
- const intersects = this.raycaster.intersectObjects(targets, false);
3428
- console.debug("Raycast took " + (Date.now() - start) + "ms for " + targets.length + " possible targets with " + intersects.length + " results");
3429
- if (intersects.length > 0) {
3430
- this.handleRaycasterObjects(intersects);
3431
- }
3432
- });
3455
+ const canvas = this.renderer.renderer.domElement;
3456
+ if (event.target !== canvas || event.button !== 0 || !(event.ctrlKey || event.metaKey)) return;
3457
+ const rect = canvas.getBoundingClientRect();
3458
+ const x = event.clientX - rect.left, y = event.clientY - rect.top;
3459
+ if (rect.width <= 0 || rect.height <= 0 || x < 0 || y < 0 || x >= rect.width || y >= rect.height) return;
3460
+ this.mouse.set(x / rect.width * 2 - 1, 1 - y / rect.height * 2);
3461
+ this.renderer.camera.updateWorldMatrix(true, false);
3462
+ this.renderer.scene.updateMatrixWorld(true);
3463
+ this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3464
+ this.handleRaycasterObjects(this.raycaster.intersectObjects(this.findMeshChildren(this.renderer.scene), false));
3433
3465
  }
3434
3466
  appendTo(el) {
3435
3467
  el.append(this.objectInfoContainer);
3436
3468
  el.append(this.objectControlsContainer);
3437
3469
  }
3438
3470
  handleRaycasterObjects(intersections) {
3439
- console.debug(intersections);
3440
- const firstIntersection = intersections[0];
3441
- if (firstIntersection && firstIntersection.object) {
3442
- const firstObject = firstIntersection.object;
3443
- let targetIntersection = void 0;
3444
- let targetObject = void 0;
3445
- const firstSceneObjectIntersection = intersections.find((i) => i.object && i.object.parent && isSceneObject(i.object.parent));
3446
- if (firstSceneObjectIntersection && firstSceneObjectIntersection.object) {
3447
- targetIntersection = firstSceneObjectIntersection;
3448
- targetObject = firstSceneObjectIntersection.object;
3449
- } else {
3450
- targetIntersection = firstIntersection;
3451
- targetObject = firstObject;
3471
+ const hit = intersections[0];
3472
+ if (!hit) return;
3473
+ const instance = this.getIntersectionInstance(hit);
3474
+ this.selectObject(instance?.instanceable ?? hit.object, hit, instance);
3475
+ }
3476
+ getIntersectionInstance(hit) {
3477
+ if (hit?.instanceId === void 0) return void 0;
3478
+ for (let parent = hit.object.parent; parent; parent = parent.parent) {
3479
+ if (isSceneObject(parent)) {
3480
+ const instance = parent.getInstanceReference(hit.object, hit.instanceId);
3481
+ if (instance) return instance;
3452
3482
  }
3453
- if (!targetIntersection || !targetObject) return;
3454
- this.selectObject(targetObject, targetIntersection);
3455
3483
  }
3484
+ return void 0;
3456
3485
  }
3457
- selectObject(targetObject, targetIntersection) {
3486
+ selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
3458
3487
  this.selectedObject = targetObject;
3459
3488
  console.log(p7, "selected", targetObject);
3460
- this.redraw(targetObject, targetIntersection);
3489
+ this.redraw(targetObject, targetIntersection, instance);
3461
3490
  }
3462
- redraw(targetObject, targetIntersection) {
3491
+ redraw(targetObject, targetIntersection, instance) {
3463
3492
  this.objectInfoContainer.innerHTML = help;
3464
3493
  if (targetIntersection) {
3465
3494
  this.addInfoLine("Distance", "D", targetIntersection.distance);
@@ -3472,8 +3501,8 @@ var SceneInspector = class {
3472
3501
  if (isSceneObject(targetObject.parent)) {
3473
3502
  }
3474
3503
  }
3475
- if ("atlas" in targetObject) {
3476
- const atlas = targetObject["atlas"];
3504
+ const atlas = "atlas" in targetObject ? targetObject["atlas"] : void 0;
3505
+ if (atlas?.image.canvas) {
3477
3506
  const img = atlas.image.canvas;
3478
3507
  img.style.width = "100px";
3479
3508
  img.style.height = "100px";
@@ -3482,28 +3511,31 @@ var SceneInspector = class {
3482
3511
  this.objectInfoContainer.prepend(img);
3483
3512
  }
3484
3513
  this.objectControlsContainer.innerHTML = "";
3485
- this.addControls(targetObject, targetIntersection);
3514
+ this.addControls(targetObject, targetIntersection, instance);
3486
3515
  }
3487
- addControls(object, intersection) {
3516
+ addControls(object, intersection, instance) {
3488
3517
  const container = document.createElement("div");
3489
3518
  container.append(this.separator("Select Parent/Child"));
3490
3519
  if (object.parent) {
3491
3520
  container.append(this.buttonControl("Select Parent " + object.parent.constructor.name + " " + object.parent.name, "P", () => {
3492
- this.selectObject(object.parent, intersection);
3521
+ this.selectObject(object.parent, intersection, instance);
3493
3522
  }));
3494
3523
  }
3495
3524
  if (object.children.length > 0) {
3496
3525
  let i = 1;
3497
3526
  for (let child of object.children) {
3498
3527
  container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
3499
- this.selectObject(child, intersection);
3528
+ this.selectObject(child, intersection, instance);
3500
3529
  }));
3501
3530
  }
3502
3531
  }
3503
3532
  container.append(this.separator());
3504
- container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3533
+ const selectedInstance = instance && (object === instance.instanceable || object === intersection?.object) ? instance : void 0;
3534
+ if (!selectedInstance) {
3535
+ container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3536
+ }
3505
3537
  container.append(this.separator("Mesh"));
3506
- this.addObjectControls(object, intersection, container);
3538
+ this.addObjectControls(object, intersection, container, selectedInstance);
3507
3539
  container.append(this.separator());
3508
3540
  this.objectControlsContainer.append(container);
3509
3541
  }
@@ -3515,78 +3547,26 @@ var SceneInspector = class {
3515
3547
  this.objectInfoContainer.append(document.createElement("br"));
3516
3548
  return el;
3517
3549
  }
3518
- addObjectControls(target, intersection, container) {
3550
+ addObjectControls(target, intersection, container, instance) {
3519
3551
  const posRange = 16 * 16;
3520
3552
  const rotRange = 360;
3521
3553
  const scaleRange = 4;
3522
- if (typeof intersection !== "undefined" && typeof intersection.instanceId !== "undefined" && isSceneObject(target) && target.isInstanced) {
3523
- const scObj = target;
3524
- container.append(this.separator("Position"));
3525
- let pos = scObj.getPositionAt(intersection.instanceId);
3526
- container.append(this.rangeControl("X Position", "X", -posRange + pos.x, posRange + pos.x, pos.x, 1, (v) => {
3527
- pos = scObj.getPositionAt(intersection.instanceId);
3528
- pos.x = v;
3529
- scObj.setPositionAt(intersection.instanceId, pos);
3530
- }));
3531
- container.append(this.rangeControl("Y Position", "Y", -posRange + pos.y, posRange + pos.y, pos.y, 1, (v) => {
3532
- pos = scObj.getPositionAt(intersection.instanceId);
3533
- pos.y = v;
3534
- scObj.setPositionAt(intersection.instanceId, pos);
3535
- }));
3536
- container.append(this.rangeControl("Z Position", "Z", -posRange + pos.z, posRange + pos.z, pos.z, 1, (v) => {
3537
- pos = scObj.getPositionAt(intersection.instanceId);
3538
- pos.z = v;
3539
- scObj.setPositionAt(intersection.instanceId, pos);
3540
- }));
3541
- container.append(this.separator("Rotation"));
3542
- let rot = scObj.getRotationAt(intersection.instanceId);
3543
- container.append(this.rangeControl("X Rotation", "X", 0, rotRange, Math.round(toDegrees(rot.x)), 1, (v) => {
3544
- rot = scObj.getRotationAt(intersection.instanceId);
3545
- rot.x = toRadians(v);
3546
- scObj.setRotationAt(intersection.instanceId, rot);
3547
- }));
3548
- container.append(this.rangeControl("Y Rotation", "Y", 0, rotRange, Math.round(toDegrees(rot.y)), 1, (v) => {
3549
- rot = scObj.getRotationAt(intersection.instanceId);
3550
- rot.y = toRadians(v);
3551
- scObj.setRotationAt(intersection.instanceId, rot);
3552
- }));
3553
- container.append(this.rangeControl("Z Rotation", "Z", 0, rotRange, Math.round(toDegrees(rot.z)), 1, (v) => {
3554
- rot = scObj.getRotationAt(intersection.instanceId);
3555
- rot.z = toRadians(v);
3556
- scObj.setRotationAt(intersection.instanceId, rot);
3557
- }));
3558
- container.append(this.separator("Scale"));
3559
- let scl = scObj.getScale();
3560
- container.append(this.rangeControl("X Scale", "X", 0, scaleRange, scl.x, 0.1, (v) => {
3561
- scl = scObj.getScaleAt(intersection.instanceId);
3562
- scl.x = v;
3563
- scObj.setScaleAt(intersection.instanceId, scl);
3564
- }));
3565
- container.append(this.rangeControl("Y Scale", "Y", 0, scaleRange, scl.y, 0.1, (v) => {
3566
- scl = scObj.getScaleAt(intersection.instanceId);
3567
- scl.y = v;
3568
- scObj.setScaleAt(intersection.instanceId, scl);
3569
- }));
3570
- container.append(this.rangeControl("Z Scale", "Z", 0, scaleRange, scl.z, 0.1, (v) => {
3571
- scl = scObj.getScaleAt(intersection.instanceId);
3572
- scl.z = v;
3573
- scObj.setScaleAt(intersection.instanceId, scl);
3574
- }));
3575
- } else if (isTransformable(target)) {
3576
- const parent = target;
3554
+ const transform = instance ?? (isTransformable(target) ? target : void 0);
3555
+ if (transform) {
3556
+ const parent = transform;
3577
3557
  container.append(this.separator("Position"));
3578
3558
  let pos = parent.getPosition();
3579
- container.append(this.rangeControl("X Position", "X", -posRange, posRange, pos.x, 1, (v) => {
3559
+ container.append(this.rangeControl("X Position", "X", pos.x - posRange, pos.x + posRange, pos.x, 1, (v) => {
3580
3560
  pos = parent.getPosition();
3581
3561
  pos.x = v;
3582
3562
  parent.setPosition(pos);
3583
3563
  }));
3584
- container.append(this.rangeControl("Y Position", "Y", -posRange, posRange, pos.y, 1, (v) => {
3564
+ container.append(this.rangeControl("Y Position", "Y", pos.y - posRange, pos.y + posRange, pos.y, 1, (v) => {
3585
3565
  pos = parent.getPosition();
3586
3566
  pos.y = v;
3587
3567
  parent.setPosition(pos);
3588
3568
  }));
3589
- container.append(this.rangeControl("Z Position", "Z", -posRange, posRange, pos.z, 1, (v) => {
3569
+ container.append(this.rangeControl("Z Position", "Z", pos.z - posRange, pos.z + posRange, pos.z, 1, (v) => {
3590
3570
  pos = parent.getPosition();
3591
3571
  pos.z = v;
3592
3572
  parent.setPosition(pos);
@@ -3675,6 +3655,7 @@ var SceneInspector = class {
3675
3655
  toggle.checked = val;
3676
3656
  toggle.addEventListener("change", (e) => {
3677
3657
  change(toggle.checked);
3658
+ this.renderer.scene.dirty = true;
3678
3659
  });
3679
3660
  label.append(toggle);
3680
3661
  label.append(document.createElement("br"));
@@ -3687,7 +3668,6 @@ var SceneInspector = class {
3687
3668
  label.setAttribute("title", name);
3688
3669
  labelText.style.width = "18%";
3689
3670
  labelText.style.display = "inline-block";
3690
- labelText.innerText = `${id} (${val})`;
3691
3671
  const range = document.createElement("input");
3692
3672
  range.setAttribute("type", "range");
3693
3673
  range.style.width = "80%";
@@ -3695,8 +3675,10 @@ var SceneInspector = class {
3695
3675
  range.min = `${min}`;
3696
3676
  range.step = `${step}`;
3697
3677
  range.value = `${val}`;
3678
+ labelText.innerText = `${id} (${range.value})`;
3698
3679
  const onChange = () => {
3699
3680
  change(parseFloat(range.value));
3681
+ this.renderer.scene.dirty = true;
3700
3682
  labelText.innerText = `${id} (${range.value})`;
3701
3683
  };
3702
3684
  range.addEventListener("input", onChange);