Unity实用案例之——屏幕画线和线框渲染

游戏里经常会遇到各种画线的需求,今天我们利用GL来实现其中的两个画线功能。

一、屏幕画线

屏幕画线是一种很好的用户交互方式,通过屏幕画线可以控制游戏中的各种元素,Unity提供了UnityEnige.GL库很方便的实现了这个功能。首先我们来看如何实现两点之间画线:

void DrawLine(Vector3 start, Vector3 end) 
{
    if (!beginDraw)
        return;
    GL.PushMatrix();
    GL.LoadOrtho();

    lineMaterial.SetPass(0);
    GL.Begin(GL.LINES);

    GL.Vertex3(start.x, start.y, start.z);
    GL.Vertex3(end.x, end.y, end.z);

    GL.End();
    GL.PopMatrix();
}

可以看到,只要确定好两点位置,调用GL.Vertex3(float x, float y, float z)将点的位置作为参数传就去就好了。
OK,那么有了以上基础,我们稍作改动,就可以实现屏幕实时画线了,首先要记录拖动时的点的位置:

void OnGUI()
{
    Event e = Event.current;

    if (e != null && e.type != null) {
        if (e.type == EventType.MouseDown) {
            beginDraw = true;
        }
        if (e.type == EventType.MouseDrag) {

            if (Vector3.Distance(curPos, Input.mousePosition) > interval) {
                curPos = Input.mousePosition;

                posList.Add(new Vector3(curPos.x / Screen.width, curPos.y / Screen.height, 0));
            }
        }
        if (e.type == EventType.MouseUp) {
            beginDraw = false;
            ClearLines();
        }
    }
}

void ClearLines() 
{
    beginDraw = false;
    posList.Clear();
    curPos = Vector3.zero;
}

其中,interval用来控制点与点之间的间距,然后利用GL完成点连线:

void DrawLine() 
{
    if (!beginDraw)
        return;
    GL.PushMatrix();
    GL.LoadOrtho();

    lineMaterial.SetPass(0);
    GL.Begin(GL.LINES);
    for (int i = 0; i < posList.Count - 1; i++) {
        Vector3 pos = posList[i];

        GL.Vertex3(pos.x, pos.y, pos.z);
        GL.Vertex3(posList[i + 1].x, posList[i + 1].y, posList[i + 1].z);
    }

    GL.End();
    GL.PopMatrix();
}

完成后效果:
这里写图片描述
这里需要注意的一点是,因为两点成一线,GL.Vertex3()要成对出现,比如说A,B,C三个点,那么就要写成:
//线段AB
GL.Vertex3(A);
GL.Vertex3(B);
//线段BC
GL.Vertex3(B);
GL.Vertex3(C);
//线段CA
GL.Vertex3(C);
GL.Vertex3(A);

而不是
GL.Vertex3(A);
GL.Vertex3(B);
GL.Vertex3(C);

二、线框渲染(Wireframe)

将物体以线框显示,常见于特殊的游戏效果表现,或者建筑设计展示,也是3D软件中模型显示的基本功能,包括Unity里也有这个功能,但仅限于Scene窗口。那么如何在Game中实现同样的效果呢,方法也不少,今天介绍一种GL+Shader的方案。万变不离其宗,既然用了GL,那么原理还是一样的,只是这次绘制的线是基于网格顶点信息:

private void OnRenderObject()
    {
        LineMat.SetColor("_LineColor", LineColor);
        Mesh mesh = meshFilter.sharedMesh;

        var vertices = mesh.vertices;
        var triangles = mesh.triangles;

        lines = new Vector3[triangles.Length];
        int count = 0;
        for (int i = 0; i < triangles.Length/3; i++)
        {
            lines[count++] = vertices[triangles[i*3]];
            lines[count++] = vertices[triangles[i*3 + 1]];
            lines[count++] = vertices[triangles[i*3 + 2]];
        }

        LineMat.SetPass(0);

        GL.PushMatrix();

        //转换到世界坐标
        GL.MultMatrix(transform.localToWorldMatrix);

        GL.Begin(GL.LINES);

        for (int i = 0; i < lines.Length/3; i++)
        {
            GL.Vertex(lines[i*3]);
            GL.Vertex(lines[i*3 + 1]);
            GL.Vertex(lines[i*3 + 1]);
            GL.Vertex(lines[i*3 + 2]);
            GL.Vertex(lines[i*3 + 2]);
            GL.Vertex(lines[i*3]);
        }

        GL.End();

        GL.PopMatrix();
    }

可以看到,在绘制三角形的时候,首尾各一次,其他顶点出现两次。为了控制绘制线框的颜色,接下来,需要一个简单的Shader:

Shader "LineColor" {

    Properties{
        _LineColor ("Line Color", Color) = (1.0, 1.0, 1.0, 1.0)
    }

    SubShader {
        Pass {
            Tags { "RenderType"="Opaque"}
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct v2f
            {
                half4 pos : SV_POSITION;
            };

            fixed4 _LineColor;

            v2f vert(appdata_base  v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }

            fixed4 frag(v2f i) : COLOR
            {
                return _LineColor;
            }

            ENDCG
        }
    }
}

