用three.js創造時空裂縫特效

語言: CN / TW / HK

呀哈嘍!這裏是alphardex。

Snipaste_2022-11-21_22-35-00.jpg

最近受到輪迴系作品《寒蟬鳴泣之時》中時空裂縫場景的啟發,我用three.js實現了一個實時渲染的時空裂縫場景。本文將簡要地介紹下實現該效果的要點。

以下特效全屏觀看效果最佳~

http://code.juejin.cn/pen/7168065415069827124

建模

多邊形形狀

首先,創造一個最初始的平面

1.png

建模,也就是定製化geometry

要想創建玻璃碎片一般的形狀的話,也就是要創造一個多邊形的形狀

這就要用到kokomi.js的這2個函數createPolygonShapepolySort:前者能接收一系列的點來創造一個多邊形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();

2.png

隨機多邊形

為了創建隨機的多邊形,我特意設計了一套算法,大致是這樣的:

  1. 多邊形是按二維網格排布的,這樣就能儘可能避免有重合的情況出現
  2. 多邊形的邊數edgeCount按個人喜好用隨機概率來控制
  3. 多邊形的第一個點決定了它在網格上的位置,其他的點是以它為圓心延伸出來的隨機角度的點(跟圓有關因此用到了極座標公式)

```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; }; ```

用該算法來創建多邊形組,再調整下相機和多邊形組的位置和縮放,就有了下圖的效果

3.png

漂浮動畫

將多邊形組整體向上偏移,超出界限則重置高度

4.gif

```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; }); ```

將相機靠近,你就會覺得像是每個多邊形在上升(其實是整體的容器在上升)

5.gif

接下來還有2點可以優化下:

  1. 要想達成一種大小錯落的層次感,我們可以拷貝一份多邊形組,將其的z軸位置往後移即可
  2. 要想達成無限上升的動畫“假象”,我們需要再整體拷貝一份多邊形組(包括組本身和偏移z軸後的組),將它和之前的那組在y軸上錯開,這樣動畫就能無限銜接了

光照

這裏可以自由表現,可以嘗試以下幾種手法:

  1. 漫反射光和鏡面反射光相結合
  2. 扭曲頂點、法線和uv
  3. 根據光線動態計算透明度,以形成玻璃般的效果

後期處理

同樣也可以自由表現,可以嘗試以下幾種手法:

  1. RGB扭曲(該特效所採用的)
  2. 色差
  3. 景深效果
  4. 噪聲點陣

最後

希望本文能給你創作新特效的靈感,keep creating~