使用 Three.js 实现掉落的甜甜圈

99 阅读1分钟

使用 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…

学习视频:www.bilibili.com/video/BV14D…