Here is the shader:
#include "basepool.fx"
#define SPEC_EXPON 64.0
#define TOX_TABLE_SIZE 256
#define TOX_FORMAT "g16r16"
// transform object vertices to world-space:
#define gWorldXf g_mWorld
// transform object normals, tangents, & binormals to world-space:
#define gWorldITXf transpose(g_mInvWorld)
// transform object vertices to view space and project them in perspective:
#define gWvpXf g_mWorldViewProj
// provide tranform from "view" or "eye" coords back to world-space:
#define gViewIXf g_mInvView
#define gLamp0Dir g_lights[0].xyz
#define gLamp0Color g_lights[0].Specular.xyz
#define gAmbiColor g_lights[0].Ambient.xyz
#define gSurfaceColor g_lights[0].Diffuse.xyz
cbuffer cbUserChange
{
float gKd;
float gKs;
float URep;
float VRep;
};
float Bumpy=1.0;
Texture2D gColorTexture;
SamplerState gColorSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
Texture2D gNormalTexture;
SamplerState gNormalSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
Texture2D gSpecTex;
SamplerState gSpecSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
//This had to be adapted because the inputs aren't right.
struct appdata {
float3 Position : POSITION;
float4 UV : TEXTURE;
float4 Normal : NORMAL;
float4 Tangent : TANGENT;
};
struct vertexOutput {
float4 HPosition : POSITION;
float2 UV : TEXCOORD0;
float3 WorldNormal : TEXCOORD1;
float3 WorldView : TEXCOORD2;
float3 WorldTangent : TEXCOORD3;
float3 WorldBinorm : TEXCOORD4;
};
vertexOutput basicVS(appdata IN,
uniform float4x4 WorldITXf,
uniform float4x4 WorldXf,
uniform float4x4 ViewIXf,
uniform float4x4 WvpXf
) {
vertexOutput OUT = (vertexOutput)0;
//recalculate binormal
float3 Binormal=cross(IN.Tangent,IN.Normal);
OUT.WorldNormal = normalize(mul(IN.Normal,WorldITXf).xyz);
OUT.WorldTangent = normalize(mul(IN.Tangent,WorldITXf).xyz);
OUT.WorldBinorm = normalize(mul(Binormal,WorldITXf).xyz);
float4 Po = float4(IN.Position.xyz,1.0); // object coordinates
float3 Pw = mul(Po,WorldXf).xyz; // world coordinates
#ifdef FLIP_TEXTURE_Y
OUT.UV = (float2(URep,-VRep) * IN.UV.xy);
#else /* ! FLIP_TEXTURE_Y */
OUT.UV = (float2(URep,VRep) * IN.UV.xy);
#endif /* ! FLIP_TEXTURE_Y */
OUT.WorldView = normalize(ViewIXf[3].xyz - Pw); // obj coords
OUT.HPosition = mul(Po,WvpXf); // screen clipspace coords
return OUT;
}
float4 toksvigPS(vertexOutput IN,
uniform float3 SurfaceColor,
uniform sampler2D NormalSampler,
uniform float Kd,
uniform float Ks,
uniform float3 LightDir,
uniform float3 LampColor,
uniform float3 AmbiColor,
uniform sampler2D SpecSampler
) : COLOR {
float3 Nn = /*normalize*/(IN.WorldNormal);
float3 Tn = /*normalize*/(IN.WorldTangent);
float3 Bn = /*normalize*/(IN.WorldBinorm);
float3 bumps = 2.0 * (tex2D(NormalSampler,IN.UV).xyz-(0.5).xxx);
float3 Na = bumps.x * Tn + bumps.y * Bn + bumps.z * Nn;
float3 Vn = normalize(IN.WorldView);
float3 Ln = /*normalize*/(-LightDir); // normalize() required? FXComposer should provide pre-norm'd value
float3 Hn = normalize(Vn + Ln);
float NaH = dot(Hn,Na);
float NaNa = dot(Na,Na);
//float2 texelAdjust = (0.5/TOX_TABLE_SIZE).xx;
//float s = tex2D(SpecSampler,float2(NaH,NaNa)+texelAdjust).x;
float s = tex2D(SpecSampler,float2(NaH,NaNa)).x;
Nn = normalize(Na);
float ldn = dot(Ln,Nn);
ldn = max(ldn,0);
float3 diffContrib = ldn * LampColor;
float3 specContrib = ((s * Ks) * LampColor);
// add, incorporating ambient light term
#ifdef DO_COLORTEX
float3 colorTex = SurfaceColor * tex2D(ColorSampler,IN.UV).xyz;
#define SURF_COLOR colorTex
#else /* !DO_COLORTEX */
#define SURF_COLOR SurfaceColor
#endif /* !DO_COLORTEX */
float3 result = SURF_COLOR*(Kd*diffContrib+AmbiColor) + specContrib;
return float4(result.xyz,1.0);
}
float4 nonToksvigPS(vertexOutput IN,
uniform float3 SurfaceColor,
uniform sampler2D NormalSampler,
uniform float Kd,
uniform float Ks,
uniform float3 LightDir,
uniform float3 LampColor,
uniform float3 AmbiColor
) : COLOR {
float3 Nn = normalize(IN.WorldNormal);
float3 Tn = normalize(IN.WorldTangent);
float3 Bn = normalize(IN.WorldBinorm);
float3 bumps = (Bumpy*2.0) * (tex2D(NormalSampler,IN.UV).xyz-(0.5).xxx);
Nn = (bumps.x*Tn + bumps.y*Bn + bumps.z*Nn);
Nn = normalize(Nn);
float3 Vn = normalize(IN.WorldView);
float3 Ln = normalize(-LightDir); // normalize() required?
float3 Hn = normalize(Vn + Ln);
float hdn = dot(Hn,Nn);
float ldn = dot(Ln,Nn);
float4 litVec = lit(ldn,hdn,SPEC_EXPON);
float3 diffContrib = litVec.y * LampColor;
float3 specContrib = ((litVec.z * Ks) * LampColor);
// add, incorporating ambient light term
#ifdef DO_COLORTEX
float3 colorTex = SurfaceColor * tex2D(ColorSampler,IN.UV).xyz;
#define SURF_COLOR colorTex
#else /* !DO_COLORTEX */
#define SURF_COLOR SurfaceColor
#endif /* !DO_COLORTEX */
float3 result = SURF_COLOR*(Kd*diffContrib+AmbiColor) + specContrib;
return float4(result.xyz,1.0);
}
RasterizerState DisableCulling { CullMode = NONE; };
DepthStencilState DepthEnabling { DepthEnable = TRUE; };
DepthStencilState DepthDisabling {
DepthEnable = FALSE;
DepthWriteMask = ZERO;
};
BlendState DisableBlend { BlendEnable[0] = FALSE; };
technique10 Toksvig10{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, basicVS(gWorldITXf,gWorldXf,
gViewIXf,gWvpXf) ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, toksvigPS(gSurfaceColor,gNormalSampler,
gKd,gKs,gLamp0Dir,gLamp0Color,gAmbiColor,gSpecSampler) ) );
SetRasterizerState(DisableCulling);
SetDepthStencilState(DepthEnabling, 0);
SetBlendState(DisableBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF);
}
}
technique10 Non_Toksvig10{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, basicVS(gWorldITXf,gWorldXf,
gViewIXf,gWvpXf) ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, nonToksvigPS(gSurfaceColor,gNormalSampler,
gKd,gKs,gLamp0Dir,gLamp0Color,gAmbiColor) ) );
SetRasterizerState(DisableCulling);
SetDepthStencilState(DepthEnabling, 0);
SetBlendState(DisableBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF);
}
}
Save to effectsbank/common and name however you like (e.g. NormalMap.fx). Do not try to add the shader to a dynamic entity in editor mode - it will crash same as it does if you try to add bumpent.fx in the editor. Add the shader to the FPE file.
To view the ps3 shader go to:
http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html
And find "Toksvig NormalMaps"