Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Taulin

Skinned Mesh SDK example outlined

This topic is 6025 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

It was time for me to learn that dang example. So, while going through the example, I decided to make notes as I went along, and here they are. I hope they look OK on the web page. Anyway, say what you wish, fix what you like, comment about it if you must. This is just my first draft I finished not more than 10 minutes ago, so try not to complain too loudly. EDIT - It looks like my unicode notepad messed some things up. I will post another version later if anyone wants it.
    
LoadMeshHierarchy
	This is where it all begins.

1)	Make sure we have a file name.
2)	Create a new DrawElement
3)	Delete the DrawElement¡¯s frameRoot, and create a new Sframe for it.
4)	Set the DrawElement¡¯s frameAnimHead to NULL.
5)	Create a DirectXFile with DirectXFileCreate()
6)	Register the templates.
7)	Create an enum object with our filename using the DirectXFile we just made.
8)	Start looping through the enumerated DirectXFile Data objects
	(a)	Calling  LoadFrames we will give it a pointer to the Sframe we created in step 3, and the current file data.
9)	Now that all of the data is loaded in, we need to call FindBones giving it our frameRoot Sframe and the DrawElement itself. 
10)	Set the DrawElement¡¯s name to the file name we just loaded everything from.
11)	Call DeleteSelectedMesh. Deletes the Applications¡¯s selected DrawElement.
12)	Change DrawElements¡¯s Next to the same value as Application¡¯s Head.  This is because we may have more than one DrawElement.  At the beginning, Head should be NULL.
13)	Make the Application¡¯s Head point to our new DrawElement.  We now just put the DrawElement into the Application¡¯s DrawElement linked list.
14)	 Make the Application¡¯s Selected point to the new DrawElement.
15)	 Make the Application¡¯s selected mesh point to the new DrawElement¡¯s FrameRoot¡¯s mesh.
16)	Make the Application¡¯s selected Frame point to the DrawElement¡¯s frameRoot.
17)	Calculate the BoundingSphere for the DrawElement by calling CalculateBoundingSphere giving it the DrawElement.
18)	Call SetProjectionMatrix  The usual calculations, but set the vertex shader constant also.

-----------------------------------------------------
Load Frames
   Called by - LoadMeshHierarchy
   Given ¨C Data, Sframe(parent)

1)	Get the type of Data
2)	Determined by what type the data is do something else..
	(a)	TID_D3DRMMesh  - Call LoadMesh
	(b)	TID_D3DRMFrameTransformMatrix ¨C Get the data and use it as the Frame¡¯s matRot and matRotOrig
	(c)	TID_D3DRMAnimationSet ¨C Call LoadAnimationSet
	(d)	TID_D3DRMAnimation ¨C Call LoadAnimation
	(e)	TID_D3DRMFrame
		¢ىCreate a new Sframe- tempFrame
		¢ډSet tempFrame¡¯s name from the data
		¢ۉAdd tempFrame to the handed in parent frame.  This will put it in the parent¡¯s children linked list.  (It will become the parent¡¯s child¡¯s sibling)
		¢܉Start iterating through the Data¡¯s data.  For each data, call LoadFrames giving it the new data, and the new tempFrame.
3)	sdf
	
------------------------------------------------------
LoadMesh
   Called by - LoadFrames
  Given ¨C Data, Sframe that will hold the data

	Since this is dealing with loading a mesh (before calling this function, it was determined that the Data is indeed holding Mesh data), this function deals with creating a new MeshContainer, filling it in with the data given to up from Data, then adding it to the Sframe that was also handed it.

1)	Create a MeshContainer
2)	Set MeshContainer¡¯s name from Data
3)	Get the mesh data from Data.  
	(a)	Put Adjacency and materials in temp storage
	(b)	Put number of Materials, BoneNames, BoneOffsetBuffers and the skin mesh into our new MeshContainer we just made.
	(c)	Cast the Adjacency data into LPDWORD and also put it in our MeshContainer by malocing a new array and memcpy¡¯ing it in.
4)	We now need to fill in our MeshContainers pMesh¡­

5)	If the Mesh has bones:
	(a)	In our MeshContainer, malloc enough space for the number of bones in the buffer.
	(b)	Cast the data in the BoneOffsetBuf as an array of matrices and put them in the MeshContainers¡¯s BoneOffsetMat.
	(c)	Call GenerateMesh giving it our MeshContainer.  
