Fx Composer 2 Metal Shader Doesn'T Draw Correctly With Xna?

Started by
2 comments, last by Spa8nky 13 years, 3 months ago
I'm using a metal shader obtained from FX and I've commented it so it makes more sense to me. The problem is that the vertex shader:



// Data from application vertex buffer [XNA]
struct appdata
{
float3 Position : POSITION0;
float4 UV : TEXCOORD0;
float4 Normal : NORMAL0;
float4 Tangent : TANGENT0;
float4 Binormal : BINORMAL0;
};


vertexOutput VertexShaderFunction(appdata IN,
uniform float4x4 WorldITXf, // our four standard "untweakable" xforms
uniform float4x4 WorldXf,
uniform float4x4 ViewIXf,
uniform float4x4 WvpXf,
uniform float3 LampDir
)
{
vertexOutput OUT = (vertexOutput)0;

OUT.WorldNormal = mul(WorldITXf,IN.Normal).xyz;
OUT.WorldTangent = mul(WorldITXf,IN.Tangent).xyz;
OUT.WorldBinormal = mul(WorldITXf,IN.Binormal).xyz;

float4 Po = float4(IN.Position.xyz,1); // Homogeneous location coordinates (object)
float4 Pw = mul(WorldXf,Po); // Convert to "world" space

#ifdef OBJECT_SPACE_LIGHTS
float4 Lo = float4(LampDir.xyz,0.0); // Light in object space
float4 Lw = mul(WorldXf,Lo); // Convert to "world" space
OUT.LightVec = -normalize(Lw).xyz;
#else /* !OBJECT_SPACE_LIGHTS -- standard world-space lights */
OUT.LightVec = -normalize(LampDir);
#endif

#ifdef FLIP_TEXTURE_Y
OUT.UV = float2(IN.UV.x,(1.0-IN.UV.y));
#else
OUT.UV = IN.UV.xy;
#endif

OUT.WorldView = normalize(float3(ViewIXf[0].w,ViewIXf[1].w,ViewIXf[2].w) - Pw.xyz);
OUT.HPosition = mul(WvpXf,Po);

return OUT;
}



is producing this result:

MetalShaderProblem.png


instead of draw a box.

I'm setting the HLSL parameters as follows:




effect.Parameters["gViewIXf"].SetValue(Matrix.Invert(game.ActiveCamera.ViewMatrix));
effect.Parameters["gWorldXf"].SetValue(worldTransform);
effect.Parameters["gWorldITXf"].SetValue(Matrix.Invert(Matrix.Transpose(worldTransform)));
effect.Parameters["gWvpXf"].SetValue(worldTransform * game.ActiveCamera.ViewProjectionMatrix);


The model used has all the correct elements in its vertex format for input:




struct appdata
{
float3 Position : POSITION0;
float4 UV : TEXCOORD0;
float4 Normal : NORMAL0;
float4 Tangent : TANGENT0;
float4 Binormal : BINORMAL0;
};


My view matrix is created as follows:



// Make our view matrix
Matrix.CreateFromQuaternion(ref orientation, out matrix_View);

matrix_View.M41 = -Vector3.Dot(Right, position);
matrix_View.M42 = -Vector3.Dot(Up, position);
matrix_View.M43 = -Vector3.Dot(-Forward, position);
matrix_View.M44 = 1.0f;

// Create the combined view-projection matrix
Matrix.Multiply(ref matrix_View, ref matrix_Projection, out matrix_ViewProj);



My projection matrix is created like so:



private void Perspective(float aspect_Ratio, float z_NearClipPlane, float z_FarClipPlane)
{
nearClipPlaneZ = z_NearClipPlane;
farClipPlaneZ = z_FarClipPlane;

float yZoom = 1.0f / (float)Math.Tan(MathHelper.ToRadians(GlobalSettings.FOV_X) * 0.5f);
float xZoom = yZoom / aspect_Ratio;

matrix_Projection.M11 = xZoom;
matrix_Projection.M12 = 0.0f;
matrix_Projection.M13 = 0.0f;
matrix_Projection.M14 = 0.0f;

matrix_Projection.M21 = 0.0f;
matrix_Projection.M22 = yZoom;
matrix_Projection.M23 = 0.0f;
matrix_Projection.M24 = 0.0f;

matrix_Projection.M31 = 0.0f;
matrix_Projection.M32 = 0.0f;
matrix_Projection.M33 = z_FarClipPlane / (nearClipPlaneZ - farClipPlaneZ);
matrix_Projection.M34 = -1.0f;

matrix_Projection.M41 = 0.0f;
matrix_Projection.M42 = 0.0f;
matrix_Projection.M43 = (nearClipPlaneZ * farClipPlaneZ) / (nearClipPlaneZ - farClipPlaneZ);
matrix_Projection.M44 = 0.0f;
}


