assigning multiple entities to be controlled by same skeleton is impossible Topic is solved

Problems building or running the engine, queries about how to use features etc.
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Hi, all!
It looks like Ogre fundamentally can't support modular characters using the same skeleton.
At least I can't make it work for a while now.

Code: Select all

                if (characterModelsTop.find(e) !=
                    characterModelsTop.end()) {
                    Ogre::String skeletonName =
                        bodyEnt->getMesh()
                            ->getSkeletonName();
                    Ogre::MeshPtr mesh =
                        Ogre::MeshManager::getSingleton()
                            .getByName(
                                characterModelsTop
                                    [e]);
                    if (!mesh)
                        mesh = Ogre::MeshManager::getSingleton()
                                   .load(characterModelsTop
                                         [e],
                                     "General");
                    mesh->setSkeletonName(skeletonName);
                    Ogre::Entity *characterTop =
                        eng.mScnMgr->createEntity(mesh);
                    characterTop->shareSkeletonInstanceWith(
                        bodyEnt);
                    bodyNode->attachObject(characterTop);
                }

If I don't set mesh's skeleton characterTop->shareSkeletonInstanceWith(bodyEnt); asserts as it checks that skeleton it gets is the same.
If I set mesh's skeleton I get assertion that skeleton already exists. So it is impossible to make it work at all whatever I do, also
blender2ogre exporter also creates skeleton for each mesh so it doesn't solve my problem and it is impossible for meshes to share a skeleton.
Is it a bug or intended behavior?

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

This particular snipped asserts

Code: Select all

                    Ogre::String skeletonName =
                        bodyEnt->getMesh()
                            ->getSkeletonName();
                    Ogre::MeshPtr mesh =
                        Ogre::MeshManager::getSingleton()
                            .load(characterModelsTop
                                      [e],
                                  "General");
                    OgreAssert(
                        mesh,
                        "No mesh " +
                            characterModelsTop[e]);
                    mesh->setSkeletonName(skeletonName);
                    Ogre::Entity *characterTop =
                        eng.mScnMgr->createEntity(mesh);

with
terminate called after throwing an instance of 'Ogre::ItemIdentityException'
what(): ItemIdentityException: Skeleton with the name male-clothes-toprobe.skeleton already exists. in ResourceManager::add at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreResourceManager.cpp (line 152)
Aborted (core dumped)
And male-clothes-toprobe.skeleton is the name of original mesh's skeleton, not set by mesh->setSkeletonName(skeletonName);
so it tries to create new skeleton under that name for some wicked reason. For now it all looks as broken as it can possibly be.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

It looks like the way I tried it it is impossible.
I have to have separate skeletons and control them independently.
The skeleton sharing works only for entities created from the same mesh. Even if skeleton is the same data-wise but different object,
sharing will not work. So at export time in Blender one must have copy skeleton and all animation states into all clothes and play animations on all parts
at the same time.
The other approach is to export all clothes as submeshes in single mesh and hide all except ones that are needed.
Both ways are very expensive and basically a showstopper. The only feasible way is to have character mesh for every clothing combination.

chilly willy
Halfling
Posts: 82
Joined: Tue Jun 02, 2020 4:11 am
x 27

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by chilly willy »

I just tested to make sure and sharing a skeleton instance between entities with two different meshes works perfectly fine. According to your second post, you experience the issue even when you don't call shareSkeletonInstanceWith(). Is the exception being thrown in setSkeletonName() or createEntity()?

Learn to use your debugger and step into the code (including Ogre code) to figure out where exactly things go wrong. In this case 1) why is it trying to load the old skeleton instead of the one you specify and 2) why does it fail if its already loaded instead of just using the loaded one.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

chilly willy wrote: Sun Feb 15, 2026 8:29 am

I just tested to make sure and sharing a skeleton instance between entities with two different meshes works perfectly fine. According to your second post, you experience the issue even when you don't call shareSkeletonInstanceWith(). Is the exception being thrown in setSkeletonName() or createEntity()?

Learn to use your debugger and step into the code (including Ogre code) to figure out where exactly things go wrong. In this case 1) why is it trying to load the old skeleton instead of the one you specify and 2) why does it fail if its already loaded instead of just using the loaded one.

When I setSkeletonName() on the mesh, the assert happens on createEntity().

Code: Select all

