XDRender_LightMode_Anisotropic(2) 各项异性着色(2) 切线

XDRender_LightMode_Anisotropic(2) 各项异性着色(2) 切线

image-20201121220145384

一、为何是切线

image-20201120164651501

还是这个图, 需要更深的理解.

为何需要切线来做?

其实我们去看一个图和一个算法能更清楚, 这里就需要说明什么叫各项异性的异性来源. 可以理解为当不同的观察角度,会有不同的影响因子. (有点薛定谔了 哈哈).

观察角度

这里观察角度就是ViewDir

影响因子

得出的影响因子,其实还是法线. 这是这时候的法线由于我们的观察角度被改变了.

其实这样做的原因,还是由于精度和性能, 可以详细非常细非常细的丝线, 环绕的法线就有一圈. 这时候我们不可能完全物理来计算. 所以做了一个近似. 只需要有个切线(变化了一丢丢的)加上观察角度. 就能算出一个大概.

下面是一个还不够细的线, 想象我们再进入微观一点.

image-20201120170141288

细看这个不完全符合物理的

float Aniso_StrandSpecular(float3 T, float3 V, float L, float exponent)
{
    float3 H = normalize(L + V);
    float dotTH = dot(T, H);
    float sinTH = sqrt(1.0 - dotTH*dotTH);
    float dirAtten = smoothstep(-1.0, 0.0, dot(T, H));
    return dirAtten * pow(sinTH, exponent);
}

二、切线、法线到切线, 切线和方向影响到法线

1、法线到切线的一种步骤

法线纹理

​ 在切线空间

法线

​ 根据计算出的切线空间的法线,经过空间转换,得到世界空间

切线

​ 这时候(世界空间下)根据法线和副切线 得到切线

(世界空间)扰动了切线

​ 法线加重对切线的影响

inputData.tangentWS = ShiftTangent(tangentWS,input.normalWS,_CustomData.z);
影响计算

几种经验:

dot(N,H)^specularity

其中切线方向可以用外部纹理等给到

fixed HdotA = dot(normalize(Normal + AnisoDirection), halfVector);  
    float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180f)));
  
    float spec = saturate(pow(aniso, Gloss * 128) );
sin(T,H)^specularity

1、Kajiya-Kay

![image-20201120171519068](file:///Users/wumingfei/Documents/OneDriver/OneDrive%20-%20sensetime/DaoZhangOneNote/MYBlobTemp/Render/XDGameEngine/XDGameEngine_Unity/Pass_Light/XDRender_LightMode_Anisotropic2.assets/image-20201120171519068.png?lastModify=1605864195)

2、 circle各向异性, 对Kajiya-Kay一种近似

image-20201120171423587
ward各向异性

这里主要是有粗糙度对两个方向的影响

第一张

ward各向异性分布函数的优点是可以使用comb贴图,也就是各向异性方向贴图,有作为tangent方向矫正各向异性高光形状及方向的功能

if (dotLN < 0.0) // light source on the wrong side?
            {
               specularReflection = vec3(0.0, 0.0, 0.0); 
                  // no specular reflection
            }
            else // light source on the right side
            {
               float dotHN = dot(halfwayVector, normalDirection);
               float dotVN = dot(viewDirection, normalDirection);
               float dotHTAlphaX = 
                  dot(halfwayVector, tangentDirection) / _AlphaX;
               float dotHBAlphaY = dot(halfwayVector, 
                  binormalDirection) / _AlphaY;
 
               specularReflection = attenuation * vec3(_SpecColor) 
                  * sqrt(max(0.0, dotLN / dotVN)) 
                  * exp(-2.0 * (dotHTAlphaX * dotHTAlphaX 
                  + dotHBAlphaY * dotHBAlphaY) / (1.0 + dotHN));
            }
 
         }

迪斯尼的G和D两项

// specular
    float aspect = sqrt(1-anisotropic*.9);
    float ax = max(.001, sqr(roughness)/aspect);
    float ay = max(.001, sqr(roughness)*aspect);
float D_GTR2_aniso(float dotHX, float dotHY, float dotNH, float ax, float ay)
{
       float deno = dotHX * dotHX / (ax * ax) + dotHY * dotHY / (ay * ay) + dotNH * dotNH;
       return 1.0 / (PI * ax * ay * deno * deno);
 
}
/ Smith GGX G项,各项异性版本
// Derived G function for GGX
float smithG_GGX_aniso(float dotVN, float dotVX, float dotVY, float ax, float ay)
{
        return 1.0 / (dotVN + sqrt(pow(dotVX * ax, 2.0) + pow(dotVY * ay, 2.0) + pow(dotVN, 2.0)));
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
头发各向异性渲染Shader 这个是04年的一个ppt,主要介绍了头发的渲染,其追到源头还是要看这个原理。 各向异性的主要计算公式: 主要代码如下: 切线混合扰动部分(这部分也可以用T+k*N,来对切线进行扰动): float3x3 tangentTransform = float3x3(i.tangentDir, i.bitangentDir, i.normalDir); float3 _T_var = UnpackNormal(tex2D(_Tangent, TRANSFORM_TEX(i.uv0, _Tangent))); float3 temp = lerp(_TangentParam.xyz, _T_var, _BlenfTangent); float3 T = normalize(mul(float3(temp.xy,0), tangentTransform)); 主要是通过改变切线的xy值来造成头发高光部分的多样性。 高光部分,按公式计算即可: float StrandSpecular(float3 T, float3 V, float3 L, float exponent) { float3 H = normalize(L + V); float dotTH = dot(T, H); float sinTH = sqrt(1 - dotTH*dotTH); float dirAtten = smoothstep(-1, 0, dotTH); return dirAtten*pow(sinTH, exponent); } 注意,为了模拟的更贴近真实性,应用两层高光,第一层高光代表直射光直接反射出去,第二层代表次表面散射现象具体看代码。 最终渲染部分: float4 HairLighting(float3 T, float3 N, float3 L, float3 V, float2 uv, float3 lightColor) { float diffuse = saturate(lerp(0.25, 1.0, dot(N, L)))*lightColor; float3 indirectDiffuse = float3(0, 0, 0); indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb; // Ambient Light float3 H = normalize(L + V); float LdotH = saturate(dot(L, H)); float3 specular = _Specular*StrandSpecular(T, V, L, exp2(lerp(1, 11, _Gloss))); //float specMask = tex2D(_SpecMask, TRANSFORM_TEX(uv, _SpecMask)); specular += /*specMask*/_SubColor*StrandSpecular(T, V, L, exp2(lerp(1, 11, _ScatterFactor))); float4 final; float4 base = tex2D(_MainTex, TRANSFORM_TEX(uv, _MainTex)); float3 diffuseColor = (_Color.rgb*base.rgb); //float ao = tex2D(_AO, TRANSFORM_TEX(uv, _AO)).g; final.rgb = (diffuse + indirectDiffuse)*diffuseColor + specular*lightColor* FresnelTerm(_Specular, LdotH); //final.rgb *= ao; final.a = base.a; clip(final.a - _CutOff); return final; } 这里我注释掉了AO和高光遮罩,需要的同学可以加上。 最后一点为了不让头发的边经过clip之后太硬,需要进行两个通道的belnd。 第二个pass使用以下指令: Blend SrcAlpha OneMinusSrcAlpha ZWrite Off 注意第二个通道无需再进行clip操作。 至此,头发渲染完毕。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值