Jump to content
  • Advertisement
Sign in to follow this  
davoy9

Converting LHS shader to RHS

This topic is 3260 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So the problem is, I have a nice collection of shaders written for DirectX, which assumes LHS geometry. Only problem is, I want to use them in XNA, which is RHS. Bummer! Mostly the changes are very minor, but sometimes not so easy. Attached is a shader (from RenderMonkey) which nearly works with a single change on line 54. Any shader/maths wizards out there willing to glance through the code and suggest other changes needed? An explanation would be good too, so I can work through the others myself. Code follows:

//**************************************************************//
//  Effect File exported by RenderMonkey 1.6
//
//  - Although many improvements were made to RenderMonkey FX  
//    file export, there are still situations that may cause   
//    compilation problems once the file is exported, such as  
//    occasional naming conflicts for methods, since FX format 
//    does not support any notions of name spaces. You need to 
//    try to create workspaces in such a way as to minimize    
//    potential naming conflicts on export.                    
//    
//  - Note that to minimize resulting name collisions in the FX 
//    file, RenderMonkey will mangle names for passes, shaders  
//    and function names as necessary to reduce name conflicts. 
//**************************************************************//

//--------------------------------------------------------------//
// PerPixel
//--------------------------------------------------------------//
//--------------------------------------------------------------//
// Single Pass
//--------------------------------------------------------------//
string Spherical_Harmonic_Lighting_PerPixel_Single_Pass_Teapot : ModelData = "C:\\Program Files\\AMD\\RenderMonkey 1.82\\Examples\\Media\\Models\\Teapot.3ds";

float4x4 view_proj_matrix : ViewProjection;
float4x4 view_matrix : View;
float4x4 inv_view_matrix;
//------------------------------------------------------------------//
// Spherical harmonic lighting, per-pixel illumination effect       //
//                                                                  //
// (c) Nathaniel Hoffman 2003                                       //
//                                                                  //
// Based on 'An Efficient Representation for Irradiance             //
// Environment Maps', SIGGRAPH 2001, by Ravi Ramamoorthi and Pat    //
// Hanrahan from Stanford University                                //
//------------------------------------------------------------------//

struct VS_OUTPUT
{
   float4 Pos:       POSITION;
   float4 Tex:       TEXCOORD0;
   float3 Normal:    TEXCOORD1;
   float3 Tangent:   TEXCOORD2;
   float3 Binormal:  TEXCOORD3;
};
VS_OUTPUT Spherical_Harmonic_Lighting_PerPixel_Single_Pass_Vertex_Shader_main(
   float4 vPosition: POSITION,
   float4 vNormal:   NORMAL,
   float4 vTex:      TEXCOORD,
   float4 vTangent:  TANGENT,
   float4 vBinormal: BINORMAL )
{
   VS_OUTPUT Out = (VS_OUTPUT) 0; 
   //--Out.Pos = mul(view_proj_matrix, vPosition);
   Out.Pos = mul(vPosition, view_proj_matrix);

   Out.Tex = vTex;

   // Rotate tangent basis from object/world space to view
   // space (in RenderMonkey lights are defined in view space)
   float4 nvec = float4(vNormal.x, vNormal.y, vNormal.z, 0.0);
   float4 tvec = float4(vTangent.x, vTangent.y, vTangent.z, 0.0);
   float4 bvec = float4(vBinormal.x, vBinormal.y, vBinormal.z, 0.0);

   //Out.Normal = mul(nvec, view_matrix);
   //Out.Tangent = mul(tvec, view_matrix);
   //Out.Binormal = mul(bvec, view_matrix);
   Out.Normal = mul(view_matrix, nvec);
   Out.Tangent = mul(view_matrix, tvec);
   Out.Binormal = mul(view_matrix, bvec);

   return Out;
}




float4x4 g_sh_matrix
<
   string UIName = "g_sh_matrix";
   string UIWidget = "Numeric";
   bool UIVisible =  false;
> = float4x4( -0.02, -0.02, 0.09, -0.03, -0.02, 0.02, -0.09, 0.18, 0.09, -0.09, -0.07, -0.09, -0.03, 0.18, -0.09, -0.01 );
float4x4 r_sh_matrix
<
   string UIName = "r_sh_matrix";
   string UIWidget = "Numeric";
   bool UIVisible =  false;
> = float4x4( 0.09, -0.05, 0.24, -0.15, -0.05, -0.09, -0.11, 0.20, 0.24, -0.11, -0.12, -0.17, -0.15, 0.20, -0.17, -0.07 );
float4x4 b_sh_matrix
<
   string UIName = "b_sh_matrix";
   string UIWidget = "Numeric";
   bool UIVisible =  false;
> = float4x4( -0.13, -0.05, 0.06, 0.01, -0.05, 0.13, -0.20, 0.31, 0.06, -0.20, -0.11, -0.14, 0.01, 0.31, -0.14, -0.03 );
texture bump_map_Tex
<
   string ResourceName = "C:\\Program Files\\AMD\\RenderMonkey 1.82\\Examples\\Media\\Textures\\FieldstoneBumpDOT3.tga";
>;
sampler bump_map = sampler_state
{
   Texture = (bump_map_Tex);
   MAGFILTER = LINEAR;
   MINFILTER = LINEAR;
   MIPFILTER = LINEAR;
};
texture rgb_map_Tex
<
   string ResourceName = "C:\\Program Files\\AMD\\RenderMonkey 1.82\\Examples\\Media\\Textures\\Fieldstone.tga";
