threejs 贴图动画总结

简介: threejs 贴图动画总结

引言


在三维可视化中,会涉及到很多动画,其中贴图动画是其中很重要的一种,本文介绍几种贴图动画的思路,供大家一起探讨。


流动动画


流动动画通过设置贴图的repeat属性,并不断改变贴图对象的offset让贴图产生流动效果。这种动画不难实现,首先加载贴图,如下所示:


let img = new Image();
img.src = './images/path.png';
let texture = new eg.Texture(img);
img.onload = function () {
    texture.needsUpdate = true;
}
texture.repeat.set(100,1);
tube.material.map= texture;
function render(){
 tube.material.map.wrapS = eg.RepeatWrapping;
 tube.material.map.offset.set(offset,0);
 tube.material.map.needsUpdate = true;
 offset += 0.01;
}


上面代码,实现了一个tube(管道),然后给管道加了一个贴图texture。 在渲染的时候,不断更新texture对象的offset的值,此时就可以生产流动的动画。如下图所示:


微信图片_20220425141736.gifflow.gif


雪碧图动画(Sprite Sheet)


图集也就是常说的雪碧图,就是把一系列小图按照一定的布局放到一张大图上面。在使用的时候,截取大图的一部分来获取某个小图。 这在web端是一种常用的手段,通常用于减少图片数量,从而降低网络请求数量。


通过雪碧图的方式,可以把动画的系列动作的每一帧都布局在雪碧图上。然后通过雪碧图创建texture对象,设置贴图的repeat和offset,让每次绘制获取雪碧图上的某一帧图像,不断改变offset,就可以形成绘制不同帧的动画效果。比如下面的图片:


微信图片_20220425141739.png

image.png


微信图片_20220425141742.pngimage.png


下面这个threejs的demo,就是这样的效果,所以此处不再赘述代码,有兴趣的读者可以查看demo的源代码。


https://stemkoski.github.io/Three.js/Texture-Animation.html  效果如下图所示:


微信图片_20220425141745.gif

flow2.gif


GIF动画


gif图片本身自带动画,如果gif放到Image对象上,动画会自动播放,只是当把gif作为贴图对象的图片的时候。不会自动播放动画。


要自动播放gif动画,需要使用解析gif的库,把gif图片的每一帧解析出来, 并把每一帧图像绘制到一个canvas上,把canvas作为贴图对象的图片。大致代码如下:


加载gif图片,并解析图片。其中解析图片用到了一个库omggif,利用里面的GifReader可以解析gif图片的帧数据:


import { GifReader } from 'omggif';
  const loader = new FileLoader(this.manager);
    loader.setPath(this.path);
    loader.setResponseType('arraybuffer');
    loader.load(url, (response) => {
      const gifData = new Uint8Array(response);
      const reader = new GifReader(gifData);
      if (onLoad) onLoad(reader);
    }, onProgress, onError);


然后不断的更新贴图的图像:


draw() {
      if (!this.reader) {
        return;
      }
      const { reader, image, context } = this;
      const { width, height } = image;
      const frameNum = ++this.frameNumber % reader.numFrames();
      const frameInfo = reader.frameInfo(frameNum);
      if (frameNum === 0) {
        // always clear canvas to start
        context.clearRect(0, 0, width, height);
      } else if (this.previousFrameInfo && this.previousFrameInfo.disposal === 2) {
        // disposal was "restore to background" which is essentially "restore to transparent"
        context.clearRect(this.previousFrameInfo.x,
                          this.previousFrameInfo.y,
                          this.previousFrameInfo.width,
                          this.previousFrameInfo.height);
      }
      const imageData = context.getImageData(0, 0, width, height);
      reader.decodeAndBlitFrameRGBA(frameNum, imageData.data);
      context.putImageData(imageData, 0, 0);
      this.needsUpdate = true;
      this.previousFrameInfo = frameInfo;
      this.timeoutId = setTimeout(this.draw.bind(this), (frameInfo.delay || 2) * 10);
    }


最终的gif贴图效果如下图所示


微信图片_20220425141749.gif

flow3.gif


APNG动画


APNG图片和gif图片是类似的,也是动画图片。不过相对于gif来说。APNG可以设置半透明,边缘锯齿不严重,所以使用APNG的图片的效果要优于gif图片。


