Forum

I was trying to add normal map to skinning effect, bug it couldn't get compiled

//@author: vvvv group
//@help: Effect processing for skinned mesh with directional light.
//@tags: skeleton, bones, collada, shading
//@credits: SlimDX

float4 LightDirection	= {0.0f, 0.0f, -1.0f, 1.0f};
float4 LightDiffuse	= {0.6f, 0.6f, 0.6f, 1.0f};
float4 MaterialAmbient	= {0.1f, 0.1f, 0.1f, 1.0f};
float4 MaterialDiffuse	= {0.8f, 0.8f, 0.8f, 1.0f};

static const int MaxMatrices = 60;
float4x4 SkinningMatrices[MaxMatrices](MaxMatrices);
float4x4 tW: WORLD;
float4x4 tVP : VIEWPROJECTION;
float4x4 tWVP: WORLDVIEWPROJECTION;

//texture
texture Tex <string uiname="Texture";>;
sampler Samp = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (Tex);          //apply a texture to the sampler
    MipFilter = LINEAR;         //sampler states
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};
float4x4 tColor <string uiname="Color Transform";>;

texture TexNor <string uiname="Normal Texture";>;
sampler SampNor = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (TexNor);          //apply a texture to the sampler
    MipFilter = LINEAR;         //sampler states
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

struct VSInput
{
	float4 Position			: POSITION;
	float4 BlendWeights		: BLENDWEIGHT;
	int4   BlendIndices		: BLENDINDICES;
	float3 TextureCoordinates	: TEXCOORD0;
};

struct VSOutput
{
	float4 Position			: POSITION;
	float2 TextureCoordinates	: TEXCOORD0;
	float4 BlendWeights		: BLENDWEIGHT;
	int4   BlendIndices		: BLENDINDICES;
};

float3 Diffuse(float3 normal)
{
	float cosTheta;

	cosTheta = max(0.0f, dot(normal, -LightDirection.xyz));

	return (cosTheta);
}

VSOutput VS(VSInput input)
{
	VSOutput output = (VSOutput)0;

        /*
         * ---------- Skinning ----------
         */
	float4 blendWeights = input.BlendWeights;
	int4 indices = input.BlendIndices;
	
	float4 pos = 0;
        for (int i = 0; i < 4; i++)
        {
            pos = pos + mul(input.Position, SkinningMatrices[indices[i](indices[i)]) * blendWeights[i](i);
        }


	output.Position = mul(pos, tWVP);
	output.TextureCoordinates = input.TextureCoordinates.xy;

	return output;
}


float invlerp (float x, float SourceMin, float SourceMax)
{
        return (x - SourceMin) / (SourceMax - SourceMin);
}

float3 invlerp (float3 x, float SourceMin, float SourceMax)
{
        return (x - SourceMin) / (SourceMax - SourceMin);
}


float4 PS(VSOutput input)  : COLOR
{
	float4 blendWeights = input.BlendWeights;
	int4 indices = input.BlendIndices;
	float4 norm_tex = tex2D(SampNor, input.TextureCoordinates);
	norm_tex.w = 0;
	
		float3 norm = 0;
	for (int i = 0; i < 4; i++)
    {
        norm = norm + mul(norm_tex, SkinningMatrices[indices[i](indices[i)]) * blendWeights[i](i);
    }
	norm = normalize(norm);
	
	float4	diff;	
	diff.xyz = MaterialAmbient.xyz + Diffuse(norm) * MaterialDiffuse.xyz;
	diff.w = 1.0f;

    float4 col = tex2D(Samp, input.TextureCoordinates);
    col.rgb *= diff;
    return mul(col, tColor);
}

technique SkinnedMesh
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS();
		PixelShader = compile ps_3_0 PS();
	}
}

Error Message

I’m not familiar with hlsl, could you guys teach me how to display a collada model including animation and normal texture?

Just a general idea, try changing “vs_3_0” and “ps_3_0” to “vs_4_0” and “ps_4_0” for more registers to work with (regarding the first error, haven’t really looked at your code).

@herbst Thanks for reply.
I tried that but the compiler said:
error X3506: Only 3_x and earlier targets are supported on this compiler.

So I think my code may have something wrong.

hello agalloch,

the problem here is that your shader exceeds the shader model 3 register count as the compiler states, so you could either remove some inputs and/or lower your bone matrix input count. for shader model 4 or 5 to work you’d have to adapt the shader to those shader models and ofcourse use the dx 11 version of vvvv. (doesn’t work on stock vvvv+addons)

hi m4d,

static const int MaxMatrices = 50;
float4x4 SkinningMatrices[MaxMatrices](MaxMatrices);

I changed the MaxMatrices to 50 and it finally got compiled. So, does this mean that I can’t load the model which has more than 50 bones?

yeah, unfortunately that is exactly the case.

edit: well, to be exact you could load models with >50 bones but you would only be able to set the first 50 bone matrices through this shader. a possible way to work around this problem could be to break bigger models up into parts with total bonecount <= 50.

Fortunately our models don’t have too many bones. :D
Sorry for replying late and Thanks for the good explanation

Another way which also allows “unlimited” bones is to send the skinning transforms in a texture.

In dx11 you can use structured buffers instead, which makes life easier.

Also depending on normal map but it’s likely that you will need tangents for your model.

can I bump that thread. i really would like to see what vux described here. It is something in between cryptic and enlightening for me.

@tekcor : it’s simple really.

In dx11 I use a buffer for skinning (since also using instancing most times, so I build a big fat buffer then do lookup in vs).

Since in dx9 you don’t have access to that, you can apply the same technique as for particles.

Let’s say you have 1024 bones, and one model (to keep it simple, but variable bone size / multiple models is just a little bit more code).

You create a texture (4 channels float32), size:
4 rows and 1024 columns (or opposite)

Each column represents a full bone matrix.

Each row is one part of the matrix.

So you write your data as dynamic texture (making sure you layout properly).

Then in VS you do texture lookup (tex2dLod)
You need 4 lookup per bone (since basically uv will be something like)
float4 row1 = tex2dlod(float2(boneid/bonecount,0),0);
float4 row2 = tex2dlod(float2(boneid/bonecount,0.333333),0);

and so on…
Don’t forget to use either point sampler or no sampling, and to make sure to clamp.

That’s it, from your 4 rows reconstruct your matrix and do as usual.

Thanks that makes sense. DX9 part is clear. Now it seems like I have to investigate Buffers in DX11 more. Having a working DX11 skinning shader would be real good. I searched the internet for an example but it seems this kind of stuff is not freely available.

suspect that it’s easy to port dx9 > dx11
as for the buffers will be bit more advance, but also easy
checking…
hmmm not compiling dunno why yet…

ok compiled, but not working, some high logic missing a guess…

skinning11.zip (3.1 kB)

thats a good step antokhio!

line 74: implicit truncation of vector type

but it compiles anyway…