Lostlogic

Ok, so I have model rendering working with custom effects thanks to the help of members here. The problem I have now is that if I use the effects generated by the FX Composer (Nvidia product,) my models always render at 0,0,0.

Here is the code I'm using to render models with a custom effect called "SimpleEffect":


public void DrawModel( int index, Vector3 trans, Vector3 rot, Vector3 scale, float aspectRatio, Camera camera, GraphicsDeviceManager graphics )
{
int iMeshCount = 0;
int iEffectCount = 0;
Matrix world;

// Sanity check
if (myModel[index] == null)
{
return;
}

//Copy any parent transforms
Matrix[] transforms = new Matrix[myModel[index].Bones.Count];
myModel[index].CopyAbsoluteBoneTransformsTo(transforms);

// Update the viewProjection...
simpleEffect.Parameters["viewProjection"].SetValue(camera.view * camera.projection);
simpleEffect.Begin();

foreach (EffectPass pass in simpleEffect.CurrentTechnique.Passes)
{
pass.Begin();
iMeshCount = 0;
foreach (ModelMesh mesh in myModel[index].Meshes)
{
// Retrieve the texture
BasicEffect basicEffect = (BasicEffect)myModel[index].Meshes[iMeshCount].Effects[iEffectCount];
if (basicEffect.Texture != null || basicEffect.Texture == null)
{
simpleEffect.Parameters["objectTexture"].SetValue(basicEffect.Texture);
}

// Position, rotation, scale, of the object

world = transforms[mesh.ParentBone.Index];
world *= Matrix.CreateScale(scale);
world *= Matrix.CreateRotationY(rot.X);
world *= Matrix.CreateRotationY(rot.Y);
world *= Matrix.CreateRotationY(rot.Z);
world *= Matrix.CreateTranslation(trans);
simpleEffect.Parameters["world"].SetValue(world);
simpleEffect.CommitChanges(); // Commit parameter changes made between effect Begin/End pairs

graphics.GraphicsDevice.Indices = mesh.IndexBuffer;
for (int i = 0; i < mesh.MeshParts.Count; i++)
{
ModelMeshPart part = mesh.MeshPartsIdea;
if (part.NumVertices > 0)
{
graphics.GraphicsDevice.VertexDeclaration = part.VertexDeclaration;
graphics.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, part.StreamOffset, part.VertexStride);
graphics.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType.TriangleList,
part.BaseVertex,
0,
part.NumVertices,
part.StartIndex,
part.PrimitiveCount);
}
}
iMeshCount++;
}
pass.End();
iEffectCount++;
}
simpleEffect.End();
}
-----------------------------------------------------------------
Here is the effect code:


// Shader global data

float4x4 viewProjection;
float4x4 world;
texture objectTexture;


sampler2D objectTextureSampler = sampler_state
{
Texture = <objectTexture>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};


void VS_Simple(in float4 pos : POSITION, float2 texCoord : TEXCOORD0,
out float4 outPos : POSITION,
out float2 outTexCoord : TEXCOORD0)
{
float4 posWorld;

posWorld = mul(pos, world);

outPos = mul(posWorld, viewProjection);

outTexCoord = texCoord; // Pass the texCoord through to the pixel shader
}


float4 PS_Simple(float2 texCoord : TEXCOORD0) : COLOR
{
float4 outColor = tex2D(objectTextureSampler, texCoord);

return outColor;
}


technique Simple
{
pass p0
{
CullMode = CCW;
VertexShader = compile vs_2_0 VS_Simple();
PixelShader = compile ps_2_0 PS_Simple();
}
}

----------------------------------------
The code above works fine as it renders my models in the proper position in the world. To give you an idea, I'm rendering a grid of models 10x10 to form 3D terrain. In the above code all is well.

When I go to use an FX Composer generated shader (the default one for transformed and lit faces,) it renders all of the models but at position 0,0,0 instead of in a nice grid.

Here is the code to render the FX Composer effect on the model:

