ARCore之路-光估计之光照强度估计

版权声明:David Wang原创ARCore文章,仅供学习研究之用,不得用于任何商业目的,未经授权不得转载! https://blog.csdn.net/yolon3000/article/details/83239651

  如前所述,光估计是一种非常复杂的技术。理想情况下,我们希望能够重建精确的光照模型,但是这需要深入的研究光照和图形学,再用数学为其建立精确的数字模型,无疑,这不是一件轻松的事情。但好消息是,ARCore将这些繁琐的技术进行了封装,提供给用户简单的使用接口,大大的简化了应用光估计的技术门槛。ARCore使用图像分析算法根据采集的当前图像确定光强,然后作为全局光应用到场景中的3D对象。本节,我们就来一探ARCore光照强度估计的秘密。打开最初我们放置狐狸的工程。

一、环境光设置

  之前我们创建的狐狸有些暗,原因是我们的场景中没有光源,我们新建一个方向光,在Inspector窗口中,设置一下Color值,适当的调低一点,Intensity调低到0.7,Shadow Type 设置为 No Shadows,通过这些设置,基本上把方向光变成了一个定向的环境光或全局光,如下图所示。

Cookie

二、ARCore光估计计算

  这里虽说是光估计计算,但实际上ARCore已经都计算好了,我们需要做只是将ARCore光估计稍微做一下变换,将其转换成一个光照参数(ColorCorrection),并使用这个参数来对所有的虚拟光照效果进行调整。
  在Hierarchy窗口并选择Environmental Light,然后在Inspector窗口会看到一个Environmental Light (Script) 脚本组件,打开这个脚本组件。

Cookie
       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);
        }

  在上面的代码中,我们首先检查代码是否在编辑器中运行,如果代码是在Unity3D编辑器中运行时,我们希望它忽略任何光估计计算。当代码在编辑器中运行时,设置 _GlobalColorCorrection 为1,即为不影响原光照计算结果,如果这个值不设置的话,所有使用光估计的Shader将为全黑。

  然后,首先检查帧的光估计是否有效,如果无效则直接返回,不做任何光估计处理。如果有效,则使用middle gray规一化这个像素强度(这是ARCore从摄像机读取图像并确定的当前像素强度值,它是一个浮点值,范围[0,1],表示从全黑到全白),注意,这里这个 middle gray 是在伽马颜色空间中(gamma space)的值,Unity3D默认使用伽马空间,在伽马空间中这个middle gray 值为0.466,在线性空间中为0.18, middle gray的含义是人类眼睛对颜色识别的临界值,小于这个值,人类眼睛就分别不出颜色了。如在晚上光线暗淡时,我们通常看不出树是绿色花是红色的,只能辨识出大致的灰度。

  需要说明的是,这段代码ARCore自带的,ARCore使用图像分析技术从摄像机图像中读取光强,并将该值转换为全局光强或颜色,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代码逻辑很简单,需要注意的是,在使用TRANSFORM_TEX时,需要定义_MainTex_ST变量,否则不起作用。

四、应用光估计

  上面我们已经编写好了Shader,现在我们要将这个Shader应用到我们模型上,新建一个Material,取名叫FoxDiffuse,Shader选择DavidWang/FoxDiffuse,然后将这个Material应用到Fox模型上,如下图所示。

Cookie
  编译、生成、运行APK应用,调整环境灯光照明,查看一下效果。ARCore光估计光照强度估计应用效果如下图所示:
Cookie

猜你喜欢

转载自blog.csdn.net/yolon3000/article/details/83239651