【问题标题】:Moving an object to a position (three.js)将对象移动到某个位置(three.js)
【发布时间】:2018-03-20 18:45:59
【问题描述】:

我正在尝试使用three.js“射击”子弹/弹丸:

let renderer, camera, scene, light, plane, cube, spheres;

initialize();
animate();

function initialize() {
  renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight);

  scene = new THREE.Scene();
  
  light = new THREE.SpotLight("#ffffff");
  light.position.y = 700;
  scene.add(light);

  plane = new THREE.Mesh();
  plane.material = new THREE.MeshToonMaterial({ color: "#0000ff" });
  plane.geometry = new THREE.PlaneGeometry(60, 30);
  plane.position.z = -50;
  scene.add(plane);

  cube = new THREE.Mesh();
  cube.material = new THREE.MeshToonMaterial({ color: "#ff0000", transparent: true, opacity: 0.85 });
  cube.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
  cube.position.y = -1;
  cube.position.z = -3;
  scene.add(cube);
  
  spheres = [];

  window.addEventListener("click", event => {
    let mouse2d = getMouse2D(event.clientX, event.clientY);
    let mouse3d = getMouse3D(mouse2d, plane.position.z);
    shoot(mouse3d);
  }, false);
}

function animate() {
  spheres.forEach(sphere => {
    // TODO: Update sphere position based on sphere.userData.target
    sphere.position.z -= 1;
  });

  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

function shoot(target) {
  let sphere = new THREE.Mesh();
  sphere.material = new THREE.MeshToonMaterial({ color: "#00ff00" });
  sphere.geometry = new THREE.SphereGeometry(0.25);
  sphere.position.x = cube.position.x;
  sphere.position.y = cube.position.y;
  sphere.position.z = cube.position.z;
  sphere.userData.target = target;
  scene.add(sphere);
  spheres.push(sphere);
}

function getMouse3D(mouse2d, z) {
  let vector = new THREE.Vector3(mouse2d.x, mouse2d.y);
  vector.unproject(camera);
  let dir = vector.sub(camera.position).normalize();
  let distance = (z - camera.position.z) / dir.z;
  return camera.position.clone().add(dir.multiplyScalar(distance));
}

function getMouse2D(x, y) {
  return new THREE.Vector2(
    (x / renderer.domElement.clientWidth) * 2 - 1,
    -(y / renderer.domElement.clientHeight) * 2 + 1
  );
}
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: #eeeeee;
}

canvas {
  display: block;
  cursor: crosshair;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.js">
</script>

如您所见,点击鼠标即可将球体从立方体射向平面。

我编写了getMouse3D() 函数来确定用户单击的平面上的位置,当生成球体时,我将其存储在sphere.userData.target 中。但我不知道如何更新每帧球体的位置,以便它朝它移动(参见TODO 评论)。换句话说,当一个球体到达平面时,它应该与它在sphere.userData.target(用户点击的地方)相交。

我该怎么做?

【问题讨论】:

  • 看看流行的补间库tween.js。许多人将它与three.js 结合使用,您会在Stack Overflow 中找到相关问题。

标签: javascript three.js


【解决方案1】:

你知道立方体的位置,你知道最终位置(目标),所以你可以计算方向,并乘以速度:

sphere.position.addScaledVector(sphere.userData.direction, sphere.userData.speed * delta);
if (sphere.position.z <= plane.position.z) sphere.userData.speed = 0; // stop, when we reached the plane

我使用THREE.Raycaster() 重新编写了您的代码以获得目标的位置(它简化了代码,因此您可以摆脱getMouse3D()getMouse2D() 函数)。

let renderer, camera, scene, light, plane, cube, spheres, raycaster = new THREE.Raycaster(), mouse = new THREE.Vector2(), intersects, clock = new THREE.Clock(), delta = 0;

initialize();
animate();

function initialize() {
  renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight);

  scene = new THREE.Scene();
  
  light = new THREE.SpotLight("#ffffff");
  light.position.y = 700;
  scene.add(light);

  plane = new THREE.Mesh();
  plane.material = new THREE.MeshToonMaterial({ color: "#0000ff" });
  plane.geometry = new THREE.PlaneGeometry(60, 30);
  plane.position.z = -50;
  scene.add(plane);

  cube = new THREE.Mesh();
  cube.material = new THREE.MeshToonMaterial({ color: "#ff0000", transparent: true, opacity: 0.85 });
  cube.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
  cube.position.y = -1;
  cube.position.z = -3;
  scene.add(cube);
  
  spheres = [];

  window.addEventListener("click", event => {
    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    intersects = raycaster.intersectObjects([plane]);
    if (intersects.length == 0) return;
    shoot(intersects[0].point);
  }, false);
}

function animate() {
  delta = clock.getDelta();
  spheres.forEach(sphere => {
    sphere.position.addScaledVector(sphere.userData.direction, sphere.userData.speed * delta);
    if (sphere.position.z <= plane.position.z) sphere.userData.speed = 0; // stop, when we reached the plane
  });

  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

function shoot(target) {
  let sphere = new THREE.Mesh();
  sphere.material = new THREE.MeshToonMaterial({ color: "#00ff00" });
  sphere.geometry = new THREE.SphereGeometry(0.5);
  sphere.position.copy(cube.position);
  sphere.userData.direction = target.sub(cube.position).normalize();
  sphere.userData.speed = 20;
  scene.add(sphere);
  spheres.push(sphere);
}
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: #eeeeee;
}

canvas {
  display: block;
  cursor: crosshair;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.js">
</script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    相关资源
    最近更新 更多