HW Skinning attempt is moving entrie mesh???

Started by
1 comment, last by chippolot 17 years, 9 months ago
Wow, I'm really lost. I'm just trying to get hardware skinning working right and am having huge problems. I finally got my mesh rendering on the screen, but it is moving as a whole (like I am rotating the whole thing smoothly) as opposed to playing the walk animation as intended. I can change the animation set and the mesh rotates in a different way, so I think that's working. I'm doing hardware palette skinning and it seems like maybe the indices are not being generated correctly? I'll paste my source for generating the mesh container and also my skinning effect::

HRESULT MeshAllocateHierarchy::CreateMeshContainer(THIS_ LPCSTR Name, CONST D3DXMESHDATA *pMeshData,
												   CONST D3DXMATERIAL * /*pMaterials*/, CONST D3DXEFFECTINSTANCE * /*pEffectInstances*/,
												   DWORD /*NumMaterials*/, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo,
												   LPD3DXMESHCONTAINER *ppNewMeshContainer)
///////////////////////////////////////////////////////////////////////////////
// Description: Function telling DirectX how to allocate memory for a mesh
// container.
// Author: bsmith
///////////////////////////////////////////////////////////////////////////////
{
	assert(mesh_);

	HRESULT hr = S_OK;

	//Set reference pointer to null
	*ppNewMeshContainer = NULL;

	//Only interested in meshes
	if (pMeshData->Type != D3DXMESHTYPE_MESH)
		return E_FAIL;

	//Create a new container
	MeshContainer* container = new MeshContainer();
	ZeroMemory(container, sizeof(*container));

	//Copy name
	if (Name) {
		size_t nameLen = strlen(Name) + 1;
		container->Name = new char[nameLen];
		memcpy(container->Name, Name, sizeof(char) * nameLen);
	}
	else
		container->Name = NULL;

	//Only interested in skinned meshes
	if (!pSkinInfo) {
		*ppNewMeshContainer = container;
		container = NULL;
		return S_OK;
	}

	//Set mesh type and copy mesh over
	container->MeshData.Type = pMeshData->Type;
	container->MeshData.pMesh = pMeshData->pMesh;
	container->MeshData.pMesh->AddRef();

	//Grab the number of faces for adjacency
	DWORD numAdj = pMeshData->pMesh->GetNumFaces()*3u; 
	container->pAdjacency = new DWORD[numAdj];
	memcpy(container->pAdjacency, pAdjacency, sizeof(DWORD)*numAdj);

	//Copy skin information
	container->pSkinInfo = pSkinInfo;
	pSkinInfo->AddRef();

	//New bone offset array and set
	DWORD numBones = pSkinInfo->GetNumBones();
	container->boneOffsets_ = new D3DXMATRIX[numBones];
	for (uint32_t i=0; i < numBones; ++i)
		container->boneOffsets_ = *(container->pSkinInfo->GetBoneOffsetMatrix(i));

	//Find the palette size that we'll be using
	container->paletteEntries_ = numBones;

	//Convert to indexed blended mesh for paletted skinning
	hr = container->pSkinInfo->ConvertToIndexedBlendedMesh(container->MeshData.pMesh, 
		D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE,
		container->paletteEntries_, container->pAdjacency,
		NULL, NULL, NULL, reinterpret_cast<DWORD*>(&container->maxInfluences_),
		reinterpret_cast<DWORD*>(&container->numBoneCombos_), &container->bufferBoneCombos_,
		&container->skinMesh_);
	if (FAILED(hr)) {
		DestroyMeshContainer(container);
		return E_FAIL;
	}

	//Make sure our bone array is large enough to hold the max amount of bones!
	//Reallocate is necessary
	if (mesh_->paletteSize_ < container->paletteEntries_) {
		if (mesh_->palette_)
			delete[] mesh_->palette_;
		mesh_->paletteSize_ = container->paletteEntries_;
		mesh_->palette_ = new D3DXMATRIX[mesh_->paletteSize_];
	}

	//Ensure the proper format for our mesh vertices!
	DWORD oldFVF = container->skinMesh_->GetFVF();
	DWORD newFVF = (oldFVF & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4;
	LPDIRECT3DDEVICE9 pDevice = NULL;
	if (FAILED(container->skinMesh_->GetDevice(&pDevice))) {
		DestroyMeshContainer(container);
		return E_FAIL;
	} 
	if (oldFVF != newFVF) {
		LPD3DXMESH newMesh = NULL;
		if (FAILED(container->skinMesh_->CloneMeshFVF(container->skinMesh_->GetOptions(), newFVF, 
			pDevice, &newMesh))) {
				DestroyMeshContainer(container);
				return E_FAIL;
		}
		container->skinMesh_->Release();
		container->skinMesh_ = newMesh;

		//Compute normals if we need to
		if (!(oldFVF & D3DFVF_NORMAL)) {
			if (FAILED(D3DXComputeNormals(container->skinMesh_, NULL))) {
				DestroyMeshContainer(container);
				return E_FAIL;
			}
		}
	}

	//Apparently (according to the d3d skinning sample), some cards cannot interperet
	//UBYTE4 decl types.  Use D3DCOLOR instead and simply convert it in the shader.
	D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
	D3DVERTEXELEMENT9 *currDecl = NULL;
	if (FAILED(container->skinMesh_->GetDeclaration(decl))) {
		DestroyMeshContainer(container);
		return E_FAIL;
	}

	//Find the offending type and convert!
	currDecl = decl;
	while (currDecl->Stream !=  0xff) {
		if (currDecl->Usage == D3DDECLUSAGE_BLENDINDICES && currDecl->UsageIndex == 0)
			currDecl->Type = D3DDECLTYPE_D3DCOLOR;
		currDecl++;
	}

	//Update Mesh with new declaration
	if (FAILED(container->skinMesh_->UpdateSemantics(decl))) {
		DestroyMeshContainer(container);
		return E_FAIL;
	}

	//Set return pointer
	*ppNewMeshContainer = container;
	container = NULL;

	return hr;
}


and the effect:

//--------------------------------------------------------------------
// Skinned Mesh Effect with per pixel specular
// Author: Ben Smith
// Date  : November 30th, 2005
//--------------------------------------------------------------------

#include "StdFunctions.fx"

//--------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------
#ifndef MATRIX_PALETTE_SIZE
#define MATRIX_PALETTE_SIZE 35
#endif

float	 NumInfluences;
float4x3 BonePalette[MATRIX_PALETTE_SIZE];
float4x4 World : WORLD;

struct VS_IN
{
	float4 Pos : POSITION;
	float3 BlendWeights : BLENDWEIGHT;
	float4 BlendIndices : BLENDINDICES;
	float3 Normal : NORMAL;
	float3 TexCoord : TEXCOORD0;
};

struct VS_OUT
{
	float4 Pos : POSITION;
	float2 TexCoord : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float4 MPos : TEXCOORD2;
};

struct SKIN_OUT
{
	float4 Pos;
	float3 Normal;
};

SKIN_OUT Skin(float4 Pos, float3 BlendWeights, float4 BlendIndices, float3 Normal, int NumInfluences)
{
	SKIN_OUT Output = (SKIN_OUT)0;
	
	float LastWeight = 1.0f;
	float Weight;
	float BWArray[3] = (float[3])BlendWeights;
	int BIArray[4] =  (int[4])D3DCOLORtoUBYTE4(BlendIndices);
	for (int boneIndex = 0; (boneIndex < 3) && (boneIndex < NumInfluences-1); ++boneIndex)
	{
		Weight = BlendWeights[boneIndex];
		LastWeight -= Weight;
		Output.Pos.xyz += mul(Pos, BonePalette[BlendIndices[boneIndex]])*Weight;
		Output.Normal += mul(Normal, BonePalette[BlendIndices[boneIndex]])*Weight;
	}
	Output.Pos.xyz += mul(Pos, BonePalette[BlendIndices[NumInfluences-1]])*LastWeight;
	Output.Normal += mul(Normal, BonePalette[BlendIndices[NumInfluences-1]])*LastWeight;
	
	return Output;
}

VS_OUT VSSkin(VS_IN Input, uniform int NumInfluences)
{
	VS_OUT Output = (VS_OUT)0;
	
	SKIN_OUT SkinOut = Skin(Input.Pos, Input.BlendWeights, Input.BlendIndices, Input.Normal, NumInfluences); 
	
	Output.Pos = mul(float4(SkinOut.Pos.xyz, 1.0f), ViewProjection);
	Output.Normal = normalize(SkinOut.Normal);
	Output.TexCoord = Input.TexCoord;
	Output.MPos = SkinOut.Pos;
	
	return Output;
}

sampler Sampler = sampler_state
{
    Texture = (Tex);
};

struct PS_OUT
{
	float4 Color : COLOR;
};

PS_OUT PSRenderScene(VS_OUT Input, uniform bool RenderTexture)
{
	PS_OUT Output;
    
	float3 phong = PhongVertexLighting(Input.MPos, Input.Normal, World, CameraEye,
								 LightDir, mDiffuse, mSpecular, mEmissive, mPower);
    
    if (RenderTexture)
		Output.Color.rgb = tex2D(Sampler, Input.TexCoord) * phong;
	else
		Output.Color.rgb = phong;
	
	Output.Color.a = mAlpha;
    
    return Output;
}

VertexShader vsArray[4] = {	compile vs_2_0 VSSkin(1),
							compile vs_2_0 VSSkin(2),
							compile vs_2_0 VSSkin(3),
							compile vs_2_0 VSSkin(4)};

technique RenderScene
{
	pass Skin
	{
		//Clockwise culling for RHW
		CULLMODE = NONE;//CW;
		
		ZENABLE = true;
		ZWRITEENABLE = true;

        VertexShader = (vsArray[NumInfluences]);
        PixelShader  = compile ps_2_0 PSRenderScene(true);
	}
}

technique RenderScene_NoTexture
{
	pass Skin
	{
		//Clockwise culling for RHW
		CULLMODE = NONE;//CW;
		
		ZENABLE = true;
		ZWRITEENABLE = true;

        VertexShader = (vsArray[NumInfluences]);
        PixelShader  = compile ps_2_0 PSRenderScene(false);
	}
}


Sorry, I know that's a lot of source code, but I have no idea what to do at this point... any ideas? Also note that this code is very similar to the Direct3D MultiAnimation sample. I tried to sync up the two projects to make sure that the shader input it the same. Currently, I've got it so the shader constants that are being uploaded are the same but the MultiAnimation project works and mine doesnt...
Advertisement
does the error also occurs if you are to use software skinning. Also how are you updating your mesh bone matrices? Plus what is your draw function?
No error with software skinning.
Draw call is a simple skinMesh_->DrawSubset(0);
Actually, I got it working. I removed the section of code in createMeshContainer about changing the UBYTE4's to D3DCOLORs (for GeForce4 cards, I think) and also removed the D3DCOLORtoUBYTE4 function in the shader. It works now, but what could have been wrong with this? The D3D sample does it too...

This topic is closed to new replies.

Advertisement