Is it possible to fadeIn or fadeOut the opacity with a group of entity?

In this image,you can see that I have a Group entity,which contains a lot of entities,such as dragon rabbit and so on.

What I want to do is to fadeIn all the entities off the Group.

There is one solution that I fadeIn the entity one by one with the fadeIn function at the same time.

But I think it must be not the good way to handle it.

So,who can give me some suggestion?

I have an idea that maybe I could fadeIn the Group entity.

However,I don’t know how to do this.

Could anyone help me?

This is my project.

https://playcanvas.com/project/429480/overview/exhibition

PlayCanvas does not have this concept of groups that can be faded in or out (or in general groups where the parent can have material properties that affect child Entities).

So the best way to do this is to have a generic function to fade a material in / out and then apply it on all the materials that you want. You can get creative with the way you want to get those materials but you could just iterate all the child Entities and if they have a model component then get the material for all the mesh instances of the model and fade it in / out.

1 Like

Thank you vaios.

I have to write down a generic function for this,since the PlayCanvas don’t have relative API.

Dear vaios

This is my code about the question.

I wrote down this function a fews days ago.

Because I have to fadeIn a lot of entities at the same time,I use a closure for this.

I know the best way to fadeIn entity is use update function.

However,I don’t know how to do this with the update function.

Because I don’t know how to use closure with update function.

Could you give me some suggestion?

This is my anther code to fadeIn entity with update function.

Like you said you shouldn’t use setInterval for things that are changing over time, because that won’t be smooth, and it will not pause when the application is paused for example etc. You always want to use the application’s dt for these things.

Now there are lots of ways one could do this. In your case you have a parent Entity and you want to fade all its children. So you could have a script on the parent Entity and in the update method, go through all the children of the Entity, and call set_parameter on all the mesh instances of the materials. For example something like this (I haven’t tested this so might have some typos):

fadeIn = function (duration) {
    this.opacityStart = 0;
    this.opacityEnd = 1;
    this.duration = duration;
    this.timer = 0;
    this.fade = true;
}

fadeOut = function (duration) {
    this.opacityStart = 1;
    this.opacityEnd = 0;
    this.duration = duration;
    this.timer = 0;
    this.fade = true;
}

update = function (dt) {
     if (this.fade) {
        this.timer += dt;
        if (this.timer >= this.duration) {
            this.fade = false;
        }

        var opacity = pc.math.lerp(this.opacityStart, this.opacityEnd, Math.min(this.timer / this.duration, 1));

        for (var i = 0; i < this.entity.children.length; i++) {
            var child = this.entity.children[i];
            if (! child.model) continue;

            var meshInstances = child.model.meshInstances;
            for (var mi = 0; mi < meshInstances.length; mi++) {
                var material = meshInstances[mi].material;
                if (! material) continue;

                material.setParameter('material_opacity', opacity);
            }
        }
     }
}

(made a small correction on the code there)

Thank you vaios.

I will think about this with your suggestion.

Thank you so much.

Thanks Vaios, this seems reasonable.

Up until now I was using the dt value to set and update the material opacity directly. I think it gets around 6 updates over the course of 2 seconds, so it fades in 6 steps that is. Any pros or cons of using Lerp instead?

  • Björn

These things are usually done by interpolating a value between 2 other values. For example in your case you interpolate between 0 (transparent) and 1 (opaque). So what you usually do is have a variable that acts as a timer on which you add dt, another variable that specifies the total duration of the interpolation and then you calculate a value t that goes between 0 and 1 by dividing your timer with the duration. To achieve different easing methods you pass the t from an easing function and then finally you call lerp. Here are some easing functions:

And some pseudocode:

this.timer += dt;
var t = easing(this.timer / this.duration);
var opacity = pc.math.lerp(0, 1, t);
1 Like

Hi again

I’ve just tried your code, it works great! but I went straight to using this:

material.opacity = opacity;
material.update();

Also had to add the update() to make it work. Any reason to use setParameter instead?

Going to try the easing next.

setParameter just changes uniform value directly, and nothing else.
While setting value on material does does not changes parameter, then calling update will revalidate whole material and re-create shader, possibly leading to recompilation - sometimes it is desired by user.
But if you do know that your shader has opacity already (should be not 1.0 initially), then setParameter - is way better from performance point of view.

material.update - is expensive.

2 Likes

Oh great. All materials are opaque from start yes, is that what you mean? I’m using it on a toggle button to fade in and out an object.

Material tries to be clever, if it has opacity 1.0, then it wont even include uniform for regulating opacity into a shader. For performance reasons.
So you wont be able to regulate opacity property from setParameter. But if you set opacity to 0.999 for example, then it will include it into shader code, and setParameter will have effect.

But the code works perfectly?

Does setParameter still defines uniforms even if material has no uniform in shader? Yes it does, but it is not used.

As said before, both methods work, but update on material - is expensive, and if you do call update every loop for many materials - you will start loosing FPS and potentially lead to shader recompilations which lead to frame freezes, depending on complexity of scene.

1 Like

Actually, I’m not following anymore. But this is the code I used, and it seems to work perfectly.

Fade.prototype.fadeIn = function() {
    
    console.log("ENTER fadeIn()");
    this.opacityStart = 0;
    this.opacityEnd = 1;
    this.timer = 0;
    this.fade = true;
};

Fade.prototype.fadeOut = function() {
    
    console.log("ENTER fadeOut()");
    this.opacityStart = 1;
    this.opacityEnd = 0;
    this.timer = 0;
    this.fade = true;
};

// update code called every frame
Fade.prototype.update = function(dt) {

    //console.log("ENTER update, this.fade=" + this.fade);
    if (this.fade) {
            
        // Increase timer with dt
        this.timer += dt;
        
        // Break fade if timer reached duration
        if (this.timer >= this.duration) {
            this.fade = false;
        }

        // Quint easing
        var t = this.ease(this.timer / this.duration);
        var opacity = pc.math.lerp(this.opacityStart, this.opacityEnd, t);
        
        // Linear interpolation easing lerp
        //var opacity = pc.math.lerp(this.opacityStart, this.opacityEnd, Math.min(this.timer / this.duration, 1));

        // Loop through meshes of this model. 
        for (var i = 0; i < this.meshes.length; i++) {
            
            var material = this.meshes[i].material;
            if (! material) continue;
            
            material.setParameter('material_opacity', opacity);
        }
     }
    
};

// Easing function
Fade.prototype.ease = function(t) {
    return (t<0.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t);
};

I also added this in Initialize to be able to set opacity on the materials:

    this.meshes = this.entity.model.meshInstances; 
    
    // Loop throug materials and enable blending
    // Set blend type to normal to allow for opacity blending.
    for (i = 0; i < this.meshes.length; i++) {
        this.meshes[i].material.blendType = pc.BLEND_NORMAL;
    }
    
1 Like

Bear in mind, that material - might be shared between models.
If you want to override uniform for specific mesh, then use:
this.meshes[i].setParameter(...

Right! I didn’t event consider that. Is setparameter documented?

Can I use this directly on the mesh you say?

setParameter('material_opacity', opacity);

It is not really documented, as parameters are not documented too, and behaviour of it is not great.
Yes you can set it on mesh.

@bjorn.syse We have a sample project of fading in/out models here if you want to see ‘full’ code: https://playcanvas.com/editor/scene/474057

1 Like