Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

lxf2023-04-25 22:24:01

前言

之前断断续续地跟着大帅的Threejs零基础直通浅学了一下threejs,投入精力不大却也学到了一些Threejs技巧和api。由于这个教学主要讲的是Threejs创建内容,再结合平时见过的一些3D项目中大量的动画及操作,不由得发出3D项目也太复杂了的感慨。

最近大帅邀请胖达老师带来了元宇宙实战特训,具体讲解了如何使用Blender进行3D建模、添加动画以及如何在Threejs中展示、控制3D模型,解答了我的疑惑,原来一些看似复杂的3D项目可以如此简单的实现。

下面就带来甜甜圈案例,来了解threejs安装和基础应用

Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

分析需求

要实现动图中的甜甜圈效果,按照代码层面的思路肯定是利用threejs创建好甜甜圈然后改变其位置来实现动画效果,看着好像也还行但其实自己去实现这个甜甜圈以及动画效果还是太复杂了。这不,胖达老师给我们带来了实战解决方案

我们可以到3D模型资源网站上去下载一些甜甜圈的模型,然后通过Blender对模型进行细节处理,处理成我们想要的形状。由于之前接触过3DMAX,感觉这部分处理都差不多,都是些点线面的处理以及材质贴图等等。在Blender中我们不光能够构建模型,我们还能给模型添加帧动画,这样实现的模型在Threejs中引入后能够很简单的实现其动画。

实现

通过npm下载Threejs

npm i three

在项目中引用Threejs

import * as THREE from 'three';

创建场景和相机以及渲染器,将渲染器添加到dom

/**
 * 创建场景和相机以及渲染器
 */
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(
    75,// 广角
    window.innerWidth / window.innerHeight,// 压缩比
    0.01,// 场景的近距离锥体
    10// 场景的远距离锥体
)
const renderer = new THREE.WebGLRenderer({ 
  antialias: true // 抗锯齿(开启就会消耗更多得性能
})
// 设置渲染器大小
renderer.setSize(window.innerWidth,window.innerHeight)
// 将渲染器添加到dom
document.body.appendChild(renderer.domElement)

创建环境光

/**
 * 创建环境光
 */
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);

创建几何体,测试一下我们场景搭建是否成功

/**
 * 创建几何体 (用于测试)
 */
const boxGeometry =new  THREE.BoxGeometry(1,1,1)
const boxMaterial = new THREE.MeshBasicMaterial({
  color: 0xdedede
})
const boxMesh = new THREE.Mesh(boxGeometry,boxMaterial)
scene.add(boxMesh)

创建关键帧动画,渲染搭建的场景和相机

/**
 * 创建关键帧动画
 */
function animate () {
  requestAnimationFrame(animate)
  renderer.render(scene,camera)
}
​
animate()

这样基础场景就搭建好了,但是这时查看会发现页面漆黑,我们用于测试创建的集合体也不见踪影,其实是由于相机初始位置是(0,0,0)处于几何体的内部,所以我们要挪一下相机位置

// 放置相机位置,要不然是在盒子里面,一片黑
camera.position.set(0,0,2)

创建控制器控制相机

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// ....// 创建控制
const controls = new OrbitControls(camera,renderer.domElement)
​
function animate () {
  // ....
  
  controls.update()
}

此时效果如下

Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

添加hdr环境贴图

/**
 * 添加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);
  });

Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

场景到这里就布置好啦,接下来添加3D模型

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// ....let donuts;
new GLTFLoader().load('../resources/models/donuts.glb', (gltf) => {
    console.log(gltf);
    scene.add(gltf.scene);
    donuts = gltf.scene;
})

效果如下

Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

这样我们的3D模型就加载好了,是不是很简单。

但是现在甜甜圈还是没有动效的,如何去给它增加动效呢,我们可能会想到获取到每个甜甜圈对象然后手工写代码给它增加动效,接着就引申出来我们该如何获取甜甜圈对象,下面打印出加载的模型看看包含哪些属性

Threejs+Blender实现甜甜圈掉落效果| 大帅老猿threejs特训

我们可以看到scene对象中含有一些Mesh,这些其实就是我们在Blender中构建的各个模型,我们可以通过改变这些Mesh的位置去达到动画的效果。

但我们还看到animations中有6个AnimationClip,其实这6个AnimationClip就对应了我们在Blender中给6个甜甜圈创建的动画,这6个AnimationClip包含了6个甜甜圈的动画信息,下面看下如何使用

let donuts;
let mixer;
new GLTFLoader().load('../resources/models/donuts.glb', (gltf) => {
    console.log(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() {
  // ....
  if (mixer) {
    mixer.update(0.02);
  }
}
​

这样一个简单的甜甜圈案例就实现啦

总结

虽然这个案例比较简单,但是它能够让我们了解程序开发和美术资源是如何协作的,我们可以学习到3D模型如何在Threejs中被使用,相信能够帮助大家打开Threejs的大门。当然胖达老师后面的课程中有讲到更为复杂的元宇宙场景如何实现,以及如何载入人物模型控制其运动,更加能够激起大家的兴趣,以后有空再和大家分享。

大家也可以直接公众号搜索大帅老猿学习Threejs相关知识,

可以加入猿创营 (v:dashuailaoyuan),一起交流学习。