前言
- 以前断断续续地通过大帅Threejs零度基点的直通来浅学Threejs,虽然没怎么花力气,但也学到了一些Threejs的技巧和api。
- 这门课主要讲的是Threejs的制作内容,在平时看过的几个3D项目中大量的动画和操作结合在一起,不由得感慨3D项目也太复杂了。
最近,大帅邀请胖达老师带来了元宇宙实战特训,具体介绍了如何用Blender进行3D建模、添加动画以及在Threejs中展示和控制3D模型,解答了我的疑问。 看起来很复杂的3D项目能这么容易实现吗? - 下面通过看看甜甜圈的盒子吧,看看threejs的安装和基础APP应用程序
分析需求
- 要实现动图的圆环效果,代码级思想要求利用threejs制作圆环,并改变其位置以实现动画效果。 看起来也不错,但其实要自己实现这个甜甜圈和动画效果太复杂了。 这不,胖达老师给我们带来了实战性的解决方案。
1、下载模型
- 可以去3D模型资源网站下载甜甜圈的模型,在Blender中详细处理模型,按照我们想要的形式处理。 因为以前接触过3DMAX,所以我觉得这部分的处理大部分相同,是虚线面的处理和材质贴图等。 除了构建模型外,Blender还可以向模型中添加逐帧动画,这样实现的模型引入Threejs后可以轻松实现动画。
2、代码实现
1、在npm上下载Threejs
npm i three
2、在项目中引用Threejs
import * as THREE from 'three';
3、创建场景、摄影机和渲染器,并将渲染器添加到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)
4、创建环境光
/**
* 创建环境光
*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);
5、创建几何体并看一下场景构建是否成功
/**
* 创建几何体 (用于测试)
*/
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)
6、创建关键帧动画,并渲染生成的场景和摄影机
/**
* 创建关键帧动画
*/
function animate () {
requestAnimationFrame(animate)
renderer.render(scene,camera)
}
animate()
7、这样就完成了基础场景,但此时看页面一片漆黑。 为了测试而制作的集合体也消失了。 实际上,摄影机的初始位置是( 0,0,0 )位于几何体内部,因此会偏移摄影机的位置
// 放置相机位置,要不然是在盒子里面,一片黑
camera.position.set(0,0,2)
8、控制器控制相机的制作
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// ....
// 创建控制
const controls = new OrbitControls(camera,renderer.domElement)
function animate () {
// ....
controls.update()
}
9、添加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);
});
10、添加三维模型
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;
})
这样就加载了我们的3D模型。
很简单吧?
但是,现在对甜甜圈也没有效果。 如何提高效果呢? 你可能会考虑一个一个地得到甜甜圈的对象,然后手工编写代码来提高效果。 然后,我们来考虑一下该如何获得甜甜圈的对象。
打印下面加载的模型,看看包含什么属性
您可以看到scene对象包含几个Mesh。
这些实际上是用Blender构建的各个模型,可以通过改变这些Mesh的位置来获得动画效果。
但是,我们还发现animations有六个AnimationClip。 实际上,这6个动画剪辑与在Blender中为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),一起交流学习。`