18
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

UnityでGLを使って空間に線を描く方法

HoloLensでお絵かきアプリを作成した時に、線の描き方について調べたので簡単にまとめます。

はじめに

お絵かきアプリで空間に線を描くには、いくつか方法があります。
- LineRendererを使う
- GLを使って、太さが1pxの線を描く
- GLを使って、ポリゴンで線を描く

LineRendererを使う方法

LineRendererを使うことで簡単に線を描くことができます。

lineRenderer.positionCount = positions.Length;
lineRenderer.SetPositions(positions);

1つのLineRenderでは1つの線しか描けないため、お絵かきアプリの様にたくさんの線を描画する場合、LineRendererが大量に生成されるので、ちょっと。。。

GLで太さ1pxの線を描く方法

UnityではGLを使えるので、こちらを使って線を描くことができます。
https://docs.unity3d.com/ScriptReference/GL.html

private void OnRenderObject()
{
    // Materialの初期化と設定、詳しくは↑のUnityのScriptReferenceを参照。
    CreateLineMaterial();

    lineMaterial.SetPass(0);

    // GL.PushMatrix()~GL.PopMatrix()の間に行われた、行列マトリクスの変更が外に漏れないようにPush&Pop。おまじない、おまじない
    GL.PushMatrix();

    // 複数の線を描画する
    foreach (var stroke in strokeSet)
    {
        GL.Begin(GL.LINE_STRIP);
        for (int i = 0; i < stroke.Nodes.Count; i++)
        {
            GL.Color(stroke.Nodes[i].color);
            GL.Vertex(stroke.Nodes[i].position);
        }
        GL.End();
    }
    GL.PopMatrix();
}

MonoBehaviourを継承したクラスの、OnRenderObject()内に描画処理を実装することで、毎フレーム描画時に処理が呼び出されます。
毎フレーム呼び出されるので、重い処理は避けたほうが良いでしょう。

色々処理をしていますが、メインとなるのはGL.Begin(GL.LINE_STRIP)~GL.End()になります。
GL.Begin(GL.LINE_STRIP)で線を描画する事を指定し、GL.Begin~GL.Endで複数の頂点情報を指定することで、指定した頂点をつないだ線が描画されます。
頂点の指定はGL.Colorで頂点カラー、 GL.Vertexで頂点座標を指定します。

GL_LINE_STRIP.png

GL.LINE_STRIP以外にも線やポリゴンを描画する方法はあるので、興味があれば "OpenGL Primitives" で検索してみると良いと思います。

なお、GL.LINE_STRIPで線を描画した場合、線の太さは1px固定となります。しかし、お絵かきアプリとしては、太さを変えたいところ。。。

GLで太さのある線を描く方法

線の太さを指定できないのなら、細い板ポリをつなげて線のようなポリゴンを描画すればいいじゃない。

という事で、イメージ的にはカラーテープでお絵かきをするような感覚ですね。

private void OnRenderObject()
{
    // Materialの初期化と設定
    CreateLineMaterial();

    lineMaterial.SetPass(0);

    GL.PushMatrix();

    // 複数の線を描画する
    foreach (var stroke in strokeSet)
    {
        GL.Begin(GL.TRIANGLE_STRIP);
        for (int i = 0; i < stroke.Nodes.Count; i++)
        {
            var node = stroke.Nodes[i];
            var next = stroke.Nodes[i + 1];

            // 線の進行方向(dir)から少し左右(offset)に散らして、TRIANGLE_STRIPで描画
            // することで、任意の幅の線(ポリゴン)を描画する。
            var dir = next.position - node.position;
            var offset = Vector3.Cross(node.normal, dir).normalized * lineWidth;

            GL.Color(node.color);
            GL.Vertex(node.position + offset);
            GL.Vertex(node.position - offset);
        }
        GL.End();
    }
    GL.PopMatrix();
}

こちらはGL.LINE_STRIPではなくGL.TRIANGLE_STRIPをGL.Beginに指定して、ポリゴンを描画しています。
以下の様に元々の線は青線の様になりますので、頂点座標(node.position)から上下にoffset分幅を持たせてポリゴンを描画します。
GL_TRIANGLE_STRIP.png

この時のoffsetの方向ですが、今回は線を描いた場所から見るときちんと幅があるように見え、上下左右に回り込んで見たら斜めに見えるようにしています。
そのためには線の頂点座標だけでなく法線情報も必要になるので、頂点座標と同じように記録して利用しています。

最後に

Unityで線を描く場合、LineRenderer以外にGLも使える。Materialも使っているのでShaderでエフェクトつけたりもできそう。
ただ、色々複雑なことをやりだすと面倒なので素直にLineRendererを使ったほうが良いのかも。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
18
Help us understand the problem. What are the problem?