unity3D多點測量、多邊形面積測量
阿新 • • 發佈:2019-01-05
直接先看先看效果,多點測量:
任意點構成的多邊形面積測量(面積顯示在左上角顯示在模型感覺太亂):
覺得要注意的就是點的自動縫合這塊,多邊形繪製頂點實時連線最後一個點,時間座標與螢幕座標到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); } }