2D animation

Please tell me the best method to represent 2D animations in 8th Wall. Is it possible to use MP4, GIF, APNG, WEBP, or sprite sheets? If there are resources to learn about these, please let me know.

Hi @kosuke_yanagi I believe in a sense most of those would work, however in my experience it’s worth exploring the MP4 route.

Now, if it’s a plain, fully opaque video, you can just add it to the <a-assets> and reference it as a texture on the plane and set the video to play.

However, if not, then the way I believe you have 2 options:

  1. Additive Blending - if your video has a black background, the additive blending will remove the black pixels from the video:
    https://www.8thwall.com/8thwall/face-effects-blending-additve/code/

  2. Green Screen - there is a component that was made to do the same as additive blending, however this will apply to a colour of choice rather than just black. If you look in the example below, you’ll see that the color attribute for the video has the exact colour of the green in the original video. Make sure you get an accurate HSL value for the colour as at the moment it doesn’t really respond to hex or rgb codes.
    Green Screen Video + World Tracking | 8th Wall Playground | 8th Wall

For the green Screen approach, I’ve found this is a pretty cool tool to get the right values:

Hope this helps :slight_smile:

3 Likes

You could also use a GIF if you want. Check out the component here:

Or can write a custom component that flips through .png files if you want transparent png or gif.

Something like this

AFRAME.registerComponent('animate-png', {
  init() {
    // load the .pngs
    const loader = new THREE.TextureLoader()
    this.pngArray = []
    this.pngArray.push(loader.load(require('./assets/image_01.png')))
    this.pngArray.push(loader.load(require('./assets/image_02.png')))
    this.pngArray.push(loader.load(require('./assets/image_03.png')))
    // Add as many images as you have in your sequence    

    this.el.addEventListener('loaded', (e) => {
      const mesh = this.el.getObject3D('mesh')
      this.material = mesh.material

      let i = 0
      this.id = setInterval((e) => {
        if (i >= this.pngArray.length) i = 0
        this.material.map = this.pngArray[i++]
        this.material.needsUpdate = true
      }, 100)
    })
  },
  remove() {
    clearInterval(this.id)
    // free the memory
    for (let i = 0; i < this.pngArray.length; i++) {
      this.pngArray[i].dispose()
    }
  },
})
1 Like