ARCore之路-环境理解之实例

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

  前面我们学习了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中,我们直接使用了 l e n g t h ( v . v e r t e x . x y z ) / M a x L e n g t h ; length(v.vertex.xyz) / _MaxLength; 请读者自行思考其中的原因。
  编译运行,效果如下:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/yolon3000/article/details/82825455
今日推荐