粉丝和我说想看3D圣诞动画????它来了

简介: 前言大家好我是Fly哥,今天是圣诞节, 首先祝大家圣诞节快乐。今天分享的是从0-1实现一个3D圣诞动画图片这篇有配套的视频链接讲解 和 源码。我会在文章末尾给出,感兴趣的同学自取哈!!!但是视频的内容过于长了,有的同学还是喜欢看文章。我就讲解下!!正题本篇文章大概花费你10分钟,读完本篇文章你可以学到下面几点,可以挑自己感兴趣的点进行阅读three.js 中加载圣诞树模型实现自定义曲线路径动画three.js 中如何 实现粒子动画three.js 音频导入 和📷 动画我们先看下圣诞动画实现的效果:图片圣诞动画基本场景的搭建首先圣诞树需要一个东西去承载, 也就


正题


本篇文章大概花费你10分钟,读完本篇文章你可以学到下面几点,可以挑自己感兴趣的点进行阅读


  1. three.js 中加载圣诞树模型


  1. 实现自定义曲线路径动画


  1. three.js 中如何 实现粒子动画


  1. three.js 音频导入 和📷 动画


我们先看下圣诞动画实现的效果:


image.png


圣诞动画


基本场景的搭建



首先圣诞树需要一个东西去承载, 也就是所谓的地面, 地面的其实使用的 「three.planeGeometry」, 这个api是用也是很简单定义平面的宽度 和长度, 所以你只需要的你的场景足够大, 也就说你平面的宽度和长度 足够大,然后你就可以看着制作出一个平面。代码如下:


const plane = new THREE.PlaneGeometry(1000, 1000)
  const material = new THREE.MeshPhongMaterial({
      map: new THREE.TextureLoader().load('./edge.jpg'),
  })


是的就这么简单的一行代码,然后配上材质, 我们看下效果:


image.png


ground


这里有同学问了这下面这两个问题??


  1. 飞哥 为啥看不到材质哇


  1. 为啥这个地面是紫色的哇


我们明明设置了材质,为啥看不到材质呢????


我给大家看下材质的图片 :


image.png


material


其实贴图的大小就这么大,然后你要贴在这么大的平面上肯定啥也看不到哇, 就好比如下这个场景:


image.png


show


紫色的就表示地面, 灰色的就是地板,这就现在的情况, 这种情况怎么解决呢, 有同学说选一个足够大的图片,可以是可以,但是你看着不怪嘛, 另一个比较聪明的同学,可以不可以有浏览器中图片 「repeat」 属性呢??是的材质当然是支持的

其实你创建的texture 可以用来操作横向纹理 和纵向 纹理的铺法

分别对应下面这两个属性


.wrapS


这个值定义了纹理贴图在水平方向上将如何包裹,在UV映射中对应于「U」。默认值是THREE.ClampToEdgeWrapping,即纹理边缘将被推到外部边缘的纹素。其它的两个选项分别是THREE.RepeatWrapping和THREE.MirroredRepeatWrapping。请参阅texture constants来了解详细信息。


.wrapT : number


这个值定义了纹理贴图在垂直方向上将如何包裹,在UV映射中对应于「V」。可以使用与 .wrapS : number相同的选项。


「请注意:纹理中图像的平铺,仅有当图像大小(以像素为单位)为2的幂(2、4、8、16、32、64、128、256、512、1024、2048、……)时才起作用。宽度、高度无需相等,但每个维度的长度必须都是2的幂。这是WebGL中的限制,不是由three.js所限制的」


我们设置下横向平铺 和纵向平铺 为重复是不是就可以实现重叠了,


代码如下:


if (material.map) {
      material.map.wrapS = THREE.RepeatWrapping
      material.map.wrapT = THREE.RepeatWrapping
      material.map.repeat.x = 30
  }


然后实现上面的有很多瓷砖的效果 , 我们来解释下第二个问题  贴图是白色的 , 为什么地板 看着是紫色的, 这是为啥呢 ,


答案就是 这个材质 THREE.MeshPhongMaterial 他其实是受光照影响的,

场景中其实有两个光源:


  1. 一个环境光


  1. 一个圣诞树下的点光源


image.png


没有环境光


没有环境光,贴图的颜色也是很黑暗,所以在three.js 中环境光 是十分重要的。


雪花粒子动画



其实无论是什么粒子,你看完这一种实现 其他的粒子你可以随便拿捏。首先还是分析,粒子是啥也就是现在场景中的雪花, 其实一个三角形有 3个顶点 ,对应的矩形 就是 4个顶点,  如果一个3d 图形,有1000个甚至 有很多个顶点组成。然后我们在对每个顶点去做贴图,其实就可以生成一个有许多顶点的图形 的立方体呢 ,这就是 3d实现粒子的原理了 很简单。


