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