Jump to content
  • Advertisement
Sign in to follow this  
renqilin

D3D vertex blending?

This topic is 4794 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

i want to build skin mesh by using D3D indexed vertex blending, the problem is that some of the vertices are affected by one bone while some others are affected by two bones. i need to batch rending them in one DrawPrimitive call, how can i achieve this ? one solution is make all vertices uses the bone indices count up to the maximum bone indeices count, and set weight to 0.0f for unused bone indices. is this solution slow?

Share this post


Link to post
Share on other sites
Advertisement
That's the usual method for hardware transform. You have 3 options

Transform in software and use a dynamic VB. If your mesh is dense, and/or your pixel shader/texture stages are really simple, it may be faster to keep this work on the CPU.

Transform in hardware with fixed pipeline skinning. You rule out all nVidia cards doing this. You'll need as many weights per vertex as your maximum across all vertices of the draw call.

Transform in hardware in a vertex shader, passing bone matrices as constants, and bone ids and weights packed into vertex data. Again, you'll need as many weights on each vertex as your vertex with the most weights requires.

I typically pack the bone ids into a D3DCOLOR, and the weights into a second D3DCOLOR. I calculate the last weight in the shader, as (1-sum of other weights) so if rounding makes weight 1 = 0.999, weight 2 will become 0.001, regardless of what's stored. When doing this, ensure all unused bone ids are set to the id of the bone with the highest weight. This ensures that even if you though the bone was unused, and rounding error creeps in making it used, it's still using a valid matrix for this vertex.

Share this post


Link to post
Share on other sites
Yup I concur - though the only real option these days is with a vertex shader - its a lot simpler than it sounds, and is the most compatible of the options (Vertex shaders can be implemented in software).

I tried to use FF-only (using a matrix palette), and its not even supported on my 6800-Ultra, so a shader was my only option.

Once I had it working it was far faster than other methods and fit snugly into my current pipeline.

If you want shader code I can probably supply something...

Share this post


Link to post
Share on other sites
i appreciate for you help. but i have just one question.

Quote:

Transform in software and use a dynamic VB. If your mesh is dense, and/or your pixel shader/texture stages are really simple, it may be faster to keep this work on the CPU.


in my imagination, GPU will be left idle in this situation. how could it be faster?

and ScootA:

i will be glad if you can show some code. thanks.

Share this post


Link to post
Share on other sites
I would say always use the GPU if possible. Here is an extremely basic (but functional) real-time skinning shader:


float4x4 VIEW_PROJ_MATRIX : VIEW_PROJ_MATRIX;
float4x4 MATRIXPALETTE[50] : MATRIXPALETTE;

struct VS_INPUT
{
float4 position : POSITION;
float4 blendWeights : BLENDWEIGHT;
//these can/should be defined as ints
float4 blendIndices : BLENDINDICES;
float4 normal : NORMAL;
float4 colour : COLOR;
float2 tex0 : TEXCOORD0;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float4 colour : COLOR;
float2 tex0 : TEXCOORD0;
};

VS_OUTPUT simpleSkinShader( VS_INPUT input )
{
VS_OUTPUT output = (VS_OUTPUT) 0;

float blendWeightsArray[4] = (float[4])input.blendWeights;

float4 position = 0.0f;
float3 normal = 0.0f;

//calculate pos/normal...
position += mul(input.position, MATRIXPALETTE[input.blendIndices[0]]) * blendWeightsArray[0];
position += mul(input.position, MATRIXPALETTE[input.blendIndices[1]]) * blendWeightsArray[1];
position += mul(input.position, MATRIXPALETTE[input.blendIndices[2]]) * blendWeightsArray[2];
//position += mul(input.position, MATRIXPALETTE[input.blendIndices[3]]) * blendWeightsArray[3];

normal += mul(input.normal, (float3x3)MATRIXPALETTE[input.blendIndices[0]]) * blendWeightsArray[0];
normal += mul(input.normal, (float3x3)MATRIXPALETTE[input.blendIndices[1]]) * blendWeightsArray[1];
normal += mul(input.normal, (float3x3)MATRIXPALETTE[input.blendIndices[2]]) * blendWeightsArray[2];
//normal += mul(input.normal, (float3x3)MATRIXPALETTE[input.blendIndices[3]]) * blendWeightsArray[3];

normal = normalize(normal);

output.position = mul(position, VIEW_PROJ_MATRIX);
output.tex0 = input.tex0;
output.colour = float4(1,1,1,1);

return output;
}






I commented out the fourth blend, because I was able to make do with only three bones per vertex from Maya, to gain some speed. This shader was modified from a more complicated one so it may do some pointless things.

If you need an explanation just ask.

[edit] Would it be possible (pointless?) to have a [ source lang="HLSL" ] formatting tag? [/edit]

[Edited by - ScootA on June 1, 2005 11:50:53 AM]

Share this post


Link to post
Share on other sites
Doing skinning is a lot of work per vertex. If your mesh is dense, you'll be spending quite a bit of time doing skinning, per very few pixels. You may actually create a vertex shading bottleneck, leaving the rasterizer idle. Also, when doing multipass cumulative lighting, you're re-transforming the mesh over and over on the GPU, which, if you're stalling the pixel pipeline has gone from bad to horrible.

Skinning on the CPU will be done once, and remove the vertex shading bottleneck. Anything already in the pipeline will be rendering while your CPU is busy doing the skinning, so the GPU will (hopefully) not become idle.

When your mesh isn't dense, the vertices should be transformed long before they're needed by the rasterizer, making on GPU skinning good.

Personally, once I did the shader method, I never looked into skinning in a software mode again. I've heard developers say it's better in the cases I've mentioned, but I've never directly compared them myself. Every app is different, and unless you've got a problem with the performance of your shader skinned meshes, then don't worry about it.

Share this post


Link to post
Share on other sites
so, Namethatnobodyelsetook, i know what you mean. whether using hardware blending or software blending really depends on my situation ( CPU limitied or Shader limitied ). i think i know what i should do. thanks.

and thanks to ScootA for your code. it's very clear.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!