用three.js創造時空裂縫特效
呀哈嘍!這裏是alphardex。
最近受到輪迴系作品《寒蟬鳴泣之時》中時空裂縫場景的啟發,我用three.js實現了一個實時渲染的時空裂縫場景。本文將簡要地介紹下實現該效果的要點。
以下特效全屏觀看效果最佳~
https://code.juejin.cn/pen/7168065415069827124
建模
多邊形形狀
首先,創造一個最初始的平面
建模,也就是定製化geometry
要想創建玻璃碎片一般的形狀的話,也就是要創造一個多邊形的形狀
這就要用到kokomi.js的這2個函數createPolygonShape和polySort:前者能接收一系列的點來創造一個多邊形Shape
,後者能給無序的點進行排序以符合多邊形的描畫
創建形狀Shape
後,再傳進ExtrudeGeometry
將其3D化成geometry
即可,這裏depth
等值故意設得很小,是為了模擬玻璃碎片的纖細程度
js
let points = [
{ x: 0, y: 0 },
{ x: 25, y: 0 },
{ x: 45, y: 45 },
{ x: 0, y: 25 },
];
points = kokomi.polySort(points);
const shape = kokomi.createPolygonShape(points, {
scale: 0.01,
});
const geometry = new THREE.ExtrudeGeometry(shape, {
steps: 1,
depth: 0.0001,
bevelEnabled: true,
bevelThickness: 0.0005,
bevelSize: 0.0005,
bevelSegments: 1,
});
geometry.center();
隨機多邊形
為了創建隨機的多邊形,我特意設計了一套算法,大致是這樣的:
- 多邊形是按二維網格排布的,這樣就能儘可能避免有重合的情況出現
- 多邊形的邊數
edgeCount
按個人喜好用隨機概率來控制 - 多邊形的第一個點決定了它在網格上的位置,其他的點是以它為圓心延伸出來的隨機角度的點(跟圓有關因此用到了極座標公式)
```js const generatePolygons = (config = {}) => { const { gridX = 10, gridY = 20, maxX = 9, maxY = 9 } = config;
const polygons = [];
for (let i = 0; i < gridX; i++) { for (let j = 0; j < gridY; j++) { const points = []; let edgeCount = 3; const randEdgePossibility = Math.random(); if (randEdgePossibility > 0 && randEdgePossibility <= 0.2) { edgeCount = 3; } else if (randEdgePossibility > 0.2 && randEdgePossibility <= 0.55) { edgeCount = 4; } else if (randEdgePossibility > 0.55 && randEdgePossibility <= 0.9) { edgeCount = 5; } else if (randEdgePossibility > 0.9 && randEdgePossibility <= 0.95) { edgeCount = 6; } else if (randEdgePossibility > 0.95 && randEdgePossibility <= 1) { edgeCount = 7; } let firstPoint = { x: 0, y: 0, }; let angle = THREE.MathUtils.randFloat(0, 2 * Math.PI); for (let k = 0; k < edgeCount; k++) { if (k === 0) { firstPoint = { x: (i % maxX) * 10, y: (j % maxY) * 10, }; points.push(firstPoint); } else { // random polar const r = 10; angle += THREE.MathUtils.randFloat(0, Math.PI / 2); const anotherPoint = { x: firstPoint.x + r * Math.cos(angle), y: firstPoint.y + r * Math.sin(angle), }; points.push(anotherPoint); } } polygons.push(points); } }
return polygons; }; ```
用該算法來創建多邊形組,再調整下相機和多邊形組的位置和縮放,就有了下圖的效果
漂浮動畫
將多邊形組整體向上偏移,超出界限則重置高度
```js let floatDistance = 0; let floatSpeed = 1; let floatMaxDistance = 1;
this.update(() => { floatDistance += floatSpeed;
const y = floatDistance * 0.001; if (y > floatMaxDistance) { floatDistance = 0; }
totalG.position.y = y; }); ```
將相機靠近,你就會覺得像是每個多邊形在上升(其實是整體的容器在上升)
接下來還有2點可以優化下:
- 要想達成一種大小錯落的層次感,我們可以拷貝一份多邊形組,將其的z軸位置往後移即可
- 要想達成無限上升的動畫“假象”,我們需要再整體拷貝一份多邊形組(包括組本身和偏移z軸後的組),將它和之前的那組在y軸上錯開,這樣動畫就能無限銜接了
光照
這裏可以自由表現,可以嘗試以下幾種手法:
- 漫反射光和鏡面反射光相結合
- 扭曲頂點、法線和uv
- 根據光線動態計算透明度,以形成玻璃般的效果
後期處理
同樣也可以自由表現,可以嘗試以下幾種手法:
- RGB扭曲(該特效所採用的)
- 色差
- 景深效果
- 噪聲點陣
最後
希望本文能給你創作新特效的靈感,keep creating~