使用 Three.js 实现掉落的甜甜圈
预览效果
初始化项目
使用 vite 创建 vanilla-ts 项目。
pnpm create vite three-demo-2 --template vanilla-ts
pnpm i
然后安装 Three.js
pnpm install three
pnpm i --save-dev @types/three
写代码
把 main.ts 和 style.css 里的代码全部删掉,在里面写自己的代码
style.css
body{
margin: 0;
padding: 0;
}
main.ts
引入 Three.js 和 style.css
import * as THREE from 'three';
import './style.css'
const scene = new THREE.Scene() // 场景
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) // 透视摄像机
camera.position.set(0.0, 0.4, 1.0); // 设置相机的位置
const renderer = new THREE.WebGLRenderer({ antialias: true }) // 渲染器
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement) // 放到页面里
添加平行光
const directionLight = new THREE.DirectionalLight(0xffffff, 0.4); // 平行光
scene.add(directionLight);
添加甜甜圈(donuts.glb 可以在 GitHub 仓库里下载)
import { AnimationMixer, Group } from 'three';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
let mixer: AnimationMixer;
let donuts: Group
new GLTFLoader().load('../resources/models/donuts.glb', (gltf) => {
scene.add(gltf.scene);
donuts = gltf.scene;
mixer = new THREE.AnimationMixer(gltf.scene); // 动画混合器
const clips = gltf.animations; // 播放所有动画
clips.forEach(function (clip) {
const action = mixer.clipAction(clip);
action.loop = THREE.LoopOnce;
action.clampWhenFinished = true; // 停在最后一帧
action.play();
});
})
渲染场景
// 渲染场景
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
if (donuts) {
donuts.rotation.y += 0.01; // 让 donuts 旋转
}
if (mixer) {
mixer.update(0.02); // 推进混合器时间并更新动画
}
}
animate();
现在启动项目,pnpm run dev
,打开网页,看是否已经显示了?
但是现在还不能用鼠标拖动
添加轨道控制器
// 添加轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
添加 sky.hdr(sky.hdr 可以在 GitHub 仓库里下载)
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
// 添加 sky.hdr
new RGBELoader()
.load('../resources/sky.hdr', function (texture) {
scene.background = texture;
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.render(scene, camera);
});
GitHub 仓库:github.com/huzhengen/t…