文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

二维码还能这么玩?制作一个3D动态粒子二维码!

2024-11-29 22:06

关注

最终效果

本文最终的效果可以访问https://gallery.xieyufei.com/about查看

建模

要实现这样的效果,首先我们需要将二维码进行建模处理;网络上也有很多建模工具,这里笔者推荐使用开源且好用的Blender4进行建模;整个建模的过程较为繁琐,因此需要一定的耐心和细心;如果有更好的建模方式,欢迎在评论区留言讨论。

选中右上角的Z轴,将图片拖拽入编辑器中,最好将二维码的四周白边进行裁切;然后调整其XYZ轴位置,让其居中:

导入

Shift+A键,我们添加一个网格=>平面进来,再次调整位置,然后选择右上角的切换透视模式,快捷键是Alt+Z键;开启透视模式后,我们就可以调整平面的大小,和二维码中间部分大小相同即可。

添加并调整平面

选择平面后,继续点击Tab键进入编辑模式,Ctrl+R添加分割线,在平面的横向和纵向都添加多个分割线,滚动鼠标滚轮可以增加或减少数量,当数量刚好可以切割每个二维码的方块时点击右键确定:

添加分割线

点击左上角的面选择模式以及扩展当前选中项模式,将白色块的部分选中出来,然后点击del键进行删除,选择面选项,这个过程需要耐心慢慢选择:

注意框选面中间的小点,才能选中面。

选择删除面

删除后我们得到了这样一个图形,我们发现依然可以进行扫码:

删除完成

我们给每个黑色的小方块同时添加横向和纵向的分割线,选择所有的面,点击del删除,选择仅边和面选项

这一步也需要细心和耐心,当然你也可以在前面第一次分割的时候,分割得更细。

删除面和边

面和边删除了,我们的界面上看似什么都没有了,不过别着急,然后右上角选择点模式,我们就能看到删除了边和面之后,还有很多的小点剩余下来,我们只需要保留黑色方块中心的点;这里我们在点模式下框选黑色方块中的点后,然后使用Ctrl+I键进行反向选择,删除其他所有的点:

选择点

最终我们得到这样一个点状的图形,将其导出到glb文件即可:

最终生成的

导入模型

我们的模型处理完成后,可以导入到three.js中来了;我们导入模型后,由于模型的大小和位置可能不是我们需要的,可以对geometry进行缩放、旋转、平移操作,调整到页面上合适的位置即可:

const loader = new GLTFLoader();
let qrGeometry
loader.load("/models/qr.glb", (gltf) => {
  const geometry = gltf.scene.children[0].geometry;
  geometry
    .scale(20, 20, 20)
    .rotateX((90 / 180) * Math.PI)
    .rotateY((90 / 180) * Math.PI)
    .translate(0, 0, -20);

  qrGeometry = geometry;
});

生成随机点

然后就该用到我们的粒子Points了,我们先用随机数生成一堆的粒子,然后将Camera镜头放到粒子堆的边缘进行移动,就可以产生粒子在旋转的效果:

const getRandomPos(index) {
  const x = Math.random() * 90 - 45;
  const y = Math.random() * 90 - 45;
  const z = Math.random() * 90 - 45;
  return [x, y, z];
}
const initPoints = () => {
  const randomGeometry = new BufferGeometry();
  const verticles = [];
  for (let i = 0; i < 8000; i++) {
    const [x, y, z] = getRandomPos(i)
    verticles.push(x, y, z);
  }
  randomGeometry.setAttribute(
    "position",
    new Float32BufferAttribute(verticles, 3)
  );

  const material = new PointsMaterial({
    color: 0x333333,
    size: 0.8,
    map: new TextureLoader().load("gradient.png"),
  });

  const pt = new Points(randomGeometry, material);
  screen.add(pt);
  this.pt = pt;
};

但是这样生成出来的随机点呈现出来是一个立方体,所以摄像机在移动时需要掌控好位置,如果距离原点太远,就会出现粒子稀疏不同的情况;那么我们优化随机函数,让随机点生成在一个椭圆体的范围内,这样相机在移动时粒子就比较均匀了,不会出现分布不均的情况;这里引入三维空间下的椭圆计算公式:

椭圆的计算方程

这里的计算逻辑也很简单,有三个变量,我们通过控制变量的方式,先生成Y轴和Z轴的随机值,然后套用计算公式,就可以计算得到X轴的最大值max,再根据这个max值随机生成X轴的的坐标即可:

const getRandomPos = (index) => {
  const MAX_Y = 60;
  const MAX_Z = 80;
  const MAX_X = 80;
  const y = Math.random() * MAX_Y * 2 - MAX_Y;
  const z = Math.random() * MAX_Z * 2 - MAX_Z;
  const max = Math.sqrt(
    (1 - Math.pow(y, 2) / MAX_Y / MAX_Y - Math.pow(z, 2) / MAX_Z / MAX_Z) *
      MAX_X *
      MAX_X
  );

  const x = Math.random() * max * 2 - max;
  return [x, y, z];
};

我们看到Y轴的数值比X和Z轴都小一点,因此整个椭圆体会偏扁一点,生成出来的图形也符合我们的预期:

椭圆体

这样,我们的相机在旋转时粒子分布就相对比较均匀了;我们将镜头拉到粒子的边缘,然后绕着边缘做缓慢的环绕运动就可以看到粒子的旋转效果了:

const changeCameraView = () => {
  new Tween.Tween({
    x: 0,
  })
    .to(
      {
        x: 80,
      },
      2400
    )
    .onUpdate((pos) => {
      const { x } = pos;
      const z = Math.sqrt(80 * 80 - Math.pow(x, 2));
      this.camera.position.x = x;
      this.camera.position.z = z;
      this.camera.lookAt(new Vector3(0, 0, 0));
      this.camera.updateProjectionMatrix();
    })
    .start();
};

模型切换

随机粒子生成后,我们就可以将randomGeometry模型转换成我们上面的qrGeometry模型了,引入我们的切换模型函数,这里的函数在粒子云效果的实现里面已经详细解释了,这里不再赘述了:

const changeGeometry = (toArray, duration = 1500) => {
  const nowFloatArray = this.pt.geometry.attributes.position.array;

  const tos = this.mixFloatArray(nowFloatArray, toArray);

  new Tween.Tween({
    ...Array.from(nowFloatArray),
  })
    .to(tos, duration)
    .easing(Tween.Easing.Quadratic.InOut)
    .onComplete(() => {
      this.isChanging = false;
    })
    .onUpdate((pos) => {
      for (let key in pos) {
        const val = pos[key];
        const idx = Number(key);
        this.pt.geometry.attributes.position.array[idx] = val;
      }
      this.pt.geometry.attributes.position.needsUpdate = true;
    })
    .start();
};

在旋转镜头的同时,我们进行模型的切换:

this.changeCameraView();
setTimeout(() => {
  this.changeGeometry(qrGeometry.attributes.position.array, 1600);
}, 1600);

本文最终的效果可以访问https://gallery.xieyufei.com/about查看

总结

本文根据前文粒子云的实现效果,扩展了具体如何来实现一个二维码的粒子化效果;通过建模工具Blender,可以将我们的二维码建立模型后导入three.js中;适合网页上需要呈现展示二维码效果的地方。

来源:前端壹读内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