Alright, I'm at my wit's end with this shader.
I am trying to make a shader that does the following:
- Accepts information from 8 lights
- Uses those lights in the calculation for normal mapping
- Applies a DarkLights generated lightmap onto object
- Applies an Illumination Map onto object
From what I can tell.... this should work, but it doesn't. (How often does THAT happen when programming?
)
I loaded this shader into FX Composer and it told me that the error it's getting is that I'm doing too much arithmetic!! Well, that's really lame.
Here's the effect:
string Description = "This shader uses preview lights to produce per pixel normal mapped lighting. This shader requires lights.";
string Thumbnail = "Normal Mapping.png";
//--------------
//Untweakables
//--------------
float4x4 WorldViewProj : WorldViewProjection;
float4x4 World : World;
float4x4 WorldT : WorldTranspose;
float4x4 WorldIT : WorldInverseTranspose;
float4 LightPos[8] : LIGHTPOSITION;
float3 LightColor[8] : LIGHTCOLOR;
float3 AmbiColor : AMBIENTCOLOR;
float3 eyepos : CameraPosition;
float time : TIME;
//--------------
//Tweakables
//--------------
float SpecularPower1
<
string UIWidget = "slider";
float UIMax = 30;
float UIMin = 1;
> = 15;
texture LM
<
string ResourceName = "";
>;
sampler diffuse_smp = sampler_state
{
Texture = <LM>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
texture D
<
string ResourceName = "";
>;
sampler diffuse2_smp = sampler_state
{
Texture = <D>;
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
texture I
<
string ResourceName = "";
>;
sampler illummap_smp = sampler_state
{
Texture = <I>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
texture N
<
string ResourceName = "";
>;
sampler normalmap_smp = sampler_state
{
Texture = <N>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
struct app_in
{
float4 pos : POSITION;
float3 normal : NORMAL0;
float3 tangent : TANGENT0;
float3 binormal : BINORMAL0;
float2 uv : TEXCOORD0;
float2 lm : TEXCOORD1;
};
struct vs_out
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float2 lm : TEXCOORD2;
float3 tangent : TEXCOORD3;
float3 binormal : TEXCOORD4;
float4 wpos : TEXCOORD5;
};
vs_out VS( app_in IN )
{
vs_out OUT;
float4 pos = mul( IN.pos, WorldViewProj );
OUT.pos = pos;
OUT.wpos = mul( IN.pos, World );
OUT.uv = IN.uv;
float3 normal = normalize(mul(IN.normal.xyz,(float3x3)World ));
float3 tangent = normalize(mul(IN.tangent.xyz,(float3x3)World ));
float3 binormal = normalize(mul(IN.binormal.xyz,(float3x3)World ));
//smooth out the tangents and binormals with the normals
float3 b = normalize(cross( normal,tangent ));
b *= sign(dot(b,binormal));
float3 t = normalize(cross( normal,b ));
t *= sign(dot(t,tangent));
float3 t2 = normalize(cross( normal,binormal ));
t2 *= sign(dot(t2,tangent));
float3 b2 = normalize(cross( normal,t2 ));
b2 *= sign(dot(b2,binormal));
//pass normal, tangent, and binormal to pixel shader
OUT.normal = normal;
OUT.tangent = normalize((t+t2)*0.5);
OUT.binormal = normalize((b+b2)*0.5);
OUT.lm = IN.lm;
return OUT;
}
float luminance ( float3 rgb )
{
return rgb.r*0.3 + rgb.g*0.59 + rgb.b*0.11;
}
float4 PS( vs_out IN, uniform int numLights ) : COLOR
{
float3 color = AmbiColor;
float3 n = normalize(IN.normal);
float3 t = normalize(IN.tangent);
float3 b = normalize(IN.binormal);
//build transpose matrix
float3x3 TangentSpace = {t,b,n};
TangentSpace = transpose(TangentSpace);
n = normalize(tex2D(normalmap_smp, IN.uv)*2 - 1);
float3 e = normalize(eyepos - IN.wpos);
float eyeDist = length(eyepos - IN.wpos);
e = mul(e,TangentSpace);
float4 texColor = tex2D( diffuse2_smp, IN.uv );
//cycle through all lights, number depending on technique chosen
for ( int i = 0; i < numLights; i++ )
{
float range = LightPos[i].w;
if ( range > 0 )
{
float3 l = (LightPos[i].xyz - IN.wpos.xyz);
l = mul(l,TangentSpace);
//calculate attenuation
float dist = length(l);
float att = saturate((range-dist) / range);
//calculate diffuse lighting
l = normalize(l);
float diffuse = saturate(dot(n,l));
//caculate specular lighting
float3 h = normalize(l+e);
float spec = pow( saturate(dot(n,h)), SpecularPower1 )*(1-pow(1-diffuse,10));
//add to final color
color += (diffuse * att * LightColor[i]) + (spec * att * LightColor[i] * smoothstep(0.3,0.6,luminance(texColor.xyz)));
}
}
return (float4(color,1.0)+tex2D(diffuse_smp, IN.lm)+tex2D(illummap_smp, IN.uv)) * texColor;
}
//choose the technique corresponding to the number of lights in your application
technique PerPixelLighting
{
pass p0
{
VertexShader = compile vs_2_0 VS( );
PixelShader = compile ps_2_0 PS( 8 );
}
}
Now.. if I make the pixel shader compile with PS3.0, FX Composer doens't find anything wrong with, but it's still messing up when I try to use it like that. (AKA, the object turns invisible, which apparently is the standard red flag that the shader has encountered an error)
Here's the thing. If I change this line:
color += (diffuse * att * LightColor[i]) + (spec * att * LightColor[i] * smoothstep(0.3,0.6,luminance(texColor.xyz)));
to:
then the shader will actually work...... you know, minus the normal mapping and per pixel lighting.
As soon as I tell the LightColor to do any sort of arithmetic against anything on that line, it goes back to giving me an error.
I've been staring at and fiddling with this shader for a day and a half now, and I figured it was time to go ask for some assistance from the shader group.
Is there a way that I can get this to do what I want it to while still using PS2.0?
[EDIT]
Forgot to mention that this is the "NormalMapping" shader from DarkShader. I've simply added the DarkLights lightmapping texture and the illumination map.
[EDIT2]
The Lightmapping texture is applied properly.. and the strange thing is, the only time it will apply properly is if the "lm" texcoord starts as TEXCOORD1 and is then passed into TEXCOORD2 in the pixel shader. I don't quite understand why it won't work with any other texcoord numbers, so if someone could explain that to me as well, I'd be very greatful.
The one and only,