(gdb) bt
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737331595328) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140737331595328) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140737331595328, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff6442476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff64287f3 in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff68a4f26 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007ffff68b6d9c in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff68b6e07 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007ffff68b70bb in __cxa_rethrow () from /lib/x86_64-linux-gnu/libstdc++.so.6
#9  0x00007ffff6fd4844 in Ogre::Resource::load (this=0x55556be908f0, background=false) at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreResource.cpp:286
#10 0x00007ffff6eeec9a in Ogre::MeshManager::load (this=0x555556842ec0, filename="male-clothes-toprobe.glb", groupName="Characters", vertexBufferUsage=5 '\005', indexBufferUsage=5 '\005', 
    vertexBufferShadowed=false, indexBufferShadowed=false) at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreMeshManager.cpp:141
#11 0x00007ffff6dff963 in Ogre::EntityFactory::createInstanceImpl (this=0x55555684a450, name="Ogre/MO159", params=0x7fffffffc3f0) at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreEntity.cpp:2265
#12 0x00007ffff6f084c3 in Ogre::MovableObjectFactory::createInstance (this=0x55555684a450, name="Ogre/MO159", manager=0x555556f61860, params=0x7fffffffc3f0)
    at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreMovableObject.cpp:422
#13 0x00007ffff7045a15 in Ogre::SceneManager::createMovableObject (this=0x555556f61860, name="Ogre/MO159", typeName="Entity", params=0x7fffffffc3f0)
    at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreSceneManager.cpp:3239
#14 0x00007ffff70385df in Ogre::SceneManager::createEntity (this=0x555556f61860, entityName="Ogre/MO159", meshName="male-clothes-toprobe.glb", groupName="Characters")
    at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreSceneManager.cpp:354
#15 0x00007ffff70386da in Ogre::SceneManager::createEntity (this=0x555556f61860, entityName="Ogre/MO159", pMesh=...) at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreSceneManager.cpp:359
#16 0x00007ffff70387db in Ogre::SceneManager::createEntity (this=0x555556f61860, pMesh=...) at /media/slapin/library/ogre3/ogre/OgreMain/src/OgreSceneManager.cpp:372
#17 0x0000555555638d10 in operator() (__closure=0x55555702f270, e=..., ch=...) at /media/slapin/library/ogre3/ogre-projects/world2/src/gamedata/CharacterModule.cpp:76
#18 0x0000555555643d5d in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::invoke_callback<flecs::_::each_field, flecs::_::field_ptr>(ecs_iter_t *, const struct {...} &, size_t) (iter=0x7fffffffc9e0, func=..., i=0) at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:317
#19 0x0000555555643058 in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::invoke_unpack<flecs::_::each_field, flecs::_::field_ptr>(ecs_iter_t *, const struct {...} &, size_t, flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::Terms &) (iter=0x7fffffffc9e0, func=...) at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:367
#20 0x000055555564281d in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::invoke_unpack<flecs::_::each_field>(ecs_iter_t *, const struct {...} &, size_t, flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::Terms &) (
    iter=0x7fffffffc9e0, func=..., index=0, columns=...) at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:378
#21 0x00005555556420e0 in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::invoke(ecs_iter_t *) const (
    this=0x55555702f270, iter=0x7fffffffc9e0) at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:241
#22 0x00005555556418a5 in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::run(ecs_iter_t *) (iter=0x7fffffffc9e0)
    at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:249
#23 0x0000555555641188 in flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::run_add(ecs_iter_t *) (
    iter=0x7fffffffc9e0) at /media/slapin/library/ogre3/ogre-sdk/include/flecs/addons/cpp/delegate.hpp:277
#24 0x00005555558d8c94 in flecs_invoke_hook (world=world@entry=0x55555668b9b0, table=table@entry=0x55555d7a2b58, cr=<optimized out>, tr=<optimized out>, count=count@entry=1, row=row@entry=0, 
    entities=0x7fffffffccb8, id=<optimized out>, ti=0x55555702f180, event=300, 
    hook=0x55555564114b <flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::run_add(ecs_iter_t *)>)
    at /media/slapin/library/ogre3/flecs/src/component_actions.c:66
#25 0x0000555555921d07 in flecs_table_invoke_hook (world=world@entry=0x55555668b9b0, table=table@entry=0x55555d7a2b58, 
    callback=0x55555564114b <flecs::_::each_delegate<ECS::CharacterModule::CharacterModule(flecs::world&)::<lambda(flecs::entity, ECS::CharacterBase&)>, ECS::CharacterBase>::run_add(ecs_iter_t *)>, event=300, 
    column=column@entry=0x555570c7a4c0, entities=0x7fffffffccb8, row=0, count=1) at /media/slapin/library/ogre3/flecs/src/storage/table.c:893
