[SOLVED] How can I create an animated sprite on 2D screen UI in a 3D application?

I agree with @Mal_Duffin. Here, I managed to reach the result I was looking for but for a non-developper, it would have been difficult to find a solution.

1 Like

Sadly, I still got a problem with my solution. The material is influenced by the Skybox and the Ambiant color of my scene. So, my animated images are not rendered with their truly colors and are impacted by the ligths… :disappointed_relieved:

I still hope that one day, I will be able to drag and drop an animated gif as an image that is unlit and set that on the 2D screen space. :pray:

1 Like

Ok, here another technique that fixed my problem described in my last post. The technique uses the sprite element on 2D screen with a script.

0 - First, you need to have an animated sprite. This tutorial explained how to do that: https://youtu.be/x4xMP-J7WlU

1 - Create an image element and set this as a child of a 2D screen element.

image

2 - This image element are like this:

3 - Here the script I made and put on that image element. You can controle the start frame, the number of frames and the FPS.

var AnimateSprite = pc.createScript('animateSprite');

AnimateSprite.attributes.add('startFrame', {
    type: 'number',
    default: 0,
    description: 'Frame to start animation from'
});

AnimateSprite.attributes.add('numFrames', {
    type: 'number',
    default: 1,
    description: 'Number of frames to play before looping'
});

AnimateSprite.attributes.add('frameRate', {
    type: 'number',
    default: 1,
    description: 'Playback frames per second'
});

// initialize code called once per entity
AnimateSprite.prototype.initialize = function() {
    this.timer = 1/this.frameRate;
    this.frame = this.startFrame;
};

// update code called every frame
AnimateSprite.prototype.update = function(dt) {
            
    // calculate when to animate to next frame
    this.timer -= dt;            
    if (this.timer < 0) {
        // move to next frame
        this.frame++;
        if (this.frame >= (this.numFrames + this.startFrame)) {
            this.frame = this.startFrame;
        }

        this.entity.element.spriteFrame = this.frame;
        
         // reset the timer
        this.timer = 1/this.frameRate;
    }
};

So, it’s working well even if:

@yaustar:

Sprites weren’t supposed to be supported as children of the screen

1 Like

I get these warnings in the log when using this technique:

image

Any problems with that?

What’s the code?

Any instance of pc.Vec3/Vec4/Color that is accessed through its .data array has been made a private api.

You will get this in many older shader examples which use the .data property to pass the array to shader uniforms (quite handy I have to say).

Now you will have to access the object values through their respected properties only:

this.vec.x;
this.vec.y;
this.color.r;
// etc
2 Likes

will this help A [

pc.SpriteComponent](https://developer.playcanvas.com/en/api/pc.SpriteComponent.html) that renders sprite animations.

Yes, I was going through the sprite component aswell and I think it does what I need. Perhaps this thread was written before the animated sprite system was in place?

The only thing this code above with animated-texture.js has which I haven’t found in an animated sprite is the possibility to further adjust the material properties of the plane. For example I can use the emissive-channel on a standard material (icon on the right side),where as a sprite component (left icon) only presents a color to use. Is that right?


image

It’s this code here: https://developer.playcanvas.com/en/tutorials/animated-textures/

    // This allows us to use different settings for different Entities, but share the same material
    this.transform.set(dx, dy, x * dx, (1 - dy) - (y * dy));
    meshes[0].setParameter("texture_diffuseMapTransform", this.transform.data);
    meshes[0].setParameter("texture_emissiveMapTransform", this.transform.data);
    meshes[0].setParameter("texture_opacityMapTransform", this.transform.data);
};

Ah yes, that project needs to be updated The .data API no longer exists so you would have to copy the X, Y, Z, W values into your own float array and pass that instead to get rid of the warning.

You can see it being done here: https://github.com/playcanvas/engine/blob/master/src/deprecated.js#L278

1 Like

I see, thanks!

But would you also say the strategy is outdated aswell? Should I just use an animated sprite?

Either is fine to be honest. Whatever you are more comfortable with in this case.

1 Like

then how did i find it if it didnt exist?

Erm, what do you mean by ‘how did I find it’?

@bjorn.syse perhaps this could be of use:

1 Like

Why not use sprite & spriteFrame of Image element for animation? That’s more easy, than animate material.

1 Like

Any chance to use an emissive material on an animated sprite instead of just having the option of choosing a color?

image

The material for sprites should already be emissive?

Regardless, it you want to change the material, you will have to do it via code and via a private API. https://github.com/playcanvas/engine/blob/master/src/framework/components/sprite/component.js#L639

It’s way less emissive than standard material emissive in my tests. I’ll post a comparison tomorrow. thanks!

Here is a comparison between using this sprite sheet with two methods.

image

  1. Using Animated sprite:
  2. Using Animated texture script and standard material:

    image

Animated sprite to the left, and Animated texture to the right

It seems they are indeed quite similar looking if I use Opacity 1, and Alpha blending mode on the Standard Material. At first I had it on Addivetive Alpha, So I guess what I’m missing on the sprite is the possibility to use other blending modes, in this case an Additive Alpha would work very well. Perhaps a feature request!

2 Likes