public void DrawModel3(int index, Vector3 trans, Vector3 rot, Vector3 scale, float aspectRatio, Camera camera, GraphicsDeviceManager graphics)
{
int iMeshCount = 0;
int iEffectCount = 0;
Matrix world;

// Sanity check
if (myModel[index] == null)
{
return;
}

//Copy any parent transforms
Matrix[] transforms = new Matrix[myModel[index].Bones.Count];
myModel[index].CopyAbsoluteBoneTransformsTo(transforms);

simpleEffect.CurrentTechnique = simpleEffect.Techniques["textured"];

simpleEffect.Begin();

foreach (EffectPass pass in simpleEffect.CurrentTechnique.Passes)
{
pass.Begin();
iMeshCount = 0;
foreach (ModelMesh mesh in myModel[index].Meshes)
{
// Retrieve the texture
BasicEffect basicEffect = (BasicEffect)myModel[index].Meshes[iMeshCount].Effects[iEffectCount];
if (basicEffect.Texture != null)
{
simpleEffect.Parameters["diffuseTexture"].SetValue(basicEffect.Texture);
}

// Position, rotation, scale, of the object

world = transforms[mesh.ParentBone.Index];
world *= Matrix.CreateScale(scale);
world *= Matrix.CreateRotationY(rot.X);
world *= Matrix.CreateRotationY(rot.Y);
world *= Matrix.CreateRotationY(rot.Z);
world *= Matrix.CreateTranslation(trans);
simpleEffect.Parameters["world"].SetValue(world);
simpleEffect.Parameters["lightAmbient"].SetValue(0.2f);

simpleEffect.Parameters["worldViewProj"].SetValue((camera.view * camera.projection));

Matrix viewInverse = Matrix.Invert(camera.view);
simpleEffect.Parameters["viewInverse"].SetValue(camera.view);

Matrix worldInverseTranspose = Matrix.Invert(world);
worldInverseTranspose = Matrix.Transpose(worldInverseTranspose);
simpleEffect.Parameters["worldInverseTranspose"].SetValue(camera.view);

simpleEffect.CommitChanges(); // Commit parameter changes made between effect Begin/End pairs

graphics.GraphicsDevice.Indices = mesh.IndexBuffer;
for (int i = 0; i < mesh.MeshParts.Count; i++)
{
ModelMeshPart part = mesh.MeshPartsIdea;
if (part.NumVertices > 0)
{
graphics.GraphicsDevice.VertexDeclaration = part.VertexDeclaration;
graphics.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, part.StreamOffset, part.VertexStride);
graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
part.BaseVertex,
0,
part.NumVertices,
part.StartIndex,
part.PrimitiveCount);
}
}
iMeshCount++;
}
pass.End();
iEffectCount++;
}
simpleEffect.End();
}
----------------------------------------
And here is the shader:

string description = "Basic Vertex Lighting with a Texture";

//------------------------------------
float4x4 worldViewProj : WorldViewProjection;
float4x4 world : World;
float4x4 worldInverseTranspose : WorldInverseTranspose;
float4x4 viewInverse : ViewInverse;

texture diffuseTexture : Diffuse
<
string ResourceName = "default_color.dds";
>;

float4 lightDir : Direction
<
string Object = "DirectionalLight";
string Space = "World";
> = {1.0f, -1.0f, 1.0f, 0.0f};

float4 lightColor : Diffuse
<
string UIName = "Diffuse Light Color";
string Object = "DirectionalLight";
> = {1.0f, 1.0f, 1.0f, 1.0f};

float4 lightAmbient : Ambient
<
string UIWidget = "Ambient Light Color";
string Space = "material";
> = {0.0f, 0.0f, 0.0f, 1.0f};

float4 materialDiffuse : Diffuse
<
string UIWidget = "Surface Color";
string Space = "material";
> = {1.0f, 1.0f, 1.0f, 1.0f};

float4 materialSpecular : Specular
<
string UIWidget = "Surface Specular";
string Space = "material";
> = {1.0f, 1.0f, 1.0f, 1.0f};

float shininess : SpecularPower
<
string UIWidget = "slider";
float UIMin = 1.0;
float UIMax = 128.0;
float UIStep = 1.0;
string UIName = "specular power";
> = 30.0;


