/****************************************************************************** HLSL Skin Shader by Ben Cloward bsmji@hotmail.com http://www.monitorstudios.com/bcloward/ This shader mimics some of the properties of skin such as sub-surface sacttering, variable glossyness, subtle surface detail, and rim lighting. It's especially tailored for use on faces, but can also be used for skin in general. It uses three texture maps: a diffuse texture, a specular texture, and a normal map. It supports three point light sources and has options for controlling all surface properties. This shader is based on the HammerTime.fx shader that ships with 3ds Max and also the sub-surface scattering technique discussed on pages 272- 275 of GPU Gems 2. The most important thing that is required for the skin shader to work is texture coordinates in map channel three. You must unwrap the parts of your model that are using this shader using map channel three so that all of the faces fit within the zero to one range (no tiling), the texture coordinates can not overlap each other, and you can't mirror any of the UVs. It's also best to create the unwrap in such a way as to minimize texture seems. The sub-surface scattering turns seems into dark lines, so you'll want to minimize them and hide them if possible. This texture coordinate set won't be used to apply any of the three textures that the shader uses. It's only used internally to compute the sub-surface scattering. You can use a seperate set of texture coordinates in map channel one for the texture maps. Those coordinates can be mirrored, overlapped, and tiled if you want so you can get the most out of the texture space. You don't need to worry about minimizing or hiding texture seems in map channel one. Here's a description of the three texture maps used by the shader and what they're used for: -- Diffuse Map: The surface color of the skin. Be sure not to bake a lot of direct lighting into this map. It needs to be mostly just the diffuse color of the surface. You can change the overall color of the diffuse map using the Ambient Color control of the shader. You can also effect the surface's color using the Diffuse Color control. --Diffuse Map Alpha Channel: The alpha channel of the diffuse map is used by the shader to know how much sub-surface scattering to apply. White in the alpha channel means that light beneath the surface will be scattered the most. You would use white in areas of the face that are very fleshy - like the cheeks. Black means no sub-surface scattering. This might be used on the bridge of the nose and other areas where the skin is thin and the bone is very near the surface. In general you'll probably want to keep this alpha channel fairly light with a few darker areas. --Specular Map: This map allows you to define the color of the specular highlights on a per-pixel basis. Using this map, you could make it so the specular on the forehead is mostly green and the specular on the cheeks is mostly blue. Whatever color you want the specular to be for each part of the face - paint it in this map. You can also effect the overall color of the specular highlights using the Specular Color control of the shader. --Specular Map Alpha Channel: The alpha channel of the specular map defines the glossyness of the specular highlights. White in the alpha channel means the surface is very glossy/shiny and the specular highlight is very small and sharp. You might paint white here for the lips to make them appear wet. Black in the alpha channel means the surface is very dull/diffuse and the specular highlight is very broad and blurred. You might paint the cheeks darker here and other areas of the face that are less shiny or less reflective. You can also make the whole object more or less shiny using the Shininess Bias control of the shader. --Normal Map: The normal map defines surface features and shapes that are too small or detailed to be modeling in the geometry. You might create tiny bumps in your normal map to simulate the pores of the skin or the tiny strips on the lips. Only the specular lighting uses the normal map - so if you have your specular very low, you may not see the effects of the normal map. Since the normal map is used only by the specular, you should treat it like a bump map and not lean on it to make a very low poly face look more detailed. Try to create the main shapes of the face using polygons and mainly use the normal map for tight surface details like pores, wrinkles, etc. You can switch back and forth between positive and negative Y format normal maps using the "Flip Normal Map Green Channel" check box. The shader also supports several other additional inputs. Here are descriptions of what they do: --Rim Color: This is the color that will be used for the rim lighting on the model. Rim lighing simulates the effect of peach fuzz where the skin is brighter at glancing angles than when viewed straight on. --Rim Power: This values controls how far toward the edge the rim lighing is. Low numbers spread the rim lighting in toward the center of the model and higher numbers push the rim lighting further to the edge. --Sub-Suface Scattering Bias: This number is added together with the alpha channel of the diffuse texture to determine how much sub-surface scattering to apply. If you want your whole model to use full sub-surface scattering everywhere, set this to one. If you want to control the amount of sub-surface scattering with the diffuse map alpha channel, set this to zero. If you don't want any sub-surface scattering, set this to negative one. --Lights: The shader supports three point lights. You can define which point lights in your scene you want to use by choosing them in the drop-down boxes. Only light 1 will create specular lighting. This is a performance optimization. Lights 2 and 3 will only effect diffuse light. Don't forget that you can change the color of the lights on the standard light modifier panel. This shader is intended to be used by the DirectX 9 shader of 3DS Max and I'm pretty sure that it will only function correctly within 3DS Max since it uses some code syntax that is specific to Max. If you get it to work correctly in another application, I'd love to hear about it! */ /////////////////////////////////////////////////////////// /////////////////////////////////////// Tweakables //////// /////////////////////////////////////////////////////////// #define DCC_MAX string ParamID = "0x000001"; half4 ClearColor : DIFFUSE = {0,0,0,1.0}; half ClearDepth < string UIWidget = "none"; > = 1.0; half Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "object"; string ScriptOrder = "postprocess"; string ScriptOutput = "color"; // We just call a script in the main technique. string Script = "Technique=SkinQuality?Skin_Nicer_MoreExpensive:Skin_Cheaper_Faster;"; > = 0.8; half4 ambient : Ambient < string UIName = "Ambient Color"; > = {0.043f, 0.0f, 0.0f, 1.0f}; half4 surfColor : Diffuse < string UIName = "Diffuse Color"; > = {1.0f, 1.0f, 1.0f, 1.0f}; texture colorTexture : DiffuseMap < string name = "default_color.dds"; string UIName = "Diffuse Texture"; string TextureType = "2D"; int Texcoord = 0; int MapChannel = 1; >; half4 specularColor : Specular < string UIName = "Specular Color"; > = { 0.094f, 0.114f, 0.173f, 1.0f }; texture specTexture : SpecularMap < string name = "default_color.dds"; string UIName = "Specular Texture"; string TextureType = "2D"; int Texcoord = 0; int MapChannel = 1; >; half shininessBias < string UIWidget = "slider"; half UIMin = 0; half UIMax = 5; string UIName = "Shininess Bias"; > = 1; half4 rimColor : RimColor < string UIName = "Rim Color"; > = { 0.475f, 0.475f, 0.561f, 1.0f }; half rimPower < string UIWidget = "slider"; half UIMin = 1; half UIMax = 128; string UIName = "Rim Power"; > = 4; texture normalMap : NormalMap < string name = "default_bump_normal.dds"; string UIName = "Normal Map"; string TextureType = "2D"; int Texcoord = 0; int MapChannel = 1; >; bool direction < string gui = "slider"; string UIName = "Flip Normal Map Green Channel"; > = false; /************** light info **************/ half4 light1Pos : POSITION < string UIName = "Light 1 Position"; string Object = "PointLight"; string Space = "World"; int refID = 1; > = {100.0f, 100.0f, 100.0f, 0.0f}; half4 light1Color : LIGHTCOLOR < int LightRef = 1; string UIWidget = "none"; > = { 1.0f, 1.0f, 1.0f, 0.0f }; half4 light2Pos : POSITION < string UIName = "Light 2 Position"; string Object = "PointLight"; string Space = "World"; int refID = 2; > = {100.0f, 100.0f, 100.0f, 0.0f}; half4 light2Color : LIGHTCOLOR < int LightRef = 2; string UIWidget = "none"; > = { 1.0f, 1.0f, 1.0f, 0.0f }; half4 light3Pos : POSITION < string UIName = "Light 3 Position"; string Object = "PointLight"; string Space = "World"; int refID = 3; > = {100.0f, 100.0f, 100.0f, 0.0f}; half4 light3Color : LIGHTCOLOR < int LightRef = 3; string UIWidget = "none"; > = { 1.0f, 1.0f, 1.0f, 0.0f }; half blur < string UIWidget = "slider"; half UIMin = -1.0; half UIMax = 1.0; string UIName = "Sub-Surface Scattering Bias"; > = 0.0; /****************************************************/ /********** SAMPLERS ********************************/ /****************************************************/ sampler colorTextureSamp = sampler_state { texture = ; AddressU = WRAP; AddressV = WRAP; AddressW = WRAP; MIPFILTER = LINEAR; MINFILTER = LINEAR; MAGFILTER = Anisotropic; }; sampler2D specTextureSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Anisotropic; }; sampler2D normalMapSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Anisotropic; }; /////////////////////////////////////////////////////////// /////////////////////////////////////// Un-Tweakables ///// /////////////////////////////////////////////////////////// half4x4 WvpXf : WorldViewProjection < string UIWidget="None"; >; half4x4 worldIT : WorldInverseTranspose < string UIWidget = "None"; >; half4x4 viewInv : ViewInverse < string UIWidget = "None"; >; half4x4 world : World < string UIWidget = "None"; >; /////////////////////////////////////////////////////////// ///////////////////////////// Render-to-Texture Data ////// /////////////////////////////////////////////////////////// #define RTT_SIZE 256 half TexelIncrement < string UIName = "Texel Stride for Blur"; string UIWidget = "None"; > = 1.0f / RTT_SIZE; texture skinMap1 : RENDERCOLORTARGET < half2 Dimensions = { RTT_SIZE, RTT_SIZE }; int MIPLEVELS = 1; string format = "X8R8G8B8"; string UIWidget = "None"; int Texcoord = 1; int MapChannel = 3; >; sampler skinSamp1 = sampler_state { texture = ; MIPFILTER = NONE; MINFILTER = LINEAR; MAGFILTER = LINEAR; }; texture skinMap2 : RENDERCOLORTARGET < half2 Dimensions = { RTT_SIZE, RTT_SIZE }; int MIPLEVELS = 1; string format = "X8R8G8B8"; string UIWidget = "None"; int Texcoord = 1; int MapChannel = 3; >; sampler skinSamp2 = sampler_state { texture = ; MIPFILTER = NONE; MINFILTER = LINEAR; MAGFILTER = LINEAR; }; texture skinMap3 : RENDERCOLORTARGET < half2 Dimensions = { RTT_SIZE, RTT_SIZE }; int MIPLEVELS = 1; string format = "X8R8G8B8"; string UIWidget = "None"; int Texcoord = 1; int MapChannel = 3; >; sampler skinSamp3 = sampler_state { texture = ; MIPFILTER = NONE; MINFILTER = LINEAR; MAGFILTER = LINEAR; }; /////////////////////////////////////////////////////////// /////////////////////////////////// data structures /////// /////////////////////////////////////////////////////////// struct VS_OUTPUT_BLUR { half4 Position : POSITION; half4 Diffuse : COLOR0; half4 TexCoord0 : TEXCOORD0; half4 TexCoord1 : TEXCOORD1; half4 TexCoord2 : TEXCOORD2; half4 TexCoord3 : TEXCOORD3; half4 TexCoord4 : TEXCOORD4; half4 TexCoord5 : TEXCOORD5; half4 TexCoord6 : TEXCOORD6; half4 TexCoord7 : TEXCOORD7; half4 TexCoord8 : COLOR1; }; // input from application struct a2v { half4 position : POSITION; half2 texCoord : TEXCOORD0; half2 texCoord2 : TEXCOORD1; half3 tangent : TANGENT; half3 binormal : BINORMAL; half3 normal : NORMAL; }; // output to fragment program struct v2f { half4 position : POSITION; half4 texCoord : TEXCOORD0; half3 eyeVec : TEXCOORD1; half3 lightVec : TEXCOORD2; half3 worldNormal : TEXCOORD3; half3 worldTangent : TEXCOORD4; half3 worldBinormal : TEXCOORD5; }; // input from application struct a2v2 { half4 position : POSITION; half2 texCoord : TEXCOORD0; half2 texCoord2 : TEXCOORD1; half3 normal : NORMAL; }; // output to fragment program struct v2f2 { half4 position : POSITION; half2 texCoord : TEXCOORD0; half4 color : COLOR; }; //////////////////////////////////////////////////////////// ////////////////////////////////// vertex shaders ////////// //////////////////////////////////////////////////////////// v2f2 VS_UNWRAP_VERT_LIGHT(a2v2 In, uniform half4 light1Pos, uniform half4 light1Color, uniform half4 light2Pos, uniform half4 light2Color, uniform half4 light3Pos, uniform half4 light3Color) { v2f2 Out; Out.position.x = -In.texCoord2.x * 2 + 1; //put the model verts in UV space Out.position.y = In.texCoord2.y * 2 + 1; Out.position.z = 0.0; Out.position.w = 1.0; Out.texCoord = In.texCoord; //pass texture coordinates half3 normal = mul(In.normal, worldIT).xyz; //put the normal in world space half4 worldSpacePos = mul(In.position, world); //put the vert position in world space half4 normLight1Vec = normalize(light1Pos - worldSpacePos); //cast a ray to the light and normalize it half4 light1 = max(dot(normal,normLight1Vec),0) * light1Color; half4 normLight2Vec = normalize(light2Pos - worldSpacePos); //cast a ray to the light and normalize it half4 light2 = max(dot(normal,normLight2Vec),0) * light2Color; half4 normLight3Vec = normalize(light3Pos - worldSpacePos); //cast a ray to the light and normalize it half4 light3 = max(dot(normal,normLight3Vec),0) * light3Color; Out.color = (light1 + light2 + light3) * surfColor + ambient; //dot the light vector with the normal Out.color.a = 1.0; return Out; } v2f VS_LIGHT(a2v In, uniform half4 lightPosition) { v2f Out = (v2f)0; Out.worldNormal = mul(In.normal, worldIT).xyz; Out.worldTangent = mul(In.tangent, worldIT).xyz; Out.worldBinormal = mul(In.binormal, worldIT).xyz; //can use either positive or negative y format normal maps //comment out this if statement to save 6 instructions! if (direction == true) Out.worldTangent = -Out.worldTangent; half3 worldSpacePos = mul(In.position, world); Out.lightVec = lightPosition - worldSpacePos; Out.texCoord.xy = In.texCoord; Out.texCoord.zw = In.texCoord2; Out.eyeVec = viewInv[3].xyz - worldSpacePos; Out.position = mul(In.position, WvpXf); return Out; } VS_OUTPUT_BLUR VS_Quad_Vertical_9tap(half3 Position : POSITION, half3 TexCoord : TEXCOORD0) { VS_OUTPUT_BLUR OUT = (VS_OUTPUT_BLUR)0; OUT.Position = half4(Position, 1); half3 Coord = half3(TexCoord.x + TexelIncrement, TexCoord.y + TexelIncrement, 1); OUT.TexCoord0 = half4(Coord.x, Coord.y + TexelIncrement * 4, TexCoord.z, 1); OUT.TexCoord1 = half4(Coord.x, Coord.y + TexelIncrement * 3, TexCoord.z, 1); OUT.TexCoord2 = half4(Coord.x, Coord.y + TexelIncrement * 2, TexCoord.z, 1); OUT.TexCoord3 = half4(Coord.x, Coord.y + TexelIncrement, TexCoord.z, 1); OUT.TexCoord4 = half4(Coord.x, Coord.y, TexCoord.z, 1); OUT.TexCoord5 = half4(Coord.x, Coord.y - TexelIncrement, TexCoord.z, 1); OUT.TexCoord6 = half4(Coord.x, Coord.y - TexelIncrement * 2, TexCoord.z, 1); OUT.TexCoord7 = half4(Coord.x, Coord.y - TexelIncrement * 3, TexCoord.z, 1); OUT.TexCoord8 = half4(Coord.x, Coord.y - TexelIncrement * 4, TexCoord.z, 1); return OUT; } VS_OUTPUT_BLUR VS_Quad_Horizontal_9tap(half3 Position : POSITION, half3 TexCoord : TEXCOORD0) { VS_OUTPUT_BLUR OUT = (VS_OUTPUT_BLUR)0; OUT.Position = half4(Position, 1); half3 Coord = half3(TexCoord.x + TexelIncrement, TexCoord.y + TexelIncrement, 1); OUT.TexCoord0 = half4(Coord.x + TexelIncrement * 4, Coord.y, TexCoord.z, 1); OUT.TexCoord1 = half4(Coord.x + TexelIncrement * 3, Coord.y, TexCoord.z, 1); OUT.TexCoord2 = half4(Coord.x + TexelIncrement * 2, Coord.y, TexCoord.z, 1); OUT.TexCoord3 = half4(Coord.x + TexelIncrement, Coord.y, TexCoord.z, 1); OUT.TexCoord4 = half4(Coord.x, Coord.y, TexCoord.z, 1); OUT.TexCoord5 = half4(Coord.x - TexelIncrement, Coord.y, TexCoord.z, 1); OUT.TexCoord6 = half4(Coord.x - TexelIncrement * 2, Coord.y, TexCoord.z, 1); OUT.TexCoord7 = half4(Coord.x - TexelIncrement * 3, Coord.y, TexCoord.z, 1); OUT.TexCoord8 = half4(Coord.x - TexelIncrement * 4, Coord.y, TexCoord.z, 1); return OUT; } VS_OUTPUT_BLUR VS_Quad_Vertical_5tap(half3 Position : POSITION, half3 TexCoord : TEXCOORD0) { VS_OUTPUT_BLUR OUT = (VS_OUTPUT_BLUR)0; OUT.Position = half4(Position, 1); half3 Coord = half3(TexCoord.x + TexelIncrement, TexCoord.y + TexelIncrement, 1); OUT.TexCoord0 = half4(Coord.x, Coord.y + TexelIncrement, TexCoord.z, 1); OUT.TexCoord1 = half4(Coord.x, Coord.y + TexelIncrement * 2, TexCoord.z, 1); OUT.TexCoord2 = half4(Coord.x, Coord.y, TexCoord.z, 1); OUT.TexCoord3 = half4(Coord.x, Coord.y - TexelIncrement, TexCoord.z, 1); OUT.TexCoord4 = half4(Coord.x, Coord.y - TexelIncrement * 2, TexCoord.z, 1); return OUT; } VS_OUTPUT_BLUR VS_Quad_Horizontal_5tap(half3 Position : POSITION, half3 TexCoord : TEXCOORD0) { VS_OUTPUT_BLUR OUT = (VS_OUTPUT_BLUR)0; OUT.Position = half4(Position, 1); half3 Coord = half3(TexCoord.x + TexelIncrement, TexCoord.y + TexelIncrement, 1); OUT.TexCoord0 = half4(Coord.x + TexelIncrement, Coord.y, TexCoord.z, 1); OUT.TexCoord1 = half4(Coord.x + TexelIncrement * 2, Coord.y, TexCoord.z, 1); OUT.TexCoord2 = half4(Coord.x, Coord.y, TexCoord.z, 1); OUT.TexCoord3 = half4(Coord.x - TexelIncrement, Coord.y, TexCoord.z, 1); OUT.TexCoord4 = half4(Coord.x - TexelIncrement * 2, Coord.y, TexCoord.z, 1); return OUT; } ////////////////////////////////////////////////////// ////////////////////////////////// pixel shaders ///// ////////////////////////////////////////////////////// //////// // For two-pass blur, we have chosen to do the horizontal blur FIRST. The half4 PS_Blur_Horizontal_9tap(VS_OUTPUT_BLUR IN) : COLOR { const half4 weight[5] = { {0.021, 0.0, 0.0, 1.0}, {0.07, 0.0, 0.0, 1.0}, {0.13, 0.086, 0.086, 1.0}, {0.179, 0.244, 0.244, 1.0}, {0.2, 0.33, 0.33, 1.0}, }; half4 OutCol; OutCol = tex2D(skinSamp1, IN.TexCoord0) * weight[0]; OutCol += tex2D(skinSamp1, IN.TexCoord1) * weight[1]; OutCol += tex2D(skinSamp1, IN.TexCoord2) * weight[2]; OutCol += tex2D(skinSamp1, IN.TexCoord3) * weight[3]; OutCol += tex2D(skinSamp1, IN.TexCoord4) * weight[4]; OutCol += tex2D(skinSamp1, IN.TexCoord5) * weight[3]; OutCol += tex2D(skinSamp1, IN.TexCoord6) * weight[2]; OutCol += tex2D(skinSamp1, IN.TexCoord7) * weight[1]; OutCol += tex2D(skinSamp1, IN.TexCoord8) * weight[0]; return OutCol; } half4 PS_Blur_Vertical_9tap(VS_OUTPUT_BLUR IN) : COLOR { const half4 weight[5] = { {0.021, 0.0, 0.0, 1.0}, {0.07, 0.0, 0.0, 1.0}, {0.13, 0.086, 0.086, 1.0}, {0.179, 0.244, 0.244, 1.0}, {0.2, 0.33, 0.33, 1.0}, }; half4 OutCol; OutCol = tex2D(skinSamp2, IN.TexCoord0) * weight[0]; OutCol += tex2D(skinSamp2, IN.TexCoord1) * weight[1]; OutCol += tex2D(skinSamp2, IN.TexCoord2) * weight[2]; OutCol += tex2D(skinSamp2, IN.TexCoord3) * weight[3]; OutCol += tex2D(skinSamp2, IN.TexCoord4) * weight[4]; OutCol += tex2D(skinSamp2, IN.TexCoord5) * weight[3]; OutCol += tex2D(skinSamp2, IN.TexCoord6) * weight[2]; OutCol += tex2D(skinSamp2, IN.TexCoord7) * weight[1]; OutCol += tex2D(skinSamp2, IN.TexCoord8) * weight[0]; return OutCol; } // Relative filter weights indexed by distance from "home" texel // This set for 5-texel sampling #define WT5_0 1.0 #define WT5_1 0.8 #define WT5_2 0.4 #define WT5_NORMALIZE (WT5_0+2.0*(WT5_1+WT5_2)) half4 PS_Blur_Horizontal_5tap(VS_OUTPUT_BLUR IN) : COLOR { half4 OutCol = tex2D(skinSamp1, IN.TexCoord0) * (WT5_1/WT5_NORMALIZE); OutCol += tex2D(skinSamp1, IN.TexCoord1) * (WT5_2/WT5_NORMALIZE); OutCol += tex2D(skinSamp1, IN.TexCoord2) * (WT5_0/WT5_NORMALIZE); OutCol += tex2D(skinSamp1, IN.TexCoord3) * (WT5_1/WT5_NORMALIZE); OutCol += tex2D(skinSamp1, IN.TexCoord4) * (WT5_2/WT5_NORMALIZE); return OutCol; } half4 PS_Blur_Vertical_5tap(VS_OUTPUT_BLUR IN) : COLOR { half4 OutCol = tex2D(skinSamp2, IN.TexCoord0) * (WT5_1/WT5_NORMALIZE); OutCol += tex2D(skinSamp2, IN.TexCoord1) * (WT5_2/WT5_NORMALIZE); OutCol += tex2D(skinSamp2, IN.TexCoord2) * (WT5_0/WT5_NORMALIZE); OutCol += tex2D(skinSamp2, IN.TexCoord3) * (WT5_1/WT5_NORMALIZE); OutCol += tex2D(skinSamp2, IN.TexCoord4) * (WT5_2/WT5_NORMALIZE); return OutCol; } half4 PS_BAREBONES(v2f2 In) : COLOR { return In.color; } // combine blurred lighting and diffuse texture and add specular and rim lighting half4 PS_Composite_Plus(v2f In,uniform half4 lightColor) : COLOR { half4 tex = tex2D(colorTextureSamp, In.texCoord.xy); //sample the diffuse texture half4 light = tex2D(skinSamp1, -In.texCoord.zw); //sample the light map pass half4 blurlight = tex2D(skinSamp3, -In.texCoord.zw); //sample the blurred light map pass half lerpAmount = clamp(tex.a + blur,0,1); //calculate the amount of blur needed half4 diffuseLight = lerp(light,blurlight,lerpAmount); //blend the two light maps based on diffuse alpha and blur bias half4 specMap = tex2D(specTextureSampler, In.texCoord.xy); half3 normal = tex2D(normalMapSampler, In.texCoord).xyz * 2.0 - 1.0; //create tangent space vectors half3 Nn = In.worldNormal; //- could be normalized, half3 Tn = In.worldTangent; // but it's 4 more instructions half3 Bn = In.worldBinormal; // and makes almost no difference //create lighting vectors - view vector and light vector half3 N = normalize((Nn * normal.z) + (normal.x * Bn + normal.y * -Tn)); half3 V = normalize(In.eyeVec); half3 L = normalize(In.lightVec.xyz); //specular component half3 H = normalize(V+L); half shininess = (shininessBias*specMap.a) * 128; half4 specularLight = pow(max(dot(H,N),0.001f), shininess) * specularColor * specMap; //rim lighting half rim = pow(1.0 - max(dot(N,V),0),rimPower); half4 rimLight = rimColor * rim; return (diffuseLight * tex * lightColor) + specularLight + rimLight; } //////////////////////////////////////////////////////////// /////////////////////////////////////// techniques ///////// //////////////////////////////////////////////////////////// technique Skin_Nicer_MoreExpensive < string Script = "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Pass=RTT_Light;" "Pass=BlurLightBuffer_Horz;" "Pass=BlurLightBuffer_Vert;" "Pass=Composite;"; > { pass RTT_Light < string Script = "RenderColorTarget0=skinMap1;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { cullmode = cw; ZEnable = true; VertexShader = compile vs_1_1 VS_UNWRAP_VERT_LIGHT(light1Pos, light1Color, light2Pos, light2Color, light3Pos, light3Color); //PixelShader = compile ps_1_1 PS_BAREBONES(); //don't need a pixel shader for this one! } pass BlurLightBuffer_Horz < string Script ="RenderColorTarget0=skinMap2;" "Clear=Color;" "Clear=Depth;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; VertexShader = compile vs_2_0 VS_Quad_Horizontal_9tap(); PixelShader = compile ps_2_0 PS_Blur_Horizontal_9tap(); } pass BlurLightBuffer_Vert < string Script = "RenderColorTarget0=skinMap3;" "Clear=Color;" "Clear=Depth;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; VertexShader = compile vs_2_0 VS_Quad_Vertical_9tap(); PixelShader = compile ps_2_0 PS_Blur_Vertical_9tap(); } pass Composite < string Script= "RenderColorTarget0=;" "Draw=Geometry;"; > { cullmode = cw; ZEnable = true; ZWriteEnable = true; AlphaBlendEnable = false; VertexShader = compile vs_1_1 VS_LIGHT(light1Pos); PixelShader = compile ps_2_0 PS_Composite_Plus(light1Color); } } ////////////// technique Skin_Cheaper_Faster < string Script = "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Pass=RTT_Light;" "Pass=BlurLightBuffer_Horz;" "Pass=BlurLightBuffer_Vert;" "Pass=Composite;"; > { pass RTT_Light < string Script = "RenderColorTarget0=skinMap1;" "Clear=Color;" "Clear=Depth;" "Draw=Geometry;"; > { cullmode = cw; ZEnable = true; VertexShader = compile vs_1_1 VS_UNWRAP_VERT_LIGHT(light1Pos, light1Color, light2Pos, light2Color, light3Pos, light3Color); //PixelShader = compile ps_1_1 PS_BAREBONES(); //don't need a pixel shader for this one! } pass BlurLightBuffer_Horz < string Script ="RenderColorTarget0=skinMap2;" "Clear=Color;" "Clear=Depth;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; VertexShader = compile vs_2_0 VS_Quad_Horizontal_5tap(); PixelShader = compile ps_2_0 PS_Blur_Horizontal_5tap(); } pass BlurLightBuffer_Vert < string Script = "RenderColorTarget0=skinMap3;" "Clear=Color;" "Clear=Depth;" "Draw=Buffer;"; > { cullmode = none; ZEnable = false; VertexShader = compile vs_2_0 VS_Quad_Vertical_5tap(); PixelShader = compile ps_2_0 PS_Blur_Vertical_5tap(); } pass Composite < string Script= "RenderColorTarget0=;" "Draw=Geometry;"; > { cullmode = cw; ZEnable = true; ZWriteEnable = true; AlphaBlendEnable = false; VertexShader = compile vs_1_1 VS_LIGHT(light1Pos); PixelShader = compile ps_2_0 PS_Composite_Plus(light1Color); } } ////////////// ////////////// eof ///