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)となります。