原理上类似,也是解析APNG图片,然后把每一帧一次绘制到canvas上,并不断更新texture对象。 解析APNG图片,使用了一个开源库,APNG-canvas。有兴趣读者可以自行研究,此处不重点讲述。


解析完成后,可以把解析的帧集合进行绘制,代码如下:


draw() {
      if (!this.reader) {
        return;
      }
      const { reader, image, context } = this;
      const { width, height } = image;
      const frameNum = ++this.frameNumber % reader.numFrames;
      const frameInfo = reader.frames[frameNum];
      if (frameNum === 0) {
        // always clear canvas to start
        context.clearRect(0, 0, width, height);
      // } else if (this.previousFrameInfo && this.previousFrameInfo.disposal === 2) {
      } else if (this.previousFrameInfo) {
        // disposal was "restore to background" which is essentially "restore to transparent"
        context.clearRect(this.previousFrameInfo.left,
                          this.previousFrameInfo.top,
                          this.previousFrameInfo.width,
                          this.previousFrameInfo.height);
      }
      const imageData = context.getImageData(0, 0, width, height);
      // reader.decodeAndBlitFrameRGBA(frameNum, imageData.data);
      // context.putImageData(imageData, 0, 0);
      context.drawImage(frameInfo.img,frameInfo.left,frameInfo.top,frameInfo.width,frameInfo.height);
      this.needsUpdate = true;
      this.previousFrameInfo = frameInfo;
      this.timeoutId = setTimeout(this.draw.bind(this), frameInfo.delay);


最终的apng贴图效果如下图所示


微信图片_20220425141754.gif1.gif


总结


本文介绍了  theejs 贴图动画的多种实现思路。包括 纹理流动,雪碧图,gif和apng动画。通过这些动画能力,可以创建出丰富多彩的可视化效果。

相关文章
Threejs实现模拟管道液体流动
Threejs实现模拟管道液体流动
3114 0
Threejs实现模拟管道液体流动
|
4月前
|
开发者
Uniapp开发鸿蒙应用时如何运行和调试项目
本文介绍了如何将Uniapp项目运行到鸿蒙设备并进行调试。内容包括运行到真机或模拟器的步骤、配置证书的方法、使用console.log打印日志以及在uni-app x项目中设置断点调试的详细流程,帮助开发者提升鸿蒙应用开发效率。
|
6月前
|
Python
使用Python实现multipart/form-data文件接收的http服务器
至此,使用Python实现一个可以接收 'multipart/form-data' 文件的HTTP服务器的步骤就讲解完毕了。希望通过我的讲解,你可以更好地理解其中的逻辑,另外,你也可以尝试在实际项目中运用这方面的知识。
271 69
|
12月前
ThreeJs使用tweenjs动画库制作动画
这篇文章介绍了如何在Three.js中使用Tween.js动画库来简化动画制作流程,并演示了如何通过简单的代码实现动画效果。
326 1
ThreeJs使用tweenjs动画库制作动画
|
9月前
|
机器学习/深度学习 人工智能 算法
昇腾AI行业案例(二):基于 AI 图像处理的安全帽检测
欢迎学习《昇腾行业应用案例》的 “基于 AI 图像处理的安全帽检测” 实验。在本实验中,你将深入了解如何运用计算机视觉(CV)领域的 AI 模型,搭建一个高效精准的安全帽检测系统,并利用开源数据集对模型效果加以验证。为此,我们将使用昇腾的AI硬件以及CANN等软件产品。
298 0
|
12月前
ThreeJs场景中添加视频
这篇文章详细说明了如何在Three.js场景中添加并播放视频,包括视频纹理的创建与应用,以及如何将视频流显示在3D模型的表面上。
375 2
ThreeJs场景中添加视频
第三章:什么是 BACnet/IP 网络
BACnet/IP 网络是一个或多个 IP 子网(IP 域)的集合,这些子网分配有单个 BACnet 网络号。BACnet 互联网络由两个或多个 BACnet 网络组成。这些网络可能是 BACnet/IP 网络,也可能使用其他指定的技术。此标准还支持以类似于 IP 子网的方式包含 IP 多播组,如下文中所述。
683 0
第三章:什么是 BACnet/IP 网络
|
开发框架 JavaScript 小程序
uni-app——如何阻止事件冒泡
uni-app——如何阻止事件冒泡
|
存储 传感器 人工智能
AliOS Things 系统架构介绍(一)
AliOS Things 系统架构介绍(一)
651 0
|
存储 JavaScript 前端开发
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