1. 程式人生 > >ARCore之路-環境理解之例項

ARCore之路-環境理解之例項

  前面我們學習了ARCore對環境中特徵點及平面的識別,並簡單介紹了Shader及Cg語言。本節主要利用這些知識點來對環境進行檢測。我們的目標是利用ARCore對環境中特徵點的檢測來估測特徵點到使用者(手機裝置)的距離遠近並可視化之。

一、思路

  在ARCore中,AR應用初始化的位置既是使用者(攝像機)的位置,同時也是世界空間的原點。Unity的顏色分量是[0.0,1.0],我們的思路是先取到所有檢測到的特徵點中的最遠的特徵點到攝像機的距離,然後將這個最遠距離傳遞給Shader程式,在渲染時,我們將每個特徵點到攝像機的距離除以這個最遠距離,那麼這個值必定在[0.0,1.0]範圍內,直接作為顏色分量進行渲染即可以看到不同距離特徵點呈現的顏色。

  具體操作過程:

  1. 開啟點雲視覺化工程,前建Assets->Scripts資料夾。
  2. 在Assets->Scripts資料夾內新建C#指令碼“PointVisualizer”。
  3. 在Assets->Materials資料夾內新建Shader “VisualPoint”。
  4. 將下文中的C#程式碼及shader程式碼分別複製到對應檔案中。
  5. 在Hierarchy視窗中,選擇VisualPoint,將其原來的視覺化指令碼及Shader刪除,新增我們編寫的C#指令碼及Shader。
這裡寫圖片描述

二、評估ARCore特徵點的距離

  這個過程我們可以直接利用ARCore對特徵點進行處理,C#指令碼“PointVisualizer”中程式碼如下。

// Wrote by David Wang 2018.09.23
using System.Collections;
using System.Collections.Generic;
using GoogleARCore;
using UnityEngine;

public class PointVisualizer : MonoBehaviour {
    private const int k_MaxPointCount = 61440;
    private float mMaxPointLength = 1.0f;
    private Mesh mMesh;
    private Material mMaterial;
private Vector3[] mPoints = new Vector3[k_MaxPointCount]; /// <summary> /// Unity start. /// </summary> public void Start() { mMesh = GetComponent<MeshFilter>().mesh; mMaterial = GetComponent<Renderer>().material; mMesh.Clear(); } /// <summary> /// Unity update. /// </summary> public void Update() { // Fill in the data to draw the point cloud. if (Frame.PointCloud.IsUpdatedThisFrame) { double len = 1.0f; for (int i = 0; i < Frame.PointCloud.PointCount; i++) { mPoints[i] = Frame.PointCloud.GetPoint(i); len = Mathf.Sqrt(mPoints[i].x * mPoints[i].x + mPoints[i].y * mPoints[i].y + mPoints[i].z * mPoints[i].z); mMaxPointLength = Mathf.Max(mMaxPointLength, (float)len); } // Update the mesh indicies array. int[] indices = new int[Frame.PointCloud.PointCount]; for (int i = 0; i < Frame.PointCloud.PointCount; i++) { indices[i] = i; } mMaterial.SetFloat("_MaxLength", mMaxPointLength); mMaxPointLength = 1.0f; mMesh.Clear(); mMesh.vertices = mPoints; mMesh.SetIndices(indices, MeshTopology.Points, 0); } } }

  這段程式碼的功能是生成特徵點頂點資料,在遍歷特徵點資料時我們取得到最遠特徵點到攝像機的距離,並將這個值傳遞給了Shader。

三、編寫Shader視覺化

  在Shader中,我們將對所有的特徵點頂點到攝像機的距離與最遠距離作比較,得到一個可以作為顏色分量的比值,Shader “VisualPoint”程式碼如下。

// Wrote by David Wang 2018.09.23
Shader "DavidWang/PointCloud" {
	Properties{
		_PointSize("Point Size", Float) = 15.0
	}
		SubShader{
				 Pass{
					  CGPROGRAM
					  #pragma vertex vert
					  #pragma fragment frag

					  #include "UnityCG.cginc"

					  struct appdata
					  {
						  float4 vertex : POSITION;
					  };

					  struct v2f
					  {
						   float4 vertex : SV_POSITION;
						   float size : PSIZE;
						   float ratio : TEXCOORD0;

					  };

					  float _PointSize;
					  float _MaxLength = 1.0f;

					  v2f vert(appdata v)
					 {
						  v2f o;
						  o.vertex = UnityObjectToClipPos(v.vertex);
						  o.size = _PointSize;
						  o.ratio = length(v.vertex.xyz) / _MaxLength;
						 return o;
					 }

					 fixed4 frag(v2f i) : SV_Target
					 {
						  return float4(i.ratio, 1.0f - i.ratio,i.ratio,1.0f);
					 }
				   ENDCG
				}
	}
}

  上述程式碼中,需要注意的是,對距離的比較需要在同一座標空間中進行,不同座標空間中的量對比是沒有意義的,在C#中,我們獲取的是特徵點相對與世界空間原點的距離(這個世界空間原點也是裝置初始化時攝像機的位置),在Shader中,我們也要獲取到特徵點相對世界空間原點的距離,這樣比較才有意義。在Shader中,我們直接使用了length(v.vertex.xyz)/MaxLength;length(v.vertex.xyz) / _MaxLength; 請讀者自行思考其中的原因。   編譯執行,效果如下:

這裡寫圖片描述