How to debug an fx file

Started by
25 comments, last by Buckeye 10 years, 1 month ago
PIX works to a certain extent. One cannot debug D3D11-only features (tesselation, compute), nonetheless, inspecting buffers/textures/render output works usually fine. Your code should pose little problems. Edit: I'm running Windows 7 and vanilla D3D11, though. PIX does not run with platform update a year ago and I don't think it runs on Win 8 either.

Silly question ... But how to do that ? I am seeing some constant buffers in the VSSetShader(). But couldn't make much from it coz the variable names in the shader files are not mentioned there. Though I can definetely see that one constant buffer object is just initialized to 0. I mean every variable inside it is 0. I have only 2 constant buffers here.


Aaah, so you can inspect buffers. Well, good. In PIX one can define the structure, meaning, copy-paste from the HLSL cbuffer definition, more or less. No idea how to do that in your case.

All zeroes sounds bad, though. As requested, show the code that updates the shader constants.
Advertisement

Ok here goes.....

These are the function I am using to set the variables. I am not good in Effects framework. Its based on the concept of Frank D Luna. May contain huge mistakes.]


void SetWorldViewProj(CXMMATRIX M) { WorldViewProj->SetMatrix(reinterpret_cast<const float*>(&M)); }
	void SetWorld(CXMMATRIX M) { World->SetMatrix(reinterpret_cast<const float*>(&M)); }
	void SetWorldInvTranspose(CXMMATRIX M) { WorldInvTranspose->SetMatrix(reinterpret_cast<const float *> (&M)); }
	void SetBoneTransforms(const XMFLOAT4X4 *M, int cnt) { BoneTransforms->SetMatrixArray(reinterpret_cast<const float*>(M), 0, sizeof(M)*cnt); }
	void SetTexTransform(CXMMATRIX M) { TexTransform->SetMatrix(reinterpret_cast<const float *> (&M)); }
	void SetEyePosW(const XMFLOAT3 &v) { EyePosW->SetRawValue(&v,0,sizeof(XMFLOAT3)); }
	void SetFogColor(const FXMVECTOR v) { FogColor->SetFloatVector(reinterpret_cast<const float *>(&v)); }
	void SetFogStart(float f) { FogStart->SetFloat(f); }
	void SetFogRange(float f) { FogRange->SetFloat(f); }
	void SetDirLights(const DirectionalLight* lights)   { DirLights->SetRawValue(lights, 0, 3 * sizeof(DirectionalLight)); }
	void SetMaterial(const Material& mat)               { Mat->SetRawValue(&mat, 0, sizeof(Material)); }
	void SetDiffuseMap(ID3D11ShaderResourceView *tex) { DiffuseMap->SetResource(tex); }

And this is how I store variables in SkinEffect class.


        WorldViewProj = mFX->GetVariableByName("gWorldViewProj")->AsMatrix();
	World = mFX->GetVariableByName("gWorld")->AsMatrix();
	WorldInvTranspose = mFX->GetVariableByName("gWorldInvTranspose")->AsMatrix();
	TexTransform = mFX->GetVariableByName("gTexTransform")->AsMatrix();
	EyePosW = mFX->GetVariableByName("gEyePosW")->AsVector();
	FogColor = mFX->GetVariableByName("gFogColor")->AsVector();
	FogStart = mFX->GetVariableByName("gFogStart")->AsScalar();
	FogRange = mFX->GetVariableByName("gFogRange")->AsScalar();
	DirLights = mFX->GetVariableByName("gDirLights");
	Mat = mFX->GetVariableByName("gMaterial");
	DiffuseMap = mFX->GetVariableByName("gDiffuseMap")->AsShaderResource();
	BoneTransforms = mFX->GetVariableByName("gBoneTransforms")->AsMatrix();

My main concern would be BoneTransforms. Am I setting it right ? I am setting the variables before rendering in this way :


        Effects::SkinFX->SetEyePosW(mCam.GetPosition());
        Effects::SkinFX->SetWorld(World);
	Effects::SkinFX->SetWorldInvTranspose(worldInvTranspose);
	Effects::SkinFX->SetWorldViewProj(worldViewProj);
	Effects::SkinFX->SetTexTransform(XMMatrixScaling(1.0f, 1.0f, 1.0f));
	Effects::SkinFX->SetDirLights(&dirLight[0]);
	
	Effects::SkinFX->SetBoneTransforms(&mBones.mBoneTransforms[0], mBones.mBoneTransforms.size());

        Effects::SkinFX->SetMaterial(Materials[i]);
        Effects::SkinFX->SetDiffuseMap(DiffuseMapSRV[i]);

There is huge possiblity that I am setting them in a wrong way. mBoneTransforms is a vector of type XMFLOAT4X4.mCam.GetPosition() returns XMFLOAT3 value.

Your concern is spot on.