#26 0x000055555592493a in flecs_table_invoke_add_hooks (world=world@entry=0x55555668b9b0, table=table@entry=0x55555d7a2b58, column_index=column_index@entry=0, entities=entities@entry=0x7fffffffccb8, 
    row=row@entry=0, count=count@entry=1, construct=true) at /media/slapin/library/ogre3/flecs/src/storage/table.c:1010
#27 0x000055555592867f in flecs_table_move (world=world@entry=0x55555668b9b0, dst_entity=<optimized out>, dst_entity@entry=979, src_entity=<optimized out>, src_entity@entry=979, 
    dst_table=dst_table@entry=0x55555d7a2b58, dst_index=dst_index@entry=0, src_table=src_table@entry=0x5555566a3408, src_index=0, construct=true) at /media/slapin/library/ogre3/flecs/src/storage/table.c:1986
#28 0x00005555558e0a21 in flecs_move_entity (world=world@entry=0x55555668b9b0, entity=entity@entry=979, record=record@entry=0x555556698d10, dst_table=dst_table@entry=0x55555d7a2b58, 
    diff=diff@entry=0x7fffffffce90, ctor=ctor@entry=true, evt_flags=0) at /media/slapin/library/ogre3/flecs/src/entity.c:218
#29 0x00005555558e19fc in flecs_commit (world=world@entry=0x55555668b9b0, entity=entity@entry=979, record=record@entry=0x555556698d10, dst_table=dst_table@entry=0x55555d7a2b58, diff=diff@entry=0x7fffffffce90, 
    construct=construct@entry=true, evt_flags=0) at /media/slapin/library/ogre3/flecs/src/entity.c:279
#30 0x00005555558d7f3a in flecs_cmd_batch_for_entity (start=1, cmds=0x5555638524b0, entity=979, diff=0x7fffffffce60, world=<optimized out>) at /media/slapin/library/ogre3/flecs/src/commands.c:942
#31 flecs_defer_end (world=<optimized out>, stage=stage@entry=0x5555566924d0) at /media/slapin/library/ogre3/flecs/src/commands.c:1143
#32 0x000055555591a3e1 in flecs_stage_merge (world=<optimized out>) at /media/slapin/library/ogre3/flecs/src/stage.c:52
#33 0x000055555591a705 in ecs_readonly_end (world=<optimized out>) at /media/slapin/library/ogre3/flecs/src/stage.c:339
#34 0x00005555558cd476 in flecs_run_pipeline (world=<optimized out>, world@entry=0x5555566924d0, pq=pq@entry=0x55555673d830, delta_time=delta_time@entry=0.0170000009)

So I guess it tries to load stuff on entity creation it considers missing but for some reason tries to load the skeleton which was previously set on it,
which is already loaded as part of mesh loading, and breaks. The error itself is kind of off as I guess the breakage comes somewhere earlier.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

if I don't setSkeletonName() there is no problem until I try shareSkeletonInstanceWith() so it is definitely triggered by setSkeletonName().

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

So I guess the sequence of events is this:

  1. I load the mesh with MeshManager::load()
  2. I setSkeleton() on it.
  3. createEntity(mesh) tries to load it again by name and load() complains that skeleton is already loaded.
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

By checking of createInstanceImpl() code it will always try to load the mesh and load() will always complain if parts are already loaded,
so either I miss the secret sequence of operations required to share skeletons from different meshes, or it is impossible.

Code: Select all

    MovableObject* EntityFactory::createInstanceImpl( const String& name,
        const NameValuePairList* params)
    {
        // must have mesh parameter
        MeshPtr pMesh;
        if (params != 0)
        {
            String groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;

        NameValuePairList::const_iterator ni;

        ni = params->find("resourceGroup");
        if (ni != params->end())
        {
            groupName = ni->second;
        }

        ni = params->find("mesh");
        if (ni != params->end())
        {
            // Get mesh (load if required)
            pMesh = MeshManager::getSingleton().load(
                ni->second,
                // autodetect group location
                groupName );
        }

    }
    if (!pMesh)
    {
        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
            "'mesh' parameter required when constructing an Entity.",
            "EntityFactory::createInstance");
    }

    return OGRE_NEW Entity(name, pMesh);

}

