在Unity中用GL库实现一个测量显示空间距离的功能

最后实现的效果如下:

 

这个功能分三个部分:

1.绘制三角面片;

2.绘制线段;

3.绘制距离文字;

 

下面细讲

1.获得鼠标点击的三角面片并绘制

这里要求鼠标点击的物体必须有mesh Collider组件,不能是box collider等几何碰撞体组件,才能获得该碰撞体组件的三角面片(查了一下,据说因为Box Collider等碰撞体是基于算法的,没有面的概念。当然速度会比mesh collider更快)

a.通过鼠标点击的RaycastHit获得三角面片的三个顶点

        MeshCollider collider = hit.collider as MeshCollider;
        if (collider == null || collider.sharedMesh == null)
            return;
        //获取碰撞器所在物体的Mesh网格
        Mesh mesh0 = collider.sharedMesh;

        //获取Mesh网格的所有顶点
        Vector3[] vertices = mesh0.vertices;
        //获取mesh的三角形索引,这里的索引的就是模型顶点数组的下标
        int[] triangles = mesh0.triangles;
        //然后通过hit.triangleIndex(摄像碰撞到的三角形的第一个点的索引)
        //然后+1 ,+2,获取三角形另外两个点的坐标
        Vector3 p0 = vertices[triangles[hit.triangleIndex * 3]];
        Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
        Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
        Transform transform = collider.transform;
        //上面的三个顶点是Mesh的本地坐标,需要用模型的Transform进行转换到世界坐标
        p0 = transform.TransformPoint(p0);
        p1 = transform.TransformPoint(p1);
        p2 = transform.TransformPoint(p2);
        triangleVertices = new Vector3[3];
        triangleVertices[0] = p0;
        triangleVertices[1] = p1;
        triangleVertices[2] = p2;

b.绘制三角形

使用Unity中的GL几何库绘制三角形:

//设置画线的颜色
Color rectColor = Color.green;

Shader shader = Shader.Find("GUI/Text Shader");
        //生成画线的材质

        Material rectMat = null;
        rectMat = new Material(shader);
        rectMat.hideFlags = HideFlags.HideAndDontSave;
        rectMat.shader.hideFlags = HideFlags.HideAndDontSave;

 


        rectMat.SetPass(0);//设置材质

 
        GL.PushMatrix();//保存摄像机变换矩阵

        //绘制三角形,设置颜色和透明度,方框内部透明
        GL.Begin(GL.TRIANGLES);
        GL.Color(new Color(rectColor.r, rectColor.g, rectColor.b, 0.1f));
        GL.Vertex3(triangleVertices[0].x, triangleVertices[0].y, triangleVertices[0].z);
        GL.Vertex3(triangleVertices[1].x, triangleVertices[1].y, triangleVertices[1].z);
        GL.Vertex3(triangleVertices[2].x, triangleVertices[2].y, triangleVertices[2].z);
        GL.End();

        //绘制三条边框,设置方框的边框颜色 边框不透明
        GL.Begin(GL.LINES);
        GL.Color(rectColor);
        GL.Vertex3(triangleVertices[0].x, triangleVertices[0].y, triangleVertices[0].z);
        GL.Vertex3(triangleVertices[1].x, triangleVertices[1].y, triangleVertices[1].z);        
        GL.Vertex3(triangleVertices[1].x, triangleVertices[1].y, triangleVertices[1].z);
        GL.Vertex3(triangleVertices[2].x, triangleVertices[2].y, triangleVertices[2].z);   
        GL.Vertex3(triangleVertices[2].x, triangleVertices[2].y, triangleVertices[2].z);
        GL.Vertex3(triangleVertices[0].x, triangleVertices[0].y, triangleVertices[0].z);
        GL.End();
        GL.PopMatrix();//恢复摄像机投影矩阵

2. 绘制射线

获得鼠标射线碰撞的点,标记该点为orin,从该点绘制一条射线,如果碰撞到物体,则标记碰撞点为end;

a.获得射线,如果鼠标点击的物体tag为“machine”则开启绘制三角面片与记录射线

        //如果鼠标点击左键
        if (Input.GetMouseButton(0))
        {
            
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.transform.tag == "machine")
                {
                    drawTrangle = true;//如果鼠标左键按下 设置开始画线标志
                    getVertices(hit);
                    Ray distanceRay = new Ray(hit.point, Vector3.forward);
                    //射线碰到了物体,hit为鼠标碰到的物体,hit1是从该物体发出的射线碰撞到的物体
                    RaycastHit hit1;
                    if (Physics.Raycast(distanceRay, out hit1))
                    {
                        orin = hit.point;
                        end = hit1.point;
                    }
                }
            }
        }

b.绘制射线,使用GL绘制


        float distance = 0;
        distance = (end - orin).magnitude;
        distanceStr = "";
        if (distance != 0)
        {
            distanceStr = distance.ToString("f2") + "m";
            GL.Begin(GL.LINES);
            GL.Color(rectColor);
            GL.Vertex3(orin.x, orin.y, orin.z);
            GL.Vertex3(end.x, end.y, end.z);
            GL.TexCoord3(end.x, end.y, end.z);  
            GL.End();
        }

3. 绘制距离文字

因为上一步绘制射线时已经记录了距离,这里主要在射线中点处绘制射线长度文字。文字在OnGUI函数中绘制

        if (distanceStr !="")
        {
            Vector3 worldPosition = new Vector3(((end + orin) / 2).x, 
                ((end + orin) / 2).y, ((end + orin) / 2).z);
            Vector3 position = camera.WorldToScreenPoint(worldPosition);
            position = new Vector2(position.x, Screen.height - position.y);
            //设置显示颜色
            GUI.color = rectColor;
            //计算文字的宽高
            Vector2 size = GUI.skin.label.CalcSize(new GUIContent(distanceStr));
            GUI.Label(new Rect( position.x - (size.x / 2),
                position.y - size.y, size.x, size.y), distanceStr);           
        }

 

需要注意的的是,要测量的两个物体必须带有碰撞体,要绘制三角面片的物体的碰撞体需有mesh collider组件。而且绘制几何体的函数一般在物体的OnRenderObject 或者相机的OnPostRender里调用,这里用的是OnPostRender,该脚本是挂在相机上的。

项目下载链接:https://download.csdn.net/download/michaelia_hu/10976196

如有疑问或建议欢迎留言!

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值