溫馨提示:這篇文章已超過(guò)653天沒(méi)有更新,請(qǐng)注意相關(guān)的內(nèi)容是否還可用!
作者:彭曉韜
日期:2020.04.28
[文章摘要]:薄膜干涉是一種日常生活中很常見(jiàn)的物理現(xiàn)象,對(duì)其干涉條件也有比較系統(tǒng)性的研究。但就自然光(太陽(yáng)光)條件下,往往大于一定厚度的薄膜(也是為什么叫薄膜干涉而不叫膜干涉的原因所在)是不會(huì)出現(xiàn)干涉的,而厚度小到與可見(jiàn)光波長(zhǎng)相近的肥皂泡,甚至接近分子直徑的油膜卻可以產(chǎn)生干涉現(xiàn)象。這就與光程差大于光的半波長(zhǎng)即可產(chǎn)生干涉的條件相背。也與光是具有動(dòng)能與動(dòng)量的粒子假設(shè)相背:光子為什么不會(huì)穿透薄到與分子直徑接近的油膜,反而會(huì)在分子表面與底面形成反射?本文就此提出一些不成熟的看法與想法,供有興趣進(jìn)一步研究者參考。
一、薄膜干涉現(xiàn)象及機(jī)理簡(jiǎn)介
從上圖一和二可知:在太陽(yáng)光照片下,空氣中分布較均勻的微小水滴可使太陽(yáng)光產(chǎn)生散射并形成類似薄膜干涉一樣的彩虹。其機(jī)理是:水滴表面的散射光與入射進(jìn)水滴并被水滴內(nèi)表面反射出來(lái)的透射光合并并照射到人眼時(shí),其復(fù)合后的光的主頻會(huì)因入射進(jìn)入水滴內(nèi)部再被反射而透射出來(lái)的光程差主要與視角度有關(guān)而出現(xiàn)不同顏色的光帶:波長(zhǎng)與光程差相同或相近或成倍數(shù)關(guān)系的光將得到加強(qiáng),其它波長(zhǎng)的光將變?nèi)酢9獬滩钚〉膹?fù)合后得到加強(qiáng)的光的頻率偏高而呈現(xiàn)出藍(lán)色光帶,反之呈現(xiàn)出紅色光帶。視高度大于太陽(yáng)視高度的水滴產(chǎn)生的光程差隨視高度減小,因此,紅光帶在下方,藍(lán)光帶在上方;而視高度小于太陽(yáng)視高度的水滴產(chǎn)生的光程差隨視高度增大,因此紅光帶在上方,藍(lán)光帶在下方。這就是彩虹為什么會(huì)出現(xiàn)上下顏色顛倒的原因所在。
圖四:薄膜干涉動(dòng)圖
【基礎(chǔ)回顧】?考點(diǎn)一 光的干涉現(xiàn)象的理解?1、光的雙縫干涉現(xiàn)象的理解? (1)光能夠發(fā)生干涉的條件:兩光的頻率相同,振動(dòng)步調(diào)相同.? (2)雙縫干涉形成的條紋是等間距的,兩相鄰亮條紋或相鄰暗條紋間距離與波長(zhǎng)成正比,即.? (3)用白光照射雙縫時(shí),形成的干涉條紋的特點(diǎn):中央為白條紋,兩側(cè)為彩色條紋.?2、薄膜干涉現(xiàn)象的理解? (1)如圖所示,豎直的肥皂薄膜,由于重力的作用,形成上薄下厚的楔形.? (2)光照射到薄膜上時(shí),在膜的前表面AA′和后表面BB′分別反射出來(lái),形成兩列頻率相同的光波,并且疊加.? (3) 原理分析?①單色光? 在P1、P2處,兩個(gè)表面反射回來(lái)的兩列光波的路程差Δr等于波長(zhǎng)的整數(shù)倍. Δr
序·薄膜干涉
前幾天讀了 @中國(guó)科普博覽 @Luyao Zou 的一篇文章,里面講了肥皂泡薄膜干涉的原理,并給出了定量測(cè)量的顏色圖
覺(jué)得十分有趣,因此才起了用Shader實(shí)現(xiàn)一下肥皂泡的想法
為什么陽(yáng)光下的泡沫是彩色的?? zhihu
一般渲染中只涉及幾何光學(xué),不會(huì)涉及干涉,但有定量測(cè)量結(jié)果后,我們可以只通過(guò)角度與薄膜厚度映射相關(guān)的色彩,從而模擬出干涉效果
項(xiàng)目下載
感興趣的小伙伴可以在Github上下載這個(gè)小項(xiàng)目:
TYJia/Bubble?github
肥皂泡模擬
肥皂泡的屬性分析
除了絢麗多彩,肥皂泡還有一些其他的屬性,也是渲染的關(guān)鍵,仔細(xì)觀察可以發(fā)現(xiàn)如下現(xiàn)象:
1. 菲涅爾現(xiàn)象
肥皂泡的菲涅爾現(xiàn)象
肥皂泡的菲涅爾現(xiàn)象是十分明顯的,當(dāng)視線與泡泡表面法線方向相同、相反時(shí),反射率較低;當(dāng)視線與泡泡表面法線垂直時(shí),反射率較高
2. 鏡面反射與光透明度
光滑,鏡面反射,暗處透明
泡泡的表面都是極為光滑的,所以是鏡面反射;不過(guò)在不反射光線或光線較弱時(shí),它是全透明的,反射光線較強(qiáng)時(shí),才會(huì)被我們看見(jiàn)
所以在進(jìn)行透明度計(jì)算時(shí),也要同時(shí)考慮反射明度
3. 雙面反射(中心對(duì)稱反射)
與水晶球不同,泡泡的內(nèi)外表面都是參與反射的,所以一個(gè)球形泡泡會(huì)形成中心對(duì)稱的反射結(jié)果
4. 流動(dòng)的表面
流動(dòng)的表面
泡泡的表面是液體,再加上一些力的作用,所以會(huì)慢慢流動(dòng),也因此會(huì)產(chǎn)生表面厚度的變化
源碼
Shader "TJia/BubbleShader" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MetalRef ("MetalRef", Range(0,1)) = 0
_MainTex("Main Tex", 2D) = "white" {}
_BumpMap ("Bumpmap (RGB)", 2D) = "bump" {}
_BumpValue ("BumpValue", Range(0,3)) = 1
_LightModle ("LightModleDiffuse (RGB)", 2D) = "white" {}
_LightModleValue("LightModleValue", Range(0,3)) = 1
_LightModleSpec ("LightModleSpec (RGB)", 2D) = "black" {}
_SpecValue ("SpecValue", Range(0,4)) = 0
_Bubble ("Bubble (RGB)", 2D) = "white" {}
_BubbleNoise("BubbleNoise",2D) = "white" {}
_BubblelValue ("Bubble Value", Range(0,2)) = 1
}
Sub***er {
Tags { "RenderType"="Transparent" "Queue" = "Transparent"}
Fog { Color [_AddFog] }
Pass {
Name "BASE"
Tags { "LightMode" = "Always" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
//#define _Shadow 1
//#define _ShadowRange 0.25
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 TtoV0 : TEXCOORD1;
float3 TtoV1 : TEXCOORD2;
float3 visual : TEXCORRD3;
float3 normal : NORMAL;
};
uniform float4 _BumpMap_ST, _DetailGreyTex_ST, _DetailBumpTex_ST;
uniform float4 _MainTex_ST;
v2f vert (appdata_tan v)
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex+_SinTime.y*v.normal*0.1);
o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);
TANGENT_SPACE_ROTATION;
o.TtoV0 = normalize(mul(rotation, UNITY_MATRIX_IT_MV[0] ));
o.TtoV1 = normalize(mul(rotation, UNITY_MATRIX_IT_MV[1] ));
o.visual = normalize(mul(rotation, -ObjSpaceViewDir(v.vertex)));
return o;
}
uniform fixed4 _Color, _ShadowColor;
uniform sampler2D _BumpMap, _Bubble, _BubbleNoise;
uniform sampler2D _LightModle;
uniform sampler2D _MainTex;
uniform sampler2D _LightModleSpec;
uniform fixed _SpecValue;
uniform fixed _BumpValue;
uniform fixed _LightModleValue, _BubblelValue;
uniform fixed _MetalRef;
float3 lum(fixed3 c)
{
return c.r * 0.2 + c.g * 0.7 + c.b * 0.1;
}
float4 frag (v2f i) : COLOR
{
fixed4 c = tex2D(_MainTex, i.uv.xy);
float3 normal = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
normal.xy *= _BumpValue;
normal = normalize(normal);
float v_n_an*** = saturate(acos(dot(-i.visual,normal))*2/3.14);
float BubbleR = tex2D(_BubbleNoise, i.uv.xy+float2(0,_Time.x)).r;
float BubbleG = tex2D(_BubbleNoise, i.uv.xy+float2(BubbleR*0.5,_Time.x)*0.9+0.05*_SinTime.x).g;
float BubbleB = tex2D(_BubbleNoise, i.uv.xy+float2(BubbleG*0.5,_Time.x)*1.1-0.05*_SinTime.y).b;
float BubbleNoise = saturate(BubbleR * BubbleG * BubbleB * 4);
fixed4 Bubble = tex2D(_Bubble, fixed2(BubbleNoise, v_n_an***));
float3 correctiveNormal = normalize(reflect(i.visual, normal));
normal = normalize(lerp(normal, correctiveNormal, _MetalRef));
half2 vn;
vn.x = dot(i.TtoV0, normal);
vn.y = dot(i.TtoV1, normal);
fixed4 LightModleLookup = saturate(tex2D(_LightModle, vn * 0.495 + 0.505) * _Color * _LightModleValue);
//LightModleLookup.a = 1;
fixed2x2 rotSpec =
{
-1, 0,
0, -1
};
half2 vnsp = mul(rotSpec, vn);
fixed4 LightModleSpec = tex2D(_LightModleSpec, vn*0.495 + 0.505);
fixed4 LightModleSpec2 = tex2D(_LightModleSpec, vnsp*0.495 + 0.505);
LightModleSpec.rgb = lum(saturate((LightModleSpec + LightModleSpec2)*0.5).rgb) * (LightModleSpec.rgb+LightModleSpec2.rgb)*0.5;
LightModleSpec.a = 1;
fixed4 diff = c * LightModleLookup ;
fixed4 finalColor = clamp(diff + LightModleSpec * _SpecValue, 0, 1) * lerp(fixed4(1, 1, 1, 1), Bubble * 1.5, _BubblelValue);
float fresnel = saturate(pow(v_n_an***,1.6));
finalColor.a = saturate(fresnel * 0.2 + 0.8 * (fresnel+0.1) * lum(LightModleSpec.rgb * _SpecValue + 0.1) + 0.05);
return finalColor;
}
ENDCG
}
}
Fallback "VertexLit"
}
實(shí)現(xiàn)方法注釋
1. 用以模擬泡泡表面液體流動(dòng)的厚度噪聲圖
為了模擬肥皂泡厚度流動(dòng)的變化,這里使用了一張?jiān)肼晥D,RGB通道都是PS隨機(jī)生成的,厚度計(jì)算方法如下:
float BubbleR = tex2D(_BubbleNoise, i.uv.xy+float2(0,_Time.x)).r;
float BubbleG = tex2D(_BubbleNoise, i.uv.xy+float2(BubbleR*0.5,_Time.x)*0.9+0.05*_SinTime.x).g;
float BubbleB = tex2D(_BubbleNoise, i.uv.xy+float2(BubbleG*0.5,_Time.x)*1.1-0.05*_SinTime.y).b;
float BubbleNoise = saturate(BubbleR * BubbleG * BubbleB * 4);
厚度噪聲圖
2. 中心對(duì)稱的反射
這里使用了旋轉(zhuǎn)矩陣,將反射結(jié)果轉(zhuǎn)了180°,并進(jìn)行了如下的混合計(jì)算:
LightModleSpec.rgb = lum(saturate((LightModleSpec + LightModleSpec2)*0.5).rgb) * (LightModleSpec.rgb+LightModleSpec2.rgb)*0.5;
3. 基于菲涅爾和反光明度的透明度計(jì)算
菲涅爾通過(guò)視線、法線夾角得出
這里使用acos是為了薄膜干涉映射,在菲涅爾模擬中不必要
最終透明度通過(guò)菲涅爾和光照強(qiáng)度混合計(jì)算獲得:
float v_n_an*** = saturate(acos(dot(-i.visual,normal))*2/3.14);
float fresnel = saturate(pow(v_n_an***,1.6));
finalColor.a = saturate(fresnel * 0.2 + 0.8 * (fresnel+0.1) * lum(LightModleSpec.rgb * _SpecValue + 0.1) + 0.05);
最終結(jié)果如下:
拓展
改改采樣圖,調(diào)調(diào)混合模式,就可以當(dāng)流動(dòng)的防護(hù)罩來(lái)用啦~
發(fā)表評(píng)論
還沒(méi)有評(píng)論,來(lái)說(shuō)兩句吧...