Skip to content

Commit

Permalink
feat: #35 Add joint animation system
Browse files Browse the repository at this point in the history
  • Loading branch information
ducphamhong committed Dec 30, 2019
1 parent 25cd213 commit 932791b
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 72 deletions.
4 changes: 3 additions & 1 deletion Projects/Skylicht/Engine/Source/Entity/CEntityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This file is part of the "Skylicht Engine".
#include "Transform/CWorldTransformSystem.h"
#include "RenderMesh/CJointSystem.h"
#include "RenderMesh/CRenderMeshSystem.h"
#include "RenderMesh/CJointAnimationSystem.h"
#include "RenderMesh/CSoftwareSkinningSystem.h"
#include "Culling/CCullingSystem.h"

Expand All @@ -40,6 +41,7 @@ namespace Skylicht
addSystem<CComponentTransformSystem>();
addSystem<CJointSystem>();
addSystem<CWorldTransformSystem>();
addSystem<CJointAnimationSystem>();
addSystem<CSoftwareSkinningSystem>();
addRenderSystem<CCullingSystem>();
addRenderSystem<CRenderMeshSystem>();
Expand Down Expand Up @@ -154,7 +156,7 @@ namespace Skylicht
int numEntity = m_entities.size();

for (IEntitySystem* &s : m_systems)
{
{
for (int i = 0; i < numEntity; i++)
{
if (entity[i]->isAlive())
Expand Down
66 changes: 36 additions & 30 deletions Projects/Skylicht/Engine/Source/Importer/Collada/CColladaLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ This file is part of the "Skylicht Engine".
#include "RenderMesh/CRenderMeshData.h"
#include "RenderMesh/CJointData.h"
#include "Culling/CCullingData.h"
#include "Transform/CWorldTransformData.h"

namespace Skylicht
{
Expand Down Expand Up @@ -1506,8 +1507,8 @@ namespace Skylicht

// unit scale
float unitScale = 1.0f;
if (m_unit != "meter")
unitScale = m_unitScale;
//if (m_unit != "meter")
// unitScale = m_unitScale;

while (stackColladaNodes.size())
{
Expand All @@ -1519,16 +1520,31 @@ namespace Skylicht
if (node->Parent && node->Parent->Entity)
parent = node->Parent->Entity;

// get parent
CWorldTransformData *parentTransform = NULL;
if (parent != NULL)
parentTransform = parent->getData<CWorldTransformData>();

// create entity
CEntity* entity = output->createEntity();

// tag this entity
node->Entity = entity;

// add transform
core::matrix4 relativeTransform = node->Transform;
core::vector3df unitTranslate = relativeTransform.getTranslation() * unitScale;
relativeTransform.setTranslation(unitTranslate);

// add entity with transform
CStringImp::convertUnicodeToUTF8(node->Name.c_str(), name);
output->addTransformData(entity, parent, relativeTransform, name);

// add joint data if this node is JOINT
if (node->Type == L"JOINT")
{
CJointData *jointData = entity->addData<CJointData>();
jointData->BoneName = name;

if (node->ChildLevel == 0)
jointData->BoneRoot = true;
Expand All @@ -1539,42 +1555,29 @@ namespace Skylicht
jointData->SID = name;
}

CStringImp::convertUnicodeToUTF8(node->Name.c_str(), name);
jointData->BoneName = name;

// default matrix
jointData->DefaultRelativeMatrix = node->Transform;

// get parent
CJointData *parentJoint = NULL;
if (parent != NULL)
parentJoint = parent->getData<CJointData>();
// default relative matrix
jointData->DefaultRelativeMatrix = relativeTransform;

// calc animation matrix
if (jointData->BoneRoot == true || parentJoint == NULL)
jointData->DefaultAnimationMatrix = node->Transform;
if (jointData->BoneRoot == true)
jointData->DefaultAnimationMatrix = relativeTransform;
else
jointData->DefaultAnimationMatrix.setbyproduct_nocheck(parentJoint->DefaultAnimationMatrix, jointData->DefaultRelativeMatrix);
jointData->DefaultAnimationMatrix.setbyproduct_nocheck(parentTransform->World, jointData->DefaultRelativeMatrix);

// current animation is default matrix
// animation is default matrix
jointData->AnimationMatrix = jointData->DefaultAnimationMatrix;

// store for next construct skinned mesh
m_nameToJointData[jointData->BoneName] = jointData;
m_sidToJointData[jointData->SID] = jointData;
}
else
{
CStringImp::convertUnicodeToUTF8(node->Name.c_str(), name);
}

// add transform
core::matrix4 mat = node->Transform;
core::vector3df unitTranslate = mat.getTranslation() * unitScale;
mat.setTranslation(unitTranslate);

// add entity
output->addTransformData(entity, parent, mat, name);
// calc world transform
CWorldTransformData *transformData = entity->getData<CWorldTransformData>();
if (parentTransform != NULL)
transformData->World.setbyproduct_nocheck(parentTransform->World, transformData->Relative);
else
transformData->World = transformData->Relative;

// construct geometry & controller in node
if (node->Instance.size() > 0)
Expand Down Expand Up @@ -1640,6 +1643,8 @@ namespace Skylicht
{
renderMesh->setSoftwareSkinning(true);
}

renderMesh->setSkinnedMesh(true);
}
}
}
Expand Down Expand Up @@ -1730,8 +1735,9 @@ namespace Skylicht
}