6)	If the Mesh does not have bones:
	(a)	This Mesh does not have animations, so just copy the data from the skinned mesh into our pMesh by calling the SkinnedMesh¡¯s GetOriginalMesh.

7)	Now we must handle the materials and textures¡­
8)	If we do not have any materials and textures
	(a)	Set the MeshContainer¡¯s material and texture array to 1.
	(b)	Make a default Material, and set the texture to NULL.
9)	If we do have some materials and textures¡­
	(a)	Create the texture and material arrays based on how many materials (cMaterials) we have.
	(b)	Get a pointer to the array of materials and loop through them.
	(c)	For each material, copy its D3Dmat data into our MeshContainers material array.
	(d)	If the material also has a texture name, load up the texture and place it at the same index as the material.
10)	Finally, add this new MeshContainer to the Sframe (parent) that was handed in.

------------------------------------------------------
Generate Mesh
   Called by ¨C LoadFrames()
   Given : A Mesh Container.  This MeshContainer should already have its SkinnedMesh member filled in, and it has bones.

	We know the Skinned mesh in our Mesh Container has bones, so we just generate the pMesh.   The mesh is created by using ConvertToIndexedBlendedMesh, but then the new mesh¡¯s FVF is tested to determine face influence, and reconstructed if it needs to have a different FVF.

1)	D3DINDEXEDVS drawing mode
	(a)	Get the palette size (max 28)
	(b)	Create the pMesh by using ConvertToIndexedBlendedMesh.  This will create a mesh that can be rendered with one call.
	(c)	If the new mesh¡¯s FVF¡¯s PositionMask is D3DFVF_XYZ, it can only have a face influence of 1, other wise ????
	(d)	If the new mesh¡¯s FVF is not the same as the one we want to use, call CloneMesh (which creates a new mesh based upon a desired FVF) and then set pMesh to the new one just created.


------------------------------------------------------
Load Animation Set
   Called by ¨C LoadFrames()

1)	Make a new tempFrame Sframe.
2)	Add the new tempFrame to the Parent frame passed in.
3)	Set its bAnimationFrame flag to true.
4)	Set its name from the Data
5)	Enumerate through the Data¡¯s children Data
	(a)	Get the new data type and make sure it is TID_D3DRMAnimation.
	(b)	Call LoadAnimation giving it the new Data and the new tempFrame

------------------------------------------------------
Load Animation
   Called by ¨C LoadFrames(), LoadAnimationSet()

1)	Make a new tempFrame Sframe
2)	Add the new tempFrame to the Parent frame passed in
3)	Set its bAnimation flag to true.
4)	Add this frame to the master DrawElements Animation linked list (made way back in LoadMeshHierarchy and passed down through the ages)
5)	Enumerate through the Data¡¯s data
	(a)	If the new data can be queried as a IID_IdirectXFileDataReference then¡­
		¢ىMake Sure data type is TID_D3DRMFrame
		¢ډMake sure our tempFrame does not have a pFrameToAnimate already
		¢ۉGet the name of this new data node.
		¢܉Using this name, get a pointer the frame with the same name from the DrawElement using the DrawElement¡¯s FindFrame(name) function.
		¢݉Set our new tempFrame¡¯s pFrameToAnimate pointer to the frame just found from the DrawElement.
	(b)	Else if it is not a DataReference then it is a IID_IDirectXFileData
		¢ىGet the Data type
			1.	TID_D3DRMFrame ¨C Call LoadFrame giving it this data and the new tempFrame as a parent
			2.	TID_D3DRMAnimationOptions ¨C Do nothing
			3.	TID_D3DRMAnimationKey
	(c)	Get the data in this data as a void pointer
	(d)	Get the type from index 0
	(e)	Get the Keys from index 1
	(f)	KeyType 0 ¨C Rotate Key
	(g)	KeyType 1 ¨C Scale
	(h)	KeyType 2 ¨C Position
	(i)	KeyType 4 - Matrix

------------------------------------------------------
DeleteSelectedMesh
   Called by ¨C LoadMeshHierarchy()
	Delete the DrawElement that the Application is pointing to via the m_pdeSelected member.

------------------------------------------------------
FindBones
   Called by ¨C LoadMeshHiearchy()
1)	Starting with the MeshContainer of our RootFrame..
	(a)	If it has a SkinnedMesh¡­
		¢ىGet a list of Bone Names from the MeshContainers¡¯s BoneNamesBuffer
		¢ډFor each of those names, find the Frame in our DrawElement via its FindFrame(name) method
		¢ۉIn our current MeshContainer, at the same index as the current bone name, set the bone matrix equal to the found frame¡¯s combined matrix.
	(b)	Go on to the next MeshContainer in this list.
