下载一个免费的3D模型
sketchfab.com/3d-models?d… three.js官方推荐使用glTF(gl传输格式)
建立场景、相机和渲染器
// 创建场景
const scene = new THREE.Scene();
// 创建纹理加载器
// const textureLoader = new THREE.TextureLoader();
// // 加载纹理
// const texture = textureLoader.load('/background.jpeg');
// // 设置背景为纹理
// scene.background = texture;
scene.background = new THREE.Color(0xa7b3cc);
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight - 200);
// 渲染器添加到容器中
containerRef.current?.appendChild(renderer.domElement);
设置场景背景
// const textureLoader = new THREE.TextureLoader();
// // 加载纹理
// const texture = textureLoader.load('/background.jpeg');
// // 设置背景为纹理
// scene.background = texture;
scene.background = new THREE.Color(0xa7b3cc);
设置相机位置
camera.position.set(0, 0, 5);
渲染器添加到容器中
containerRef.current?.appendChild(renderer.domElement);
建立光源
// 添加灯光
// AmbientLight的第二个参数是光源的强度
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
// 增加光源的强度
// ambientLight.intensity = 2
scene.add(ambientLight);
// 添加方向光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
directionalLight.position.set(0, 0, 5);
// directionalLight.intensity = 2
scene.add(directionalLight);
调整光源的强度
ambientLight.intensity = 2 // 或者设置THREE.AmbientLight()的第二个参数
调整光源的位置
directionalLight.position.set(0, 0, 5);
载入3D模型
// 导入植物模型
let flowerScene: THREE.Object3D;
loader.load('/orchid_flower/scene.gltf', function (flower) {
// 调整模型大小
flower.scene.scale.set(0.1, 0.1, 0.1);
// 调整模型位置
flower.scene.position.set(-4, 1, 7);
scene.add(flower.scene);
flowerScene = flower.scene
}, undefined, function (error) {
console.error(error);
});
调整模型大小
gltf.scene.scale.set(0.5, 0.5, 0.5);
调整模型位置
gltf.scene.position.set(-2, -2, 0);
调整模型旋转
gltf.scene.rotation.y = - Math.PI / 2;
辅助功能:添加辅助线
// AxesHelper是Three.js 库中的一个辅助对象,用于在三维场景中可视化地表示三个坐标轴(X、Y 和 Z 轴)。它通常用于调试和演示目的,帮助开发者理解场景中物体的方向和空间关系。
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
辅助功能:添加轨道控制器
// 添加轨道控制器,允许用户通过鼠标拖动模型,旋转和缩放
const controls = new OrbitControls(camera, renderer.domElement);
渲染场景
let requestId: number;
// 渲染循环
function animate() {
requestId = requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
animate();
渲染容器
<main>
<div ref={containerRef} >
</div>
</main>
实现鼠标点击,植物变大
实现植物变大的动画效果,需要安装一个createjs库。
// 导入createjs
import 'createjs/builds/1.0.0/createjs.min.js'
// 处理鼠标点击事件
const handleClick = (event: MouseEvent) => {
// 计算鼠标在屏幕上的位置
const mouse = new THREE.Vector2();
mouse.x = ((event.clientX - renderer.domElement.offsetLeft) / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -((event.clientY - renderer.domElement.offsetTop) / renderer.domElement.clientHeight) * 2 + 1;
// 射线投射
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([flowerScene], true);
if (intersects.length > 0) {
if (flowerScene) {
// 植物变大的动画
// THREE.Vector3 是 Three.js 库中的一个类,用于表示三维空间中的向量。向量是具有大小和方向的量,在三维空间中,一个向量通常由三个分量组成,分别对应 x、y、z 轴上的数值。
// THREE.Vector3 类提供了许多方法来操作和处理这些向量,例如加法、减法、标量乘法、点积、叉积等。
const targetScale = new THREE.Vector3(0.3, 0.3, 0.2); // 目标缩放比例
const duration = 20000; // 动画持续时间(毫秒)
createjs.Tween.get(flowerScene.scale)
.to({
x: targetScale.x,
y: targetScale.y,
z: targetScale.z,
onStart() {
console.log('start')
},
onUpdate: () => {
renderer.render(scene, camera);
}
}, duration)
}
}
}
window.addEventListener('click', handleClick)
注意: 设置容器DOM节点style={{ position: 'relative' }}导致的raycaster射线检测不到或者不准确
实现悬浮物品展示文字效果
- 在渲染容器节点同级下增加新的节点
<div ref={tooltipRef} style={{ position: 'fixed', zIndex: 1000, top: 0, left: 0, display: 'none', backgroundColor: 'white' }}></div>
- js实现
let tooltipRef = useRef<HTMLDivElement>(null);
const hanldeMouseMove = (event: MouseEvent) => {
// 计算鼠标在屏幕上的位置
const mouse = new THREE.Vector2();
mouse.x = ((event.clientX - renderer.domElement.offsetLeft) / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -((event.clientY - renderer.domElement.offsetTop) / renderer.domElement.clientHeight) * 2 + 1;
// 射线投射
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
// 检查是否点击了模型
const intersects = raycaster.intersectObjects([flowerScene], true);
if (intersects.length > 0) {
// 点击了模型,显示提示
if (tooltipRef.current) {
tooltipRef.current.style.display = 'block';
tooltipRef.current.style.top = event.clientY + 'px';
tooltipRef.current.style.left = event.clientX + 'px';
tooltipRef.current.innerText = 'flower'
}
} else {
if (tooltipRef.current) {
tooltipRef.current.style.display = 'none';
}
}
}
window.addEventListener('mousemove', hanldeMouseMove)
页面销毁时,清理场景、相机和渲染器,事件监听
cancelAnimationFrame(requestId)
window.removeEventListener('mousemove', hanldeMouseMove)
window.removeEventListener('click', handleClick)
scene.clear()
camera.clear()
renderer.clear()
renderer.dispose()