1. 程式人生 > >unity3D多點測量、多邊形面積測量

unity3D多點測量、多邊形面積測量

直接先看先看效果,多點測量:


任意點構成的多邊形面積測量(面積顯示在左上角顯示在模型感覺太亂):


覺得要注意的就是點的自動縫合這塊,多邊形繪製頂點實時連線最後一個點,時間座標與螢幕座標到GUI座標系之間的裝換,還是直接上程式碼明瞭

核心指令碼:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class RayMeasure : MonoBehaviour {

   // public NumeberControl nbc;
    //public int lineCount = 100;
   // public float radius = 3.0f;
    public Camera camera;
    static Material lineMaterial;
    static void CreateLineMaterial()
    {
        if (!lineMaterial)
        {
        
            Shader shader = Shader.Find("Hidden/Internal-Colored");
            lineMaterial = new Material(shader);
            lineMaterial.hideFlags = HideFlags.HideAndDontSave;
            // Turn on alpha blending
            lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
            lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
            // Turn backface culling off
            lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
            // Turn off depth writes
            lineMaterial.SetInt("_ZWrite", 0);
        }
    }

    public void OnRenderObject()
    {
        CreateLineMaterial();
        lineMaterial.SetPass(0);
        GL.PushMatrix();
        GL.Begin(GL.LINES);
        for (int i = 0; i < lv.Count; i++)
        {
            GL.Vertex3(lv[i].x, lv[i].y+2.5f, lv[i].z);
        }
        GL.End();
        GL.PopMatrix();
    }
    bool sb = false;
    //圓點的預製體
    public GameObject aim;
    //單位的預製體
    public GameObject longs;
    //圓點的父節點 ,所有物體在子節點下
   // public Transform aimPar;
    //單位的預製體 ,所有的單位在子節點下
    //public Transform unit;
    //GL 繪製的頂點陣列  順序是  0->1  2->3 4->5    取法 0 1 3 5 7 9
    //參考UI介面
    public List<Vector3> lv;
    private  List<GameObject> aims;
    public Vector3 V3;
    void Start() {
        lv = new List<Vector3>();
        aims = new List<GameObject>();
        V3 = Vector3.zero;
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(1))//繪製多邊形
        {
            Ray ray = camera.ScreenPointToRay(Input.mousePosition);

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                //建立圓點
              GameObject go=  Instantiate(aim, new Vector3(hit.point.x, hit.point.y + 1, hit.point.z), Quaternion.Euler(90, 0, 0))as GameObject;
                aims.Add(go);
               // Debug.Log("991231:"+aims.Count);
                // aim.transform.position =new Vector3(hit.point.x, hit.point.y+1, hit.point.z) ;
                if (lv.Count >= 2)
                {
                    //存入點就是反覆存入來自動連線,0--1 1--2 2--3.。。。。類似這格式儲存點
                    if (sb)
                    {
                        lv.RemoveAt(lv.Count - 1);
                        lv.RemoveAt(lv.Count - 1);
                    }
                   // print("補線");
                    //Debug.Log("lv個數:"+lv.Count);
                    lv.Add(lv[lv.Count - 1]);
                    lv.Add(hit.point);
                    lv.Add(lv[0]);
                    lv.Add(hit.point);

                    sb = true;
                    
                }
                else
                {
                    lv.Add(hit.point);
                }

            }
            
         
            
        }
        else if (Input.GetMouseButtonDown(0))//繪製線段
        {
            Ray ray = camera.ScreenPointToRay(Input.mousePosition);

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
               aims.Add( Instantiate(aim, new Vector3(hit.point.x, hit.point.y + 3f, hit.point.z), Quaternion.Euler(90, 0, 0))as GameObject);

                if (lv.Count >= 2)
                {

                    lv.Add(lv[lv.Count - 1]);
                    lv.Add(hit.point);
                }
                else {
                    lv.Add(hit.point);
                }
            }

        }
        
    }
    
    void OnGUI() {
       // 利用gui 為了實時動態更新畫線資料
        if (lv.Count >= 2)
        {
            for (int i = 0; i < lv.Count-1; i=i+2)//除了第一個點和最後個點,其它點都是存了兩遍
            {
                
                Vector3 s = new Vector3((lv[i].x + lv[i + 1].x) / 2, (lv[i].y + lv[i + 1].y) / 2,(lv[i].z+ lv[i + 1].z) / 2 );

                Vector3 a = camera.WorldToScreenPoint(s);
               //注意螢幕座標系與GUI的ui座標系y軸相反,ToString(".000")保留小數點後3位數,幾個零幾位數

                GUI.Label(new Rect(a.x,Screen.height-a.y, 100, 20), "<color=red>" + Vector3.Distance(lv[i], lv[i + 1]).ToString(".000") + "</color>" + "<color=blue>" + "米" + "</color>");
                //  GUI.Label(new Rect(, (camera.WorldToScreenPoint(lv[i]).y + camera.WorldToScreenPoint(lv[i+1]).y) / 2, 100, 20), "<color=red>" + Vector3.Distance(lv[i], lv[i+1]) + "</color>" + "<color=blue>" +"米"+"</color>");
                //GUI.Label(new Rect(lv[i].x+lv[i+1].x / 2, lv[i].y + lv[i + 1].y / 2, 100, 20), "<color=red>" + Vector3.Distance(lv[i], lv[i + 1]) + "</color>" + "<color=blue>" + "米" + "</color>");
            }
        }
        if (lv.Count > 2)
        {

            //for (int j = 0; j < lv.Count - 1; j = j + 2) {
            //    V3 += lv[j];
            //}
            //Debug.Log("zong---------"+V3);
            //Vector3 average = new Vector3(V3.x/(lv.Count/2), V3.y / (lv.Count / 2), V3.z / (lv.Count / 2));
            //Debug.Log("pingjin_______________"+average);
            //Vector3 ss = camera.WorldToScreenPoint(average);
            // Debug.Log(ComputePolygonArea(lv));
            GUI.Label(new Rect(15, 15, 120, 40), "<color=green>" + ComputePolygonArea(lv).ToString(".000") + "</color>" + "<color=yellow>" + ":平方米" + "</color>");
        }
    }
    public void ClearLines() {

        sb = false;
        for (int i = 0; i < aims.Count; i++) {
            GameObject.Destroy(aims[i]);

        }
        lv.Clear();
        //lv = new List<Vector3>();
        aims.Clear();
    }
    //計算任意多邊形的面積,頂點按照順時針或者逆時針方向排列,不需要考慮y軸的座標
    double ComputePolygonArea(List<Vector3> points)
    {
        int point_num = points.Count;
        if (point_num < 3) return 0.0;
        float s = points[0].z * (points[point_num - 1].x - points[1].x);
        for (int i = 1; i < point_num; ++i)
            s += points[i].z * (points[i - 1].x - points[(i + 1) % point_num].x);
        return Mathf.Abs(s / 2.0f);
    }
}