javascript
// 创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// 创建网格对象
const cube = new THREE.Mesh(geometry, material);
// 添加到场景
scene.add(cube);
javascript
// 网格的组成部分
console.log(cube.geometry); // 几何体
console.log(cube.material); // 材质
console.log(cube.position); // 位置(Vector3)
console.log(cube.rotation); // 旋转(Euler)
console.log(cube.scale); // 缩放(Vector3)
javascript
// 直接设置
cube.position.x = 2;
cube.position.y = 1;
cube.position.z = 0;
// 使用 set 方法
cube.position.set(2, 1, 0);
// 逐轴移动
cube.position.x += 0.1; // 向右移动
cube.position.y -= 0.1; // 向下移动
cube.position.z += 0.1; // 向屏幕内移动
// 使用向量操作
cube.position.add(new THREE.Vector3(1, 0, 0)); // 向右移动1单位
cube.position.sub(new THREE.Vector3(0, 1, 0)); // 向下移动1单位
javascript
// Three.js使用弧度制
const PI = Math.PI;
// 直接设置(弧度)
cube.rotation.x = PI / 4; // 绕X轴旋转45度
cube.rotation.y = PI / 2; // 绕Y轴旋转90度
cube.rotation.z = PI; // 绕Z轴旋转180度
// 使用 set 方法
cube.rotation.set(PI/4, PI/2, PI);
// 角度转弧度辅助函数
function degToRad(degrees) {
return degrees * (Math.PI / 180);
}
cube.rotation.x = degToRad(45); // 45度
cube.rotation.y = degToRad(90); // 90度
// 逐帧旋转(动画)
function animate() {
cube.rotation.x += 0.01; // 每帧绕X轴旋转一点
cube.rotation.y += 0.02; // 每帧绕Y轴旋转两点
}
javascript
// 均匀缩放
cube.scale.set(2, 2, 2); // 所有方向放大2倍
// 非均匀缩放
cube.scale.x = 1.5; // X轴方向拉伸1.5倍
cube.scale.y = 0.5; // Y轴方向压缩0.5倍
cube.scale.z = 1; // Z轴保持不变
// 使用向量操作
cube.scale.multiplyScalar(1.1); // 放大10%
cube.scale.divideScalar(2); // 缩小到一半
javascript
// 一次性设置所有变换
cube.position.set(3, 2, 1);
cube.rotation.set(degToRad(30), degToRad(45), 0);
cube.scale.set(1.5, 1, 1);
// 创建变换矩阵
const matrix = new THREE.Matrix4();
matrix.compose(
new THREE.Vector3(2, 1, 0), // 位置
new THREE.Quaternion().setFromEuler( // 旋转(使用四元数)
new THREE.Euler(degToRad(30), 0, 0)
),
new THREE.Vector3(1, 2, 1) // 缩放
);
cube.applyMatrix4(matrix);
javascript
// 变换顺序:缩放 → 旋转 → 平移(默认)
// 但矩阵乘法是反过来的:平移 × 旋转 × 缩放
// 方法1:手动控制顺序
cube.scale.set(2, 2, 2); // 先缩放
cube.rotation.y = degToRad(90); // 再旋转
cube.position.x = 5; // 最后平移
// 方法2:使用矩阵确保顺序
cube.matrixAutoUpdate = false; // 关闭自动更新
const transformMatrix = new THREE.Matrix4();
transformMatrix.makeRotationY(degToRad(90)); // 旋转
transformMatrix.scale(new THREE.Vector3(2, 2, 2)); // 缩放
transformMatrix.setPosition(5, 0, 0); // 平移
cube.matrix.copy(transformMatrix);
javascript
// 局部坐标(相对父级)
cube.position.set(1, 0, 0); // 相对于父对象的位置
// 获取世界坐标
const worldPosition = new THREE.Vector3();
cube.getWorldPosition(worldPosition);
console.log('世界坐标:', worldPosition);
// 获取世界旋转
const worldQuaternion = new THREE.Quaternion();
cube.getWorldQuaternion(worldQuaternion);
// 获取世界缩放
const worldScale = new THREE.Vector3();
cube.getWorldScale(worldScale);
// 获取世界变换矩阵
cube.updateMatrixWorld(); // 更新世界矩阵
const worldMatrix = cube.matrixWorld;
javascript
// 创建父对象
const parent = new THREE.Mesh(
new THREE.BoxGeometry(2, 2, 2),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
// 创建子对象
const child = new THREE.Mesh(
new THREE.BoxGeometry(0.5, 0.5, 0.5),
new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
// 建立父子关系
parent.add(child);
// 子对象相对于父对象的位置
child.position.set(1, 0, 0); // 在父对象的右侧1单位
// 移动父对象时,子对象会跟随移动
parent.position.set(3, 0, 0); // 子对象也会移动
// 从父对象移除
parent.remove(child);
scene.add(child); // 现在 child 是场景的直接子对象
javascript
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, 0);
// 看向一个点
cube.lookAt(new THREE.Vector3(10, 0, 0));
// 看向另一个对象
const targetObject = new THREE.Mesh(...);
cube.lookAt(targetObject.position);
// 看向相机
cube.lookAt(camera.position);
javascript
// 变换控制器(用于调试)
const axesHelper = new THREE.AxesHelper(2); // 坐标轴辅助
cube.add(axesHelper);
const boxHelper = new THREE.BoxHelper(cube, 0xffff00); // 包围盒辅助
scene.add(boxHelper);
// 变换Gizmo(需要导入额外库)
// import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
// const controls = new TransformControls(camera, renderer.domElement);
// controls.attach(cube);
// scene.add(controls);
javascript
// 使用GSAP动画库(推荐)
// npm install gsap
import gsap from 'gsap';
gsap.to(cube.position, {
x: 5,
duration: 2,
ease: "power2.out"
});
gsap.to(cube.rotation, {
y: Math.PI * 2,
duration: 3,
repeat: -1,
ease: "none"
});
// 使用Three.js内置动画
const clock = new THREE.Clock();
function animate() {
const delta = clock.getDelta();
const elapsedTime = clock.getElapsedTime();
// 正弦波移动
cube.position.x = Math.sin(elapsedTime) * 3;
cube.position.y = Math.cos(elapsedTime) * 3;
// 自动旋转
cube.rotation.y += delta * 1; // 每秒1弧度
// 脉动缩放
cube.scale.setScalar(1 + Math.sin(elapsedTime * 2) * 0.1);
}
javascript
// 位置限制
function clampPosition(mesh, min, max) {
mesh.position.x = THREE.MathUtils.clamp(mesh.position.x, min.x, max.x);
mesh.position.y = THREE.MathUtils.clamp(mesh.position.y, min.y, max.y);
mesh.position.z = THREE.MathUtils.clamp(mesh.position.z, min.z, max.z);
}
// 平滑移动(Lerp)
function smoothMove(mesh, targetPosition, alpha = 0.1) {
mesh.position.lerp(targetPosition, alpha);
}
// 限制旋转角度
function clampRotation(mesh, axis, minAngle, maxAngle) {
const angle = mesh.rotation[axis];
mesh.rotation[axis] = THREE.MathUtils.clamp(angle, minAngle, maxAngle);
}
javascript
// 1. 批量更新
cube.matrixAutoUpdate = false; // 关闭自动矩阵更新
function updateTransforms() {
cube.updateMatrix(); // 手动更新
cube.updateMatrixWorld(true); // 更新世界矩阵
}
// 2. 使用 InstancedMesh 批量渲染相同对象
const instances = 100;
const instancedMesh = new THREE.InstancedMesh(geometry, material, instances);
for (let i = 0; i < instances; i++) {
const matrix = new THREE.Matrix4();
matrix.setPosition(
Math.random() * 10 - 5,
Math.random() * 10 - 5,
Math.random() * 10 - 5
);
instancedMesh.setMatrixAt(i, matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;
// 3. 使用 BufferGeometry 的 transform 方法(性能更高)
geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(2, 0, 0));
javascript
// 创建可交互的3D对象
class InteractiveObject {
constructor(geometry, material) {
this.mesh = new THREE.Mesh(geometry, material);
this.velocity = new THREE.Vector3();
this.acceleration = new THREE.Vector3();
this.drag = 0.98;
}
update(deltaTime) {
// 应用加速度
this.velocity.add(this.acceleration.clone().multiplyScalar(deltaTime));
// 应用阻力
this.velocity.multiplyScalar(this.drag);
// 更新位置
this.mesh.position.add(this.velocity.clone().multiplyScalar(deltaTime));
// 重置加速度
this.acceleration.set(0, 0, 0);
}
applyForce(force) {
this.acceleration.add(force);
}
}
// 使用示例
const interactiveCube = new InteractiveObject(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x3498db })
);
// 在动画循环中
function animate() {
const deltaTime = clock.getDelta();
// 应用重力
interactiveCube.applyForce(new THREE.Vector3(0, -9.8, 0));
// 更新物理
interactiveCube.update(deltaTime);
// 边界检测
if (interactiveCube.mesh.position.y < -5) {
interactiveCube.mesh.position.y = -5;
interactiveCube.velocity.y *= -0.8; // 反弹
}
}
变换顺序:缩放 → 旋转 → 平移(矩阵运算时反过来)
坐标系统:注意局部坐标与世界坐标的区别
性能优先:使用 matrixAutoUpdate = false 和手动更新优化性能
父子关系:合理使用层级结构组织场景
动画优化:使用插值(lerp)和缓动函数实现平滑动画
实用工具:善用辅助对象和控制器进行调试和开发