Code: Select all

    MeshPtr MeshManager::load( const String& filename, const String& groupName,
        HardwareBuffer::Usage vertexBufferUsage,
        HardwareBuffer::Usage indexBufferUsage,
        bool vertexBufferShadowed, bool indexBufferShadowed)
    {
        MeshPtr pMesh = static_pointer_cast<Mesh>(createOrRetrieve(filename,groupName,false,0,0,
                                         vertexBufferUsage,indexBufferUsage,
                                         vertexBufferShadowed,indexBufferShadowed).first);
        pMesh->load();
        return pMesh;
    }

Code: Select all

    void Resource::load(bool background)
    {
        // Early-out without lock (mitigate perf cost of ensuring loaded)
        // Don't load if:
        // 1. We're already loaded
        // 2. Another thread is loading right now
        // 3. We're marked for background loading and this is not the background
        //    loading thread we're being called by

    if (mIsBackgroundLoaded && !background) return;

    // This next section is to deal with cases where 2 threads are fighting over
    // who gets to prepare / load - this will only usually happen if loading is escalated
    bool keepChecking = true;
    LoadingState old = LOADSTATE_UNLOADED;
    while (keepChecking)
    {
        // quick check that avoids any synchronisation
        old = mLoadingState.load();

        if ( old == LOADSTATE_PREPARING )
        {
            while( mLoadingState.load() == LOADSTATE_PREPARING )
            {
                                OGRE_LOCK_AUTO_MUTEX;
            }
            old = mLoadingState.load();
        }

        if (old!=LOADSTATE_UNLOADED && old!=LOADSTATE_PREPARED && old!=LOADSTATE_LOADING) return;

        // atomically do slower check to make absolutely sure,
        // and set the load state to LOADING
        if (old==LOADSTATE_LOADING || !mLoadingState.compare_exchange_strong(old,LOADSTATE_LOADING))
        {
            while( mLoadingState.load() == LOADSTATE_LOADING )
            {
                                OGRE_LOCK_AUTO_MUTEX;
            }

            LoadingState state = mLoadingState.load();
            if( state == LOADSTATE_PREPARED || state == LOADSTATE_PREPARING )
            {
                // another thread is preparing, loop around
                continue;
            }
            else if( state != LOADSTATE_LOADED )
            {
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Another thread failed in resource operation",
                    "Resource::load");
            }
            return;
        }
        keepChecking = false;
    }

    // Scope lock for actual loading
    try
    {

                OGRE_LOCK_AUTO_MUTEX;



        if (mIsManual)
        {
            if (old==LOADSTATE_UNLOADED && mLoader)
            {
                mLoader->prepareResource(this);

                if (!background)
                    _firePreparingComplete();
            }

            preLoadImpl();

            // Load from manual loader
            if (mLoader)
            {
                mLoader->loadResource(this);
            }
            else
            {
                // Warn that this resource is not reloadable
                LogManager::getSingleton().stream(LML_TRIVIAL)
                    << "Note: " << mCreator->getResourceType()
                    << " instance '" << mName << "' was defined as manually "
                    << "loaded, but no manual loader was provided. This Resource "
                    << "will be lost if it has to be reloaded.";
            }
            postLoadImpl();
        }
        else
        {

            if (old==LOADSTATE_UNLOADED)
            {
                prepareImpl();

                if (!background)
                    _firePreparingComplete();
            }
                                                                                                                                                                                             249,13        51%
            preLoadImpl();

            if (mGroup == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
            {
                // Derive resource group
                changeGroupOwnership(
                    ResourceGroupManager::getSingleton()
                    .findGroupContainingResource(mName));
            }

            loadImpl();

            postLoadImpl();
        }

        // Calculate resource size
        mSize = calculateSize();

    }
    catch (...)
    {
        // Reset loading in-progress flag, in case failed for some reason.
        // We reset it to UNLOADED because the only other case is when
        // old == PREPARED in which case the loadImpl should wipe out
        // any prepared data since it might be invalid.
        mLoadingState.store(LOADSTATE_UNLOADED);

        OGRE_LOCK_AUTO_MUTEX;
        unloadImpl();

        // Re-throw
        throw;
    }

    mLoadingState.store(LOADSTATE_LOADED);
    _dirtyState();

    // Notify manager
    if(mCreator)
        mCreator->_notifyResourceLoaded(this);

    // Fire events, if not background
    if (!background)
        _fireLoadingComplete();


}
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

If I do mesh->load() after setSkeleton() call, nothing wrong happens on this load(), it happens later on createEntity().
So the problem is not with load() per se but with something createEntity() does. Maybe I need to clone the mesh... but that is really weird...

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Yes, mesh cloning worked, so I guess something is broken in the core, but I at least have a workaround for now.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

