Unityでグリッドとボックスをラインで描く

Unityの`GL`を使って、グリッドとボックスをラインで描く方法です。
スクリプトを適当なGameObjectに持たせると、そのオブジェクトのTransforomをもとにレンダリングします。

# グリッドをラインで描く

![grid.jpg](https://qiita-image-store.s3.amazonaws.com/0/61569/fc7acd46-2ccd-ebdb-9860-b1dc526cb8ef.jpeg)

```csharp:LineGrid.cs
using UnityEngine;

[ExecuteInEditMode]
public class LineGrid : MonoBehaviour
{
    [SerializeField] private Vector2 scale = new Vector2(10f, 10f);
    [SerializeField] private Vector2Int division = new Vector2Int(10, 10);
    [SerializeField] private Material material;

    private void OnRenderObject()
    {
        Vector2 stepSize = scale / division;
        Vector2 halfScale = scale * 0.5f;
        material.SetPass(0);
        GL.PushMatrix();
        GL.MultMatrix(transform.localToWorldMatrix);
        for (int x = 0; x <= division.x; x++)
        {
            GL.Begin(GL.LINES);
            for (int z = 0; z < division.y; z++)
            {
                GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
                GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, (z + 1) * stepSize.y - halfScale.y));
            }
            GL.End();
        }
        for (int z = 0; z <= division.y; z++)
        {
            GL.Begin(GL.LINES);
            for (int x = 0; x < division.x; x++)
            {
                GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
                GL.Vertex(new Vector3((x + 1) * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
            }
            GL.End();
        }
        GL.PopMatrix();
    }
}
```

平面的なグリッドでいいならば、もっと単純に端から端までを一直線に線を描けばいいと思います。今回はグリッドの格子点ごとに高さ（y座標の値）を変えることを想定して細かく線を描いています。

#　ボックスをラインで描く

![box.jpg](https://qiita-image-store.s3.amazonaws.com/0/61569/0e2bb953-1925-87a6-51d6-aaab01774b20.jpeg)


```csharp:LineBox.cs
using UnityEngine;

[ExecuteInEditMode]
public class LineBox : MonoBehaviour
{

    [SerializeField] private Vector3 scale = new Vector3(10f, 10f, 10f);
    [SerializeField] private Material material;

    private void OnRenderObject()
    {
        Vector3 halfScale = scale * 0.5f;
        material.SetPass(0);
        GL.PushMatrix();
        GL.MultMatrix(transform.localToWorldMatrix);
        drawRectXY(halfScale, -halfScale.z);
        drawRectXY(halfScale, halfScale.z);
        drawLineZ(halfScale, -halfScale.x, -halfScale.y);
        drawLineZ(halfScale, halfScale.x, -halfScale.y);
        drawLineZ(halfScale, halfScale.x, halfScale.y);
        drawLineZ(halfScale, -halfScale.x, halfScale.y);
        GL.PopMatrix();
    }

    private void drawRectXY(Vector3 halfScale, float z)
    {
        GL.Begin(GL.LINE_STRIP);
        GL.Vertex(new Vector3(-halfScale.x, -halfScale.y, z));
        GL.Vertex(new Vector3(halfScale.x, -halfScale.y, z));
        GL.Vertex(new Vector3(halfScale.x, halfScale.y, z));
        GL.Vertex(new Vector3(-halfScale.x, halfScale.y, z));
        GL.Vertex(new Vector3(-halfScale.x, -halfScale.y, z));
        GL.End();
    }

    private void drawLineZ(Vector3 halfScale, float x, float y)
    {
        GL.Begin(GL.LINES);
        GL.Vertex(new Vector3(x, y, -halfScale.z));
        GL.Vertex(new Vector3(x, y, halfScale.z));
        GL.End();
    }
}
```

# 作例

グリッドの高さ（y座標）を`Mathf.PerlinNoise`でずらしています。
ボックスはTransformコンポーネントのrotationで回転させています。

![10fps.gif](https://qiita-image-store.s3.amazonaws.com/0/61569/b91c25a1-8cfe-23c0-223f-e370c200c6e9.gif)