共计 3517 个字符,预计需要花费 9 分钟才能阅读完成。
引言
在三维可视化中,会波及到很多动画,其中贴图动画是其中很重要的一种,本文介绍几种贴图动画的思路,供大家一起探讨。
流动动画
流动动画通过设置贴图的 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 的值,此时就能够生产流动的动画。如下图所示:
雪碧图动画(Sprite Sheet)
图集也就是常说的雪碧图,就是把一系列小图依照肯定的布局放到一张大图下面。在应用的时候,截取大图的一部分来获取某个小图。这在 web 端是一种罕用的伎俩,通常用于缩小图片数量,从而升高网络申请数量。
通过雪碧图的形式,能够把动画的系列动作的每一帧都布局在雪碧图上。而后通过雪碧图创立 texture 对象,设置贴图的 repeat 和 offset,让每次绘制获取雪碧图上的某一帧图像,一直扭转 offset,就能够造成绘制不同帧的动画成果。比方上面的图片:
上面这个 threejs 的 demo,就是这样的成果,所以此处不再赘述代码,有趣味的读者能够查看 demo 的源代码。
https://stemkoski.github.io/T… 成果如下图所示:
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 贴图成果如下图所示
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 贴图成果如下图所示
总结
本文介绍了 theejs 贴图动画的多种实现思路。包含 纹理流动,雪碧图,gif 和 apng 动画。通过这些动画能力,能够创立出丰富多彩的可视化成果。
如果对可视化感兴趣,能够和我交换,微信 541002349(可入微信群)。另寻求有三维建模能力,UI 设计能力的人员。
关注公号“ITMan 彪叔”能够及时收到更多有价值的文章。