认识图形渲染中的各向异性

本文探讨了物理材料的各向异性特性及其在渲染技术中的应用,详细解释了各向异性表面如何通过法线扰动规则在不同方向上展现独特的光学效果,如拉丝金属和CD的闪光面。文章还提到了在微观层面各向同性模型如何叠加形成宏观的各向异性光照效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、物理材料中的各向异性

各向异性是指材料的性质会因为方向的不同呈现不同的特性,最常见的就是半导体,在反方向上几乎不导电;

物理性质可以在不同的方向进行测量。如果各个方向的测量结果是相同的,说明其物理性质与取向无关,就称为各向同性。如果物理性质和取向密切相关,不同取向的测量结果迥异,就称为各向异性。造成这种差别的内在因素是材料结构的对称性。在气体、液体或非晶态固体中,原子排列是混乱的,因而就各个方向而言,统计结果是等同的,所以其物理性质必然是各向同性的。而晶体中原子具有规则排列,结构上等同的方向只限于晶体对称性所决定的某些特定方向。所以一般而言,物理性质是各向异性的;晶体是各向异性的,非晶体是各向同性的,在渲染中使用各向异性时,我们主要指光学各向异性

二、渲染中材质的各项异性

各项异性表面从表面上细致的纹理、槽或丝缕来获得它特有的外观,比如拉丝金属、CD的闪光面。当使用普通的材质进行光照时,计算仅考虑表面的法线向量、到光源的向量、及到相机的向量。但是对于各向异性表面,没有真正可以使用的连续的法线向量,因为每个丝缕或槽都有各种不同的法线方向,法线方向和槽的方向垂直

其实在渲染中来实现各向异性光照时,并不是让每一个顶点在不同的方向都拥有不同的法线信息,它的计算是基于片元着色器的;如果是各项同性,我们只需要通过插值得到各个片元的法线信息即可,而对于各向异性来说,我们需要在片元着色器中根据法线扰动规则重新计算法线,这样,虽然看起来是一个平面,但它上面的像素却会因为法线扰动而形成一些纹理、凹槽的效果,从而展示出更多的细节表现,而且,法线的扰动通常是有规律的,所以在不同的方向上,表现出的效果可能会不一样,从而表现出所谓的光学各向异性;

在正常距离下,观看者看不到刻面或凹槽,而是从这种表面看到整体照明效果;

各向异性的光照效果,在微观下,微表面下的光照模型其实是各向同性的,而叠加起来之后得到整体上的各向异性的效果;

这个法线扰动规则可以是一个公式,也可以是一张纹理;

各向异性的头发渲染:Jim's GameDev Blog by chengkehan,该文章对各向异性的阐述最为清晰;

三、各项异性的实际使用

各向异性照明:10.9 Anisotropic Lighting

Unreal ngine 各向异性光照:UDK | AnisotropicLightingCH

毛发及眼球的渲染技术:毛发及眼球的渲染技术 - UWA Blog

各向异性拉丝金属:https://docs.arnoldrenderer.com/pages/viewpage.action?pageId=118227110

头发各向异性渲染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、付费专栏及课程。

余额充值