所以雪花粒子,就是搭配顶点材质, 其实就是这样的一个材质 「PointsMaterial」,和上面的高光材质一样使用


我们对每个粒子的位置去做随机性,是不是就可以制造出所谓的效果了。直接上代码:


const geo = new THREE.BufferGeometry()
  // 设置1000个顶点
  const vertices = []
  for (let i = 0; i < 10000; i++) {
      const x = Math.random() * 2000 - 1000
      const y = Math.random() * 2000 - 1000
      const z = Math.random() * 2000 - 1000
      vertices.push(x, y, z)
  }
  geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
  // 加载雪花贴图
  const texture = new THREE.TextureLoader().load(
      './snow.png',
  )
  const material = new THREE.PointsMaterial({
      size: 20,
      map: texture,
      blending: THREE.AdditiveBlending,
      depthTest: false,
      transparent: true,
  })
  material.color.setHSL(0.9, 0.05, 0.5)
  const particles = new THREE.Points(geo, material)


这里要注意的事,不是生成mesh ,而是使用 THREE.Points,  或者说这两个有什么不同的呢 ???底层的webgl 渲染方式不一样xdm


  1. 「points一个用于显示点的类。由WebGLRenderer渲染的点使用 gl.POINTS。」


  1. 「mesh 表示基于以三角形为polygon mesh(多边形网格 他是以面去渲染的」


因为顶点的大小是 固定的,如果想看粒子的大小,你可以改材质的size 就可以实现了。


场景默认大小是20 ,我们改成50 的你可以看下效果 :


image.png


50的大小


有点丑呵呵哈哈哈!!!!!


至于动画 就很简单的, 一句话概括 ,整体动, 我们只需要对这个particles整体 去做动画就好了,自然所有粒子就开始动了。


if (this.particle) {
      this.particle.rotation.y = time
  }


3d路径环绕动画



我们一步一步拆解, 首先你得有3d 路径 对吧, 这里的使用的Three.js 的api


使用一个点的列表然后你就可以得到一个 闭合的3D曲线  然后 在将这个3d 曲线分成 n个点, 最后将这n个点, 生成一个geometry,


其实一条线, 然后three.js 去创建闭合的曲线。


this.curve = new THREE.CatmullRomCurve3(
      this.curveHandles.map((handle) => handle.position),
      true,
      'centripetal',
  )
  const points = this.curve.getPoints(50)
  const line = new THREE.LineLoop(
      new THREE.BufferGeometry().setFromPoints(points),
      new THREE.LineBasicMaterial({
          visible: false,
          // linecap: 'round', //ignored by WebGLRenderer
          // linejoin: 'round'
      }),
  )


THREE.CatmullRomCurve3:简单介绍下使用Catmull-Rom算法, 从一系列的点创建一条平滑的三维样条曲线。然后three.js 封装好了插值方法,可以将这条曲线拆分成很多个点对吧, 线有了, 这时候我们去场景中加载文字立方体,不清楚的同学 看下 这篇文章


「浅谈3d文字」


image.png


图片


默认文字立方体是这样的,如果让他的朝向 和曲线的方向一致呢,其实这里用到了three.js 另一个工具类, flow 其实你只要传给mesh 和路线给他,然后设置他就自动完成路径匹配了,代码如下:


this.flow = new InstancedFlow(1, undefined, geometry, material);
  this.flow.updateCurve(0, this.curve)
  this.scene.add(this.flow.object3D)
  this.flow.setCurve(0, 0);


image.png


路径弯曲


其实在3d 中有种很难的 就是吸附这种其实特别像圆柱面的侧面 ,你仔细看下。接下里有了方法,然后怎么去运动呢 对吧 , 这个也不用担心,这个工具类已经帮我们封装好了。


if (this.flow) {
    this.flow.moveAlongCurve(0.002)
 }


沿着自定义曲线每秒移动多少,然后到终点自动回头。这个方法是要 requestAnimation里面哦。


模型导入和音乐加载


模型我也是找了很多网站, 最后还是free3d.com 这个里面找到了很多免费的模型,其实模型的导入无非就是three.js 有对应的loader 去加载,然后你根文件的类型去找到对应的loader, 我这里的圣诞树的话,其实obj loader , mtl loader这个是加载材质信息的, 因为圣诞树上材质,


const obj = new OBJLoader() //obj加载器
const mtl = new MTLLoader() //材质文件加载器
mtl.load('./tree/12150_Christmas_Tree_V2_L2.mtl', (materials) => {
    // 返回一个包含材质的对象MaterialCreator
    //obj的模型会和MaterialCreator包含的材质对应起来
    obj.setMaterials(materials)
    obj.load('./tree/12150_Christmas_Tree_V2_L2.obj', (tree) => {
        //tree.receiveShadow = true;
        tree.castShadow = true
        this.tree = tree
        this.tree.scale.set(0.4, 0.4, 0.4) //放大obj组对象
        // 先绕Y轴旋转 在绕 x 轴旋转
        const matrix = new THREE.Matrix4().makeRotationY(Math.PI / 2).makeRotationX(-Math.PI / 2)
        this.tree.rotation.setFromRotationMatrix(matrix)
        this.tree.position.set(0, -5, 0)
        this.scene.add(this.tree) //返回的组对象插入场景中
    })
})


如果你在模型导入的时候时常找不到模型, 你可以先将模型先放大,后面在做位置微调就好了。


音乐的加载three.js 中有对应的音乐加载器,然后将音乐绑在相机上,会有声音变化的效果,代码如下


addMusic() {
      const listener = new THREE.AudioListener();
      this.camera.add(listener);
      // 创建一个非位置音频对象  用来控制播放
      const audio = new THREE.Audio(listener);
      // 创建一个音频加载器对象
      const audioLoader = new THREE.AudioLoader();
      // 加载音频文件,返回一个音频缓冲区对象作为回调函数参数
      audioLoader.load('./music.mp3', function (AudioBuffer) {
          // console.log(AudioBuffer)
          // 音频缓冲区对象关联到音频对象audio
          audio.setBuffer(AudioBuffer);
          audio.setLoop(false); //是否循环
          audio.setVolume(1); //音量
          // 播放缓冲区中的音频数据
          audio.pause()
          audio.play(); //play播放、stop停止、pause暂停
      });
  }


最后我在讲下这运镜的动画是怎么实现的


相机动画



看镜头不断从远到近,不断地反复轮回,其实核心就一个字 改变相机的位置,但是你如果一直加 整个场景的东西 就会看不见了,


所以现在的需求固定相机在某个位置,然后到某一个位置后就返回。如图:


image.png




其实也就是在A点和B 点 相机来回摆动,形成了错觉, 整个场景在动的感觉,其实这里用到了正余弦函数:我们看下两个的图像


image.png


图像


为啥这两个 这么符合 无论 是哪一个函数 他们的取值范围永远是 【-1,1】 而且同时也有单调性, 不像线性渐变辣么突兀,所以对相机运用这个动画非常适合,大家以后如果有这种场景,可以使用这个公式


y = default + K * cos / sin(time)


default默认是 一开始大小, K 其实就是 最终的位置  减去默认的大小 就可以了,这样就不用担心了  哈哈哈哈!!


代码如下:


this.camera.position.x = Math.sin(time * 0.0005) * 150
  this.camera.position.z = 100 + Math.cos(time * 0.0005) * 150
  this.camera.position.y = 30 + Math.cos(time * 0.0005) * 30
相关文章
|
5月前
情人节浪漫3D照片墙【附源码】
情人节浪漫3D照片墙【附源码】
48 4
|
5月前
|
JSON 人工智能 数据格式
在PAI Artlab一键实现欧洲杯粉丝专属贴纸制作
嘿,各位足球狂热分子,准备好迎接欧洲杯的狂欢了吗?你的加油装备还缺了点啥?别担心,ArtLab平台一键贴纸生成工作流,来给这足球盛宴加点料啦!快来,让我们一起把激情和创意混搭出新高度!
在PAI Artlab一键实现欧洲杯粉丝专属贴纸制作
|
对象存储
七夕快到了,来创造一副浪漫的鹊桥插画吧
本次通过加载和推理SD模型对象存储OSS Bucket,挂载到PAI-EAS服务,实现模型部署,加载和推理SD模型,制作属于自己的七夕画作。
|
前端开发 机器人 程序员
六一 特效~ 你也是大小孩
六一 特效~ 你也是大小孩
108 0
|
C语言 C++
C/C++实现跨年表白烟花
C/C++实现跨年表白烟花
471 0
|
JavaScript 前端开发 程序员
【中秋征文】手把手教你海面月亮升起中秋节特效制作
【中秋征文】手把手教你海面月亮升起中秋节特效制作
234 0
【中秋征文】手把手教你海面月亮升起中秋节特效制作
|
计算机视觉 索引
七夕礼物:火柴人特效制作
七夕礼物:火柴人特效制作
327 1
七夕礼物:火柴人特效制作
|
安全 前端开发 JavaScript
圣诞节用女神照片做了一个旋转木马
圣诞节用女神照片做了一个旋转木马
193 0
圣诞节用女神照片做了一个旋转木马
|
前端开发 JavaScript
「寒草的中秋献礼🥮,实现30s前端创意动画」陪你看日落和月升|与你赏星空和诗歌
「寒草的中秋献礼🥮,实现30s前端创意动画」陪你看日落和月升|与你赏星空和诗歌
290 1
下一篇
无影云桌面