void SetBoneTransforms(const XMFLOAT4X4 *M, int cnt) { BoneTransforms->SetMatrixArray(reinterpret_cast<const float*>(M), 0, sizeof(M)*cnt); }
sizeof(M) is the size in bytes, times how many matrices gives ... a lot. Edit: My C++ reading skills at fault. M is a pointer, so this is probably 4 or 8. Still wrong though.

The doc for this function is a bit confusing (not sure if 'elements' means array or matrix elements). Luna uses it like so:



void SetBoneTransforms(const XMFLOAT4X4* M, int cnt){ BoneTransforms->SetMatrixArray(reinterpret_cast<const float*>(M), 0, cnt); }
Worth a shot. Also check (or compare to Luna's) the other calls.

Unbird,

I can kiss you. I owe you a drink buddy.... biggrin.png biggrin.png biggrin.png . This stupid mistake made me waste 3 weeks . An average catastrophe in the life of a programmer.

I imported it. But it does not seem perfect. Mesh is somewhat distorted. I used only 4 weights where my model contained 6 weights at some vertices . May be that's the reason. Do you know any DXGI format to take 6 input in the input layout. Here is what it looks like now.

Distorted_zps9059219d.png

Devil's in the details. Three weeks sounds really frustrating, glad it (somehow) works now.

Just one question: Can you now debug the shaders ?

6 components ? Nope, but no need to. You can distribute it across a 4- and a 2-component. Or use 6 one-component (scalars). Probably need to play around a bit to find out which is most convenient (or even works) and what performance implications arise.

One can go even further and pack more info with some bit-hackery. Only do this if you do have a bottleneck in the vertex size. Just one hint: bone indices probably don't need full 32 bit ints.

Again, thanks unbird. Now debugger works. But it seems when I try to use the default offset matrix provided by the model, it gets more distorted. Guess I have got some more matrix multiplication to do. Just one question is it necessary to multiply each offset matrix with its parent matrix and global inverse transform ?

Fact about 6 weights. Yes I guess I can use 2 separate format to store 6 weights . Do I have to change the semantic index in the input layout then ?

About the integer part, I think 8 bit is sufficient. DXGI_FORMAT_R8G8B8A8_UINT.


is it necessary to multiply each offset matrix with its parent matrix and global inverse transform ?

Not sure what you mean by "parent" matrix and "global inverse" transform. Can you describe?

Also, take another look at my skinned mesh article. The names I use for various matrix arrays aren't the same as you seem to be using, but you should be able to find your equivalents.

You mention that your mesh uses 6 weights, but you're only inputting 4. How do you do that? You can't simply ignore the other two. Can you explain a little?

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


You mention that your mesh uses 6 weights, but you're only inputting 4. How do you do that? You can't simply ignore the other two

Guess gotta fix that first . But identity matrix shows something now that's a relief even if it is some what distorted.


Not sure what you mean by "parent" matrix and "global inverse" transform.

I am not so sure about assimp myself . This is what I did :

1. Got the offset matrix for each bone stored in the model. [I am not sure if it is really offset matrix you meant, but Assimp is referring to it as offset matrix in the aiBone structure. (http://assimp.sourceforge.net/lib_html/structai_bone.html)

2. Now got the scene root node's global transformation matrix and inversed it. According to Ogglev's tutorial(http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html)

3. Then I traversed the whole scene to find the bones. I used this technique according to the above tutorial.

  • Pass parent's transformation matrix and child in the function.
  • Multiply it by child's offset
  • Multiply the above product with child's offset again and global inverse transform to get child transform (confused)
  • Recursively called the function

I am really confused about this whole thing. Can you tell me what is the mOffsetMatrix in Assimp. And which matrix it represents in your article. That would be really helpful.

I'm not familiar with Assimp's implementation but it appears the ReadNodeHierarchy function is the combined equivalent of the CalulateTransformationMatrices, CalcCombinedMatrix and CalculateFinalMatrix functions in my tutorial. Although I looked at the link you posted (labeled Tutorial 38) I don't see the steps you outline.

The NodeTransformation is the bone's to-Parent animation matrix. That's multiplied by the parent's animation matrix to form the bone's to-Root animation matrix. That's multiplied by the bone's offset matrix. The role of the "global inverse transform" isn't quite clear to me, I'm afraid.

FYI, it appears that the author of that tutorial doesn't quite understand the code he provides. He describes it as starting with a child and "traveling" to it's parent. The code itself, however, clearly indicates that ReadNodeHierarchy is first called [ ReadNodeHeirarchy(AnimationTime, m_pScene->mRootNode, Identity);] with a root node (the "ultimate" parent) argument, the node's transforms are calculated, and ReadNodeHierarchy is called for each child - working it's way from parent to child, not the other way 'round. The code is straightforward but the author's description is very misleading.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

In the assimp's documentation it says that mOffsetMatrix is the "Matrix that transforms from mesh space to bone space in bind pose." . So, can you tell me what does it mean actually ?

This topic is closed to new replies.

Advertisement