在前面的章节中, 我们已经学习了如何估计光照强度和如何估算光照方向这两个重要的影响视觉感受的光照因素,但还有一个问题没有解决,那就是光照颜色的问题。利用前面学习的知识,我们没办法处理冷暖灯光切换后虚拟物体光照的颜色问题,如在室内放置一个虚拟物体,开始我们使用红色灯光照明,这时我们能比较准确的评估出光照强度与方向,然后,我们关闭红色灯光,打开黄色灯光照明,这个光照颜色在虚拟物体上没有变化,而真实的情况并非如此,真实的情况是红色灯光照明物体应该偏红,黄色灯光照明物体应该偏黄。物体呈现的颜色与周围环境的色调有很大的关联。虚拟物体应该也要有类似的反映才能真实的反映出光照变化,如下图,虚拟物体在经过穿红色衣服的人时其颜色应该发生变化。
下面我们就来解决这个照明颜色的问题。
一、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应用,使用红色背景与不使用背景(调整环境颜色),查看一下效果。下图效果可能还不太明显,但也能看出变化,在后面的综合应用中,我们会采用一种更加复杂和高级的技术来提升这个效果。