/** * VDM -- View-dependent Displacement Mapping * L. Wang, X. Wang, X. Tong, S. Lin, S. Hu, B. Guo, HY. Shum * * HLSL implementation by Nico Galoppo * :: COMP 236 course project, Spring 2004 * :: University of North Carolina, Chapel Hill */ #define INTERPOLATION #define PI 3.14159265358979323846f #define PI2 6.28318530717958647692f float4x4 worldMatrix : World; float4x4 worldIMatrix : WorldInverse; float4x4 wvpMatrix : WorldViewProjection; float4x4 viewIMatrix : ViewInverse; texture diffuseTexture : Diffuse < string ResourceName = "e:\\nico\\debug.tga"; >; texture normalMap : Normal < string ResourceName = "C:\\Documents and Settings\\nico\\Desktop\\VDMCaster\\bumps-normal.tga"; >; texture phongMap < string texturetype = "2D"; string function = "Phong"; int width = 256, height = 256; >; //texture sphericalMap //< // string texturetype = "3D"; // string function = "toSpherical"; // int width = 256, height = 256, depth=256; //>; texture heightMap < string ResourceName = "C:\\Documents and Settings\\nico\\Desktop\\VDMCaster\\bumps.tga"; >; texture vdmMap < string ResourceName = "C:\\Documents and Settings\\nico\\Desktop\\VDMCaster\\bumpsVDM.png"; >; float3 lightDir : Direction < string UIName = "Light direction"; string Object = "DirectionalLight"; string Space = "World"; > = { 0.0f, 0.0f, 1.0f }; float4 lightColor : Diffuse < string UIName = "Dir Light Color"; string UIWidget = "Color"; > = { 0.5f, 0.5f, 1.0f, 0.0f }; float4 ambientColor : Ambient < > = { 0.1f, 0.1f, 0.1f, 0.0f }; float4 diffuseColor : Diffuse < > = { 0.9f, 0.9f, 0.9f, 0.0f }; float4 specularColor : Specular < > = { 0.5f, 0.5f, 0.5f, 0.0f }; float bumpHeight < string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 5.0; float UIStep = 0.01; > = 1.0; float hOffset < string UIWidget = "slider"; float UIMin = 0; float UIMax = 3.5; float UIStep = 0.0001; > = 1.0; float dScale < string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 20.0; float UIStep = 0.001; > = 1.0; float clipScale < string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 2.0; float UIStep = 0.001; > = 1.0; struct a2v { float4 Position : POSITION; // object space float3 Normal : NORMAL; float2 TexCoord : TEXCOORD0; float3 Tangent : TANGENT; float3 Binormal : BINORMAL; }; // to float2 toSpherical(float3 dir : POSITION) : COLOR { float theta = PI2 - atan2(dir.x, dir.y); if (theta > PI2) theta = theta - PI2; return float2(acos(dir.z), theta); } // Vertex shader struct v2f { float4 Position : POSITION; // clip space float2 TexCoord0 : TEXCOORD0; float2 TexCoord1 : TEXCOORD1; float3 L : TEXCOORD2; // tangent space float3 H : TEXCOORD3; float3 V : TEXCOORD4; float2 lightAngle : TEXCOORD5; float2 viewAngle : TEXCOORD6; }; v2f VDMVS(a2v IN, uniform float4x4 WorldViewProj, uniform float4x4 WorldMatrix, uniform float4x4 WorldIMatrix, uniform float4x4 viewIMatrix, uniform float3 LightDir, uniform float bumpScale ) { v2f OUT; // copy texture coordinates OUT.TexCoord0 = IN.TexCoord; OUT.TexCoord1 = IN.TexCoord; // transform position to clip space OUT.Position = mul(IN.Position, WorldViewProj); // compute the 3x3 tranform from object space to tangent space float3x3 objToTangentSpace; objToTangentSpace[0] = IN.Tangent * bumpScale; objToTangentSpace[1] = IN.Binormal * bumpScale; objToTangentSpace[2] = IN.Normal; float4 vertexPos = mul(IN.Position, WorldMatrix); // world space position // light vector float3 lightVec = -LightDir; lightVec = mul(lightVec, (float3x3) WorldIMatrix); // transform back to object space OUT.L = mul(objToTangentSpace, lightVec); // transform from object to tangent space // eye vector float3 eyeVec = viewIMatrix[3].xyz - vertexPos.xyz; // world space eye vector eyeVec = mul(eyeVec, (float3x3) WorldIMatrix); // transform back to object space eyeVec = normalize(eyeVec); float3 tangentEyeVec = mul(objToTangentSpace, eyeVec); tangentEyeVec = normalize(tangentEyeVec); // half-angle vector float3 H = normalize(lightVec + eyeVec); OUT.H = mul(objToTangentSpace, H); // transform to tangent space // vdm angles OUT.lightAngle = toSpherical(OUT.L); OUT.viewAngle = toSpherical(tangentEyeVec); OUT.V = tangentEyeVec; return OUT; } // Blinn/Phong lighting model // - this function is also used to build the look-up table texture float4 Phong(float2 dots : POSITION) : COLOR { const float shininess = 90.0; // this needs to be constant for building texture float NdotL = dots.x; float NdotH = dots.y; float diffuse = max(NdotL, 0.0); float specular = pow(NdotH, shininess); if (NdotL <= 0) specular = 0; return float4(diffuse, diffuse, diffuse, specular); } // Pixel shaders half4 VDMPS_3(v2f IN, uniform sampler2D colorTex, uniform sampler2D normalTex, uniform sampler2D phongTex, uniform sampler2D vdmTex, uniform half4 ambientColor, uniform half4 diffuseColor, uniform half4 specularColor ) : COLOR { IN.lightAngle = toSpherical(IN.L); IN.viewAngle = toSpherical(IN.V); // index into composed VDM map ====================================================== int iTheta, iPhi; float tPhi = modf(IN.viewAngle.x / PI * 16, iPhi); float tTheta = modf(IN.viewAngle.y / PI * 16, iTheta); float2 vdm_xy; vdm_xy.x = (iPhi + IN.TexCoord0.x) / 16.0; if (iTheta > 15) vdm_xy.x = vdm_xy.x + 0.5; vdm_xy.y = (iTheta + IN.TexCoord0.y) / 16.0; // view-dependent distance ========================================================== float3 dVDM = tex2D(vdmTex, vdm_xy); #ifdef INTERPOLATION float2 steptexX = float2(1.0/16.0, 0); float2 steptexY = float2(0, 1.0/16.0); float2 steptexXY = float2(1.0/16.0, 1.0/16.0); float3 dVDMPhi1 = (1-tPhi) * tex2D(vdmTex,vdm_xy) + tPhi * tex2D(vdmTex, vdm_xy + steptexX); float3 dVDMPhi2 = (1-tPhi) * tex2D(vdmTex, vdm_xy + steptexY) + tPhi * tex2D(vdmTex, vdm_xy + steptexXY); //dVDM.r = (1-tTheta) * dVDMPhi1.r + tTheta * dVDMPhi2.r; dVDM = (1-tTheta) * dVDMPhi1 + tTheta * dVDMPhi2; #endif // silhouette determination ========================================================= if (dVDM.g > 0.75) clip(-1); // real texture coordinates ========================================================= float2 dT = dScale * dVDM.r * IN.V.xy; // predefined phong lighting ======================================================== half4 uN = tex2D(normalTex, IN.TexCoord0 - dT); half4 colorMap = tex2D(colorTex, IN.TexCoord0 - dT); half3 N = uN.xyz*2.0 - 1.0; half NdotL = dot(N, IN.L); half NdotH = dot(N, IN.H); half4 light = tex2D(phongTex, half2(NdotL, NdotH)); // shadow determination ============================================================= float height = 1 - uN.a; float2 lightOffset = height * tan(IN.lightAngle.x) * IN.L.xy; float2 lightIntersection = vdm_xy + (lightOffset - dT) / 16.0; // distance to the light float3 dL1 = (1-tPhi) * tex2D(vdmTex, lightIntersection) + tPhi * tex2D(vdmTex, lightIntersection + steptexX); float3 dL2 = (1-tPhi) * tex2D(vdmTex, lightIntersection + steptexY) + tPhi * tex2D(vdmTex, lightIntersection + steptexXY); //dVDM.r = (1-tTheta) * dVDMPhi1.r + tTheta * dVDMPhi2.r; //float dL = (1-tTheta) * dL1 + tTheta * dL2; float dL = tex2D(vdmTex, lightIntersection); int shadow = 1; float distToLightSurface = height / cos(IN.lightAngle.x) - hOffset; if (dL < distToLightSurface) shadow = 0; // output =========================================================================== //return ambientColor*colorMap + light*diffuseColor*colorMap + light.a*specularColor; //return ambientColor + light*diffuseColor + light.a*specularColor; //return half4(dVDM.r * dScale + dVDM.g, 0,0,1); //return half4(length(IN.V.xy), 0, 0, 1); // Debug light offset --------------------------------------------------------------- //return half4(lightOffset, 0, 1); // Debug light offset --------------------------------------------------------------- //return half4(0, IN.lightAngle.y, 0, 1); // Debug heights -------------------------------------------------------------------- //return half4(1 - tex2D(normalTex, IN.TexCoord1 - dT).a, 0, 0, 1); // Debugging full phong lighting ---------------------------------------------------- //return ambientColor*colorMap; shadow = 1; return //saturate(1 - dVDM.g) * (ambientColor*colorMap + shadow * (light*diffuseColor*colorMap + light.a*specularColor)); (ambientColor*colorMap + shadow * (light*diffuseColor*colorMap + light.a*specularColor)); // Debugging specular lighting ------------------------------------------------------ //return light.a*specularColor; // Debugging simple diffuse lighting ------------------------------------------------ //return light*diffuseColor*colorMap; // Debugging normals ---------------------------------------------------------------- //return half4(tex2D(normalTex, IN.TexCoord1 - dT).xyz, 1); // Debugging colors ----------------------------------------------------------------- //return colorMap; // Debugging depths ----------------------------------------------------------------- half4 debug = IN.viewAngle.y / PI2; if (IN.viewAngle.y <0) debug = half4(1, 0, 0, 1); return debug; } sampler2D diffuseSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; AddressU =clamp; AddressV =clamp; BorderColor = 0x00000000; }; sampler2D normalSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; }; sampler2D phongSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = None; AddressU = Clamp; AddressV = Clamp; }; sampler2D vdmSampler = sampler_state { Texture = ; MinFilter =none; MagFilter =none; MipFilter =none; AddressU = Wrap; AddressV = Wrap; }; sampler2D heightSampler = sampler_state { Texture = ; MinFilter =Linear; MagFilter =Linear; MipFilter =Linear; }; //sampler3D sphericalSampler = sampler_state //{ // Texture = ; // MinFilter =Linear; // MagFilter =Linear; // MipFilter =Linear; //}; technique Step0 { pass p0 { VertexShader = compile vs_1_1 VDMVS(wvpMatrix, worldMatrix, worldIMatrix, viewIMatrix, lightDir, bumpHeight); PixelShader = compile ps_2_a VDMPS_3(diffuseSampler, normalSampler, phongSampler, vdmSampler, ambientColor, lightColor, specularColor); } }