theme: jzman
灵感图
每次都根据灵感图写代码,我都快成灵感大王了,本文较长,跨度较大,效果较好,请耐心看完,本文阶段代码有tag可以分部查看
前言
这是B站的一段视频,用3D渲染的方式表达各个大厂的logo如何制作出来的,其中提取出一小段,用于本文的灵感,就是这个图的切割效果,下文不包含激光的圆圈和工作平台,只有切割的光线、切割效果和分离动画,灵感图中切割的部分是超过logo的,如果有UI设计师,可以让设计师给提供分段的svg,我孤军奋战没有那么些资源,文中的点位都是从logo的svg文件获取的,场景创建就不赘述了,以前的文章也讲过很多次,那么我们开始吧
准备工作
- threejs
- ts
- vite
找一个这个小鸟的svg文件。
将svg文件的点位获取出来并将svg加入到场景中
渲染svg
```typescript // 加载模型 const loadModel = async () => {
svgLoader.load('./svg/logo.svg', (data) => {
const material = new THREE.MeshBasicMaterial({
color: '#000',
});
for (const path of data.paths) {
const shapes = SVGLoader.createShapes(path);
for (const shape of shapes) {
const geometry = new THREE.ShapeGeometry(shape);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh)
}
}
renderer.setAnimationLoop(render)
})
} loadModel() ```
渲染结果
svg加载出来后的shape
就是组成当前logo的所有关键点位信息,接下来要做的是将这个logo以正确的角度放置在场景,再将这些关键点位生成激光运动路径,比如一个圆弧,是一个贝塞尔曲线,有两个定点,几个手柄,通过不同的角度组成曲线,而我们要做的是一条布满点位的曲线作为运动路径
获取曲线点位
这里用到的api是# CubicBezierCurve
贝塞尔曲线的基类Curve对象提供的方法getPoints
.getPoints ( divisions : Integer ) : Array
divisions -- 要将曲线划分为的分段数。默认是 5.
为了更方便的查看我们创建的点位,我们将生成的点位信息创建一个cube
```ts // 加载模型 const loadModel = async () => { ... for (const curve of shape.curves) { /* * .getPoints ( divisions : Integer ) : Array * divisions -- 要将曲线划分为的分段数。默认是 5. */ const points = curve.getPoints(100); console.log(points); for (const v2 of points) { const geometry = new THREE.BoxGeometry(10, 10, 10); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); cube.position.set(v2.x, v2.y, 0) scene.add(cube); }
}
...
}
}
renderer.setAnimationLoop(render)
})
} loadModel() ```
从图中可以看出,现在cube已经绕着logo围成一圈了,但是有一个现象,就是路径长的地方cube比较稀疏,而路径比较短的曲线cube比较密集,上面代码创建的关键点位信息都是以100的数量创建,所以会导致这种情况,曲线的疏密程度决定将来激光的行走速度,为了保证不管多长的路径,他们的行走速度是一样的,那么我们需要动态计算一下到底该以多少个点位来生成这条路径
ts ... const length = curve.getLength (); const points = curve.getPoints(Math.floor(length/10)); ...
在遍历curve的时候,通过getLength
获取曲线的长度