汽车喷漆效果的实现
给汽车身体喷漆是一个复杂的过程,车身油漆是昂贵分层形式,往往包含染料层,搪瓷金属箔悬浮层.
由于这些接二连三油漆表面层,展示出了一种复杂的光学交互,使车看起来平滑,光泽。
完整的HLSL像素着色器代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | structPsInput{      float2 Tex : TEXCOORD0;      float3 Tangent : TEXCOORD1;      float3 Binormal : TEXCOORD2;      float3 Normal : TEXCOORD3;      float3 View : TEXCOORD4;      float3 SparkleTex : TEXCOORD5;};float4 main(PsInput i) : COLOR{      // 取得当前的法线图      float3 vNormal = tex2D( normalMap, i.Tex );      // 缩放和偏移让其在[-1.0, 1.0]区域内:      vNormal = 2.0f * vNormal - 1.0f;      // 获得高频率扰动的法线,通过查询一个噪声图。      float3 vFlakesNormal = tex2D(microflakeNMap, i.SparkleTex);      // 别忘了转换到 [-1.0, 1.0] 区域内:      vFlakesNormal = 2 * vFlakesNormal - 1.0;      // 计算以下公式      // Np1 = ( a * Np + b * N ) / || a * Np + b * N || where a << b      //      float3 vNp1 = microflakePerturbationA * vFlakesNormal + normalPerturbation * vNormal ;      // 计算以下公式      // Np2 = ( c * Np + d * N ) / || c * Np + d * N || where c == d      float3 vNp2 = microflakePerturbation * ( vFlakesNormal + vNormal ) ;      // 因为需要与法线点乘求夹角,所以我们必须将它归一化一下      float3 vView = normalize( View );      // 把表面法线转换好世界空间中来,计算bump map的方法。      float3x3 mTangentToWorld = transpose( float3x3( Tangent, Binormal, Normal ) );      float3 vNormalWorld = normalize( mul( mTangentToWorld, vNormal ));      // 计算夹角余玄      floatfNdotV = saturate(dot( vNormalWorld, vView));      // 计算出反射向量      float3 vReflection = 2 * vNormalWorld * fNdotV - vView;      // 我们需要一个gloss值来读环境图,在真实的demo中,反射效果会有轻微的模糊。      floatfEnvBias = glossLevel;      // 用反射向量采样环境图。      float4 envMap = texCUBEbias( showroomMap, float4( vReflection, fEnvBias ) );      //乘以亮度值,在a通道中储存 RGBE      envMap.rgb = envMap.rgb * envMap.a;      // 再乘以一个亮度系数      envMap.rgb *= brightnessFactor;      // 将切线空间中的法线变换到世界坐标中来.      float3 vNp1World = normalize( mul( mTangentToWorld, vNp1) );      // 法线和视线点乘,得到斐涅尔系数      floatfFresnel1 = saturate( dot( vNp1World, vView ));      // 将第二个法线也同样重切线空间中变换到世界坐标中来.      float3 vNp2World = normalize( mul( mTangentToWorld, vNp2 ));      // 同样的方法得到第二个斐涅尔系数.      floatfFresnel2 = saturate( dot( vNp2World, vView ));      // 开始合成所有层了.      // 根据公式三      floatfFresnel1Sq = fFresnel1 * fFresnel1;      float4 paintColor = fFresnel1 * paintColor0 +      fFresnel1Sq * paintColorMid +      fFresnel1Sq * fFresnel1Sq * paintColor2 +      pow( fFresnel2, 16 ) * flakeLayerColor;      // 最后与反射的环境贴图合成在一起,形成最终的结果.      floatfEnvContribution = 1.0 - 0.5 * fNdotV;      float4 finalColor;      finalColor.a = 1.0;      finalColor.rgb = envMap * fEnvContribution + paintColor;      returnfinalColor;} | 
结论
此代码所使用的算法,经验更大于真实的物理属性,所以需要不断得调整常数值,
来使最终得到一个满意的效果.
    失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。
 
                    
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号