//------------------------------------
struct vertexInput {
float3 position : POSITION;
float3 normal : NORMAL;
float4 texCoordDiffuse : TEXCOORD0;
};

struct vertexOutput {
float4 hPosition : POSITION;
float4 texCoordDiffuse : TEXCOORD0;
float4 diffAmbColor : COLOR0;
float4 specCol : COLOR1;
};

//------------------------------------
vertexOutput VS_TransformAndTexture(vertexInput IN)
{
vertexOutput OUT;
OUT.hPosition = mul( float4(IN.position.xyz , 1.0) , worldViewProj);
OUT.texCoordDiffuse = IN.texCoordDiffuse;

//calculate our vectors N, E, L, and H
float3 worldEyePos = viewInverse[3].xyz;
float3 worldVertPos = mul(IN.position, world).xyz;
float4 N = mul(IN.normal, worldInverseTranspose); //normal vector
float3 E = normalize(worldEyePos - worldVertPos); //eye vector
float3 L = normalize( -lightDir.xyz); //light vector
float3 H = normalize(E + L); //half angle vector

//calculate the diffuse and specular contributions
float diff = max(0 , dot(N,L));
float spec = pow( max(0 , dot(N,H) ) , shininess );
if( diff <= 0 )
{
spec = 0;
}

//output diffuse
float4 ambColor = materialDiffuse * lightAmbient;
float4 diffColor = materialDiffuse * diff * lightColor ;
OUT.diffAmbColor = diffColor + ambColor;

//output specular
float4 specColor = materialSpecular * lightColor * spec;
OUT.specCol = specColor;

return OUT;
}

//------------------------------------
sampler TextureSampler = sampler_state
{
texture = <diffuseTexture>;
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
};

//-----------------------------------
float4 PS_Textured( vertexOutput IN): COLOR
{
float4 diffuseTexture = tex2D( TextureSampler, IN.texCoordDiffuse );
return IN.diffAmbColor * diffuseTexture + IN.specCol;
}

//-----------------------------------
technique textured
{
pass p0
{
VertexShader = compile vs_1_1 VS_TransformAndTexture();
PixelShader = compile ps_1_1 PS_Textured();
}
}

----------------------------------------
I'm guessing it has something to do with the view matrix or world matrix I'm passing in but am not sure what is breaking down. I did one test where I commented out the "
simpleEffect.Parameters["world"].SetValue(world);" call and it made no difference.....which is suprising as I thought the set world call would be important

Thoughts



Re: XNA Framework Problem with FX Composer generated .fx files and model position

Leaf.

Your vertex shader doesn't use the "world" parameter to calculate the output position, it uses the "worldViewProjection" parameter and you are setting that parameter to view * projection, instead of world * view * projection.

Cheers,
Leaf.






Re: XNA Framework Problem with FX Composer generated .fx files and model position

Shazen

Try these two changes.


From:
simpleEffect.Parameters["worldInverseTranspose"].SetValue(camera.view);

To:
simpleEffect.Parameters["worldInverseTranspose"].SetValue( worldInverseTranspose);

and

From:
simpleEffect.Parameters["worldViewProj"].SetValue((camera.view * camera.projection));

To:
simpleEffect.Parameters["worldViewProj"].SetValue((world * camera.view * camera.projection));
(as Leaf suggested)




Re: XNA Framework Problem with FX Composer generated .fx files and model position

Lostlogic

Shazen wrote:
Try these two changes.


From:
simpleEffect.Parameters["worldInverseTranspose"].SetValue(camera.view);

To:
simpleEffect.Parameters["worldInverseTranspose"].SetValue( worldInverseTranspose);

and

From:
simpleEffect.Parameters["worldViewProj"].SetValue((camera.view * camera.projection));

To:
simpleEffect.Parameters["worldViewProj"].SetValue((world * camera.view * camera.projection));
(as Leaf suggested)

Wow, I completely missed the fact that I did the inverted math but forgot to load the value. Thanks for catching that. It works great now! :)