the final snippet which works:

Code: Select all

                if (characterModelsTop.find(e) !=
                    characterModelsTop.end()) {
                    Ogre::String skeletonName =
                        bodyEnt->getMesh()
                            ->getSkeletonName();
                    Ogre::MeshPtr mesh = 
                        Ogre::MeshManager::getSingleton()
                            .load(characterModelsTop
                                      [e],
                                  "General");
                    Ogre::String mname = mesh->getName();
                    mesh = mesh->clone(mname + "_clone");
                    OgreAssert(
                        mesh,
                        "No mesh " +
                            characterModelsTop[e]);
                    Ogre::String clothSkeleton =
                        mesh->getSkeletonName();
                    if (clothSkeleton != skeletonName) {
                        mesh->setSkeletonName(
                            skeletonName);
                        mesh->load();
                        if (Ogre::SkeletonManager::getSingleton()
                                .resourceExists(
                                    clothSkeleton))
                            Ogre::SkeletonManager::
                                getSingleton()
                                    .remove(clothSkeleton);
                    }
                    Ogre::Entity *characterTop =
                        eng.mScnMgr->createEntity(mesh);
                    characterTop->shareSkeletonInstanceWith(
                        bodyEnt);
                    bodyNode->attachObject(characterTop);
                    characterModelsTop[e] = characterTop;
                }
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Looks like with GLTF workflow it is impossible to use multiple .glb files with Ogre on the same skeleton as it looks like the skeletons get rearrenged on import, so all weights and animations will go haywire. So the only out of the box way is to have single export with many submeshes. Will try to make blender2ogre work for this case. Otherwise meshes will have to be processed in code to fix weights. I tested with Godot and my exports worked there fine with modular characters, so there is no error on Blender side.

chilly willy
Halfling
Posts: 82
Joined: Tue Jun 02, 2020 4:11 am
x 27

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by chilly willy »

Are you using background loading?

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

No, only normal foreground loading.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Well, I find that I need to retarget mesh hardware buffers for each submesh to make skeleton sharing work. The bone indices are off even though GLTF files have the same skeleton, in Ogre I see the same bones have different bone index.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

But implementation of bone retargeting is beyond my expertise at the moment. So all I can do now is export everything into one .glb and hide or just drop this game project and forget about it.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Well, it looks like with gltf I will have trouble with submeshes as they are not named, so I will have to try some different approach.
The approach with hiding subentities works fine though, but it is too hard to use because I will have to guess submesh index and they might change...

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

I converted to .mesh workflow using blender2ogre and found it working.

  1. Because of skeleton sharing I don't need to set anything to meshes and skeleton sharing works out of the box, just need to run shareSkeletonInstanceWith(); I still need to export everything together but that is automatable with Blender scripts, and meshes can be selected easily.
    2. Materials with gltf export from Blender are much, much better than with blender2ogre export, i.e. I can't make normal map work (mesh goes grey or black) while
    with .glb it works out of the box :( probably some normal map format issues... (I use OpenGL ES 2.0 RenderSystem)
    fixed everything via blender settings and scripts
    Anyway it looks like I can progress farther, thanks a lot for all the help!
User avatar
sercero
Bronze Sponsor
Bronze Sponsor
Posts: 547
Joined: Sun Jan 18, 2015 4:20 pm
Location: Buenos Aires, Argentina
x 203

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by sercero »

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 388
Joined: Fri May 23, 2025 5:04 pm
x 28

Re: assigning multiple entities to be controlled by same skeleton is impossible

Post by slapin »

Yes, and that is what I use now for .mesh-based workflow and thanks a lot for good plugin. I was trying to use .gltf-based workflow but it is not practical to use due to large number of woes. The good side of gltf is that it packages everything inside and has no namespace issues. With .mesh based workflow I have to care about unique names for everything, which adds a lot of maintenance work and debugging, but that is unavoidable.
Also I need to mention that for .mesh workflow I have to merge all my clothes from different .blend files into one .blend otherwise skeleton sharing doesn't work (as I was writing in this thread for gltf-based woes with setSkeletonName()). It would be nice if I could tell exporter (e.g. with custom property) that I'd like to share with external skeleton so the meshes would end up with some skeleton name embedded instead of new skeleton. I think that would work if I export with the same skeleton, just different .blend file. Also I think that could allow to force skeleton name for skeleton itself as currently I always get names like male.001.skeleton for skeletons as data blocks get manipulated severely in my pipeline...