Sunday, July 31, 2016

Confusion Of Exporting Model, Animation

Confusion Of Exporting Model, Animation

Hellow !

I 'm going to export models using the assimp sdk.  I will only export joint nodes and mesh nodes, and animation data.

The output format will look like this:

<JointNode>  lcltransform  .....

    <meshNode>  lcltransform....  <\meshNode>

<\JointNode>

 

But, assimp scene nodes are not just joint nodes and mesh nodes, and "pure node", which is used to pass transform, the root is the most apparent one.

I 'm confusing that  whether it will go wrong, if I don't export these nodes, because I'm afraid that some "pure nodes" would have a non-identity transform !!

 

In the animation part , I will use these code:

std::map<std::string, Joint*> name2Joint;

struct animation 

{
  void export() 
   {
     export(duration, tickPersecond);
     for(node in influenced nodes) 
     {
        jointID = name2Joint[node.name];
        export(jointID, frame.pos, frame.rot, frame.scale);
     }
    }  
};
 
 
My animation system is the one of the most naivest animation system in the world , it can only import, and display .
I have not begin to code, and I don't know if it will work, so
I will show my code,  and if someone find any mistake or have a better implementation, please tell. 
 
 
 
Here's are my data structure regarding animation in the engine side:
struct Frame 
{
   _pos, _rot, _scale; // all are  reference to parent
};
 
struct JointFrame 
{
  _jointID;                                        // will be used to find joint node at update time
  vector<Frame> _frames;
};
 
struct Animation 
{
  vector<JointFrame> _jointFrames;
  void update();
};
 
 
And here's the data structure of Model in engine side:
 
struct SceneNode 
  SceneNode  *_parent;
    pos, rot, scale;             // all are  reference to parent
  _globalTransform;
  virtual  void update();
  virtual   void postUpdate()=0;
};
 
struct Joint : public SceneNode 
{
  Matrix4f _invBindMat;  // inverse bind matrix
};
 
 
struct Model  : public SceneNode  
//why it inherit from SceneNode is that 
// it act as the root node of all joint nodes and model nodes,   somewhat look like  assimp root node
{
   vector<Mesh> _meshes;  
   vector<Joint*> _joints;
   vector<Matrix4f> _JointFinalMats
   void PostUpdate();       // use to update _JointFinalMats after all Joints' GlobalTransform have updated, will be called by Scene
};
 
struct Scene
{
  vector<SceneNode*> _nodes;
};
 

 

The flowchart of updates :

scene::update()

{

   animation.update();  // joint.lcltransform = ...

    foreach(node in _nodes) node.update();

    foreach(node in _nodes) node.postUpdate();

     

}

 

void Animation ::update() 
{
   for(jointFrame in   _jointFrames) 

   {

      frame = jointFrame.findFrame(gametime);

      joint =   this->parentModel.findJoint(jointFrame._jointID);

 

      // all are reference to parent

      joint->setPos(frame._pos);

      joint->setRot(frame._rot); 

      joint->setScale(frame._scale);  

   }

}

 

void SceneNode::update() 
{
   _globalTransform = localTransform(_pos, _rot, _scale)  *    _parent->_globalTransform ;

}

 

void Model::postUpdate() 
{

   
    foreach(joint in _joints) 

    {

       _JointFinalMats[joint.ID] =  joint._invBindMat * joint._globalTransform;

   }
}

 

 

After I have attached joints to scene graph,  and Scene::update will call joint::update, where  jointFinalMat = inverseBindposeMat *  jointGlobalTransform

will take place. Since the jointGlobalTransform has contain  ToRootMat,  I will pass a identity matrix to shader as a world matrix.

The code will look like :

if(mesh.hasBone) 
{

    worldMat = Identity;

else 
{
  worldMat =  mesh.globalTransfom

 

the shader code:

cbuffer cbPerObject : register(b0)
{
row_major float4x4 worldMat;
row_major float4x4 worldInvTransposeMat;
row_major float4x4 worldviewprojMat;
};
 
cbuffer cbSkinned : register(b1)
{
row_major float4x4 boneMat[96];
};

 

 
struct SkinnedVertexIn
{
float3 PosL       : POSITION;
float3 NormalL    : NORMAL;
float3 TangentL   : TANGENT;
float2 Tex        : TEXCOORD;
uint4 BoneIndices : BONEINDICES;
float4 Weights    : WEIGHTS;
};

 

 
VertexOut vsmain(SkinnedVertexIn vin)
{
VertexOut vout;
float weights[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
weights[0] = vin.Weights.x;
weights[1] = vin.Weights.y;
weights[2] = vin.Weights.z;
weights[3] = 1.0f - weights[0] - weights[1] - weights[2];
 
float3 posL = float3(0.0f, 0.0f, 0.0f);
float3 normalL = float3(0.0f, 0.0f, 0.0f);
float3 tangentL = float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < 4; ++i)
{
posL += weights[i] * mul(float4(vin.PosL, 1.0f), boneMat[vin.BoneIndices[i]]).xyz;
normalL += weights[i] * mul(vin.NormalL, (float3x3)boneMat[vin.BoneIndices[i]]);
tangentL += weights[i] * mul(vin.TangentL.xyz, (float3x3)boneMat[vin.BoneIndices[i]]);
}
 
vout.PosW = mul(float4(posL, 1.0f), worldMat).xyz;
vout.NormalW = mul(normalL, (float3x3) worldInvTransposeMat);
vout.TangentW = mul(tangentL, (float3x3)worldMat);
vout.PosH = mul(float4(posL, 1.0f), worldviewprojMat);
vout.Tex = vin.Tex;
return vout;
}

No comments:

Post a Comment