Skip to main content
GameDev.net gamedev.net
🔒 Locked

HLSL skinning

Started by JohnnyCode Oct 2, 2009 at 8:47 AM 2 replies 3.5k views
Original Post
JohnnyCode
JohnnyCode
hello, I have this issue. Recently I ported my engine from ogl to dx. I had a ogl skinning shader. I rewrote the shader to HLSL. But with the HLSL version I get a strange artifact. The mesh gets animated but some verticies animate differently, some verticies animate properly. I can tell I get about 70% of verticies animating well, the rest of them absolutely unexpectedly animating. I thought the problem might be weights or indicies I send by the stream but my CPU code for stream data creation is just the same like in ogl version. I work with the same mesh file format (arbitrary one). I feed the stream with the same data as in ogl version but there might by some problem with vertex declaration. Here is my vertex declaration in dx.

D3DVERTEXELEMENT9 decl[] =
				{
					{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
					{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },  
					{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
					{ 2, 32, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }, 	 
					{ 2, 36, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 },
					D3DDECL_END()
				};

As you can see stream 2 is associated with bones info. Here is how I feed the stream

char* boneIDs = new char[vert*4];
char* boneWeights = new char[vert*4];
inputf.read((char*)boneWeights,vert*4*sizeof(char));
inputf.read((char*)boneIDs,vert*4*sizeof(char));
		IDirect3DVertexBuffer9* bonebuff =	m_pVerBuff->GetBonesBuffer();
		GetScene()->GetDevice()->GetD3DDevice()->CreateVertexBuffer(
			m_iNumOfVerticies*sizeof(BoneVertex),
			0 /*Usage*/, 0, D3DPOOL_DEFAULT, &bonebuff, NULL 
			);
		BoneVertex* data;
		bonebuff->Lock(0,0,(void**)&data,D3DLOCK_DISCARD);
		for (long i=0;i<m_iNumOfVerticies;i++)
		{
			(data+i)->id1 = *(boneIDs+i*4);
			(data+i)->id2 = *(boneIDs+i*4+1);
			(data+i)->id3 = *(boneIDs+i*4+2);
			(data+i)->id4 = *(boneIDs+i*4+3);
			(data+i)->w1 = *(boneWeights+i*4+0);
			(data+i)->w2 = *(boneWeights+i*4+1);
			(data+i)->w3 = *(boneWeights+i*4+2);
			(data+i)->w4 = *(boneWeights+i*4+3);
		}
		bonebuff->Unlock();

the BoneVertex structure is defined as follows

struct BoneVertex {
	unsigned char id1,id2,id3,id4;
	unsigned char w1,w2,w3,w4;
};

Matricies data are fed to the shader the same way like in ogl version. They are column major matricies. I bind the stream when rendering. I think I have the stucky in the HLSL shader Here is ogl version of the skinning shader

uniform vec3 u_direction;
uniform mat4 u_modelmatrix;
uniform mat4 u_identitymatrix;
uniform mat4 u_modelmatrixinverse;
uniform mat4 u_model_view_proj_matrix;
uniform mat4 u_pose[32];

varying vec3 normal;
varying vec3 lightDir;
varying vec2 Texcoord;
varying float matid;

attribute vec4 BoneWeight;
attribute vec4 BoneID;
attribute int BoneID1;
attribute int BoneID2;
attribute int BoneID3;
attribute int BoneID4;
/*attribute float MaterialID;*/


  void main()
{

mat4 mat = u_pose[BoneID1] * BoneWeight[0];
mat += u_pose[BoneID2] * BoneWeight[1];
mat += u_pose[BoneID3] * BoneWeight[2];
mat += u_pose[BoneID4] * BoneWeight[3];

   
	if (mat[0]==0.0)
		mat = u_identitymatrix;
gl_Position = u_model_view_proj_matrix * mat * gl_Vertex; 

and here is the HLSL one

static const int MAX_MATRICES = 16;
float3 u_direction;
float4x4 u_modelmatrix;
float4x4 u_identitymatrix;
float4x4 u_modelmatrixinverse;
float4x4 u_model_view_proj_matrix;
float4x4 u_pose[MAX_MATRICES] : WORLDMATRIXARRAY;

bool haslayer2;
bool haslayer3;
bool u_light1;
bool u_light2;

texture baseMap;
texture baseMapB;
texture baseMapC;
texture baseMapD;

sampler2D sTex0A = sampler_state {
   Texture = <baseMap>;
   MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};


struct VS_OUTPUT_BASE
{
   float4 Pos    : POSITION;
   float3 normal   : TEXCOORD0;
   float3 lightDir  : TEXCOORD1;
   float2 Texcoord  : TEXCOORD2;
};

VS_OUTPUT_BASE mainV(
   float4 inPos  : POSITION,
   float3 inNorm : NORMAL,
   float2 inTex  : TEXCOORD0,
   float4 indicies  : BLENDINDICES,
   float4 weights : BLENDWEIGHT
)
{
VS_OUTPUT_BASE Out = (VS_OUTPUT_BASE) 0;

    float3 Pos = 0.0f;
    float4 src = float4(inPos.xyz,1.0f);

   Pos += mul(u_pose[int(indicies.x)] ,src) *  weights.x/255;
   Pos += mul(u_pose[int(indicies.y)] ,src) *  weights.y/255;
   Pos += mul(u_pose[int(indicies.z)] ,src) *  weights.z/255;
   Pos += mul(u_pose[int(indicies.w)] ,src) *  weights.w/255;

Out.Pos  = mul(u_model_view_proj_matrix,float4(Pos,1.0f) );

What possibly coild couse some verticies to animate unexpectedly, some correctly? matricies data are the same like in ogl version.
janta
janta
left vs right hand? Bone transforms with translation vs without translation?

have you tried with a simple mesh and a simple animation to narrow down the problem?
JohnnyCode
JohnnyCode
I found the problem ! it was vertex declaration. The bone info is in stream 2, but I was setting wrong byte offset.
JohnnyCode
JohnnyCode
It is so usefull to post a problem. You can see clearly the problematic parts and narrow donw the catch immediately. I was hot head for 2 days with this, I just posted the problem and,,, I spot the catch when reading my post the second time :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.