>;
sampler rgb_map = sampler_state
{
   Texture = (rgb_map_Tex);
   MAGFILTER = LINEAR;
   MINFILTER = LINEAR;
   MIPFILTER = LINEAR;
};
//------------------------------------------------------------------//
// Spherical harmonic lighting, per-pixel illumination effect       //
//                                                                  //
// (c) Nathaniel Hoffman 2003                                       //
//                                                                  //
// Based on 'An Efficient Representation for Irradiance             //
// Environment Maps', SIGGRAPH 2001, by Ravi Ramamoorthi and Pat    //
// Hanrahan from Stanford University                                //
//------------------------------------------------------------------//


float4 Spherical_Harmonic_Lighting_PerPixel_Single_Pass_Pixel_Shader_main(
   float4 Tex:       TEXCOORD0,  
   float3 Normal:    TEXCOORD1,
   float3 Tangent:   TEXCOORD2,
   float3 Binormal:  TEXCOORD3 ) : COLOR
{
   float4 c;
   float3x3 rotation;
   float3 normal3;
   float4 normal4;

   // Matrix to transform from tangent space into light space)
   rotation = float3x3(Tangent, Binormal, Normal);

   // Get normal
   normal3 = tex2D(bump_map, Tex) * 2.0 - 1.0;

   // Transform normal into light space
   normal3 = mul(normal3, rotation);

   normal4 = float4(normal3, 1.0);

   // Evaluate spherical harmonic
   c.r = dot(mul(r_sh_matrix, normal4), normal4);
   c.g = dot(mul(g_sh_matrix, normal4), normal4);
   c.b = dot(mul(b_sh_matrix, normal4), normal4);
   c.a = 1.0;

   // Multiply by rgb factor (and scale by two)
   c = c * tex2D(rgb_map, Tex) * 2.0;
  
   return c;
}







//--------------------------------------------------------------//
// Technique Section for Advanced Illumination Effects.Spherical Harmonic Lighting.PerPixel
//--------------------------------------------------------------//
technique PerPixel
{
   pass Single_Pass
   {

      VertexShader = compile vs_1_1 Spherical_Harmonic_Lighting_PerPixel_Single_Pass_Vertex_Shader_main();
      PixelShader = compile ps_2_0 Spherical_Harmonic_Lighting_PerPixel_Single_Pass_Pixel_Shader_main();
   }

}

Share this post


Link to post
Share on other sites
Advertisement
Hey davoy9

I've just briefly looked through the shader and as far as I can tell there's nothing should wouldn't work in a RHS system. Generally the only difference between a LHS and RHS is the direction of the Z-axis. In a RHS system the Z values get smaller when you move down the view direction and vice versa.

The thing you will need to do however are to make sure that you're being consistent throughout the application. You cannot mix LHS and RHS matrices and expect them to return anything useful.

You will properly have to recalculate some new default SH matrices but that's it.

Again I might be mistaking to feel free to correct me if I'm wrong :)

Edit:
On a side-note I would properly start out doing something a bit less complex than a per-pixel SH lighting solution.

Share this post


Link to post
Share on other sites
Turns out there are 3 problems with this shader.
1. view_proj_matrix has to be transposed, or nothing useful happens.
2. view_matrix has to be transposed and reversed, or you get a nice view of the back of the model.
3. xna vertex stream seems not to contain binormals, so the colours come out wrong. Not sure how to fix that one yet.

Yes, I already did some simpler shaders and they seem to work OK. RenderMonkey is a good place for testing complex shaders on DX, but the challenge is then getting them to work in XNA.

Thanks for the tips.

Share this post


Link to post
Share on other sites
I did an end-run around the whole problem with XNA: I wrote a simple routine to generate a Left-handed projection matrix (and look direction matrix) in XNA, so that I could keep using the left-handed coordinate system that I'm used to :)


using Microsoft.Xna.Framework;

namespace Procyon.Math
{

public static class MatrixHelper
{
public static Matrix LookDir(Vector3 position, Vector3 dir, Vector3 up)
{
Vector3 zAxis = Vector3.Normalize(dir);
Vector3 xAxis = Vector3.Normalize(Vector3.Cross(up, zAxis));
Vector3 yAxis = Vector3.Cross(zAxis, xAxis);
Matrix a = new Matrix();

a.M11 = xAxis.X;
a.M21 = xAxis.Y;
a.M31 = xAxis.Z;
a.M41 = -Vector3.Dot(xAxis, position);

a.M12 = yAxis.X;
a.M22 = yAxis.Y;
a.M32 = yAxis.Z;
a.M42 = -Vector3.Dot(yAxis, position);

a.M13 = zAxis.X;
a.M23 = zAxis.Y;
a.M33 = zAxis.Z;
a.M43 = -Vector3.Dot(zAxis, position);

a.M14 = 0.0f;
a.M24 = 0.0f;
a.M34 = 0.0f;
a.M44 = 1.0f;
return a;
}
public static Matrix Perspective(float fov, float aspect, float zn, float zf)
{
float yScale = 1.0f / (float)System.Math.Tan(fov/2);
float xScale = yScale / aspect;

Matrix a = new Matrix();
a.M11 = xScale;
a.M22 = yScale;
a.M33 = zf/(zf-zn);
a.M34 = 1.0f;
a.M43 = -zn*zf/(zf-zn);
a.M44 = 0;
return a;
}
}
}



Problem solved! :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!