Threejs 坐标定义
局部坐标和世界坐标
局部坐标(Local Coordinates)
局部坐标是相对于对象自身的坐标系。每个对象都有自己的局部坐标系,其中原点位于对象的中心,轴通常是沿着对象的主要方向(例如,X轴、Y轴、Z轴)。
局部原点:对象的原点。
轴方向:通常与对象的方向有关。
在局部坐标系中,变换(如平移、旋转和缩放)是相对于对象自身进行的。
世界坐标(World Coordinates)
世界坐标是相对于整个场景的全局坐标系。世界坐标系是场景的参考坐标系,其中原点通常是场景的中心,轴方向是固定的(例如,X轴向右,Y轴向上,Z轴向前或向后)。
世界原点:场景的中心点。
轴方向:通常是固定的,X、Y、Z轴。
父子对象中的坐标关系
父子对象关系
在Three.js中,父对象和子对象之间形成了层次结构。子对象的变换是相对于其父对象的局部坐标系进行的。这意味着:
子对象继承父对象的变换:父对象的变换(位置、旋转、缩放)会影响子对象的最终位置。
变换叠加:子对象的变换会叠加到父对象的变换上。
局部坐标与世界坐标的转换
从局部坐标转换为世界坐标
将一个对象的局部坐标转换为世界坐标需要考虑所有父对象的变换。Three.js提供了localToWorld方法来进行这种转换。
const localPosition = new THREE.Vector3(1, 0, 0);
const worldPosition = object.localToWorld(localPosition.clone());
console.log('World Position:', worldPosition);
在上面的代码中,localPosition是相对于对象的局部坐标,通过localToWorld方法转换成了世界坐标worldPosition。
从世界坐标转换为局部坐标
将世界坐标转换为对象的局部坐标可以使用worldToLocal方法。这个过程需要考虑从世界坐标系到对象局部坐标系的逆变换。
const worldPosition = new THREE.Vector3(10, 0, 0);
const localPosition = object.worldToLocal(worldPosition.clone());
console.log('Local Position:', localPosition);
在这个例子中,worldPosition是世界坐标,通过worldToLocal方法转换为localPosition,即相对于对象的局部坐标。
实际应用示例
1. 父子对象关系
假设我们有一个父对象和一个子对象,父对象在世界坐标系中的位置是(5, 5, 5),子对象在父对象局部坐标系中的位置是(2, 0, 0)。
// 创建父对象
const parentObject = new THREE.Object3D();
parentObject.position.set(5, 5, 5); // 设置父对象的位置
// 创建子对象
const childGeometry = new THREE.BoxGeometry(1, 1, 1);
const childMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const childObject = new THREE.Mesh(childGeometry, childMaterial);
childObject.position.set(2, 0, 0); // 相对于父对象的局部位置
// 添加子对象到父对象
parentObject.add(childObject);
// 添加父对象到场景
scene.add(parentObject);
在这个示例中,子对象的最终世界坐标是父对象位置和子对象位置的和,即(7, 5, 5)。
2. 转换子对象的世界坐标
如果我们想将子对象从世界坐标移动到新的父对象,同时保持其世界坐标不变,我们可以进行如下操作:
复制代码
// 获取子对象的当前世界位置
const currentWorldPosition = new THREE.Vector3();
childObject.getWorldPosition(currentWorldPosition);
// 创建一个新的父对象
const newParentObject = new THREE.Object3D();
newParentObject.position.set(10, 10, 10); // 新父对象的位置
// 将子对象添加到新的父对象
newParentObject.add(childObject);
// 将新的父对象添加到场景
scene.add(newParentObject);
// 将世界坐标转换为新的局部坐标
const newLocalPosition = newParentObject.worldToLocal(currentWorldPosition.clone());
// 更新子对象的局部坐标
childObject.position.copy(newLocalPosition);
在这个示例中,我们将子对象从一个父对象移到另一个父对象,并保持其在世界坐标中的位置不变。
3. 动态更新对象的局部和世界坐标
有时候,我们需要动态更新对象的位置和变换。这可以通过手动调整局部坐标来实现,以便于保持其在世界坐标系中的预期位置。
复制代码
// 动态调整子对象的位置
const newWorldPosition = new THREE.Vector3(20, 20, 20); // 目标世界位置
// 将世界坐标转换为新的局部坐标
const newLocalPosition = parentObject.worldToLocal(newWorldPosition.clone());
// 更新子对象的局部位置
childObject.position.copy(newLocalPosition);
在这个示例中,子对象被动态调整到目标世界位置newWorldPosition。
4. 检查和调试坐标变换
为了调试和确认对象的变换是否正确,可以打印对象的局部和世界坐标来检查。
复制代码
// 获取局部坐标
console.log('Local Position:', childObject.position);
// 获取世界坐标
const worldPosition = new THREE.Vector3();
childObject.getWorldPosition(worldPosition);
console.log('World Position:', worldPosition);
// 获取局部变换矩阵
console.log('Local Matrix:', childObject.matrix);
// 获取世界变换矩阵
console.log('World Matrix:', childObject.matrixWorld);
通过这些日志信息,可以方便地检查和验证对象的变换是否符合预期。
总结
- 局部坐标:相对于对象自身的坐标系,用于定义对象的局部位置、旋转和缩放。
- 世界坐标:相对于场景的全局坐标系,表示对象在整个场景中的位置。
- 父子对象:子对象的变换是相对于其父对象的局部坐标系进行的,父对象的变换会影响到所有子对象。
- 坐标转换:使用localToWorld和worldToLocal方法在局部和世界坐标之间进行转换,以满足复杂场景需求。