//--------------------------------------------------------------// // Car Paint Effect Group_DX9 //--------------------------------------------------------------// //--------------------------------------------------------------// // MultiTone Car Paint w/out Env. Mapping //--------------------------------------------------------------// //--------------------------------------------------------------// // MultiTone Car Paint Pass //--------------------------------------------------------------// #define MaxLights 3 //----------------------------------------------------------------------------------// // 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 // //----------------------------------------------------------------------------------// struct VS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; float3 Tan : TANGENT; float3 Norm : NORMAL; }; struct VS_OUTPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; float3 Tan : TEXCOORD1; float3 Norm : 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 float4x4 World, uniform float4x4 WorldViewProjection, uniform float3 CameraPosition, uniform float microflakeTiling ) { 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.Norm = normalize(mul(World,float4(input.Norm,0.0f))); Out.Tan = normalize(input.Tan); // 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, uniform float4 paintColorMid, uniform float4 paintColor2, uniform float4 paintColor0, uniform float glossLevel, uniform float brightnessFactor, uniform float3 microflakePerturbation, uniform float4 flakeLayerColor, uniform float normalPerturbation, uniform float microflakePerturbationA, uniform sampler microflakeNMap : register(s0), uniform sampler normalMap : register(s1), uniform samplerCUBE showroomMap : register(s2) ) : 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.Tan, float3(0.0, 0.0, 0.0), input.Norm ) ); 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; }