1.
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
也就相当于(sqrt(1-dot(T,H)^2))^specularity
在ATI 2004 年的“hair rendering and shading”中提到,其中又有specular shift等特点不在此赘述
3.
ward各向异性分布函数
wiki的解释如下
The Ward anisotropic distributionuses two user-controllable parameters αx and αy to control the anisotropy. If the two parameters are equal, then an isotropic highlight results. The specular term in the distribution is:
The specular term is zero if N·L < 0 or N·V < 0. All vectors are unit vectors. The vector V is the viewing direction, L is the direction from the surface point to the light, H is the half-angle direction between V and L, N is the surface normal, and X and Y are two orthogonal vectors in the normal plane which specify the anisotropic directions.
ward各向异性分布函数的优点是可以使用comb贴图,也就是各向异性方向贴图,有作为tangent方向矫正各向异性高光形状及方向的功能
http://www.poopinmymouth.com/tutorials/comb-map.html
unity wiki有相关算法
https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Brushed_Metal
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));
}
}
在Autodesk的uber shader(大杂烩shader)中也用了这个分布函数
其中的comb tex直接取代了tangent方向
comb tex相当于是一个法线贴图,所以使用的时候需要unpack
float3 WardAniso(float3 N, float3 H, float NdotL, float NdotV, float Roughness1, float Roughness2, float3 anisotropicDir, float3 specColor)
{
float3 binormalDirection = cross(N, anisotropicDir);
float HdotN = dot(H, N);
float dotHDirRough1 = dot(H, anisotropicDir) / Roughness1;
float dotHBRough2 = dot(H, binormalDirection) / Roughness2;
float attenuation = 1.0;
float3 spec = attenuation * specColor
* sqrt(max(0.0, NdotL / NdotV))
* exp(-2.0 * (dotHDirRough1 * dotHDirRough1
+ dotHBRough2 * dotHBRough2) / (1.0 + HdotN));
return spec;
}
float4 anisotropicDir = float4(T, 1); // alpha is the blinn-aniso mask
if (UseAnisotropicDirectionMap)
{
float2 anisoDirUV = pickTexcoord(AnisotropicTexcoord, IN.texCoord0, IN.texCoord1, IN.texCoord2);
if (AnisotropicDirectionType == 0) // use tangent map for direction
{
anisotropicDir = AnisotropicTexture.Sample(SamplerAnisoWrap, anisoDirUV);
anisotropicDir.xyz = anisotropicDir.xyz * 2 - 1; // unpack
}
}
--wolf96 2016/10/31