2

introduction

In 3D visualization, many animations are involved, of which texture animation is a very important one. This article introduces several ideas for texture animation for everyone to discuss together.

Flow animation

Flow animation sets the repeat property of the texture and constantly changes the offset of the texture object to make the texture flow. This kind of animation is not difficult to achieve, first load the texture, as shown below:

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;
}

The above code implements a tube (pipe), and then adds a texture to the pipe. During rendering, the offset value of the texture object is constantly updated, and then a flowing animation can be produced. As shown below:

flow.gif

Sprite Sheet Animation

The atlas is also commonly referred to as the Sprite map, which is to put a series of small pictures on top of a large picture according to a certain layout. When in use, take a part of the big picture to get a small picture. This is a common method on the web, and is usually used to reduce the number of pictures, thereby reducing the number of network requests.

Through the Sprite map, each frame of the series of animation actions can be laid out on the Sprite map. Then create a texture object through the Sprite map, set the repeat and offset of the texture, so that every time you draw a certain frame of the image on the Sprite map, constantly changing the offset, you can form the animation effect of drawing different frames. For example, the following picture:

image.png

image.png

The following threejs demo has such an effect, so I won’t repeat the code here, and interested readers can check the source code of the demo.

https://stemkoski.github.io/Three.js/Texture-Animation.html The is shown in the figure below:

flow2.gif

GIF animation

The gif picture itself has its own animation. If the gif is placed on the Image object, the animation will play automatically, only when the gif is used as the image of the texture object. The animation will not play automatically.
To automatically play gif animation, you need to use a library that parses gif, parse each frame of the gif image, and draw each frame of image to a canvas, using the canvas as the image of the texture object. The approximate code is as follows:

Load the gif picture and parse the picture. Among them, a library omggif is used to parse pictures, and the frame data of gif pictures can be parsed by using the GifReader inside:

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);

Then continuously update the image of the texture:

 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);
    }

The final gif texture effect is shown in the figure below

flow3.gif

APNG animation

APNG pictures and gif pictures are similar, and they are also animated pictures. But compared to gif. APNG can be set to be semi-transparent, and the edges are not severely jagged, so the effect of using APNG is better than that of gif images.

The principle is similar, it also parses the APNG image, then draws each frame to the canvas at a time, and continuously updates the texture object. To parse APNG images, an open source library, APNG-canvas, is used. Interested readers can research on their own, and I will not focus on it here.

After the analysis is complete, the analyzed frame set can be drawn, the code is as follows:

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);

The final apng texture effect is shown in the figure below

1.gif

Summarize

This article introduces multiple implementation ideas of theejs texture animation. Including texture flow, sprite, gif and apng animation. Through these animation capabilities, colorful visualization effects can be created.

If you are interested in visualization, you can communicate with me on WeChat 541002349 (you can join the WeChat group).

Follow the public account "ITMan Biaoshu" to receive more valuable articles in time.


netcy
204 声望120 粉丝

欢迎对canvas、webgl、图形学感兴趣的读者订阅专栏。