Specular map diffuse shader
by Jameson Bennett · in Torque Game Engine Advanced · 05/25/2005 (10:12 am) · 9 replies
There's been some demand for a diffuse color bump mapped shader that uses a bitmap to define the specular color, attenuation and power rather than individual values. This allows artists freedom to play around and create interesting materials. With differing specular values a wide range of visual 'texture' can be defined. I put together a quick example to post on the forums based on the procedural textures generated by TSE. Hopefully it will help others mess around a bit with this technique. Feel free to use as needed, I've added comments in the pixel shader file to illustrate how to change the alpha channels used.
NOTE: this shader has not been profiled nor optimized. I expect it may not be too bad, but does involve another texture lookup vs. the standard shader and a few more calculations (muls and adds). I also have been lazy and only compiled under 2.0 to test that it works as expected: you may be able to compile and run it under an earlier version.
in materials.cs: (server/scripts)
in shaders.cs: (server/scripts)
in materialMap.cs: (data)
NOTE: this shader has not been profiled nor optimized. I expect it may not be too bad, but does involve another texture lookup vs. the standard shader and a few more calculations (muls and adds). I also have been lazy and only compiled under 2.0 to test that it works as expected: you may be able to compile and run it under an earlier version.
in materials.cs: (server/scripts)
datablock CustomMaterial(MySpecMapCustomMat)
{
version = 2.0;
texture[0] = "~/data/test/myskin";
texture[1] = "~/data/test/myskinNorm";
texture[2] = "~/data/test/myskinSpec";
shader = JSkinSpecMap;
};Of course make sure the above myskin matches your myskin.png files.in shaders.cs: (server/scripts)
datablock ShaderData( JSkinSpecMap )
{
DXVertexShaderFile = "shaders/JSkinSpecMapV.hlsl";
DXPixelShaderFile = "shaders/JSkinSpecMapP.hlsl";
pixVersion = 2.0;
};in materialMap.cs: (data)
addMaterialMapping("mydtsmodeltexture", "material: MySpecMapCustomMat");About the author
jam3son.com
Recent Threads
#2
Let me know how it works out!
05/25/2005 (10:14 am)
Finally the Pixel shader, save as JSkinSpecMapP.hlsl in the shaders directory://*****************************************************************************
// OSJ basic skin pixel shader
// Based on TSE procedural shader
// modifications:
// specular map rgb used for specular color,
// spec alpha used for specular power (range 1-128)
// black will not bring the specular to a power (ie spec^1),
// white will bring spec^128
// specular attenuation is still controlled by the diffuse color map alpha channel.
// black will show no specular (fully attenuated), white will show full specular
//*****************************************************************************
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct ConnectData
{
float2 texCoord : TEXCOORD0;
float4 lightVec : TEXCOORD2;
float3 pixPos : TEXCOORD3;
float3 eyePos : TEXCOORD4;
};
struct Fragout
{
float4 col : COLOR0;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Fragout main( ConnectData IN,
uniform sampler2D diffuseMap : register(S0),
uniform sampler2D bumpMap : register(S1),
uniform sampler2D specMap : register(S2),
uniform float4 ambient : register(C2)
)
{
Fragout OUT;
//Diffuse
float4 diffuseColor = tex2D(diffuseMap, IN.texCoord);
OUT.col = diffuseColor;
//Bump
float4 bumpNormal = tex2D(bumpMap, IN.texCoord);
float4 bumpDot = saturate( dot(bumpNormal.xyz * 2.0 - 1.0, IN.lightVec.xyz) );
OUT.col *= bumpDot + ambient;
//Specular
float3 eyeVec = normalize(IN.eyePos - IN.pixPos);
float3 halfAng = normalize(eyeVec + IN.lightVec.xyz);
float specular =
saturate( dot(bumpNormal.xyz * 2.0 - 1.0, halfAng) ) * IN.lightVec.w;
//SpecMap-->
//get data from the specular map
float4 specColor = tex2D(specMap, IN.texCoord);
//tighten edge of specular based on power defined by the specMap alpha channel
//scale and offset for 1-128 scale
specular = pow(specular, (specColor.a * 127) +1);
//change '127' to change the overall range
//blend in and attenuate according to the diffuse color alpha
//exhange the above specColor.a with the below diffuseColor.a
//if you want to use the channels differently
//or possibly use bumpNormal.a for either if you want to
//use the normal map alpha channel
OUT.col += specColor * specular * diffuseColor.a;
//SpecMap<--
return OUT;
}Let me know how it works out!
#3
05/25/2005 (1:15 pm)
Nice..
#4
02/25/2008 (2:17 am)
The hlsl code does not seem to be compatible with the current TGEA 1.0.3.
#5
02/25/2008 (5:53 am)
Replace "datablock" with "new" and it should work.
#6
That done I'd like to submit it to the community as a resource...
JoZ
02/25/2008 (12:45 pm)
Jameson, sometime ago I merged 2 shaders submitted as resources in order to have a Parallax shader capable of specular and dynamic lights... What i think it miss is specular based on a texture instead of having the material completely specular... Dou you think you can take a look into it?That done I'd like to submit it to the community as a resource...
JoZ
#7
03/23/2008 (10:52 pm)
Thanks - just what I was looking for :)
#8
06/20/2008 (12:20 pm)
Any idea why no matter what color I put for the sun's ambient color in the mission editor, the ambient value in this shader is always gray?
Torque 3D Owner Jameson Bennett
//***************************************************************************** // OSJ basic skin vertex shader // Based on TSE procedural shader // modified to correct for normal map issue //***************************************************************************** //----------------------------------------------------------------------------- // Structures //----------------------------------------------------------------------------- struct VertData { float2 texCoord : TEXCOORD0; float3 T : TEXCOORD2; float3 B : TEXCOORD3; float3 N : TEXCOORD4; float3 normal : NORMAL; float4 position : POSITION; }; struct ConnectData { float4 hpos : POSITION; float2 outTexCoord : TEXCOORD0; float4 outLightVec : TEXCOORD2; float3 pos : TEXCOORD3; float3 outEyePos : TEXCOORD4; }; //----------------------------------------------------------------------------- // Main //----------------------------------------------------------------------------- ConnectData main( VertData IN, uniform float4x4 modelview : register(C0), uniform float3 inLightVec : register(C24), uniform float3 eyePos : register(C20), uniform float4x4 objTrans : register(C12) ) { ConnectData OUT; OUT.hpos = mul(modelview, IN.position); OUT.outTexCoord = IN.texCoord; float3x3 objToTangentSpace; objToTangentSpace[0] = IN.T; objToTangentSpace[1] = IN.B; //WORKAROUND //this: objToTangentSpace[2] = IN.normal; //was originally (uncomment below and comment out above //to use this shader for interiors): //objToTangentSpace[2] = IN.N; //should be changed back after ms3 when IN.N is fixed for ts OUT.outLightVec.xyz = -inLightVec; OUT.outLightVec.xyz = mul(objToTangentSpace, OUT.outLightVec); OUT.pos = mul(objToTangentSpace, IN.position.xyz / 100.0); OUT.outEyePos.xyz = mul(objToTangentSpace, eyePos.xyz / 100.0); OUT.outLightVec.w = step( 0.0, dot( -inLightVec, IN.normal ) ); return OUT; }