/****************************************************************************** Copyright Alex Hogan, 2006 The author accepts no liability from your use or misuse of the content provided here. Use at your own risk. This work is derived from the cg Blinn Material.cgfx included with Alias Maya 7.0, and although it has been modified heavily some pieces or the original shader remain. Description: This is my uber character shader. It features: - Regular Color, Normal, Specular, Glossy, and Ambient Occlusion Maps - Cubic Reflection and Ambient Light - Real basic Sub-Surface scattering hack - 2 Directional lights for highlights, Blinn model for specularity - It has an alpha technique, although Maya doesn't sort that well It gets me what I want for characters inside of Maya, however, it's certainly not optimized for real-time use, unless you are making a game with few character on screen at once. Just a quick warning on this one - all the comments have been stripped out by a preprocessor. I use a lot of #include statements, and they don't play well with Maya. ******************************************************************************/ string description = "Uber Character Blinn Shader"; string url = "http://www.alexhogan.com"; float4x4 worldMatrix : World; float4x4 wvpMatrix : WorldViewProjection; float4x4 worldViewMatrix : WorldView; float4x4 worldViewMatrixI : WorldViewInverse; float4x4 viewInverseMatrix : ViewInverseTranspose; float4x4 ViewInv : ViewInverse; float4x4 wvIT : WorldViewInverseTranspose; float4x4 viewMatrix : View; texture colorMapTex : Diffuse < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\white.jpg"; string ResourceType = "2D"; >; sampler2D colorMap = sampler_state { Texture = < colorMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture normalMapTex : Height < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\normal_test.dds"; string ResourceType = "2D"; >; sampler2D normalMap = sampler_state { Texture = < normalMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture glossyMapTex : Diffuse < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\white.jpg"; string ResourceType = "2D"; >; sampler2D glossyMap = sampler_state { Texture = < glossyMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture specMapTex : Diffuse < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\white.jpg"; string ResourceType = "2D"; >; sampler2D specMap = sampler_state { Texture = < specMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture occMapTex : Diffuse < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\white.jpg"; string ResourceType = "2D"; >; sampler2D occMap = sampler_state { Texture = < occMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture sssMaskMapTex : Diffuse < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\black.jpg"; string ResourceType = "2D"; >; sampler2D sssMaskMap = sampler_state { Texture = < sssMaskMapTex >; MinFilter = LinearMipMapLinear; MagFilter = Linear; }; texture reflectionMapEnvTex : Environment < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\Cube_SkyReflection.dds"; string ResourceType = "Cube"; >; samplerCUBE reflectionMap = sampler_state { Texture = < reflectionMapEnvTex >; MagFilter = Linear; }; texture ambientLightMapEnvTex : Environment < string ResourceName = "G:\\dev\\TOB\\sourceart\\common\\Cube_AmbientLight.dds"; string ResourceType = "Cube"; >; samplerCUBE ambientLightMap = sampler_state { Texture = < ambientLightMapEnvTex >; MagFilter = Linear; }; float ambientAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 1; float UIStep = 0.1; string UIName = "Ambient Intensity"; > = 1; float directAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 1; float UIStep = 0.1; string UIName = "Direct Insensity"; > = 1; float backLightAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 1; float UIStep = 0.1; string UIName = "Backlight Insensity"; > = 1; float3 directColor : Ambient < string UIName = "Direct Color"; string UIWidget = "Color"; string Type = "Color"; > = {1.0,1.0,1.0}; float3 backLightColor : Ambient < string UIName = "Backlight Color"; string UIWidget = "Color"; string Type = "Color"; > = {1.0,1.0,1.0}; float3 sssColor : Ambient < string UIName = "SSS Color"; string UIWidget = "Color"; string Type = "Color"; > = {1.0,0.0,0.0}; float normalMapAmount < string UIWidget = "slider"; float UIMin = -5; float UIMax = 5; float UIStep = 0.1; string UIName = "Bump Amount"; > = 1; float glossyAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 1; float UIStep = 0.1; string UIName = "Glossy Amount"; > = 1; float specularAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 10; float UIStep = 0.1; string UIName = "Specular Intensity"; > = 1; float backLightSpecularAmount < string UIWidget = "slider"; float UIMin = 0; float UIMax = 10; float UIStep = 0.1; string UIName = "Specular Intensity"; > = 1; float specExpon < string UIWidget = "slider"; float UIMin = 0; float UIMax = 5; float UIStep = 0.01; string UIName = "Specular Power"; > = 12; float backLightSpecExpon < string UIWidget = "slider"; float UIMin = 0; float UIMax = 5; float UIStep = 0.01; string UIName = "Backlight Specular Power"; > = 12; float4 lightVec : Direction < string UIName = "Light Position"; string Space = "World"; > = {0,50,0,0}; float4 backLightVec : Direction < string UIName = "Back Light Position"; string Space = "World"; > = {0,50,0,0}; struct a2v { float4 Position : POSITION; float2 TexCoord : TEXCOORD0; float3 Tangent : TEXCOORD1; float3 Binormal : TEXCOORD2; float3 Normal : NORMAL; }; struct v2f { float4 Position : POSITION; float2 TexCoord : TEXCOORD0; float4 TexCoord1 : TEXCOORD1; float4 TexCoord2 : TEXCOORD2; float4 TexCoord3 : TEXCOORD3; float3 Norm : TEXCOORD4; }; v2f VertexShader(a2v IN) { v2f OUT; OUT.TexCoord.xy = IN.TexCoord; float3x3 TangentToObjSpace; float3 vtan = IN.Tangent; float3 vbinorm = IN.Binormal; float3 vnorm = IN.Normal; OUT.Norm.xyz = IN.Normal; TangentToObjSpace[0] = float3(vtan.x, vbinorm.x, vnorm.x); TangentToObjSpace[1] = float3(vtan.y, vbinorm.y, vnorm.y); TangentToObjSpace[2] = float3(vtan.z, vbinorm.z, vnorm.z); OUT.TexCoord1.xyz = TangentToObjSpace[0]; OUT.TexCoord2.xyz = TangentToObjSpace[1]; OUT.TexCoord3.xyz = TangentToObjSpace[2]; float4 Pobject = float4(IN.Position.xyz, 1); float4 Pworld = mul(worldMatrix,Pobject); float4 eyeVector = Pworld - viewInverseMatrix[3]; OUT.TexCoord1.w = eyeVector.x; OUT.TexCoord2.w = eyeVector.y; OUT.TexCoord3.w = eyeVector.z; OUT.Position = mul(wvpMatrix,Pobject); return OUT; } float4 PixelShader( v2f IN, uniform float isTransparent ) : COLOR { float3 normal = tex2D(normalMap, IN.TexCoord.xy).xyz * 2.0 - 1.0; normal = float3(normal.x * normalMapAmount, normal.y * normalMapAmount, normal.z); float3 eyevec = normalize(float3(IN.TexCoord1.w, IN.TexCoord2.w, IN.TexCoord3.w)); float3 worldNorm; float3 Tn = normalize( float3(IN.TexCoord1.x,IN.TexCoord2.x,IN.TexCoord3.x ) ); float3 Bn = normalize( float3(IN.TexCoord1.y,IN.TexCoord2.y,IN.TexCoord3.y ) ); float3 Nn = normalize( float3(IN.TexCoord1.z,IN.TexCoord2.z,IN.TexCoord3.z ) ); worldNorm = normalize( mul( normal, float3x3(Tn,Bn,Nn) ) ); float3 realWorldNorm = normalize(mul(float3x3(worldMatrix), float3(worldNorm.xyz) )); float3 lookup = normalize(reflect(eyevec, worldNorm)); float3 inverseLookup = reflect( -eyevec, worldNorm); float3 v = mul(worldNorm, float3x3(worldViewMatrixI)); float4 diffuse = tex2D( colorMap, IN.TexCoord.xy).rgba; float3 glossyColor = tex2D( glossyMap,IN.TexCoord.xy).rgb * glossyAmount; float lightMod = saturate( dot( realWorldNorm, normalize(lightVec.xyz)) ); float backLightMod = saturate( dot( realWorldNorm, normalize(backLightVec.xyz)) ); float3 directLight = directColor * lightMod * directAmount; float3 backLight = backLightColor * backLightMod * backLightAmount; float3 ambientOcclusion = tex2D( occMap,IN.TexCoord.xy).rgb; float3 ambientLight = texCUBE( ambientLightMap, realWorldNorm ).rgb * ambientAmount * saturate( lightMod + 0.25 ); ambientLight *= ambientOcclusion; float3 sssContribution = sssColor * tex2D(sssMaskMap, IN.TexCoord.xy ).r; sssContribution = lerp( sssContribution, float3(0,0,0), lightMod); float3 hvec = ( normalize(lightVec.xyz) + normalize(-eyevec) ) / 2; hvec = normalize( hvec ); float3 hvec2 = ( normalize(backLightVec.xyz) + normalize(-eyevec) ) / 2; hvec2 = normalize( hvec2 ); float specularIntensity = pow( max( dot(hvec, realWorldNorm), 0 ), specExpon ); float specularIntensity2 = pow( max( dot(hvec2, realWorldNorm), 0 ), backLightSpecExpon ); float3 specMapIn = tex2D( specMap,IN.TexCoord.xy).rgb; float3 specularColor = specMapIn * specularAmount * specularIntensity * ( directColor * directAmount ); float3 specularColor2 = specMapIn * backLightSpecularAmount * specularIntensity2 * ( backLightColor * backLightAmount ); float3 reflectionColor = texCUBE( reflectionMap, lookup) * glossyAmount * glossyColor; float3 color = (diffuse.rgb * (directLight + backLight + ambientLight ) ) + reflectionColor + specularColor + specularColor2 + sssContribution; float transparentAmount = diffuse.a + specularColor; return float4( color.rgb, lerp( 1.0, transparentAmount, isTransparent ) ); } technique CharacterBlinn { pass { DepthTestEnable=true; DepthMask = true; DepthFunc = LEqual; VertexProgram = compile arbvp1 VertexShader(); FragmentProgram = compile arbfp1 PixelShader( 0 ); } } technique CharacterBlinn_Transparent { pass { DepthTestEnable=true; DepthMask = true; DepthFunc = LEqual; BlendEnable = true; BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha); VertexProgram = compile arbvp1 VertexShader(); FragmentProgram = compile arbfp1 PixelShader( 1 ); } }