注意:该代码封装了一个子组件,使用时需要在主页面中引入
import React, { useState, useEffect, useRef } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
import './index.less'
const Car = () => {
// 创建一个 ref 来引用相机对象
const camRef = useRef();
// 创建一个 ref 来引用渲染器对象
const rendererRef = useRef();
// 创建一个 ref 来引用 transform 控制器对象
const transformRef = useRef();
// 创建一个 ref 来引用鼠标控制器对象
const orbitsRef = useRef();
// 创建 state 来存储车身放大缩小比例
const [scale, setScale] = useState(1);
// 初始化 Three.js 场景
useEffect(() => {
// 获取画布容器
const container = document.getElementById('threeContainer');
// 创建一个 Three.js 场景
const scene = new THREE.Scene();
// 创建一个 Three.js 相机
const camera = new THREE.PerspectiveCamera(
75,
container.offsetWidth / container.offsetHeight,
0.1,
1000
);
// 设置相机位置
camera.position.set(-8, 2.5, 10);
// 添加相机对象到对象列表中
scene.add(camera);
// 创建一个 Three.js 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.setClearColor('#fff');
rendererRef.current = renderer;
// 添加渲染器对象到 DOM 元素中
container.appendChild(renderer.domElement);
// 创建一个 Three.js 显示对象
const carGroup = new THREE.Group();
scene.add(carGroup);
// 创建车身模型
const cube = new THREE.Mesh(new THREE.BoxGeometry(2, 1, 1), new THREE.MeshLambertMaterial({
color: 0xffffff,
}))
carGroup.add(cube);
// 创建车头模型
const headGeometry = new THREE.CylinderGeometry(0, 0.5, 1, 5);
const headMaterial = new THREE.MeshStandardMaterial({ color: '#0000ff' });
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.x = 1.5;
carGroup.add(head);
//轮胎
const tire1 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
color: 0xffffff
}))
//THREE.TorusGeometry` 是用于创建圆环几何体的类,接受以下四个参数:
//`radius`:圆环的总半径,默认值为1。
//`tube`:圆环的管道半径,默认值为0.4。
//`radialSegments`:圆环的弧线段数,默认值为8。
//`tubularSegments`:圆环的管道线段数,默认值为6。
//其中,`radius` 和 `tube` 控制圆环的外半径和内半径,`radialSegments` 和 `tubularSegments` 分别控制圆环的弧线段数和管道线段数。
//对于 `THREE.TorusGeometry(0.2,0.08,8,20)`,它创建了一个外半径为0.2,内半径为0.08,弧线段数为8,管道线段数为20的圆环几何体。
const tire2 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
color: 0xffffff
}))
const tire3 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
color: 0xffffff
}))
const tire4 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
color: 0xffffff
}))
carGroup.add(tire1, tire2, tire3, tire4);
tire1.position.set(0.5, -0.5, 0.5);
tire2.position.set(-0.65, -0.5, 0.5);
tire3.position.set(0.5, -0.5, -0.5);
tire4.position.set(-0.65, -0.5, -0.5);
// 创建一个灯光
const light = new THREE.PointLight(0xffffff, 1, 100);
light.position.set(0, 2, 2);
scene.add(light);
// 绑定鼠标控制器
const orbits = new OrbitControls(camera, renderer.domElement);
orbitsRef.current = orbits;
// 启用防止缩放时更新对象的功能
orbits.enableDamping = true;
// 绑定变换控制器
const transform = new TransformControls(camera, renderer.domElement);
transform.attach(carGroup);
transformRef.current = transform;
scene.add(transform);
// 通过 requestAnimationFrame 动态更新场景
const animate = () => {
requestAnimationFrame(animate);
// 每次旋转角度增加 0.01,与防止缩放时更新对象的功能配合使用
transform.rotateZ(0.01);
// 将相机对象指向车身对象
camRef.current.lookAt && camRef.current.lookAt(body.position);
// 更新渲染器对象
rendererRef.current.render(scene, camera);
};
animate();
// 销毁场景
const cleanup = () => {
container.removeChild(renderer.domElement);
scene.remove(carGroup);
renderer.dispose();
orbits.dispose();
transform.dispose();
};
// 组件卸载时销毁场景
return cleanup;
}, []);
return <div id='threeContainer' className='car_container' ref={camRef} />
};
export default Car;