Three.js OrbitControls设置目标后模型位移问题求助
问题描述
场景中有两个立方体:
const material1 = new THREE.MeshBasicMaterial({color: '#00ff00'}); const cube1 = new THREE.Mesh(geometry, material1); cube1.position.set(0, 0, 0); const material2 = new THREE.MeshBasicMaterial({color: '#ffff00'}); const cube2 = new THREE.Mesh(geometry, material1); cube1.position.set(-3, 0, 0);
Cube1(绿色)位于原点(屏幕中心位置),Cube2(黄色)沿X轴偏移-3。按住鼠标左键拖动可看到Cube2(黄色)绕Cube1(绿色)旋转,这是OrbitControls的默认效果。
需求是实现Cube1(绿色)绕Cube2(黄色)旋转,使用语句control.target = cube2.position;虽达成旋转效果,但Cube2(黄色)被拉回原点,不符合预期,求解决方法。
完整代码如下:
<template> <div ref="container" style="width: 100%; height: 100%"></div> </template> <script setup lang="ts"> import { ref, onMounted } from "vue"; import * as THREE from "three"; // 轨道控制器 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; const container = ref(null); // 场景 相机 渲染 轨道控制器 模型 let scene, camera, renderer, control, cube1, cube2; let axesHelper1, axesHelper2, gridHelper; onMounted(() => { init(); animate(); // 监听窗口变化 window.addEventListener("resize", () => { // 重置渲染器宽高比 renderer.setSize(window.innerWidth, window.innerHeight); // 重置相机宽高比 camera.aspect = window.innerWidth / window.innerHeight; // 更新相机投影矩阵 camera.updateProjectionMatrix(); }); }); // 场景 function initScene() { scene = new THREE.Scene(); } // 相机 function initCamera() { camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 5000, ); camera.position.z = 20; scene.add(camera); } // 轨道控制器 function initControl() { control = new OrbitControls(camera, renderer.domElement); // 设置阻尼 control.enableDamping = true; control.dampingFactor = 0.05; } // 渲染 function initRenderer() { // 创建渲染器 antialias 抗锯齿 renderer = new THREE.WebGLRenderer({ antialias: true }); // 尺寸 renderer.setSize(window.innerWidth, window.innerHeight); // 设置像素比 renderer.setPixelRatio(window.devicePixelRatio); container.value.appendChild(renderer.domElement); } // 模型 function initModel() { const geometry = new THREE.BoxGeometry(1, 1, 1); // region 原点 const material1 = new THREE.MeshBasicMaterial({ color: "#00ff00" }); cube1 = new THREE.Mesh(geometry, material1); cube1.position.set(0, 0, 0); axesHelper1 = new THREE.AxesHelper(2); cube1.add(axesHelper1); scene.add(cube1); // endregion 原点 // region 模型2 const material2 = new THREE.MeshBasicMaterial({ color: "#ffff00" }); cube2 = new THREE.Mesh(geometry, material2); cube2.position.set(-5, 0, 0); axesHelper2 = new THREE.AxesHelper(2); cube2.add(axesHelper2); scene.add(cube2); // endregion 模型2 // 网格辅助器 gridHelper = new THREE.GridHelper(10, 10); scene.add(gridHelper); } function init() { // 场景 initScene(); // 相机 initCamera(); // 渲染器 initRenderer(); // 轨道控制器 initControl(); // 模型 initModel(); } function animate() { requestAnimationFrame(() => { animate(); }); control.update(); // 重新渲染 renderer.render(scene, camera); } </script> <style scoped></style>
解决方案
问题出在直接将control.target赋值为cube2.position——OrbitControls的target属性是Vector3对象的引用,当你直接赋值cube2.position后,控制器会修改这个向量来控制相机环绕,而cube2.position是立方体本身的位置属性,这就导致立方体被强制拉到控制器的目标点。
方法1:通过相机环绕实现视觉上的Cube1绕Cube2旋转
创建独立的Vector3对象复制cube2的位置作为控制器目标,避免影响立方体本身的位置:
- 调整
init函数的执行顺序,先初始化模型再初始化控制器,确保cube2已设置位置:
function init() { initScene(); initCamera(); initRenderer(); // 先初始化模型,再初始化控制器 initModel(); initControl(); }
- 在
initControl中设置独立的目标向量:
function initControl() { control = new OrbitControls(camera, renderer.domElement); control.enableDamping = true; control.dampingFactor = 0.05; // 复制cube2的位置作为控制器目标 control.target.copy(cube2.position); }
此时相机将环绕cube2的位置旋转,从视觉上呈现Cube1绕Cube2旋转的效果,同时Cube2会保持初始位置。
方法2:让Cube1主动绕Cube2旋转
如果需要Cube1真正主动绕Cube2做圆周运动,可在animate函数中添加旋转逻辑:
function animate() { requestAnimationFrame(animate); // 让cube1以cube2为中心做圆周运动 const angle = Date.now() * 0.001; const radius = 5; // 旋转半径 cube1.position.x = cube2.position.x + Math.cos(angle) * radius; cube1.position.z = cube2.position.z + Math.sin(angle) * radius; control.update(); renderer.render(scene, camera); }
这种方式下,Cube1会持续绕Cube2旋转,配合OrbitControls可从任意角度观察运动过程。
内容的提问来源于stack exchange,提问作者nieyuan1980
相关产品推荐
相关产品推荐

