Advertisement

I making GPU Skinning(MD5 Format)

Started by August 28, 2018 11:17 AM
5 comments, last by xycsoscyx 6 years, 5 months ago

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....

Have you tried changing skinPos to a float4 instead of float3? There's some rules for alignment in cbuffers, cannot remember them - but you could see if that helps in any way?
I would multiply the three matrices on the CPU, and just pass the final matrix to the shader, saves you two muls per vertex!

 

.:vinterberg:.

Advertisement

Can you post a screenshot of what you mean be strange?  Strange as in all points have collapsed into the center, strange as in the arms are backwards, strange as in...?

Also, second on  vinterberg's suggestion to try float4 for the position, you might have some packing issues going on using float3 (I don't recall how arrays of float3 values get handled).

If youre passing a position and rotation per joint per frame (as opposed to using inverse bind matrix), youd normally center the bone head then rotate then translate. I dont see you do that and also I dont understand: 


2.0 * cross(rot.xyz,cross(rot.xyz,v) + rot.w * v) // huh is this a rotation based on identity position?

If every thing is set to identity first, then just rotate one joint or only translate one joint etc how does it look?

6 hours ago, xycsoscyx said:

Can you post a screenshot of what you mean be strange?  Strange as in all points have collapsed into the center, strange as in the arms are backwards, strange as in...?

Also, second on  vinterberg's suggestion to try float4 for the position, you might have some packing issues going on using float3 (I don't recall how arrays of float3 values get handled).

Ok. Here!

untitled_zpsv9koici1.png

Where does the parent come into play with any of this?  I see you storing it, but never actually using it to transform the child against the parents transformation, shouldn't each bone be relative to the parent?  That doesn't entirely explain the screenshot because it would typically leave everything imploded in the center, but it should still be used somewhere.

What document are you using for explaining the MD5 model and animation format?  http://tfc.duke.free.fr/coding/md5-specs-en.html?

This topic is closed to new replies.

Advertisement