Jump to content

[SOLVED] Remove animation layer


photo

Recommended Posts

Hello!

I have some problems with animation tracks. In our project, we solved them. It would be desirable that the decision appeared and in UNiGiNE.
When we remove animation layer (ObjectMeshSkinned::removeLayer / setNumLayers)  bones don't recalculated. See void MeshSkinned::update_frames
 

// single layer

if(instance->layers.size() == 1) {

   const Layer &layer = instance->layers[0];

   const char *bones_0 = layer.bones.get();

   const Frame *frames_0 = layer.frames.get();

   for(int i = 0; i < num_frames; i++) {

   if(bones_0 == 0) continue;

      frames.xyz = frames_0.xyz;

      frames.rot = frames_0.rot;

     bones = 1;

   }

}

 

This condition skeep inactive bones
if(bones_0 == 0) continue;

We can activate bone by calingObjectMeshSkinned::setFrameBoneTransform or ObjectMeshSkinned::setFrame.

 

Maybe it is worth proposing the standard solution?

Link to comment

Our solution. Sorry, comments in russian :ph34r:

 

   //--------------------------------------------------------------------------
   /// Удалить анимационный слой
   bool CObjectMeshSkinned::RemoveAnimationLayer(int idAnimation_)
   {
      TIdAnim2Layer::iterator itLayer = m_IdAnim2Layer.find(idAnimation_);
      if (itLayer == m_IdAnim2Layer.end() || itLayer->second < 0)
         return false;  // такого слоя не существует

      ::ObjectMeshSkinned* pOMS = getOMS();
      size_t nNumLayers = m_IdAnim2Layer.size() - 1;
      if (0 == nNumLayers)
      {
         pOMS->removeLayer(itLayer->second);
         itLayer->second = -1;
        
         updateBonesFromZeroLayer();

         return true;
      }

      // сохраним информацию о настройках анимационных дорожек перед исключением слоя,
      // т.к потом в мапке m_IdAnim2Layer поплывут все индексы слоев
      struct SAnimContext
      {
         int idAnim, from, to;
         float frameTime, weight;
         TIdAnim2Layer::iterator itAnimMap;
      } animContext;

      bm::vector<SAnimContext> animsParams;
      animsParams.reserve(nNumLayers);

      TIdAnim2Layer::iterator it = m_IdAnim2Layer.begin(), iEnd = m_IdAnim2Layer.end();
      do
      {
         if (it == itLayer || it->second < 0)
            continue;   // слой для удаления или не активный его запоминатьне будем

         animContext.idAnim = it->first;
         pOMS->setLayer(it->second);

         assert(pOMS->getAnimationID() == animContext.idAnim); // есть синхронизация с движком

         animContext.from        = pOMS->getFrameFrom();
         animContext.to          = pOMS->getFrameTo();
         animContext.frameTime   = pOMS->getFrameTime();
         animContext.weight      = pOMS->getWeight();
         animContext.itAnimMap   = it;

         animsParams.push_back(animContext);
      } while (++it != iEnd);

      itLayer->second = -1;

      // ребиндинг анимаций и слоев
      // Скорей всего потрем анимацию костей из 0 слоя выставленную кодом (xml каналами)
      pOMS->setNumLayers(animsParams.size() + 1);

      for (int i = 0, nCount = (int)animsParams.size(); i < nCount; )
      {
         const SAnimContext& animContext = animsParams;
         int nLayer = ++i;

         pOMS->setLayer(nLayer);

         pOMS->setAnimationID(animContext.idAnim);
         pOMS->setWeight(animContext.weight);
         pOMS->setFrame(animContext.frameTime, animContext.from, animContext.to);

         animContext.itAnimMap->second = nLayer;
         assert(animContext.itAnimMap->first == animContext.idAnim);
      }

      updateBonesFromZeroLayer();

      return true;
   }

   //--------------------------------------------------------------------------
   /// Активизировать трансформацию костей из 0 анимационного слоя.
   /// Такие штуки нужны для того, чтобы восстановить исходное положение костей
   /// с учетом выставленных значений через программные интерфейс SetBoneTransform.
   /// Такой код нужен из-за логической кривизны UNiGiNE
   /// см. методы MeshSkinned::update_frames, MeshSkinned::setFrame, MeshSkinned::getFrame
   /// Если кость не активная, то трансформация с нее не читается.
   /// Активизировать кость можно вызовом метода MeshSkinned::setFrame/setFrameBoneTransform
   /// это приводит к записи 1 в layer.bones[bone] = 1;
   void CObjectMeshSkinned::updateBonesFromZeroLayer()
   {
      ::ObjectMeshSkinned* pOMS = getOMS();
      pOMS->setLayer(0);

      const int numMaxBones = 128;
      int numBones = pOMS->getNumBones();
      assert(numBones < numMaxBones);
      VectorStack<mat4, numMaxBones> bonesTransform;

      // Опрашиваем текущие трансформации костей
      for (int i = 0; i < numBones; ++i)
         bonesTransform.appendFast(pOMS->getFrameBoneTransform(i));
      // Выставляем теже самые трансформации костей
      for (int i = 0; i < numBones; ++i)
         pOMS->setFrameBoneTransform(i, bonesTransform);

      // Возможно стоит скинуть еще Кеш углов Эйлера
   }

Link to comment
  • 1 month later...

You can copy your layer transformations into the buffer and restore it after layer removing.

Moreover setFrameBoneTransformEnabled/setBufferBoneTransformEnabled() function will be available in the next SDK.

Link to comment
×
×
  • Create New...