Вращение камеры вокруг центра выбранного элемента three.js

Рейтинг: 0Ответов: 0Опубликовано: 01.07.2023

В сцене у меня есть несколько 3D объектов, объекты выделяются при клике (меняется материал) при этом задается centerPoint - это центр выбранной геоментрии или 0,0,0. Я пытаюсь создать навигацию в сцене и вращать камеру вокруг выбранного элемента, вращение происходит при перемещении мыши и зажатых колесике мыши + Shift. Чтобы камера вращалась вокруг точки я использовал camera.lookAt(centerPoint) , но кажеться это не верно, потому что при выборе другого объекта и начале вращения камера перескакивает в новую позицию. Как от этого избавиться?

Можно конечно переместить камеру в новую позицию плавно, а затем начать вращение, но кажеться в 3D редакторах это реализовано по-другому, вращение идет сразу вокруг другого объекта,не могу понять как это реализовать.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
const renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);

const light = new THREE.AmbientLight(0x404040, 2);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.castShadow = true;
scene.add(directionalLight);
scene.add(light);

directionalLight.shadow.mapSize.width = 1080;
directionalLight.shadow.mapSize.height = 1080;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 500;

const geometry = new THREE.BoxGeometry(1, 1, 1);

const material = new THREE.MeshStandardMaterial({
  color: 0xf5f5f5,
  flatShading: true,
  metalness: 0.5
});
material.castShadow = true;

const cube = new THREE.Mesh(geometry, material);
const cube2 = new THREE.Mesh(geometry, material);

cube.receiveShadow = true;
cube.castShadow = true;
scene.add(cube);
scene.add(cube2);
cube2.position.set(5, 0, 0);


const planeGeometry = new THREE.PlaneGeometry(10, 10);
const plane = new THREE.Mesh(planeGeometry, material);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
plane.receiveShadow = true;
scene.add(plane);

var elements = [];
elements.push(plane);
elements.push(cube);
elements.push(cube2);

camera.position.z = 5;

var domelement = renderer.domElement;
var domEvents = new THREEx.DomEvents(camera, renderer.domElement);
var pan = false;
var shift = false;
let prevMouseX = 0;
let prevMouseY = 0;

var centerPoint = new THREE.Vector3(0, 0, 0);
var distance = camera.position.distanceTo(centerPoint);

domelement.addEventListener("mousedown", (event) => {

  if (event.which !== 2) {
    return;
  }
  prevMouseX = event.clientX;
  prevMouseY = event.clientY;
  pan = true;
});

domelement.addEventListener("mousemove", (event) => {
  let moveSpeed = 0.005;
  let mouseX = event.clientX;
  let mouseY = event.clientY;

  if (pan && !shift) {
    let deltaX = (mouseX - prevMouseX) * moveSpeed;
    let deltaY = (mouseY - prevMouseY) * moveSpeed;

    let cameraOffset = new THREE.Vector3(-deltaX, deltaY, 0);
    cameraOffset.applyQuaternion(camera.quaternion);
    camera.position.add(cameraOffset);
  }

  if (pan && shift) {
    const mouseXDelta = mouseX - prevMouseX;
    const mouseYDelta = mouseY - prevMouseY;

    const angleX = -(mouseXDelta / window.innerWidth) * Math.PI * 2;
    const angleY = (mouseYDelta / window.innerHeight) * Math.PI * 2;

    const quaternionX = new THREE.Quaternion().setFromAxisAngle(
      new THREE.Vector3(0, 1, 0),
      angleX
    );
    const quaternionY = new THREE.Quaternion().setFromAxisAngle(
      new THREE.Vector3(1, 0, 0),
      angleY
    );

    const deltaQuaternion = new THREE.Quaternion().multiplyQuaternions(
      quaternionX,
      quaternionY
    );

    const currentPosition = camera.position.clone().sub(centerPoint);
    const newPosition = currentPosition.applyQuaternion(deltaQuaternion);

    camera.position.copy(newPosition.add(centerPoint));
    camera.lookAt(centerPoint);
  }

  prevMouseX = mouseX;
  prevMouseY = mouseY;
});

domelement.addEventListener("mouseup", (event) => {

  X = event.clientX;
  Y = event.clientY;
  pan = false;
});

domelement.addEventListener("mouseleave", (event) => {

  X = event.clientX;
  Y = event.clientY;
  pan = false;
});

document.addEventListener("keydown", function(event) {
  if (event.shiftKey) {
    shift = true;
  }
});

document.addEventListener("keyup", function(event) {
  if (event.code.toString().includes("Shift")) {
    shift = false;
  }
});

var activeElement = null;

for (let el of elements) {
  domEvents.addEventListener(
    el,
    "click",
    function(event) {
      for (let e of elements) {

        e.material = material;

      }

      let newMaterial = new THREE.MeshStandardMaterial({
        color: 0x106be3,
        flatShading: true,
        metalness: 0.5,
        transparent: true,
        opacity: 0.95
      });
      if (!pan && !shift) {

        activeElement = event.target;
        activeElement.material = newMaterial;

        let middle = new THREE.Vector3();
        let geometry = activeElement.geometry;

        geometry.computeBoundingBox();
        geometry.boundingBox.getSize(middle);

        middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2;
        middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2;
        middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2;
        activeElement.localToWorld(middle);
        centerPoint = middle;

      }
    },
    false
  );
}

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();
<body></body>
<script src="https://rawgit.com/jeromeetienne/threex.domevents/master/threex.domevents.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.154.0/three.min.js"></script>

Ответы

Ответов пока нет.