if (buffer)
{
{
colladaMesh->addMeshBuffer(buffer);
buffer->recalculateBoundingBox();
buffer->drop();
}
}
Expand Down Expand Up @@ -1791,8 +1797,8 @@ namespace Skylicht
core::array<u32> indices;

float unitScale = 1.0f;
if (m_unit != "meter")
unitScale = m_unitScale;
//if (m_unit != "meter")
// unitScale = m_unitScale;

// if have the normal & texcoord
if (tri->NumElementPerVertex == 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
!@
MIT License
Copyright (c) 2019 Skylicht Technology CO., LTD
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This file is part of the "Skylicht Engine".
https://github.com/skylicht-lab/skylicht-engine
!#
*/

#include "pch.h"
#include "CJointAnimationSystem.h"

namespace Skylicht
{
CJointAnimationSystem::CJointAnimationSystem()
{

}

CJointAnimationSystem::~CJointAnimationSystem()
{

}

void CJointAnimationSystem::beginQuery()
{
m_meshs.set_used(0);
}

void CJointAnimationSystem::onQuery(CEntityManager *entityManager, CEntity *entity)
{
CRenderMeshData *renderer = entity->getData<CRenderMeshData>();
if (renderer != NULL && renderer->isSkinnedMesh())
{
CSkinnedMesh *mesh = NULL;

if (renderer->isSoftwareSkinning() == true)
mesh = dynamic_cast<CSkinnedMesh*>(renderer->getOriginalMesh());
else
mesh = dynamic_cast<CSkinnedMesh*>(renderer->getMesh());

if (mesh != NULL)
m_meshs.push_back(mesh);
}
}

void CJointAnimationSystem::init(CEntityManager *entityManager)
{

}

void CJointAnimationSystem::update(CEntityManager *entityManager)
{
CSkinnedMesh** meshs = m_meshs.pointer();
for (u32 i = 0, n = m_meshs.size(); i < n; i++)
{
CSkinnedMesh *skinnedMesh = meshs[i];

for (u32 j = 0, numJoint = skinnedMesh->Joints.size(); j < numJoint; j++)
{
CSkinnedMesh::SJoint& joint = skinnedMesh->Joints[j];

// skinMat = animMat * invMat * bindShapMat
// note:
// AbsoluteAnimationMatrix is a transform of bone at pos (0,0,0)
core::matrix4 mat;
mat.setbyproduct(joint.GlobalInversedMatrix, skinnedMesh->BindShapeMatrix);
joint.SkinningMatrix.setbyproduct(joint.JointData->AnimationMatrix, mat);
}
}
}
}
50 changes: 50 additions & 0 deletions Projects/Skylicht/Engine/Source/RenderMesh/CJointAnimationSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
!@
MIT License
Copyright (c) 2019 Skylicht Technology CO., LTD
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This file is part of the "Skylicht Engine".
https://github.com/skylicht-lab/skylicht-engine
!#
*/

#pragma once

#include "Entity/IEntitySystem.h"
#include "CRenderMeshData.h"

namespace Skylicht
{
class CJointAnimationSystem : public IEntitySystem
{
protected:
core::array<CSkinnedMesh*> m_meshs;

public:
CJointAnimationSystem();

virtual ~CJointAnimationSystem();

virtual void beginQuery();

virtual void onQuery(CEntityManager *entityManager, CEntity *entity);

virtual void init(CEntityManager *entityManager);

virtual void update(CEntityManager *entityManager);
};
}
29 changes: 21 additions & 8 deletions Projects/Skylicht/Engine/Source/RenderMesh/CRenderMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,13 @@ namespace Skylicht
{
CRenderMeshData *spawnRender = spawnEntity->addData<CRenderMeshData>();
spawnRender->setMesh(srcRender->getMesh());
spawnRender->setSkinnedMesh(srcRender->isSkinnedMesh());
spawnRender->setSoftwareSkinning(srcRender->isSoftwareSkinning());
if (spawnRender->isSoftwareSkinning() == true)

// init software skinning
if (spawnRender->isSkinnedMesh() && spawnRender->isSoftwareSkinning() == true)
spawnRender->initSoftwareSkinning();

renderers.push_back(spawnRender);
}

Expand Down Expand Up @@ -142,14 +145,24 @@ namespace Skylicht

// re-map joint with new entity in CEntityManager
for (CRenderMeshData *&r :renderers)
{
CSkinnedMesh *skinMesh = dynamic_cast<CSkinnedMesh*>(r->getMesh());
if (skinMesh != NULL)
{
if (r->isSkinnedMesh() == true)
{
for (u32 i = 0, n = skinMesh->Joints.size(); i < n; i++)
CSkinnedMesh *skinMesh = NULL;

if (r->isSoftwareSkinning() == true)
skinMesh = dynamic_cast<CSkinnedMesh*>(r->getOriginalMesh());
else
skinMesh = dynamic_cast<CSkinnedMesh*>(r->getMesh());

if (skinMesh != NULL)
{
CSkinnedMesh::SJoint& joint = skinMesh->Joints[i];
joint.EntityIndex = entityIndex[joint.EntityIndex];
for (u32 i = 0, n = skinMesh->Joints.size(); i < n; i++)
{
CSkinnedMesh::SJoint& joint = skinMesh->Joints[i];
joint.EntityIndex = entityIndex[joint.EntityIndex];
joint.JointData = entityManager->getEntity(joint.EntityIndex)->getData<CJointData>();
}
}
}
}
Expand Down
Loading

0 comments on commit 932791b

Please sign in to comment.