//--------------------------------------------------------------// // Car Paint Effect Group_DX9 //--------------------------------------------------------------// //--------------------------------------------------------------// // MultiTone Car Paint w/out Env. Mapping //--------------------------------------------------------------// //--------------------------------------------------------------// // MultiTone Car Paint Pass //--------------------------------------------------------------// #define MaxLights 3 float4x4 World; float4x4 WorldViewProjection; //----------------------------------------------------------------------------------// // Phenomenological car paint visual effect: Simulates build up of paint coats // // on the metallic surface of a car or any other object. This visual effect // // emulates the suspended layers of microflakes in the paint coat as well as // // blends between several colors of paint based on the viewing angle. // // // // Author: Natalya Tatarchuk // // (based on the original assembly shader written by John Isidoro) // // // // Used in ATI's Car demo for Radeon 9700 launch, found here: // // http://www.ati.com/developer/demos/r9700.html // // // // (C) ATI Research, 2003 // //----------------------------------------------------------------------------------// float4 paintColorMid; float4 paintColor2; float4 paintColor0; float glossLevel; float brightnessFactor; float microflakeTiling; float3 microflakePerturbation; float4 flakeLayerColor; float normalPerturbation; float microflakePerturbationA; sampler microflakeNMap : register(s0); sampler normalMap : register(s1); samplerCUBE showroomMap : register(s2); struct VS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; float3 Tangent : TANGENT; float3 Binormal : BINORMAL; float3 Normal : NORMAL; }; struct VS_OUTPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; float3 Tangent : TEXCOORD1; float3 Binormal : TEXCOORD2; float3 Normal : TEXCOORD3; float3 View : TEXCOORD4; float3 SparkleTex : TEXCOORD5; }; //--------------------------------------------------------------// // Full Car Paint Effect //--------------------------------------------------------------// //--------------------------------------------------------------// // Pass 0 //--------------------------------------------------------------// //----------------------------------------------------------------------------------// // Phenomenological car paint visual effect: Simulates build up of paint coats // on the metallic surface of a car or any other object. This visual effect // emulates the suspended layers of microflakes in the paint coat as well as // blends between several colors of paint based on the viewing angle. // // Author: Natalya Tatarchuk // (based on the original assembly shader written by John Isidoro) // // Used in ATI's Car demo for Radeon 9700 launch, found here: // http://www.ati.com/developer/demos/r9700.html // // (C) ATI Research, 2003 //----------------------------------------------------------------------------------// VS_OUTPUT mainFullVS(VS_INPUT input, uniform float3 CameraPosition ) { VS_OUTPUT Out = (VS_OUTPUT) 0; // Propagate transformed position out: Out.Pos = mul( WorldViewProjection, input.Pos ); // Compute view vector: Out.View = CameraPosition - mul(World, input.Pos); //Out.View = normalize( mul(InverseView, float4( 0, 0, 0, 1)) - input.Pos ); // Propagate texture coordinates: Out.Tex = input.Tex; // Propagate tangent, binormal, and normal vectors to pixel shader: Out.Normal = normalize(mul(World,input.Normal)); Out.Tangent = normalize(input.Tangent); Out.Binormal = normalize(input.Binormal); // Compute microflake tiling factor: Out.SparkleTex = float4( input.Tex * microflakeTiling, 0, 1 ); // Normalize the light directions //Out.Light = normalize(LightDirection0); //Out.Light[1] = normalize(LightDirection1); //Out.Light[2] = normalize(LightDirection2); return Out; } //----------------------------------------------------------------------------------// // Phenomenological car paint visual effect: Simulates build up of paint coats // // on the metallic surface of a car or any other object. This visual effect // // emulates the suspended layers of microflakes in the paint coat as well as // // blends between several colors of paint based on the viewing angle. // // // // Author: Natalya Tatarchuk // // (based on the original assembly shader written by John Isidoro) // // // // Used in ATI's Car demo for Radeon 9700 launch, found here: // // http://www.ati.com/developer/demos/r9700.html // // // // (C) ATI Research, 2003 // //----------------------------------------------------------------------------------// float4 mainFullPS(VS_OUTPUT input) : COLOR { // fetch from the incoming normal map: float3 vNormal = tex2D( normalMap, input.Tex ); // Scale and bias fetched normal to move into [-1.0, 1.0] range: vNormal = 2 * vNormal - 1.0; // Microflakes normal map is a high frequency normalized // vector noise map which is repeated across all surface. // Fetching the value from it for each pixel allows us to // compute perturbed normal for the surface to simulate // appearance of microflakes suspected in the coat of paint: float3 vFlakesNormal = tex2D( microflakeNMap, input.SparkleTex ); // Don't forget to bias and scale to shift color into [-1.0, 1.0] range: vFlakesNormal = 2 * vFlakesNormal - 1.0; // This shader simulates two layers of microflakes suspended in // the coat of paint. To compute the surface normal for the first layer, // the following formula is used: // Np1 = ( a * Np + b * N ) / || a * Np + b * N || where a << b // float3 vNp1 = microflakePerturbationA * vFlakesNormal + normalPerturbation * vNormal ; // To compute the surface normal for the second layer of microflakes, which // is shifted with respect to the first layer of microflakes, we use this formula: // Np2 = ( c * Np + d * N ) / || c * Np + d * N || where c == d // float3 vNp2 = microflakePerturbation * ( vFlakesNormal + vNormal ) ; // The view vector (which is currently in world space) needs to be normalized. // This vector is normalized in the pixel shader to ensure higher precision of // the resultinv view vector. For this highly detailed visual effect normalizing // the view vector in the vertex shader and simply interpolating it is insufficient // and produces artifacts. float3 vView = normalize( input.View ); // Transform the surface normal into world space (in order to compute reflection // vector to perform environment map look-up): float3x3 mTangentToWorld = transpose( float3x3( input.Tangent, input.Binormal, input.Normal ) ); float3 vNormalWorld = normalize( mul( mTangentToWorld, vNormal )); // Compute reflection vector resulted from the clear coat of paint on the metallic // surface: float fNdotV = saturate(dot( vNormalWorld, vView)); float3 vReflection = 2 * vNormalWorld * fNdotV - vView; // Here we just use a constant gloss value to bias reading from the environment // map, however, in the real demo we use a gloss map which specifies which // regions will have reflection slightly blurred. float fEnvBias = glossLevel; // Sample environment map using this reflection vector: float4 envMap = texCUBEbias( showroomMap, float4( vReflection, fEnvBias ) ); // Premultiply by alpha: envMap.rgb = envMap.rgb * envMap.a; // Brighten the environment map sampling result: envMap.rgb *= brightnessFactor; // Compute modified Fresnel term for reflections from the first layer of // microflakes. First transform perturbed surface normal for that layer into // world space and then compute dot product of that normal with the view vector: float3 vNp1World = normalize( mul( mTangentToWorld, vNp1) ); float fFresnel1 = saturate( dot( vNp1World, vView )); // Compute modified Fresnel term for reflections from the second layer of // microflakes. Again, transform perturbed surface normal for that layer into // world space and then compute dot product of that normal with the view vector: float3 vNp2World = normalize( mul( mTangentToWorld, vNp2 )); float fFresnel2 = saturate( dot( vNp2World, vView )); // // Compute final paint color: combines all layers of paint as well as two layers // of microflakes // float fFresnel1Sq = fFresnel1 * fFresnel1; float4 paintColor = fFresnel1 * paintColor0 + fFresnel1Sq * paintColorMid + fFresnel1Sq * fFresnel1Sq * paintColor2 + pow( fFresnel2, 16 ) * flakeLayerColor; // Combine result of environment map reflection with the paint color: float fEnvContribution = 1.0 - 0.5 * fNdotV; float4 finalColor; finalColor.a = 1.0; finalColor.rgb = envMap * fEnvContribution + paintColor; return finalColor; }