トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

unity_script_opengl

OpenGL描画

スクリーン上で独自のOpenGL描画を行うことができます。

 スクリーンに2D描画

ここではメインカメラにスクリプトを割り当て、そこで記述します。
MonoBehaviour派生クラスの「OnPostRender」関数を使用することで、カメラに対するOpenGL描画が行われます。

private Material m_material;

void Start () {
  // マテリアルの生成.
  m_material = new Material(
    "Shader \"myShader\" {" +
    "  SubShader {" +
    "    Pass {" +
    "       ZWrite Off" +
    "       Cull Off" + 
    "       BindChannels {" +
    "         Bind \"vertex\", vertex Bind \"color\", color" +
    "       }" +
    "    }" +
    "  }" +
    "}"
  );
  m_material.hideFlags = HideFlags.HideAndDontSave;
  m_material.shader.hideFlags = HideFlags.HideAndDontSave;
}

void OnPostRender() {
  if (m_material != null) {
      m_material.SetPass(0);  // マテリアルのパス0を割り当て.
  
      GL.PushMatrix();
      GL.LoadOrtho();   // 2D描画として処理.
      GL.Begin(GL.TRIANGLES);

        GL.Color(Color.red);
        GL.Vertex3( 0.0f, 0.0f, 0.0f );

        GL.Color(Color.green);
        GL.Vertex3(0.0f, 1.0f, 0.0f );

        GL.Color(Color.blue);
        GL.Vertex3(0.5f, 0.5f, 0.0f );

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

これを実行すると以下のように描画されます。

スクリーンの左下を(0, 0)、右上を(1, 1)として、三角形を描画しています。
この際に「GL.Color」で指定した色が頂点カラーとして使用されてグラデーションします。
三角形は「時計回りが表」となる点に注意してください。逆向きだと隠れて見えなくなります。

マテリアルの生成

m_material = new Material("xxxx");

のところは、シェーダーのソースを記載しています。
シェーダーとしては、以下のものをテキストで格納しています。

Shader "myShader" {
  SubShader {
    Pass {
      ZWrite Off
      Cull Off
      BindChannels {
        Bind "vertex", vertex Bind "color", color
      }
    }
  }
}

「ZWrite Off」でZバッファへの書き込みは無効化、「Cull Off」で裏面は非表示。
「BindChannels」内の記述により、GL.Colorで指定する色を頂点カラーとして指定します。

GL描画

m_material.SetPass(0);

で描画で使用するマテリアルの指定。

「GL.PushMatrix();」〜「GL.PopMatrix();」で囲むことにより、変換行列を使用後に復帰できるようにします。

「GL.LoadOrtho()」でスクリーンにあわせた2D描画を行います。スクリーンの左下が(0, 0)、右上が(1, 1)になります。

「GL.Begin(GL.TRIANGLES);」〜「GL.End();」内で三角形の頂点の色と頂点座標を指定します。
「GL.Color」の指定は、GL.Begin 〜 GL.Endの中で指定しないと反映されません。

 スクリーンに2D描画 +テクスチャ指定

private Texture2D m_texture;
private Material m_material;

void Start () {
   // テクスチャの作成.
   m_texture = new Texture2D(32, 32, TextureFormat.ARGB32, false);
   for (int y = 0; y < m_texture.height; y++) {
       for (int x = 0; x < m_texture.width; x++) {
           if ((x & 1) != 0 && (y & 1) == 0) m_texture.SetPixel(x, y, Color.red);
           else m_texture.SetPixel(x, y, Color.white);
       }
   }
   m_texture.Apply();
   
   // マテリアルの作成.
   m_material = new Material(
        "Shader \"myShader\" {" +
        "  Properties {" +
        "    _MainTex (\"Base (RGB)\", 2D) = \"white\" {}" +
        "  }" +
        "  SubShader {" +
        "    Pass {" +
        "       ZWrite Off" +
        "       Cull Off" +            
        "       BindChannels {" +
        "         Bind \"vertex\", vertex Bind \"color\", color" +
        "       }" +
        "       SetTexture [_MainTex] {" +
        "         constantColor (1.0, 1.0, 1.0, 1.0)" +
        "         Combine texture * primary DOUBLE, texture * constant" +
        "       }" +           
        "    }" +
        "  }" +
        "}"
   );
   m_material.hideFlags = HideFlags.HideAndDontSave;
   m_material.shader.hideFlags = HideFlags.HideAndDontSave;
   m_material.mainTexture = m_texture;
   m_material.color = Color.white;
}

void OnPostRender() {
   if (m_material != null) {
       m_material.SetPass(0);
       GL.PushMatrix();
       GL.LoadOrtho();
       GL.Begin(GL.TRIANGLES);
           GL.Color(Color.white);

           GL.TexCoord2(0.5f, 1.0f);
           GL.Vertex3( 0.0f, 0.0f, 0.0f );

           GL.TexCoord2(0.0f, 0.0f);
           GL.Vertex3(0.0f, 1.0f, 0.0f );

           GL.TexCoord2(1.0f, 0.0f);
           GL.Vertex3(0.5f, 0.5f, 0.0f );

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

テクスチャ(Texture2D)の作成は「テクスチャの作成」を参照。
マテリアル作成時のシェーダーのテキストで

        "  Properties {" +
        "    _MainTex (\"Base (RGB)\", 2D) = \"white\" {}" +
        "  }"

の指定でメインテクスチャをパラメータとして指定できるようにします。

        "       SetTexture [_MainTex] {" +
        "         constantColor (1.0, 1.0, 1.0, 1.0)" +
        "         Combine texture * primary DOUBLE, texture * constant" +
        "       }" +           

の箇所でテクスチャ色を取得します。

「m_material.mainTexture = m_texture;」で、生成したm_texture(Texture2D)を割り当てます。

OnPostRender関数内のOpenGL描画部では「GL.TexCoord2」でUV値を指定することで、テクスチャが反映されます。


 ラインを描画

ここでは、emptyのGameObjectをシーンに配置し、新しいC#スクリプトを生成してGameObjectに割り当てておきます。
以下、3次元として配置する例です。

private Material m_lineMaterial;

void Start () {
  // ライン描画用のマテリアルを生成.
  m_lineMaterial = new Material(
    "Shader \"myShader\" {" +
    "  SubShader {" +
    "    Pass {" +
    "       ZWrite Off" +
    "       Cull Off" + 
    "       BindChannels {" +
    "         Bind \"vertex\", vertex Bind \"color\", color" +
    "       }" +
    "    }" +
    "  }" +
    "}"            
  );
  m_lineMaterial.hideFlags = HideFlags.HideAndDontSave;
  m_lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
}

void OnRenderObject() {
   if (m_lineMaterial != null) {
       m_lineMaterial.SetPass(0);
       
       GL.PushMatrix();
       GL.Begin(GL.LINES);
           GL.Color (Color.red);
           GL.Vertex3(0.0f, 0.0f, 0.0f);
           GL.Vertex3(0.0f, 2.0f, 0.0f);
               
           GL.Vertex3(0.0f, 2.0f, 0.0f);
           GL.Vertex3(0.0f, 2.0f, 2.0f);
   
           GL.Vertex3(0.0f, 2.0f, 2.0f);
           GL.Vertex3(0.0f, 0.0f, 2.0f);
           
           GL.Color (Color.green);
           GL.Vertex3(0.0f, 0.0f, 0.0f);
           GL.Vertex3(0.0f, 2.0f, 2.0f);

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

シェーダーの作成に関しては、面を描画する場合と同じです。
色情報を取得し、それをそのままライン描画の色として反映します。

「OnRenderObject」関数で、「GL.Begin(GL.LINES);」〜「GL.End();」の間にラインの座標指定を行います。

のように4本のラインが描画されます。中央より少し左に寄っている小さな球が原点位置です。

 太さのあるラインを描画

UnityのGLでは、太さのあるラインの描画はできないため「GL.Begin (GL.QUADS)」を使って1ラインごとに四角形を描画していきます。

// 太さのある線を描画.
void DrawLine2D(Vector3 v0, Vector3 v1, float lineWidth) {
  Vector3 n = ((new Vector3(v1.y, v0.x, 0.0f)) - (new Vector3(v0.y, v1.x, 0.0f))).normalized * lineWidth;
  GL.Vertex3(v0.x - n.x, v0.y - n.y, 0.0f);
  GL.Vertex3(v0.x + n.x, v0.y + n.y, 0.0f);
  GL.Vertex3(v1.x + n.x, v1.y + n.y, 0.0f);
  GL.Vertex3(v1.x - n.x, v1.y - n.y, 0.0f);
}

void OnRenderObject() {
  if (m_lineMaterial != null) {
    m_lineMaterial.SetPass(0);
   
    float lineWidth = 2.0f;        // ラインの太さ.
           
    // スクリーン上のラインの太さに変換.
    float thisWidth = 1.0f / Screen.width * lineWidth * 0.5f;
           
    GL.PushMatrix();
    GL.LoadOrtho();
    GL.Begin (GL.QUADS);
      GL.Color (Color.red);
      DrawLine2D(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.8f, 0.0f), thisWidth);
      DrawLine2D(new Vector3(0.0f, 0.8f, 0.0f), new Vector3(0.5f, 0.5f, 0.0f), thisWidth);
      DrawLine2D(new Vector3(0.5f, 0.5f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f), thisWidth);
    GL.End();
    GL.PopMatrix();
  }
}

 ビューポートの指定

デフォルトでは、スクリーンの左下が(0, 0)、右上が(1, 1)ですが、
Viewportの指定で変更することができます。

GL.PushMatrix();
GL.LoadPixelMatrix();
GL.Viewport(new Rect(0, 0, Screen.width, Screen.height));

... 何か描画処理.

GL.PopMatrix();

とLoadPixelMatrixとViewportの指定を行うと、スクリーンの左下が(0, 0)、右上が(Screen.width, Screen.height)となります。