Dynamic loading of the model

Hello. In my projects, I have previously implemented the mechanics of selecting the body and head on the site and uploading them to the game. I used anim and model components, which are now obsolete.
In a new project I want to use render component and anim stat graph.
Now I have a customized prefab with animation on the stage
Screenshot_2
I have anim stategraph in the “Character Test_1” component, the render component in Ch36. I load the model like this:

           const path = data.data[0].draco_model_web_path
           this.app.assets.loadFromUrl(path,'container',(a,b)=>{
           this.avatarBody.addComponent('render',{
            type:"asset",
            asset:b.resource.render
          }); 
        })

I use draco loader, but there are a lot of renders components in the array, and they are not loaded by this method. But if there is one render, then there are also no changes on the scene.

Tell me how to replace render correctly so that it picks up anim stategraph

If you are trying to create the entities needed for the model you are loading, use https://developer.playcanvas.com/en/api/pc.ContainerResource.html#instantiateRenderEntity

Example here: Loading Draco Compressed GLBs | Learn PlayCanvas

2 Likes

Thanks, it worked. Now I need to add anim component. This component is located in the entity on the scene
I add it like this

 this.app.assets.loadFromUrl(path, 'container', (a,b)=>{
            const entity = b.resource.instantiateRenderEntity({
                castShadow: true
            })
            this.app.root.addChild(entity)
            
            entity.addComponent('anim',{
                type:'component',
                asset:this.avatarBody.parent.c.anim
            })
            
            entity.c.anim.baseLayer = this.avatarBody.parent.c.anim.baseLayer
            entity.c.anim.stateGraph = this.avatarBody.parent.c.anim.stateGraph
            entity.c.anim.rebind();

the component is added, but the animation is not played. And the baseLayer field remains empty. Maybe there is another way to do this?

The way I do it is:

var renderRootEntity = asset.resource.instantiateRenderEntity();
renderRootEntity.addComponent('anim', { activate: true });
renderRootEntity.anim.assignAnimation('idle', self.animation.resource, 1, true);

The assignAnimation function will create a state if one doesn’t exist and assigns the animation resource to it.

1 Like

I understand correctly, are you creating a new anim component? In my case, there is already a model on the stage that has an anim configured, and I just need to clone it to the created model.

I guess you just need to create an empty anim

   this.app.assets.loadFromUrl(path, 'container', (a,b)=>{
            const entity = b.resource.instantiateRenderEntity({
                castShadow: true
            })
            this.app.root.addChild(entity)
            
            entity.addComponent('anim',{
                activate:true
            })

now I need to add anim stat graph from assets, and run, which method to use for this?

If you have a state graph, use https://developer.playcanvas.com/en/api/pc.AnimComponent.html#loadStateGraph with the state graph resource

1 Like
    this.app.assets.loadFromUrl(path, 'container', (a,b)=>{
        const entity = b.resource.instantiateRenderEntity({
            castShadow: true
        })
        this.app.root.addChild(entity)
        
        entity.addComponent('anim',{
            activate:true
        })

       entity.anim.loadStateGraph(this.graphAsset.resource)
       entity.anim.rebind()
       entity.anim.reset()

    })

Indeed, the component was correctly applied. But the animation is not played, the model is in T-pose. Maybe you need to manually start it?

That would imply that the root bone may be set incorrectly. If you have a project link that you can share, that would help in getting you up and running.

1 Like

We spoke to each other by private message and found that there were two main issues:

With the anim state graph, it won’t animate unless every state in the graph has been given an animation on the anim component.

ie:

this.app.assets.loadFromUrl(path, 'container', (a,b)=>{
    const entity = b.resource.instantiateRenderEntity({
        castShadow: true
    })
    
    // Create a root node for this entity to match what the animation expects
    const rootNode = new pc.Entity('RootNode');
    this.app.root.addChild(rootNode);
    rootNode.addChild(entity);

    // Scale the entity to match what the animation expects
    rootNode.setLocalScale(0.01, 0.01, 0.01);
    entity.setLocalScale(1, 1, 1);

    rootNode.addComponent('anim',{
        activate:true
    });

    rootNode.anim.loadStateGraph(this.graphAsset.resource);
    const idleAnimAsset = this.app.assets.find('idle.glb', 'animation');
    const upBallAnimAsset = this.app.assets.find('UpBall.glb', 'animation');
    const lKickAnimAsset = this.app.assets.find('kick_L.glb', 'animation');
    const rKickAnimAsset = this.app.assets.find('kick_R.glb', 'animation');
    const failAnimAsset = this.app.assets.find('fail.glb', 'animation');
    
    rootNode.anim.assignAnimation('idle', idleAnimAsset.resource);
    rootNode.anim.assignAnimation('New state 6', upBallAnimAsset.resource);
    rootNode.anim.assignAnimation('lHit', lKickAnimAsset.resource);
    rootNode.anim.assignAnimation('rHit', rKickAnimAsset.resource);
    rootNode.anim.assignAnimation('fail', failAnimAsset.resource);
    
    // The graph doesn't have any anim mappings, these have to be done on
    // component. All states need to have an animation for any animation 
    // to play
})

The model and animation had a mismatch in hierarchy too as it looked like model wasn’t rigged correctly for the animation used or the animation was using the correct model rig. For the sake of the project, I had to add an extra node in the hierarchy and change the scale to have it animate.

    // Create a root node for this entity to match what the animation expects
    const rootNode = new pc.Entity('RootNode');
    this.app.root.addChild(rootNode);
    rootNode.addChild(entity);

    // Scale the entity to match what the animation expects
    rootNode.setLocalScale(0.01, 0.01, 0.01);
    entity.setLocalScale(1, 1, 1);

TLDR, the animation and model had a mismatch in the rig :sweat_smile:

1 Like