返回
有趣的!3D效果让二维图片动起来了,全是Three.js的功劳!
前端
2023-11-22 02:53:20
用 Three.js 和 React 让二维图片栩栩如生
作为技术达人和图形爱好者,探索将二维图片转化为三维视觉世界的可能性让我着迷不已。很幸运,Three.js 为我们提供了这个机会。在这个博文中,我将分享我的创作过程和技巧,帮助你使用 Three.js 和 React 技术栈将二维图片变成令人惊叹的 3D 效果。
准备工作
在你开始创作之前,需要准备一些基本工具和资源:
- Three.js 库: 从 Three.js 官网下载最新版本并将其添加到你的项目中。
- React: 使用 React 作为前端框架来构建用户界面。
- 图片资源: 选择你想要转换的二维图片,建议使用轮廓清晰、形状简单的图片。
- 3D 建模软件: 如果你需要对图片进行建模,可以使用 Blender 或 Maya 等 3D 建模软件。
创建基本场景
首先,在你的 React 项目中创建一个新的组件并导入 Three.js 库。在组件中定义一个场景(scene)、一个相机(camera)和一个渲染器(renderer)。设置相机的视角和位置,并将渲染器附加到 DOM 元素。
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
const Scene = () => {
const mountRef = useRef(null);
useEffect(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
mountRef.current.appendChild(renderer.domElement);
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
return () => {
mountRef.current.removeChild(renderer.domElement);
};
}, []);
return <div ref={mountRef} />;
};
导入图片并转换为 3D 模型
现在,让我们导入图片并将其转换为 3D 模型。使用 Three.js 中的 TextureLoader 类加载图片,创建一个平面几何体作为图片的载体,将图片纹理应用到平面几何体上,最后将平面几何体添加到场景中。
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
const Image3D = ({ image }) => {
const mountRef = useRef(null);
useEffect(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
mountRef.current.appendChild(renderer.domElement);
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(image);
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
return () => {
mountRef.current.removeChild(renderer.domElement);
};
}, []);
return <div ref={mountRef} />;
};
添加灯光和阴影
为了让图片更加逼真,我们需要添加灯光和阴影。使用 Three.js 中的 AmbientLight 类或 DirectionalLight 类添加灯光,使用 ShadowMaterial 类或 PointLight 类添加阴影。
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
const Image3D = ({ image }) => {
const mountRef = useRef(null);
useEffect(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
mountRef.current.appendChild(renderer.domElement);
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(image);
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const ambientLight = new THREE.AmbientLight(0x404040, 1);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
scene.add(ambientLight);
scene.add(directionalLight);
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
return () => {
mountRef.current.removeChild(renderer.domElement);
};
}, []);
return <div ref={mountRef} />;
};
动画效果
最后,为了让图片动起来,我们需要添加动画效果。使用 TweenMax 库或 Anime.js 库实现动画。你可以让图片旋转、平移或缩放,以创造出不同的视觉效果。
import { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import Anime from 'animejs';
const Image3D = ({ image }) => {
const mountRef = useRef(null);
useEffect(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
mountRef.current.appendChild(renderer.domElement);
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(image);
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const ambientLight = new THREE.AmbientLight(0x404040, 1);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
scene.add(ambientLight);
scene.add(directionalLight);
const [isRotating, setIsRotating] = useState(false);
useEffect(() => {
if (isRotating) {
Anime({
targets: mesh.rotation,
y: 2 * Math.PI,
duration: 2000,
easing: 'linear',
loop: true,
});
} else {
Anime.remove(mesh.rotation);
}
}, [isRotating]);
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
return () => {
mountRef.current.removeChild(renderer.domElement);
Anime.remove(mesh.rotation);
};
}, []);
return <div ref={mountRef} />;
};
常见问题解答
1. 为什么我的图片没有显示?
- 确保你正确加载了图片并将其应用到了平面几何体上。
2. 为什么我的图片没有阴影?
- 确保你添加了灯光和阴影到场景中。
3. 如何让我的图片旋转?
- 使用 TweenMax 或 Anime.js 库添加动画,让图片的旋转属性随时间变化。
4. 如何让我的图片平移?
- 与旋转类似,使用动画库让图片的平移属性随时间变化。
5. 我可以使用 Three.js 转换任何类型的图片吗?
- 是的,你可以转换任何类型的图片,但具有清晰轮廓和简单形状的图片效果最佳。