//------------------------------------------------------------------------------ // Desc : Normal Edit shader v3.0 // Author : Brice Vandemoortele (http://www.mentalwarp.com) // Date : March 2009 // contact the author at brice@mentalwarp.com for any questions, bugs or requests :) //------------------------------------------------------------------------------ //This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License // http://creativecommons.org/licenses/by-sa/3.0/ //------------------------------------------------------------------------------ //----------------------------------------------- // Matrices //----------------------------------------------- float4x4 wvpMatrix : WorldViewProjection; float4x4 wMatrix : World; float4x4 wvMatrixIT : worldviewinversetranspose; //only to fetch camera position //----------------------------------------------- float4 LightPos : Position < string UIName = "LightPosition"; string Object = "PointLight"; //string Space = "World"; > = {-54.0f, 50.0f, 100.0f, 1.0f}; float3 LightColor = {1.0, 1.0, 1.0}; #define SET_STANDARD_SAMPLER_STATES \ MinFilter = LinearMipMapLinear;\ MagFilter = Linear;\ LODBias = -.5 bool GenerateUVs = false; float UvScale = 1.0; texture normalTexture ; sampler2D normalSampler = sampler_state {Texture = ; SET_STANDARD_SAMPLER_STATES; }; float BumpScale = 1.0; bool InputWorldSpace < string UIName = "Source normal map in world space"; string UIWidget = "RadioButton"; > = false; bool OutputWorldSpace < string UIName = "Output in world space"; string UIWidget = "RadioButton"; > = false; bool OutputInUvSpace < string UIName = "Output in UV space"; string UIWidget = "RadioButton"; > = true; //--------------------------------------------- // structures //--------------------------------------------- struct vIN { float4 Position : POSITION; float3 Normal : NORMAL; float2 SourceUV : TEXCOORD0; float2 DestUV : TEXCOORD1; float3 SourceTgt : TEXCOORD2; float3 SourceBtg : TEXCOORD3; float3 DestTgt : TEXCOORD4; float3 DestBtg : TEXCOORD5; }; struct vOUT { float4 Position : POSITION; float2 SourceUV : TEXCOORD0; float3 LightDir : TEXCOORD1; float3 Nml : TEXCOORD2; float3 sTgt : TEXCOORD3; float3 sBtg : TEXCOORD4; float3 wPos : TEXCOORD5; float3 dTgt : TEXCOORD6; float3 dBtg : TEXCOORD7; }; struct ps_vtx { float2 tex; float3 light; float3 s_tgt; float3 s_btg; float3 d_tgt; float3 d_btg; float3 nml; float3 posWorld; }; struct ps_maps { float3 normal; }; //--------------------------------------------- // Vertex shader //--------------------------------------------- vOUT vertexFunction(vIN IN) { vOUT OUT; OUT.Position = mul(wvpMatrix, IN.Position); float4 uvPos = float4(IN.DestUV.x,IN.DestUV.y,0,1) * float4(2,-2,1,1) + float4(-1,1,0,0); OUT.Position = (OutputInUvSpace)? uvPos :OUT.Position; OUT.wPos = mul(wMatrix, IN.Position); OUT.SourceUV.xy = IN.SourceUV; float3 LightDir = normalize(LightPos.xyz - IN.Position.xyz); OUT.LightDir.xyz = mul(wMatrix, float4(LightDir.xyz, 0.0)).xyz; OUT.sTgt = mul(wMatrix, float4(IN.SourceTgt.xyz, 0)).xyz; OUT.sBtg = mul(wMatrix, float4(IN.SourceBtg.xyz, 0)).xyz; OUT.dTgt = mul(wMatrix, float4(IN.DestTgt.xyz, 0)).xyz; OUT.dBtg = mul(wMatrix, float4(IN.DestBtg.xyz, 0)).xyz; OUT.Nml = mul(wMatrix, float4(IN.Normal.xyz, 0)).xyz; return OUT; } //--------------------------------------------- // Pixel shader //--------------------------------------------- ps_vtx initVtx(vOUT IN) { ps_vtx OUT = (ps_vtx)0; OUT.tex = IN.SourceUV.xy; OUT.light = normalize(IN.LightDir); OUT.s_tgt = IN.sTgt; OUT.s_btg = IN.sBtg; OUT.d_tgt = IN.dTgt; OUT.d_btg = IN.dBtg; OUT.nml = IN.Nml; OUT.posWorld = IN.wPos; return OUT; } float3 worldVector(float3 inVector, float3 Nml, float3 Tgt, float3 Btg) // compute WorldSpace vector { float3 vectorlWorld; vectorlWorld.xyz = inVector.x * Tgt * BumpScale ; vectorlWorld.xyz += inVector.y * Btg * BumpScale ; vectorlWorld.xyz += inVector.z * Nml; vectorlWorld = normalize(vectorlWorld); return vectorlWorld; } float3 tangentVector(float3 inVector, float3 Nml, float3 Tgt, float3 Btg) // compute TangentSpace vector { float3 vectorlTangent; vectorlTangent.x = dot(inVector.xyz, Tgt); vectorlTangent.y = dot(inVector.xyz, Btg ); vectorlTangent.z = dot(inVector.xyz, Nml); vectorlTangent = normalize(vectorlTangent); return vectorlTangent; } void compute3PlaneUVs(float3 wNml, float3 wPos, inout float3 normal) { float3 b = abs(wNml); b = (b - 0.35) * 7; b = max( float3(0,0,0), b); b /= (b.x + b.y + b.z).xxx; float3 sw = 0; sw.xyz = (wNml.xyz < 0)? float3(-1,-1,-1) : float3(1,1,1); float2 tex1 = wPos.zy / UvScale; float2 tex2 = wPos.xz / UvScale; float2 tex3 = wPos.yx / UvScale; float3 nm1 = tex2D(normalSampler, tex1).xyz * 2 - 1; nm1.xy *= sw.x ; nm1 = worldVector(nm1, wNml, float3(wNml.y,-wNml.z, wNml.x), float3(wNml.z, -wNml.x, -wNml.y)) * b.x; float3 nm2 = tex2D(normalSampler, tex2).xyz * 2 - 1; nm2.xy *= sw.y ; nm2 = worldVector(nm2, wNml, float3(wNml.y, -wNml.x, wNml.z), float3(-wNml.x, wNml.z, -wNml.y)) * b.y; float3 nm3 = tex2D(normalSampler, tex3).xyz * 2 - 1; nm3.xy *= sw.z ; nm3 = worldVector(nm3, wNml, float3(wNml.y, wNml.z, -wNml.x), float3(-wNml.z, -wNml.x, -wNml.y)) * b.z; normal = normalize(nm1+nm2+nm3); } ps_maps fetchMap(ps_vtx IN) { ps_maps OUT = (ps_maps)0; if (GenerateUVs) compute3PlaneUVs(IN.nml.xyz, IN.posWorld.xyz, OUT.normal); else if (InputWorldSpace) OUT.normal = tex2D(normalSampler, IN.tex).xyz * 2 - 1; else OUT.normal = worldVector(tex2D(normalSampler, IN.tex).xyz * 2 - 1, IN.nml.xyz, IN.s_tgt.xyz, IN.s_btg.xyz ); return OUT; } float4 pixelFunction(vOUT IN) : COLOR { ps_vtx input_vtx = initVtx(IN); ps_maps input_maps = fetchMap(input_vtx); float LdotN = saturate(dot(input_maps.normal.xyz, input_vtx.light.xyz)); float3 final = LdotN * LightColor; if (OutputWorldSpace) {final = input_maps.normal.xyz * 0.5 + 0.5;} else {final = tangentVector(input_maps.normal.xyz, input_vtx.nml, input_vtx.d_tgt, input_vtx.d_btg) * 0.5 + 0.5;} return float4( final, 1.0); } //------------------------------------------------- // techniques //------------------------------------------------- technique BasicShader { pass P0 { VertexProgram = compile vp40 vertexFunction(); FragmentProgram = compile fp40 pixelFunction(); } }