while porting Brice's BRDF shader, I made some notes on the differences of each, so when the job needs to be done again, it would mean less work.
///////////////////////////
// GUI / Texture Init
// CgFx Maya:
// -------------
float4 LightPos : Position
<
string UIName = "LightPosition";
string Object = "PointLight";
//string Space = "World"; // maya allows object/world space
// (if not specified then object)
> = {-54.0f, 50.0f, 100.0f, 1.0f};
float3 LightColor
<
string type = "color";
string UIName = "LightColor";
string UIWidget = "Color";
> = {1.0, 1.0, 1.0};
string UIWidget = "slider";
texture BRDF
<
string Name = "brdf.tga"; // allows you to load stuff by default
string UIName = "BRDF";
string ResourceType = "2D";
>;
sampler2D diffuseSampler = sampler_state
{
Texture = <diffuseTexture>;
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
LODBias = -.5 ;
WrapS = ClampToEdge;
WrapT = ClampToEdge;
WrapR = ClampToEdge;
};
// Fx 3dsMax:
// -------------
float4 LightPos : Position
<
string UIName = "Light";
string Object = "OmniLight";
string Space = "World"; // max always feeds as world
int RefID = 0;
> = {-54.0f, 50.0f, 100.0f, 1.0f};
float4 LightColor : LightColor <
int LightRef = 0;
> = float4( 1.0f, 1.0f, 1.0f, 1.0f ); // diffuse
string UIType = "FloatSpinner";
texture DetailTex : MapDetail <
string UIName = "TextureDetail";
string type = "CUBE"; // only needed for non 2D maps
int Texcoord = 1; // which texcoord gets which mapchannel, also creates spinner for user
int MapChannel = 1;
>;
sampler2D diffuseSampler = sampler_state
{
Texture = <diffuseTexture>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipMapLodBias = -.5 ;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
///////////////////////////
// Input data
// CgFx Maya:
// -------------
// maya allows the user to script texcoord inputs
struct vIN
{
float4 Position : POSITION;
half3 Normal : NORMAL;
half4 Color : COLOR0;
half2 TexCoord : TEXCOORD0;
half3 Tangent : TEXCOORD1;
half3 Binormal : TEXCOORD2;
};
// Fx 3dsMax:
// -------------
// 3dsmax always computes tangent/binormal for channel 1
// Textures Enforce channel 1
int texcoord0 : Texcoord
<;
int Texcoord = 0;
int MapChannel = 1;
>;
// 3dsmax can only pass vertexcolor (without alpha) as texcoord
// Vertexcolor
int texcoord1 : Texcoord
<
int Texcoord = 1;
int MapChannel = 0; // -2 is valpha, -1 is illum
>;
// max feeds tangents via semantix (always for map channel 1)
struct vIN
{
float4 Position : POSITION;
half3 Normal : NORMAL;
half2 TexCoord : TEXCOORD0;
half4 Color : TEXCOORD1;
half3 Tangent : TANGENT;
half3 Binormal : BINORMAL;
};
///////////////////////////
// Shader Stuff
// CgFx Maya:
// -------------
// matrices stored column major
mul(wvpMatrix, IN.Position)
half3 EyePos = wvMatrixIT[3].xyz
// lightpos in objectspace
half3 LightDir = normalize(LightPos.xyz - IN.Position.xyz);
half3 wLightDir = mul(wMatrix, half4(LightDir.xyz, 0.0)).xyz;
// Fx 3dsMax:
// -------------
// all matrices are transposed form of Cg
// so reverse stuff (just putting "Transpose" at end of semantics, didnt work)
mul(float4(inpos, 1),(float4x4)World)
half3 EyePos = wvMatrixI[3].xyz; // none transposed
// Lightpos in world space
half3 wPos = mul(IN.Position,wMatrix).xyz;
half3 wLightDir = normalize(LightPos.xyz - wPos);
// cubemaps need different lookup, 3dsmax is Z up
float3 texcoordCubeSwizzle(float3 ref){
return float3(ref.x,ref.z,ref.y);
}
// (if x*Tangent, y*Binormal,z*Normal is used) normal maps need swizzle
float3 normalSwizzle(float3 ref){
return float3(ref.y,ref.x,ref.z);
}
///////////////////////////
// Technique
// CgFx Maya:
// -------------
CullFaceEnable=false;
DepthTestEnable=true;
DepthMask = true;
DepthFunc = LEqual;
VertexProgram = compile arbvp1 MainVS2();
FragmentProgram = compile fp40 Gloss2PS();
// Fx 3dsMax:
// -------------
AlphaBlendEnable = FALSE;
CullMode = CW;
ZWriteEnable = TRUE;
ZFunc = LESSEQUAL;
ZEnable = TRUE;
VertexShader = compile vs_1_1 MainVS2();
PixelShader = compile ps_3_0 Gloss2PS();
///////////////////////////
// Compile Profiles
//
// In theory Cg can compile to GLSL, which then is compiled by driver
// however GLSL output is still buggy, and there are no "standards"
// on whether a program runs or not, it completely depends on the hardware
//
// Directx OpenGL/Cg
//
// Vertex
//
// for regular stuff, still fairly common, most work is done in pixelshaders
// in todays games
// vs_1_1 arbvp1
//
// more complex (allows static flow control, ie uniform parameter
// "if switches" or for loops)
// static means all vertices run thru the same thing
// 2_x also brought dynamic flow control, ie per-vertex/pixel
// different code paths)
//
// vs_2_0
// vs_2_x vp30 (only nvidia)
//
// recent stuff texture lookups in vertexshader
// vs_3_0 vp40 (only nvidia)
// glslv (all, buggy)
// Pixel
//
// old <= GeForce4 stuff, still sufficient for simple normalmaps and
// texture combining
//
// ps_1_0 fp20 (only nvidia)
// ps_1_1
// ps_1_2
// ps_1_3
// ps_1_4
//
// what most hardware has today (Radeon 9600, GeforceFX and up)
// ps_2_0 arbfp1
// ps_2_a
// ps_2_b
//
// fastly becoming popular (Radeon X1300, GeForce 6xxx)
// ps_3_0 fp40 (only nvidia)
// glslf (might work not sure, buggy)
maybe it helps if someone else wants to provide shaders for both apps.
edit1: added normalmap swizzle for max (if x*Tangent, y*Binormal,z*Normal is used)
edit2: bug in max vertexcolor statement (channel 0 is vcolor)