在前面的章節中, 我們已經學習瞭如何估計光照強度和如何估算光照方向這兩個重要的影響視覺感受的光照因素,但還有一個問題沒有解決,那就是光照顏色的問題。利用前面學習的知識,我們沒辦法處理冷暖燈光切換後虛擬物體光照的顏色問題,如在室內放置一個虛擬物體,開始我們使用紅色燈光照明,這時我們能比較準確的評估出光照強度與方向,然後,我們關閉紅色燈光,打開黃色燈光照明,這個光照顏色在虛擬物體上沒有變化,而真實的情況並非如此,真實的情況是紅色燈光照明物體應該偏紅,黃色燈光照明物體應該偏黃。物體呈現的顏色與周圍環境的色調有很大的關聯。虛擬物體應該也要有類似的反映才能真實的反映出光照變化,如下圖,虛擬物體在經過穿紅色衣服的人時其顏色應該發生變化。
下面我們就來解決這個照明顏色的問題。
一、ARCore顏色估計計算
顏色估計計算實際上ARCore也已經都計算好了,我們需要做只是將ARCore顏色估計稍微做一下變換,將其轉換成一個光照參數(ColorCorrection),並使用這個參數來對所有的虛擬光照效果進行調整。
再回去看一下腳本,在Hierarchy窗口並選擇Environmental Light,然後在Inspector窗口會看到一個Environmental Light (Script) 腳本組件,打開這個腳本組件。
public void Update()
{
if (Application.isEditor && (!Application.isPlaying ||
!GoogleARCoreInternal.ARCoreProjectSettings.Instance.IsInstantPreviewEnabled))
{
// 在編輯狀態下瀏覽,設置 _GlobalColorCorrection 爲1,如果這個值不設置的話,所有使用光估計的Shader將爲全黑。
Shader.SetGlobalColor("_GlobalColorCorrection", Color.white);
// 設置 _GlobalLightEstimation是爲了後向兼容
Shader.SetGlobalFloat("_GlobalLightEstimation", 1f);
return;
}
if (Frame.LightEstimate.State != LightEstimateState.Valid)
{
return;
}
// 使用middle gray規一化這個像素強度,這裏這個 middle gray 是在伽馬顏色空間中(gamma space)。
const float middleGray = 0.466f;
float normalizedIntensity = Frame.LightEstimate.PixelIntensity / middleGray;
// 設置伽馬顏色空間中的顏色校準參數
Shader.SetGlobalColor("_GlobalColorCorrection", Frame.LightEstimate.ColorCorrection * normalizedIntensity);
// 設置 _GlobalLightEstimation是爲了後向兼容
Shader.SetGlobalFloat("_GlobalLightEstimation", normalizedIntensity);
}
這段代碼前面我們已經分析過,ARCore使用圖像分析技術從攝像機圖像中讀取當前圖像的顏色值,並計算出一個顏色校正值ColorCorrection,並將該值轉換爲全局光照顏色校正值,ARCore每幀都會更新這個估計值,然後將這個參數設置到一個全局的光照參數(_GlobalColorCorrection)。我們可以在我們需要使用光估計的Shader中引用這個值來調整顏色即可。
二、顏色估計Shader
如上節所述,ARCore已經爲我們做好光估計的所有計算,我們需要做的是利用這個光照參數(_GlobalColorCorrection)來調整我們的最終的顏色值。編寫如下Shader。
// Wrote by David Wang 2018.10.20
Shader "DavidWang/FoxDiffuse"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma exclude_renderers d3d11
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed3 _GlobalColorCorrection;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv_MainTex : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv_MainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
float3 color = float3(c.rgb * _GlobalColorCorrection);
return float4(color, c.a);
}
ENDCG
}
}
Fallback "Mobile/VertexLit"
}
這段Shader與光照強度估計用的Shader幾乎完全一樣,唯一的不同是使用_GlobalColorCorrection對顏色與光照強度進行了調整,而不是僅對光照強度進行調整。
編譯、生成、運行APK應用,使用紅色背景與不使用背景(調整環境顏色),查看一下效果。下圖效果可能還不太明顯,但也能看出變化,在後面的綜合應用中,我們會採用一種更加複雜和高級的技術來提升這個效果。