2)	Call FindBones on the currently handed in¡¯s Children and its siblings.

------------------------------------------------------
FrameMove
   Called by - ???????
1)	Loop through all the Application¡¯s DrawElements (pdeHead)
	(a)	Set the current DrawElements current time by adding the Elapsed time
	(b)	Get the DrawElement¡¯s first animated frame through its AnimHead pointer.
	(c)	Call the Fram¡¯s SetTime() and give it the DrawElement¡¯s current time.

------------------------------------------------------
Frame::SetTime()
   Called by ¨C FrameMove

1)	If this Frame has MatrixKeys..
	(a)	Figure out which keys are start and finish currently..
		¢ىMod the last frame¡¯s time by the current global time.  This will give you a value in the range of 0 and the last frame¡¯s time.
		¢ډWith this value, loop through the keys until  you find one that has a time greater than it.  This is the destination key frame.  The start keyframe is the one with an index 1 less.
		¢ۉIf the mod¡¯ed time is 0, both key frames are the first frame.
	(b)	Cast both key times to floats
	(c)	Determin LerpValue.  This is the percent that the current time is at between the start and end key frame.  
	(d)	If the LerpValue is greater than .5, then set the pFrameToAnimate¡¯s rot to the end frame, else set it to the start frame.
2)	Else if it does not have Matrix keys
	(e)	This section uses a master Result matrix.
	(f)	If it has ScaleKeys
		¢ىCalculate lerp from the scale keys. (See above Matrix keys)
		¢ډCall D3DXVec3Lerp getting a scaled scale.
		¢ۉCreate a temp Scaling matrix from the lerped scale.
		¢܉Multiply the Result matrix by this scaling matrix
	(g)	If it has RotationKeys
		¢ىCalculate lerp from the rotation keys. (See above Matrix keys)
		¢ډConstruct a spline curve using four quads from :
			1.	The two current start and stop frame rotation keys
			2.	The key before the start (loop to back if 0)
			3.	The key after the end (loop to front if end)
		¢ۉBy lerping this curve, a smooth final point can be calculated.
		¢܉Multiply the Result matrix by this scaling matrix.
	(h)	If it has Position Keys
		¢ىCalculate the lerp from the position keys. (See above Matrix keys)
		¢ډCreate a vector lerped between the two positions
		¢ۉCreate a matrix based on this new position
		¢܉Multiply the Result matrix by this position matrix.
3)	If this Frame is an bAnimateFrame, then set its Rot to the Result Matrix

------------------------------------------------------
Render
   Called by - ???????

1)	Go through each of the DrawElements, and set their root frames Rot and matTrans to the same as the current ArcBall (camera view)
2)	Clear the view port
3)	Begin Scene
4)	Make a translation matrix equal to the neg. radius of the selected DrawElement
5)	Set the Device View based upon this matrix.
6)	Loop through all of the DrawElements
	(a)	Call UpdateFrames giving it the current DrawElement¡¯s root frame, and the DrawElement itself.
	(b)	Call DrawFrames giving it the current DrawElement¡¯s root frame, and the the DrawElement itself.
7)	Draw the text on the screen.
8)	End Scene

------------------------------------------------------
UpdateFrames
	Called by ¨C Render()

1)	Start off by making the current Frame¡¯s matCombined equal to its current matrix.
2)	Concat onto combined the frame¡¯s rotation matrix.
3)	Concat onto combined the frame¡¯s translation matrix.
4)	Get the Child of the current Frame
5)	Loop through that child and its siblings
	(a)	For each of its childing, call UpdateFrames giving it the current child frame, and the combined matrix

------------------------------------------------------
Draw Frames
   Called by ¨C Render()

1)	If the handed in Frame is not NULL, set the World matrix to this current frame¡¯s combined matrix
2)	Loop Through the current Frame¡¯s meshes
	(a)	Call DrawMeshContainer giving it the current mesh.
	(b)	Keep a count of the total number of triangles drawn.
3)	Loop through this frame¡¯s children
	(c)	For each child call DrawFrames giving it the current child and total triangles drawn so far variable.

------------------------------------------------------
DrawMeshContainer
   Called by ¨C DrawFrames

	To do anything, the handed in MeshContainer must have a SkinnedMesh