OK,到这里,我们把脚本拖给一个现有的模型,就大功告成啦!
这里写图片描述
可以看到模型和线框可以同时显示,并不冲突,而且可以改变线框为自己想要的颜色,这一切都得益于GL!今天的技能Get到了吗?

  • 21
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
### 回答1: 在Unity游戏开发中,有时候需要将经纬度和Unity坐标进行相互转换。经纬度是用来表示地球上某一点位置的地理坐标,而Unity坐标则是用来表示游戏场景中各个对象的位置。 首先,我们来看如何将经纬度转换为Unity坐标。这个过程涉及到地球模型和坐标系的转换。首先需要了解Unity中使用的坐标系,Unity引擎使用的是左手坐标系,其中X轴是向右的,Y轴是向上的,而Z轴是向前的。 假设我们已经获得了一个地理位置的经纬度,可以通过Unity提供的API将经纬度转换为空间坐标。可以使用Unity的LocationService类来获取设备当前的地理位置信息,其中有一个属性latitude是用来表示纬度的,另一个属性longitude是用来表示经度的。 Unity中的LocationService类还提供了方法将经纬度转换为Unity的空间坐标。具体的转换过程可以使用LocationService的方法:Input.compass.trueHeading可以获取真北指向的方向,然后通过一些数学计算和转换矩阵可以将经纬度转换为Unity坐标。 反过来,如果我们已经有了一个Unity坐标,想要转换为经纬度,也是可以的。可以使用Unity提供的方法将Unity坐标转换为屏幕坐标,然后可以通过一些数学和地理计算,将屏幕坐标转换为经纬度。 总结一下,经纬度和Unity坐标之间的转换是一个比较常见的需求,在Unity游戏开发中可以使用Unity提供的LocationService类和一些数学计算方法来实现。同时,也可以利用一些第三方库来简化这个转换过程。 ### 回答2: Unity是一款流行的游戏引擎,它提供了许多实用功能来帮助开发者创建游戏。其中一个实用功能是经纬度和Unity坐标之间的转换。 经纬度是地球上地理位置的表示方式,由纬度(latitude)和经度(longitude)组成。在许多应用中,我们可能需要将经纬度坐标转换为Unity中的坐标系统,以便在游戏中定位和展示地理位置。 在Unity中,可以使用提供的API函数来进行经纬度和Unity坐标之间的转换。首先,我们可以使用"LocationService"类来获取设备的经纬度信息。通过调用"Input.location.Start()"函数和"Input.location.lastData.latitude"和"Input.location.lastData.longitude"属性,我们可以获取到当前设备的经纬度。 接下来,我们可以将获得的经纬度信息转换为Unity坐标。这可以通过将经纬度映射到Unity的坐标系范围内来实现。一种常见的映射方式是将地球的纬度范围[-90, 90]转换为Unity的Y坐标范围[-10, 10],将地球的经度范围[-180, 180]转换为Unity的X坐标范围[-10, 10]。可以使用简单的比例缩放来完成这个映射过程。 通过将经纬度转换为Unity坐标,我们可以在游戏中使用这些坐标来定位和展示地理位置。例如,我们可以在游戏世界中创建一个物体,并将其放置在经纬度对应的Unity坐标上,以此在游戏中呈现地理位置。这对于开发基于地理位置的游戏和应用程序非常有用。 总之,Unity提供了经纬度和Unity坐标之间转换的实用功能,使得开发者可以方便地在游戏中定位和展示地理位置。通过将经纬度转换为Unity坐标,我们可以使用这些坐标来在游戏中呈现地球上的地理位置。 ### 回答3: 在Unity中,经纬度和Unity坐标之间的转换是一个相当实用的功能,尤其在开发地理位置相关的应用程序时。 首先,我们来看经纬度转换为Unity坐标的过程。经度表示了地球上某个点的东西方向位置,而纬度表示了地球上某个点的南北方向位置。在Unity中,我们可以使用脚本来将经纬度转换为Unity中的坐标。我们可以使用标准的经纬度坐标系,其中纬度的范围是-90到90,经度的范围是-180到180。首先,我们需要确定Unity世界中一个参考点的经纬度,然后计算指定经纬度点与参考点之间的水平和垂直距离,将其转换为Unity坐标的单位。 另一方面,Unity坐标转换为经纬度也是一个常见的需求。在这种情况下,我们需要使用Unity中的Unity API来获取场景中某个物体的位置坐标,然后将其转换为经纬度值。首先,我们需要确定一个参考点的经纬度作为原点,然后计算指定点与参考点之间的水平和垂直距离。最后,通过一些数学运算和公式,我们可以将该距离转换为对应的经度和纬度值。 总结起来,经纬度和Unity坐标之间的转换可以通过一些简单的数学运算和公式实现。这个功能在开发地理位置相关的应用程序时非常有用,例如在虚拟现实游戏中创建基于真实地理位置的游戏世界,或者在实际物理位置点周围放置虚拟对象等等。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值