简介在3D可视化中,涉及到很多动画,其中贴图动画是非常重要的一个。本文介绍纹理动画的几种思路,供大家一起探讨。流动动画流动动画通过设置纹理的重复属性,不断改变纹理对象的偏移量,使纹理流动起来。这种动画不难实现,先载入纹理,如下:letimg=newImage();img.src='./images/path.png';lettexture=neweg.Texture(img);图像。onload=function(){texture.needsUpdate=true;}texture.repeat.set(100,1);tube.material.map=texture;functionrender(){tube.material.map.wrapS=eg.RepeatWrapping;管.material.map.offset.set(偏移量,0);tube.material.map.needsUpdate=true;offset+=0.01;}上面的代码实现了一个tube(管道),然后给管道添加了一个纹理。在渲染过程中不断更新纹理对象的偏移值,从而产生流动的动画。如下图所示:SpriteSheet动画(SpriteSheet)图集也俗称精灵表,就是将一系列的小图片按照一定的布局放在一张大图片上。使用时截取大图的一部分得到小图。这是web端常用的方法,通常用于减少图片数量,从而减少网络请求次数。通过spritemap,动画系列的每一帧都可以在spritemap上进行布局。然后通过sprite图像创建一个纹理对象,设置纹理的repeat和offset,让每次绘制在sprite图像上获取某一帧图像,不断改变偏移量,形成绘制不同帧的动画效果。比如下图:下面threejs的demo就有这样的效果,这里不再赘述代码。有兴趣的读者可以查看demo的源码。https://stemkoski.github.io/T...效果如下图所示:GIF动画gif图片本身自带动画。如果把gif放在Image对象上,动画会自动播放,但是当gif作为贴图对象图片的时候。动画不会自动播放。自动播放gif动画,需要使用解析gif的库,解析gif图片的每一帧,将每一帧图片绘制到画布上,将画布作为纹理对象的图像。大致代码如下:加载gif图片,解析图片。其中,使用了一个库omggif来解析图片,里面的GifReader可以用来解析gif图片的帧数据:import{GifReader}from'omggif';constloader=newFileLoader(this.manager);loader.setPath(this.path);loader.setResponseType('arraybuffer');loader.load(url,(response)=>{constgifData=newUint8Array(response);constreader=newGifReader(gifData);if(onLoad)onLoad(reader);},onProgress,onError);然后不断更新纹理的图像:draw(){if(!this.reader){return;}const{读者、图像、上下文}=this;const{宽度,高度}=图片;constframeNum=++this.frameNumber%reader.numFrames();constframeInfo=reader.frameInfo(frameNum);if(frameNum===0){//始终清除画布以开始context.clearRect(0,0,width,height);}elseif(this.previousFrameInfo&&this.previousFrameInfo.disposal===2){//处理是“恢复到后台”,本质上是“恢复到transpa租”context.clearRect(this.previousFrameInfo.x,this.previousFrameInfo.y,this.previousFrameInfo.width,this.previousFrameInfo.height);}constimageData=context.getImageData(0,0,width,height);读者。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贴图效果如下图所示APNG动画APNG图片类似于gif图片,也是动画图片,但是相比gif,APNG可以设置为半透明,边缘锯齿不严重,所以用APNG图片的效果比gif图片好,原理类似,也是解析APNG图片,然后将每一帧一次绘制到画布上,连续不断更新纹理对象,解析APNG图片,使用了一个开源库APNG-canvas,有兴趣的读者可以自行研究,这里不再赘述。解析完成后,可以把解析的集合合并进行绘制,代码如下:draw(){if(!this.reader){return;}const{读者、图像、上下文}=this;const{宽度,高度}=图片;constframeNum=++this.frameNumber%reader.numFrames;constframeInfo=reader.frames[frameNum];if(frameNum===0){//始终清除画布以开始context.clearRect(0,0,width,height);//}elseif(this.previousFrameInfo&&this.previousFrameInfo.disposal===2){}elseif(this.previousFrameInfo){//处置是“恢复到背景”,本质上是“恢复到透明”context.clearRect(this.previousFrameInfo.left,this.previousFrameInfo.top,this.previousFrameInfo.width,this.previousFrameInfo.height);}constimageData=context.getImageData(0,0,宽度,高度);//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贴图效果如下图所示总结本文介绍了theejs贴图动画的各种实现思路,包括贴图Flow、sprite、gif和apng动画。借助这些动画功能,可以创建丰富多彩的可视化效果。对可视化感兴趣的可以和我交流,微信541002349(可以进微信群)。关注公众号“ITMan表叔”,及时收到更多有价值的文章。