Can anyone please explain what might be causing this issue as I can't figure it out.
Advertisement
Are you setting the LampDir parameter anywhere? Your screenshot is too dark to see what's going on...is the geometry being transformed properly? In other words...if you set the pixel shader to just output 1, does the box still have the correct shape?

You also want to be careful with your normals, tangents, and binormals. These vectors are directions, not positions, and thus you only want to rotate them and not translate them. Typically in a vertex shader you take them as float3 inputs, and then transform them by your matrix cast to a (float3x3). Or alternatively, you can set the W component to 0. This ensures that no translation occurs.

OUT.WorldNormal = mul(IN.Normal.xyz, (float3x3)WorldITXf);
OUT.WorldNormal = mul(float4(IN.Normal.xyz, 0.0f), WorldITXf).xyz;
[font=arial, verdana, tahoma, sans-serif][size=2]<br /> [size=2]Thanks MJP.<br /> [size=2]<br /> <br /> [size=2]<code><br /> [size=2]Are you setting the LampDir parameter anywhere?<br /> [size=2]</code><br /> <br /> [size=2]<br /> <br /> [size=2]Yes, it is constant for the time being as I&#39;m not setting it in XNA:<br /> [size=2]<br /> <br /> [size=2]<code><br /> [size=2]<br /> float3 gLamp0Dir : DIRECTION &lt;<br /> string Object = &quot;DirectionalLight0&quot;;<br /> string UIName = &quot;Lamp 0 Direction&quot;;<br /> string Space = (LIGHT_COORDS);<br /> &gt; = {0.7f,-0.7f,-0.7f};<br /> [size=2]</code>[size=2]<br /> <br /> [size=2]<br /> <br /> [size=2]<code><br /> <br /> [size=2]Your screenshot is too dark to see what&#39;s going on…is the geometry being transformed properly? In other words…if you set the pixel shader to just output 1, does the box still have the correct shape?<br /> [size=2]</code><br /> [size=2]<br /> <br /> [size=2]The geometry is not being transformed properly:<br /> [size=2]<br /> <br /> <img src='http://www.rhysperkins.com/XNA/MetalShaderProblem2.png' alt='MetalShaderProblem2.png'><br /> <br /> <br /> <blockquote><br /> You also want to be careful with your normals, tangents, and binormals. These vectors are directions, not positions, and thus you only want to <span style="font-weight:bold;">rotate</span> them and not translate them. Typically in a vertex shader you take them as float3 inputs, and then transform them by your matrix cast to a (float3x3). Or alternatively, you can set the W component to 0. This ensures that no translation occurs.<br /> <br /> <br /> <br /> <br /> Casting the transform matrix to a (float3x3) also made no difference:<br /> <br /> <br /> <code><br /> <br /> //OUT.WorldNormal = mul(WorldITXf,IN.Normal).xyz;<br /> //OUT.WorldTangent = mul(WorldITXf,IN.Tangent).xyz;<br /> //OUT.WorldBinormal = mul(WorldITXf,IN.Binormal).xyz;<br /> <br /> OUT.WorldNormal = mul((float3x3)WorldITXf,IN.Normal).xyz;<br /> OUT.WorldTangent = mul((float3x3)WorldITXf,IN.Tangent).xyz;<br /> OUT.WorldBinormal = mul((float3x3)WorldITXf,IN.Binormal).xyz;<br /> </code><br /> <br /> <br /> <br /> If I change the input struct as follows:<br /> <br /> <br /> <code><br /> <br /> // Data from application vertex buffer [XNA]<br /> struct appdata <br /> {<br /> float3 Position : POSITION0;<br /> float2 UV : TEXCOORD0;<br /> float3 Normal : NORMAL0;<br /> float3 Tangent : TANGENT0;<br /> float3 Binormal : BINORMAL0;<br /> };<br /> </code><br /> <br /> <br /> <br /> Then that made no difference either.<br /> <br /> <br /> Changing the order of multiplication for the transforms:<br /> <br /> <br /> <code><br /> <br /> OUT.WorldNormal = mul(IN.Normal,WorldITXf).xyz;<br /> OUT.WorldTangent = mul(IN.Tangent,WorldITXf).xyz;<br /> OUT.WorldBinormal = mul(IN.Binormal,WorldITXf).xyz;<br /> </code><br /> <br /> <br /> <br /> Didn&#39;t change a thing.<br /> <br /> <br /> What else could it be?
OK I've solved it!

I must remember:

1) XNA != DirectX even though XNA is wrapper for DirectX.
2) Coordinate handedness is Left for DirectX BUT Right for XNA

FX Composer must export .fx files for DirectX?!

Therefore I just need change transform mul order and everything is good again. :)

Thanks for the help.

This topic is closed to new replies.

Advertisement