• ### What is your GameDev Story?

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

## Recommended Posts

Hello!

I am attempting to write my own game engine and am now at the point of implementing skinned meshes.

For testing purposes the gBones-Array only holds identity-matrices.

uniform extern float4x4 gWVP;
uniform extern texture gMainTex;

static const int MAX_NUM_BONES = 100;
uniform extern float4x4 gBones[MAX_NUM_BONES];

OutputVS TransformVS(float3 pos : POSITION0,
float3 normal : NORMAL0,
float2 tex0 : TEXCOORD0,
uint4 boneIDs : BLENDINDICES0,
float4 boneWeights : BLENDWEIGHT0)
{
OutputVS outVS = (OutputVS)0;

float4 posResult = float4(0.0f,0.0f,0.0f,0.0f);

//problem here; the following line works
posResult = mul(float4(pos,1.0f), gBones[0]);
//but if i write
//posResult = mul(float4(pos,1.0f), gBones[boneIDs[0]]);
//and just use the blendindex, i dont see the mesh anymore

outVS.pos = mul(posResult, gWVP); outVS.color = float4(0.0f,0.0f,0.0f,1.0f);

outVS.tex0 = tex0; return outVS;
}


This problem might be caused due to the uint4 type on boneIDs : BLENDINDICES0 in the vs_input. I already tried int4, uint4, float4...

Here is my vertex declaration:

D3DVERTEXELEMENT9 CustomVertexFormats::VERTEX_POSITION_NORMAL_UV_BONE4_DECL_ARRAY []=
{
{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},
{0,32,D3DDECLTYPE_UBYTE4,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0},
{0,36,D3DDECLTYPE_FLOAT4,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
D3DDECL_END()
};


I really hope someone can help me. I have been looking all over the internet but just can't find the solution.

Flo

Edited by IceBreaker23

##### Share on other sites

Do you have the debug runtimes enabled? If there's a mismatch between your vertex shader and your vertex declaration, the debug runtimes will output an error message to your debugger output window.

Honestly it's been a very long time since I worked with D3D9, and I don't remember the rules for input types for vertex shaders. If I recall correctly we always used float4 type in the shader for a UBYTE4 vertex element, since D3D9 shaders don't actually support integer type (the compiler maps them to floats in assembly). Taking a quick look at the SDK samples, this is also what the SkinnedMesh sample does.

##### Share on other sites

I have working DX9 shaders which use both int4 and float4 for the bone indices. Your shader code is all but identical to the various shaders I use.

The only difference in your code is (obviously) boneID[0]. Have you checked that the bone indices in your vertex array are correct?

EDIT: Are you sure you're loading each vertex in accordance with the vertex declaration, that you don't have (for instance) weights and indices swapped around?

EDIT2: If you're using ConvertToIndexedBlendedMesh:

are all the input parameters correct?

do you check the vertex declaration for the mesh returned from that call?

Edited by Buckeye

##### Share on other sites

Honestly it's been a very long time since I worked with D3D9, and I don't remember the rules for input types for vertex shaders. If I recall correctly we always used float4 type in the shader for a UBYTE4 vertex element, since D3D9 shaders don't actually support integer type (the compiler maps them to floats in assembly). Taking a quick look at the SDK samples, this is also what the SkinnedMesh sample does.

I was sure about this as well, so I tried changing my skinning code from float4 to uint4.. and it still works. I think newer compilers (mine is D3Dcompiler_47.dll, targeting vs_3_0) take care of the conversion under the hood, because I remember having to ifdef that part when my D3D9 path used _43 and D3D11 used _47.

Edit: as Buckeye said, can we see the code that writes to the vertex buffer?

Edited by Mona2000

##### Share on other sites

Thanks for the many replies!

I have checked if the boneIDs are correct. I added this line to my vertex shader:

if(boneIDs[0] < 32 && boneIDs[0] >= 0)
{
outVS.color = float4(boneIDs[0]/32.0f,0.0f,0.0f,1.0f);
}
else
{
outVS.color = float4(0.0f,1.0f,0.0f,1.0f);
}


So basically what this does is it makes the vertex some shade of red if the boneIDs[0] is between 0-32. Otherwise its green.

You can see the output as an attached screenshot.

The farther away from the spine the more red it gets -> just logical, since the rootBone is at the spine.

Edited by IceBreaker23

##### Share on other sites

And as requested, here the struct I use for the Vertex Buffer:

struct VERTEX_POSITION_NORMAL_UV_BONE4
{
float x,y,z;
float nx,ny,nz;
float uvx,uvy;
unsigned char boneIDs[4];
float boneWeights[4];
};


Here the vertex buffer code:

VertexBuffer::VertexBuffer(LPDIRECT3DDEVICE9 d3ddev, void *vertices, int sizeofVertex,int nVertices, IDirect3DVertexDeclaration9 *vertexDeclaration)
{
d3ddev->CreateVertexBuffer(nVertices*sizeofVertex,0,0,D3DPOOL_MANAGED,&_vertexBuffer,0);

//lock buffer
VOID* pVoid;

_vertexBuffer->Lock(0, 0, (void**)&pVoid, 0);

memcpy(pVoid, vertices, nVertices*sizeofVertex);

_vertexBuffer->Unlock();

this->_nVertices = nVertices;

this->_sizeofVertex = sizeofVertex;

this->_vertexDeclaration = vertexDeclaration;
}

//assign vertices
VERTEX_POSITION_NORMAL_UV_BONE4 *vertices = new VERTEX_POSITION_NORMAL_UV_BONE4[mesh->mNumVertices];
for(unsigned int i = 0;i < mesh->mNumVertices;i++)
{
vertices[i].x = mesh->mVertices[i].x;
vertices[i].y = mesh->mVertices[i].y;
vertices[i].z = mesh->mVertices[i].z;

vertices[i].nx = mesh->mNormals[i].x;
vertices[i].ny = mesh->mNormals[i].y;
vertices[i].nz = mesh->mNormals[i].z;

if(hasTextureCoords)
{
vertices[i].uvx = mesh->mTextureCoords[0][i].x;
vertices[i].uvy = mesh->mTextureCoords[0][i].y;
}else
{
vertices[i].uvx = 0.0f;
vertices[i].uvy = 0.0f;
}

for(int j=0;j<4;j++)
{
vertices[i].boneWeights[j] = 0.0f;
vertices[i].boneIDs[j] = 0;
}
}

for(unsigned int i = 0;i<mesh->mNumBones;i++)
{
aiBone *bone = mesh->mBones[i];
const char *boneName = bone->mName.C_Str();
if(_boneMap.count(boneName) == 0)
{
Bone boneStruct;
boneStruct.offsetMatrix = *(Matrix *)&bone->mOffsetMatrix;
_boneMap.insert(std::pair<const char *, int>(boneName, _bones.size()));
_bones.push_back(boneStruct);
}

int boneID = _boneMap.find(boneName)->second;

//assign vertex weights
for(unsigned int j = 0;j<bone->mNumWeights;j++)
{
aiVertexWeight weight = bone->mWeights[j];
unsigned int vertexID = weight.mVertexId;

bool assignedWeight = false;
for(unsigned int weightID = 0;weightID<4 && !assignedWeight;weightID++)
{
if(vertices[vertexID].boneWeights[weightID] <= 0.0f)
{
vertices[vertexID].boneWeights[weightID] = weight.mWeight;
vertices[vertexID].boneIDs[weightID] = (unsigned short)boneID;
assignedWeight = true;
}
}
if(!assignedWeight)
{
Debug::Log(filename);
Debug::Log("\nMore bone weights than possible with only 4 weights\n");
}
}
}

submesh.vertexBuffer = new VertexBuffer(d3ddev,vertices, sizeof(VERTEX_POSITION_NORMAL_UV_BONE4),mesh->mNumVertices,CustomVertexFormats::VERTEX_POSITION_NORMAL_UV_BONE4_DECL);



Btw I am using ASSIMP to load data.

I just found another weird error.

If I change the input parameters of the shader(so they dont match my vertex declaration anymore) it just doesnt give me an error in d3d9 debug mode.

##### Share on other sites

IF all you have posted is correct, the culprit for the problem comes down to gBones[boneIDs[0]]. IF the bone indices are correct but they are being accessed incorrectly, then it must be accessing a matrix other than an identity matrix.

That is, if gBones[ 0 ] works but gBones[ some-other-number ] does not work, then gBones[ some-other-number ] is an incorrect matrix. Try:

posResult = mul(float4(pos,1.0f), gBones[x]);

where x is any value from 0 to 31.

That's quick and easy and, if it works, may indicate there is, indeed, a problem accessing the boneID correctly. Otherwise, your matrices are not correct. It's trivial but we all need more clues.

Otherwise, the problem must be somewhere else.

EDIT: Although your red-shaded output indicates the bone indices are likely correct, you still haven't checked the actual values of boneIDs[ 0 ]. In general, if you have visually examined code and it appears to be correct, it's a bad trouble-shooting technique to write more code* to check for an error in existing code. That is, you shouldn't back off from boneIDs[ 0 ] to see if your red-green code is correct. If your response is: "What's wrong with the red-green code?" then you've proven the point.

The trouble-shooting approach here is:

You know where the problem manifests itself: it doesn't appear that boneIDs[ 0 ] = (0 through 31) in your shader. Start there: VERIFY (not guess or say "it makes it red") what number boneIDs[ 0 ] actually returns. You should be able to use PIX.

It boneIDs[ 0 ] is not correct, then EXAMINE the values going to the shader.

Work your way backwards, step by step, until you find the problem.

Edited by Buckeye

##### Share on other sites

Right now I am checking the gBones[] again.

I just set 100 identity matrices to the gBones-array, but it only works(i only see the mesh) from 0-61. If I go 62 or higher I dont see the mesh anymore.

unsigned int nBoneTransforms = 100;
D3DXMATRIX *matrices = new D3DXMATRIX[nBoneTransforms];
for(unsigned int i = 0;i < nBoneTransforms;i++)
{
D3DXMatrixIdentity(&matrices[i]);
}
{
Debug::Log("Failed setting SetMatrixArray()");
}


Is there anyway that this code would not work?(the SetMatrixArray does not fail)

##### Share on other sites

Why are you setting up 100 transforms? Have you examined the values for boneIDs[ ] yet? Please take a look at my previous post. Writing more code and asking why that doesn't work doesn't help anyone, least of all you.

EDIT: It appears you're just hacking, hoping to stumble on something that works. Just a suggestion, but why don't you try to solve the problem?

EDIT2: I apologize. That was a bit harsh.

If you're saying that gBones[x], for x=0 to 61, works, it appears you've established that you can access (most of) the transforms correctly. However, as mentioned in my previous post, keep to the problem at hand. Don't get sidetracked. It's very likely that the "over 61" problem has nothing to do with your algorithm, possibly shader capabilities.

What you're trying to determine is: does boneIDs[ 0 ] access data correctly?

As suggested, examine the actual values of boneIDs[ 0 ] in the shader.

Edited by Buckeye

##### Share on other sites

Well I wrote that code a while ago to make sure that all the transforms are identity matrices for debugging purposes.

And trying to solve the problem is easier said than done :D Writing more code to check what does not work usually worked for me in CPU programming. Guess that doesnt apply here...

I checked the boneIDs in PIX and they only encountered values from 0-31 while debugging a few vertices.

To recap:

-gBones are all set to identity-matrix(checked by trying out values from 0-31 statically)

-boneIDs are all set to values between 0-31(checked by debugging vertices in PIX)

posResult = mul(float4(pos,1.0f),gBones[0]); works

posResult = mul(float4(pos,1.0f),gBones[boneIDs[0]]); does not work

Do you have any suggestions for what could be the problem here?

I dont know where to continue debugging. This just seems like a very weird error.

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 9
• 13
• 9
• 9
• 15
• ### Forum Statistics

• Total Topics
634071
• Total Posts
3015340
×