- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!!!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();
}
}
これを実行すると以下のように描画されます。
{{ref_image unity_opengl_001.png}}
スクリーンの左下を(0, 0)、右上を(1, 1)として、三角形を描画しています。
この際に「GL.Color」で指定した色が頂点カラーとして使用されてグラデーションします。
三角形は「時計回りが表」となる点に注意してください。逆向きだと隠れて見えなくなります。
!マテリアルの生成
m_material = new Material("xxxx");
のところは、[[シェーダーのソース|unity_shader_basic]]を記載しています。
シェーダーとしては、以下のものをテキストで格納しています。
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)の作成は「[[テクスチャの作成|unity_script_create_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値を指定することで、テクスチャが反映されます。
{{ref_image unity_opengl_002.png}}
!!ラインを描画
ここでは、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();」の間にラインの座標指定を行います。
{{ref_image unity_opengl_draw_line.png}}
のように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();
}
}
{{ref_image unity_opengl_draw_line_with_width.png}}
!!ビューポートの指定
デフォルトでは、スクリーンの左下が(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)となります。
!!2D描画を拡張する
GLの描画は太さ1.0のラインを引くかポリゴンを描く、のコマンドしかないです。
これをラップして、
*太さのある線を描画
*破線を描画
*四角形の描画
*円の描画
*ポリゴンの描画
を行うクラスを作成。