1)	If the MeshContainer¡¯s draw method is not the same as the applications method, then call GenerateMesh giving it the current MeshContainer.
2)	D3DNONINDEXED
3)	D3DINDEXEDVS
	(a)	Set up a D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );  This will be used as an attenuation calculation later.
	(b)	If the current MeshContainer has its Software render flag set, then set the renderstate D3DRS_SOFTWAREVERTEXPROCESSING to true
	(c)	Get a reference to the vertex and index buffer of the MeshContainer.
	(d)	Set the StreamSource to the VertexBuffer on the Device
	(e)	Set the Indices on the Device
	(f)	Call Release on the VB and IB
	(g)	Using the MaxFaceInfluence (calculated earlier), use it as an index into the VertexShader array.  This is the vertex shader that will be set on the device.  
	(h)	Reinterpret cast the MeshContainers¡¯s BoneCombinationBuf to an array.
	(i)	Loop through all of the bone combinations (0 ¨C cpattr)
		¢ىLoop through all of the bone ids (palletsize)
			1.	Get the matrix id using those two indexes into the BoneCombinationBuf array.
			2.	Multiply the BoneOffsetMatrix and BoneMatrix using that id.
			3.	MultiplyTranspose this matrix with the current view matrix.
			4.	Set shader constant i*3 + 9 with this matrix
		¢ډGet the Attrib ID of the current BoneComb. 
		¢ۉUse this id to get the Ambient from the mesh¡¯s materials.
		¢܉Modulate this color with D3DXCOLOR(.25, .25, .25, 1.0)
		¢݉Get the Emissive attribute of the same material, and add it to a total emissive sum
		¢މGet the Diffuse attribute of the same material and set Vertex Shader constant 8.
		¢߉Set the Vertex Shader constant 7 with the total emissive value so far.
		¢ɓet the same materials Power to the Y element of the vector4 from above.
		¢ቕse the Vector4 as Vertex Shader contant 0
		¢≃all DrawIndexedPrimitive.
			1.	BoneComb is used to retrieve all information using the current cpattr index.
	(j)	If it was using SoftwareRendering, then set the renderstate back to false.
4)	D3DINDEXED
5)	SOFTWARE
    
[edited by - taulin on April 18, 2002 4:14:11 AM]

Share this post


Link to post
Share on other sites
Advertisement

If you could post another version thats not messed up with "¡¯s" that would be great

Share this post


Link to post
Share on other sites
I fixed it up the best I could, uploaded the new version to this page, but it's got a couple words eaten by the trash at the end. Still ... it's MUCH easier to read.

[edited by - Zaphos on April 18, 2002 9:20:46 PM]

[edited by - Zaphos on April 18, 2002 9:21:26 PM]

Share this post


Link to post
Share on other sites
Great, thanks!

I would like to add a note to this thread on how he implemented animation frames.

The Keys come in 4 flavors.
Matrix type is of course the concatination of the scale, rotation and translation together (type 4).
If the Matrix type is not used, the animation frame generatlly is made up of a combination of Scale(0), Rotation(1) and Translation(2) keys. You can see them get loaded in LoadAnimation().

During animation, actual animation (SetTime), different things occur depending on the key type for that frame.

If the keys are or type Scale, Rotation and Translation, then real lerping is occuring. Knowing the start and end frame, an actual@value somewhere in between is calculated.

However, if matrix keys are used, like the tiny.x model has, then his code does not calculate an intermediate frame, but rather just chooses the start or end matrix key, with a condition of being .5 in between the two keys, time wise.

It is real easy to use the DX matrix rappers to get an intermediate matrix, but I am not sure if the animation will be too correct. So, if you use this code, and your x file has only matrix type keys, then you will only get an animation fps cap equal to the number of key frames you put into the mode.

[edited by - taulin on April 19, 2002 3:05:15 AM]

EDIT - Changed the Key IDs

[edited by - taulin on April 19, 2002 3:05:54 AM]

Share this post


Link to post
Share on other sites
One small correction with Taulin''s post... The key types should be->
Rotation = 0
Scale = 1
Position = 2
Matrix = 4
( I made a skinned mesh exporter for TrueSpace so I''m sure this is right )

Share this post


Link to post
Share on other sites
Argh, yes indeed. I have in right in the outlined, but messed up in that last post. Thanks for pointing that out!

Share this post


Link to post
Share on other sites
I will be interested in version without "¡¯s" too, btw nice work

fix: Sorry, I didn't read Zaphos post

[edited by - Lemmy on April 19, 2002 4:57:00 AM]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!