// // Car Paint Shader // Copyright (c) NVIDIA Corporation. All rights reserved. // // NOTE: // This shader is based on the Time Machine temporal rust shader. // Car paint data was measured by Cornell University from samples // provided by the Ford Motor Company. // struct a2v { float4 OPosition : POSITION; float3 ONormal : NORMAL; float2 uv : TEXCOORD0; float3 Tangent : TEXCOORD1; float3 Binormal : TEXCOORD2; float3 Normal : TEXCOORD3; }; struct VS_OUTPUT { float4 HPosition : POSITION; // coord position in window float2 uv : TEXCOORD0; // wavy or fleck map texture coordinates float3 light : TEXCOORD1; // position of light relative to point float4 halfangle : TEXCOORD2; // Blinn halfangle float3 reflection: TEXCOORD3; // Reflection vector (per-vertex) float4 view : TEXCOORD4; // position of viewer relative to point float3 tangent : TEXCOORD5; // view-tangent matrix float3 binormal : TEXCOORD6; // ... float3 normal : TEXCOORD7; // ... float fresn : COLOR0; }; // VERTEX SHADER VS_OUTPUT main( a2v vert, // TRANSFORMATIONS uniform float4x4 ModelView, uniform float4x4 ModelViewIT, uniform float4x4 ModelViewProj, uniform float3 LightVector, // Object space LIGHT vector uniform float3 EyePosition ) // Object space EYE position { VS_OUTPUT O; // Generate homogeneous POSITION O.HPosition = mul(ModelViewProj, vert.OPosition); // Generate BASIS matrix float3x3 ModelTangent = { normalize(vert.Tangent), normalize(vert.Binormal), normalize(vert.Normal) }; // FRESNEL = { OFFSET, SCALE, POWER, UNUSED }; float4 Fresnel = { 0.1f, 4.2f, 4.4f, 0.0f }; // NEWPAINTSPEC = { MIP LOD BIAS, SPEC POWER, FRESNEL GLOSSINESS, FLECK SPEC POWER } float4 NewPaintSpec = { 0.8f, 64.0f, 3.0f, 8.0f }; float3 ClearCoat = { 0.299f,0.587f, 0.114f }; float3 FleckColor = { 0.9, 1.05, 1.0 }; float3 TangentNormal = { 0.0f, 0.0f, 1.0f }; float3 WavyScale = { 0.4, -0.4, 1.0 }; float3x3 ViewTangent = mul(ModelTangent, (float3x3)ModelViewIT); // Generate VIEW SPACE vectors float3 viewN = normalize(mul((float3x3)ModelView, vert.ONormal)); float4 viewP = mul(ModelView, vert.OPosition); viewP.w = 1-saturate(sqrt(dot(viewP.xyz, viewP.xyz))*0.01); float3 viewV = -viewP.xyz; // Generate OBJECT SPACE vectors float3 objV = normalize(EyePosition - vert.OPosition.xyz); float3 objL = normalize(LightVector); // Light is directional float3 objH = normalize(objL + objV); // Generate TANGENT SPACE vectors float3 tanL = mul(ModelTangent, objL); float3 tanV = mul(ModelTangent, objV); float3 tanH = mul(ModelTangent, objH); // Generate REFLECTION vector for per-vertex reflection look-up float3 reflection = reflect(-viewV, viewN); // Generate FRESNEL term float ndv = saturate(dot(viewN, viewV)); float FresnelApprox = (pow((1-ndv), Fresnel.z)*Fresnel.y + Fresnel.x); // Fill OUTPUT parameters O.uv.xy = vert.uv; // TEXCOORD0.xy O.light = tanL; // Tangent space LIGHT O.halfangle = float4(tanH.x, tanH.y, tanH.z, 1-exp(-viewP.w)); // Tangent space HALF-ANGLE O.reflection = reflection; // View space REFLECTION O.view = float4(tanV.x, tanV.y, tanV.z, viewP.w); // Tangent space VIEW + distance attenuation O.tangent = normalize(ViewTangent[0]); // VIEWTANGENT column 0 O.binormal = normalize(ViewTangent[1]); // VIEWTANGENT column 1 O.normal = normalize(ViewTangent[2]); // VIEWTANGENT column 2 O.fresn = FresnelApprox; // FRESNEL approximation return O; } //------------------------------- struct VS_OUTPUT { float4 HPosition : POSITION; // coord position in window float2 uv : TEXCOORD0; // wavy or fleck map texture coordinates float3 light : TEXCOORD1; // position of light relative to point float4 halfangle : TEXCOORD2; // Blinn halfangle float3 reflection: TEXCOORD3; // Reflection vector (per-vertex) float4 view : TEXCOORD4; // position of viewer relative to point float3 tangent : TEXCOORD5; // view-tangent matrix float3 binormal : TEXCOORD6; // ... float3 normal : TEXCOORD7; // ... float fresn : COLOR0; }; // PIXEL SHADER float4 main( VS_OUTPUT vert, uniform sampler2D WavyMap : register(s0), uniform samplerCUBE EnvironmentMap : register(s1), uniform sampler2D PaintMap : register(s2), uniform sampler2D FleckMap : register(s3), uniform float Ambient ) : COLOR { // NEWPAINTSPEC = { UNUSED, SPEC POWER, FRESNEL GLOSSINESS, FLECK SPEC POWER } float4 NewPaintSpec = { 0.0f, 64.0f, 3.8f, 8.0f }; float3 ClearCoat = { 0.299f,0.587f, 0.114f }; float3 FleckColor = { 0.9, 1.05, 1.0 }; float3 WavyScale = { 0.2, -0.2, 1.0 }; // Tangent space LIGHT vector float3 L = normalize(vert.light); // Tangent space HALF-ANGLE vector float3 H = normalize(vert.halfangle.xyz); // Tangent space VIEW vector float3 V = normalize(vert.view.xyz); float v_dist = vert.view.w; // Tangent space WAVY_NORMAL float3 wavyN = (float3)tex2D(WavyMap, vert.uv)*2-1; wavyN = normalize(wavyN*WavyScale); // PAINT // A normal map map could be loaded here instead if we wanted more detail // In this case we have a uniform tangent space normal (0,0,1) float n_d_l = L.z; float n_d_h = H.z; float3 paint_color = (float3)tex2D(PaintMap, float2(n_d_l, n_d_h)); // SPECULAR POWER - use a saturated diffuse term to clamp the backlighting n_d_h = saturate(n_d_l*4)*pow(n_d_h, NewPaintSpec.y); // REFLECTION ENVIRONMENT // Reflect view vector about wavy normal and bring to view space float3 R = reflect(-V, wavyN); R = R.x*vert.tangent + R.y*vert.binormal + R.z*vert.normal; float3 reflect_color = (float3)texCUBE(EnvironmentMap, R); // FLECKS // Load random 3-vector flecks from fleck_map // Reduce tiling artifacts by sampling at different frequencies float3 fleckN = (float3)tex2D(FleckMap, vert.uv*37)*2-1; fleckN = ((float3)tex2D(FleckMap, vert.uv*23)*2-1)/2 + fleckN/2; float fleck_n_d_h = saturate(dot(fleckN, H)); float3 fleck_color = FleckColor*pow(fleck_n_d_h,lerp(NewPaintSpec.y, NewPaintSpec.w, v_dist)); // Control the ambient fleckiness and also attenuate with distance fleck_color = fleck_color*Ambient*vert.halfangle.w; // DIFFUSE float k_d = saturate(n_d_l*1.2); float3 paintResult = lerp(Ambient*paint_color, paint_color, k_d); // FRESNEL float Fresnel = saturate(dot(ClearCoat, reflect_color)); Fresnel = pow(Fresnel, NewPaintSpec.z); Fresnel = saturate(vert.fresn*Fresnel); // This helps make the clear coat less omnipresent -- only the really (perceptually) bright areas reflect the most. // Show more of the specular reflection environment when in fresnel zones // diffuse * (1-fresnel) + environment * (fresnel) paintResult = lerp(paintResult, reflect_color, Fresnel); // SPECULAR // diffuse + specular + flecks paintResult = paintResult + n_d_h + fleck_color; // OUTPUT return paintResult.xyzz; }