D3D vertex blending?

Started by
8 comments, last by Muhammad Haggag 18 years, 10 months ago
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?
Advertisement
is there any body can help me ?
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.
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...
-Scoot
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.
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]
-Scoot
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.
You can get away with float4x3 matrices for skinning, world, and view. Only projection matrices actually need 4x4. It saves a constant per matrix, which back on 1.1 was a big deal.
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.
Quote:Original post by ScootA
[edit] Would it be possible (pointless?) to have a [ source lang="HLSL" ] formatting tag? [/edit]

Could be possible. Suggestions like this should go to the GDNet Comments, Suggestions and Ideas forum, where they'll get staff attention.

This topic is closed to new replies.

Advertisement