用three.js创造时空裂缝特效

呀哈喽!这里是alphardex。

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

最近受到轮回系作品《寒蝉鸣泣之时》中时空裂缝场景的启发,我用three.js实现了一个实时渲染的时空裂缝场景。本文将简要地介绍下实现该效果的要点。

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

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

建模

多边形形状

首先,创造一个最初始的平面

1.png

建模,也就是定制化geometry

要想创建玻璃碎片一般的形状的话,也就是要创造一个多边形的形状

这就要用到kokomi.js的这2个函数createPolygonShapepolySort:前者能接收一系列的点来创造一个多边形Shape,后者能给无序的点进行排序以符合多边形的描画

创建形状Shape后,再传进ExtrudeGeometry将其3D化成geometry即可,这里depth等值故意设得很小,是为了模拟玻璃碎片的纤细程度

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. 多边形的第一个点决定了它在网格上的位置,其他的点是以它为圆心延伸出来的随机角度的点(跟圆有关因此用到了极坐标公式)
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

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~

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容