Hey there,
I've been messing around with creating a custom actor shader with the base of the sample provided (CustomActorShader.fx). I'm getting different results with TVs internal actor shader and the example. See for yourself:
Custom:

Truevision:

Note that one group (at the helmet) disappears and one group gets moved. It looks like the WORLD matrix isn't correctly set. This is how the sample shader looks like: (I haven't edited a thing)
///////////////////////////////////////////////////
// Example file for custom actor shaders using GPU
///////////////////////////////////////////////////
//
// Reminder : Custom Shaders are possible via CPU actor mode
// but they are quite slow because it must transform every vertex of the actor on CPU
//
// Here we will use a faster technique made possible recently for TVActor
//
//
// The important thing is the vertex structure used by TV.
// here is the non bumpmapped version, so there is no Tangent nor Binormal vector :
struct VS_INPUT_NONBUMP
{
float3 position : POSITION ; // vertex position in the default pose
float3 normal : NORMAL; // vertex normal in the default pose
float4 blendindices : BLENDINDICES; // indices of the 4 bone indices used in the bone matrix array
float4 blendweights : BLENDWEIGHT; // weights of each bone.
float2 tex1 : TEXCOORD0; // standard texture coordinates.
};
// here is the bumpmapped version, with tangents :
struct VS_INPUT_BUMP
{
float3 position : POSITION;
float3 normal : NORMAL; //
float3 tangent : TANGENT; // this forms the tangent matrix.
float3 binormal : BINORMAL; //
float4 blendindices : BLENDINDICES;
float4 blendweights : BLENDWEIGHT;
float2 tex1 : TEXCOORD0;
};
// another important thing is how are stored the matrices.
// Warning : there are two possible versions of the skinning in the TVActor
// - a vertex shader 1.1 version, allowing max 16 bones in a draw call.
// - a vertex shader 2.0 version, allowing max 52 bones in a draw call.
// These are constant values, you can't change them.
// the easiest way is to work only with VS2.0 vertex shader mode and always allocate 52 bone matrices.
// a matrix here is only using 3 rows (float4x3) so we will use an array of float4x3, it MUST have the semantic BONES
float4x3 boneMatrices[52] : BONES;
// here is the number of bones used per vertex
int iNumBonePerVertex : BONESPERVERTEX;
// a simple world matrix is used when there is no bone influence (it must have the semantic WORLD);
float4x4 worldMat : WORLD;
// usual viewprojection to complete the transformation
float4x4 ViewProj : VIEWPROJECTION;
// here is the standard skinning function of TV to skin the position and normal
// there must be 5 versions : one for each case (0 bone blending, 1 bone blending, 2 bones blending, .. ,4 bones blending)
void TransPositionNormal( uniform int iNumBones, float4 modelPos, float3 modelNorm,
float4 boneWeights, float4 fBoneIndices, out float3 pos, out float3 norm)
{
if(iNumBones == 0)
{
pos = mul(modelPos, worldMat);
norm = mul(modelNorm, (float3x3)worldMat);
}
else
{
int4 ibone = D3DCOLORtoUBYTE4(fBoneIndices);
int IndexArray[4] = (int[4])ibone;
pos = 0;
norm = 0;
float lastweight = 0.0f;
for(int i = 0; i < iNumBones - 1; i++)
{
float4x3 mat = boneMatrices[IndexArray[i]];
lastweight = lastweight + boneWeights[i];
pos += mul(modelPos, mat) * boneWeights[i];
norm += mul(modelNorm, (float3x3)mat ) * boneWeights[i];
}
lastweight = 1 - lastweight;
float4x3 mat = boneMatrices[IndexArray[iNumBones-1]];
pos += mul(modelPos, mat) * lastweight;
norm += mul(modelNorm, (float3x3)mat ) * lastweight;
}
return;
}
// simple sample that does nothing fancy.
struct VS_OUTPUT
{
float4 position : POSITION;
float4 diffuse : COLOR0;
float2 tex : TEXCOORD0;
};
VS_OUTPUT ActorShader(uniform int iNumBones, VS_INPUT_NONBUMP inp)
{
VS_OUTPUT o = (VS_OUTPUT)0;
float3 pos, norm;
// use our skinning method
TransPositionNormal( iNumBones, float4(inp.position, 1.0f), inp.normal, inp.blendweights, inp.blendindices, pos, norm);
// then let's transform the position into clip space using view proj matrix
o.position = mul(float4(pos,1.0f), ViewProj);
o.tex = inp.tex1;
float light = dot(norm, float3(0,0,1));
o.diffuse = float4(light,light,light, 1.0f); // some weird const lighting computation
return o;
}
sampler sampler1;
texture texture0 : TEXTURE0; // tv will automatically set current texture to TEXTURE0
// simple pixel shader that just output the pixel
float4 ActorPixelShader(VS_OUTPUT inp) : COLOR0
{
return inp.diffuse * tex2D(sampler1,inp.tex);
}
VertexShader VSArray[5] = { compile vs_2_0 ActorShader(0),
compile vs_2_0 ActorShader(1),
compile vs_2_0 ActorShader(2),
compile vs_2_0 ActorShader(3),
compile vs_2_0 ActorShader(4)
};
technique ActorShader
{
pass pass0
{
VertexShader = ( VSArray[iNumBonePerVertex] );
PixelShader = compile ps_1_1 ActorPixelShader();
Texture[0] = <texture0>;
}
}
Any ideas?