整理之前的项目。发现了一个测量多边形面积的功能源码。具体效果如下:
具体实现方法如下:
场景搭建如下
脚本部分:
public class Test : MonoBehaviour
{
/// <summary>
/// 相机
/// </summary>
public Camera _camera;
public int size = 100;//文字大小
private static Material lineMaterial;
public GameObject _text;
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;
//GL 绘制的顶点数组 顺序是 0->1 2->3 4->5 取法 0 1 3 5 7 9
//参考UI界面
private List<Vector3> lv;
private List<GameObject> aims;
private Vector3 V3;
void Start()
{
lv = new List<Vector3>();
aims = new List<GameObject>();
V3 = Vector3.zero;
}
void Update()
{
if (Input.GetMouseButtonDown(0))//绘制多边形
{
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);
if (lv.Count >= 2)
{
//存入点就是反复存入来自动连线,0--1 1--2 2--3.。。。。类似这格式存储点
if (sb)
{
lv.RemoveAt(lv.Count - 1);
lv.RemoveAt(lv.Count - 1);
}
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);
}
}
}
}
void OnGUI()
{
GUIStyle text = new GUIStyle();
text.fontSize = size;
// 利用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=yellow>" + Vector3.Distance(lv[i], lv[i + 1]).ToString(".00") + "</color>" + "<color=yellow>" + "米" + "</color>", text);
}
}
if (lv.Count > 2)
{
_text.GetComponent<Text>().text = ComputePolygonArea(lv).ToString(".00");
}
}
// 清除重新测量
public void ClearLines()
{
sb = false;
for (int i = 0; i < aims.Count; i++)
{
GameObject.Destroy(aims[i]);
}
lv.Clear();
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);
}
}