Hello!
I made Skinning Function.
But that is CPU Skinning.(When I skin high polygon model, very slow)
So, I'm making GPU Skinning.
But My Program draw model strange!
Here' s my code!
This is Initalize Code
...//meshes,numjoints..etc
else if (checkString == "joints")
{
Joint tempJoint;
fileIn >> checkString; // Skip the "{"
for (int i = 0; i < MD5Model.numJoints; i++)
{
fileIn >> tempJoint.name;
if (tempJoint.name[tempJoint.name.size() - 1] != '"')
{
wchar_t checkChar;
bool jointNameFound = false;
while (!jointNameFound)
{
checkChar = fileIn.get();
if (checkChar == '"')
jointNameFound = true;
tempJoint.name += checkChar;
}
}
fileIn >> tempJoint.parentID; // Store Parent joint's ID
fileIn >> checkString; // Skip the "("
fileIn >> tempJoint.pos.x >> tempJoint.pos.z >> tempJoint.pos.y;
fileIn >> checkString >> checkString; // Skip the ")" and "("
// Store orientation of this joint
fileIn >> tempJoint.orientation.x >> tempJoint.orientation.z >> tempJoint.orientation.y;
tempJoint.name.erase(0, 1);
tempJoint.name.erase(tempJoint.name.size() - 1, 1);
float t = 1.0f - (tempJoint.orientation.x * tempJoint.orientation.x)
- (tempJoint.orientation.y * tempJoint.orientation.y)
- (tempJoint.orientation.z * tempJoint.orientation.z);
if (t < 0.0f)
{
tempJoint.orientation.w = 0.0f;
}
else
{
tempJoint.orientation.w = -sqrtf(t);
}
//ADDITION HERE!
XMVECTOR quat = XMVectorSet(tempJoint.orientation.x, tempJoint.orientation.y, tempJoint.orientation.z, tempJoint.orientation.w);
//const XMMATRIX rotation = XMMatrixRotationQuaternion(quat);
MD5Model.invbindrots.resize(MD5Model.numJoints);
MD5Model.invbindpos.resize(MD5Model.numJoints);
XMStoreFloat4(&MD5Model.invbindrots[i], XMQuaternionInverse(quat));
MD5Model.invbindpos[i] = { -tempJoint.pos.x,-tempJoint.pos.y,-tempJoint.pos.z };
//ENDADDITION
std::getline(fileIn, checkString); // Skip rest of this line
MD5Model.joints.push_back(tempJoint); // Store the joint into this models joint vector
}
//calc indices...tris..weights..etc
//And this code is calculate bone index and weights!
for (int i = 0; i < subset.vertices.size(); i++)
{
VertexStruct_SkinGPU& vert = subset.vertices[i];
vert.boneIdx[0] = 0;
vert.boneIdx[1] = 0;
vert.boneIdx[2] = 0;
vert.boneIdx[3] = 0;
for (int j = 0; j < vert.WeightCount; j++)
{
if (j >= 4)
break;
Weight& weight = subset.weights[vert.StartWeight + j];
vert.boneIdx[j] = weight.jointID;
vert.weight.x = weight.bias;
vert.weight.y = weight.bias;
vert.weight.z = weight.bias;
}
}
And this code is update code.
void Mesh_Skinned::UpdateMD5ModelGPU(Model3DGPU & MD5Model, float deltaTime, int animation)
{
MD5Model.animations[animation].currAnimTime += deltaTime; // Update the current animation time
if (MD5Model.animations[animation].currAnimTime > MD5Model.animations[animation].totalAnimTime)
MD5Model.animations[animation].currAnimTime = 0.0f;
// Which frame are we on
float currentFrame = MD5Model.animations[animation].currAnimTime * MD5Model.animations[animation].frameRate;
int frame0 = floorf(currentFrame);
int frame1 = frame0 + 1;
// Make sure we don't go over the number of frames
if (frame0 == MD5Model.animations[animation].numFrames - 1)
frame1 = 0;
float interpolation = currentFrame - frame0; // Get the remainder (in time) between frame0 and frame1 to use as interpolation factor
//std::vector<XMMATRIX> interpolatedSkeleton; // Create a frame skeleton to store the interpolated skeletons in
//interpolatedSkeleton.resize(MD5Model.animations[animation].numJoints);
// Compute the interpolated skeleton
std::vector<XMFLOAT3> animated_pos_arr;
std::vector<XMFLOAT4> animated_rot_arr;
std::vector<XMFLOAT3> skinned_pos_arr_;
std::vector<XMFLOAT4> skinned_rot_arr_;
for (int i = 0; i < MD5Model.animations[animation].numJoints; i++)
{
Joint tempJoint;
Joint joint0 = MD5Model.animations[animation].frameSkeleton[frame0][i]; // Get the i'th joint of frame0's skeleton
Joint joint1 = MD5Model.animations[animation].frameSkeleton[frame1][i]; // Get the i'th joint of frame1's skeleton
tempJoint.parentID = joint0.parentID; // Set the tempJoints parent id
// Turn the two quaternions into XMVECTORs for easy computations
XMVECTOR joint0Orient = XMVectorSet(joint0.orientation.x, joint0.orientation.y, joint0.orientation.z, joint0.orientation.w);
XMVECTOR joint1Orient = XMVectorSet(joint1.orientation.x, joint1.orientation.y, joint1.orientation.z, joint1.orientation.w);
// Interpolate positions
tempJoint.pos.x = joint0.pos.x + (interpolation * (joint1.pos.x - joint0.pos.x));
tempJoint.pos.y = joint0.pos.y + (interpolation * (joint1.pos.y - joint0.pos.y));
tempJoint.pos.z = joint0.pos.z + (interpolation * (joint1.pos.z - joint0.pos.z));
// Interpolate orientations using spherical interpolation (Slerp)
XMStoreFloat4(&tempJoint.orientation, XMQuaternionSlerp(joint0Orient, joint1Orient, interpolation));
animated_pos_arr.push_back(tempJoint.pos);
animated_rot_arr.push_back(tempJoint.orientation);
XMVECTOR arotarr = XMVectorSet(animated_rot_arr[i].x, animated_rot_arr[i].y, animated_rot_arr[i].z, animated_rot_arr[i].w);
XMVECTOR bindrot = XMVectorSet(MD5Model.invbindrots[i].x, MD5Model.invbindrots[i].y, MD5Model.invbindrots[i].z, MD5Model.invbindrots[i].w);
XMFLOAT4 rot;
XMVECTOR quat = XMQuaternionMultiply(arotarr, bindrot);
XMStoreFloat4(&rot, quat);
skinned_rot_arr_.push_back(rot);
XMVECTOR bindpos = XMVectorSet(MD5Model.invbindpos[i].x, MD5Model.invbindpos[i].y, MD5Model.invbindpos[i].z, 0);
XMVECTOR mul = XMVectorMultiply(quat, bindpos);
XMVECTOR aposarr = XMVectorSet(animated_pos_arr[i].x, animated_pos_arr[i].y, animated_pos_arr[i].z, 0);
XMVECTOR plus = aposarr + mul;
XMFLOAT3 newpos;
XMStoreFloat3(&newpos, plus);
skinned_pos_arr_.push_back(newpos);
}
MD5Model.skinned_pos_arr = skinned_pos_arr_;
MD5Model.skinned_rot_arr = skinned_rot_arr_;
}
And This is Shader(HLSL)
///////////////////////////////////////////////
//
// Skin Texture_Color Shader
// Desc: Skin Texture + Vertex Color
//
///////////////////////////////////////////////
/////////////
// Globals //
/////////////
cbuffer MatrixBuffer
{
matrix worldMat;
matrix viewMat;
matrix projMat;
float3 skinPos[128];
float4 skinRot[128];
};
//////////////
// TypeDefs //
//////////////
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float4 color : COLOR;
uint4 boneIdx : BONEID;
float4 weight : WEIGHT;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float4 color : COLOR;
};
float3 trans_for_f(float3 v, float3 pos, float4 rot)
{
return v + 2.0 * cross(rot.xyz,cross(rot.xyz,v) + rot.w * v) + pos;
}
PixelInputType SkinTextureColorVertexShader(VertexInputType input)
{
int id0 = int(input.boneIdx.x);
int id1 = int(input.boneIdx.y);
int id2 = int(input.boneIdx.z);
int id3 = int(input.boneIdx.w);
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
float3 result = trans_for_f(input.position, skinPos[id0], skinRot[id0]) * input.weight.x;
result += trans_for_f(input.position, skinPos[id1], skinRot[id1]) * input.weight.y;
result += trans_for_f(input.position, skinPos[id2], skinRot[id2]) * input.weight.z;
result += trans_for_f(input.position, skinPos[id3], skinRot[id3]) * input.weight.w;
//output.position = mul(inputpos, boneTransform);
// Calculate the position of the vertex against the world, view, and projection matrices.
float4 finalresult;
finalresult.x = result.x;
finalresult.y = result.y;
finalresult.z = result.z;
finalresult.w = 1.0f;
output.position = mul(finalresult, worldMat);
output.position = mul(output.position, viewMat);
output.position = mul(output.position, projMat);
// Store the input color for the pixel shader to use.
output.color = input.color;
// Store the texture coordinates for the pixel shader.
output.tex = input.tex;
return output;
}
Thanks! and sorry for bad english skills....