If you are using a normal map (the funky colored kind) you can use blend mapping without a shader. The resulting details look deeper.
However, here is a simple single pass shader that uses,
- A base color (I use it to allow the player to choose a custom color)
- An Alpha map (to allow the base color to show through)
- A normal map
- A color map (for the actual color details)
- A specular map
- An emissive map
Just strip out the parts you don't need.
//------------------------------------------------
// NormalMapping with Alpha mask, Base Color, Specular mask and Emissive
//------------------------------------------------
// By Evolved
// http://www.vector3r.com/
// Modified by Revenant_Chaos
// Modified more by KISTech and Green Gandalf
//--------------------------------
//-----------------
// un-tweaks
//-----------------
matrix WorldVP : WorldViewProjection;
matrix World : World;
matrix ViewInv : ViewInverse;
//-----------------
// tweaks
//-----------------
float4 Ambient = {0.1f, 0.1f, 0.1f, 1.0f};
float4 LightPosition = {0.0f, 0.0f, 0.0f, 1.0f};
float4 LightColor = {1.0f, 1.0f, 1.0f, 1.0f};
float LightRange = 500000.0f;
float U = 1.0f;
float V = 1.0f;
float SpecPower = 4.0f;
float SpecBright = 2.5f;
float EmisPower = 1.0f;
//-----------------
// Textures
//-----------------
texture BaseTX
<
string Name="";
>;
sampler2D Base = sampler_state
{
texture = <BaseTX>;
};
texture AlphaTX
<
string Name="";
>;
sampler2D Alpha = sampler_state
{
texture = <AlphaTX>;
};
texture DiffuseTX
<
string Name="";
>;
sampler2D Diffuse = sampler_state
{
texture = <DiffuseTX>;
};
texture NormalTX
<
string Name="";
>;
sampler2D Normal = sampler_state
{
texture = <NormalTX>;
};
texture SpecTX
<
string Name="";
>;
sampler2D SpecMap = sampler_state
{
texture = <SpecTX>;
};
texture EmissiveTX
<
string Name="";
>;
sampler2D EmissiveMap = sampler_state
{
texture = <EmissiveTX>;
};
//-----------------
// structs
//-----------------
struct input
{
float4 Pos:POSITION;
float2 UV:TEXCOORD;
float3 Normal:NORMAL;
float3 Tangent:TANGENT;
float3 Binormal:BINORMAL;
};
struct output
{
float4 OPos:POSITION;
float2 Tex:TEXCOORD0;
float3 LightVec:TEXCOORD1;
float3 Attenuation:TEXCOORD2;
float3 ViewVec:TEXCOORD3;
};
//-----------------
// vertex shader
//-----------------
output VS_L1(input IN)
{
output OUT;
OUT.OPos=mul(IN.Pos,WorldVP);
OUT.Tex=IN.UV*float2(U,V);
float3 WNor=mul(IN.Normal,World); WNor=normalize(WNor);
float3 Wtan=mul(IN.Tangent,World); Wtan=normalize(Wtan);
float3 Wbin=mul(IN.Binormal,World); Wbin=normalize(Wbin);
float3 WPos=mul(IN.Pos,World);
float3x3 TBN={Wtan,Wbin,WNor}; TBN=transpose(TBN);
float3 LightPos=LightPosition-WPos;
float3 ViewPos=ViewInv[3].xyz-WPos;
OUT.LightVec=mul(LightPos,TBN);
OUT.Attenuation=-LightPos/LightRange;
OUT.ViewVec=mul(ViewPos,TBN);
return OUT;
}
//-----------------
// pixel shader
//-----------------
float4 PS_L1(output IN) : COLOR
{
float4 BaseColor=tex2D(Base,IN.Tex);
float4 AlphaMap=tex2D(Alpha,IN.Tex);
float4 Texture=tex2D(Diffuse,IN.Tex);
float4 SpecTex=tex2D(SpecMap,IN.Tex);
float4 Emissive=tex2D(EmissiveMap,IN.Tex);
float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
NormalMap=normalize(NormalMap);
float3 LightV=normalize(IN.LightVec);
float3 View=normalize(IN.ViewVec);
float Normal=saturate(dot(NormalMap,LightV));
float Specular=saturate(dot(reflect(-View,NormalMap),LightV));
Specular=pow(Specular,SpecPower)*(SpecTex*SpecBright);
float4 DiffuseLight=1-saturate(dot(IN.Attenuation,IN.Attenuation));
float4 Light=DiffuseLight*LightColor*SpecTex;
float4 AlphaBlend=BaseColor*AlphaMap;
return ((AlphaBlend+Texture)*(((1+Specular)*Normal*Light)+Ambient))+(Emissive*EmisPower);
}
//-----------------
// techniques
//-----------------
technique ShipShader
{
pass p1
{
vertexShader = compile vs_2_0 VS_L1();
pixelShader = compile ps_2_0 PS_L1();
}
}
