おもちゃラボ

Unityで遊びを作ってます

Unityでテクスチャにお絵描きしよう

Unityではゲームの実行時にリアルタイムでテクスチャのピクセルを変更することが出来ます。この方法を使ってテクスチャにお絵かきをしてみたいと思います。

f:id:nn_hokuson:20161208195649p:plain

今回の記事の内容は次のとおりです。

平面の配置

まずは、シーンビューに絵を描くための平面を配置します。ヒエラルキービューから「Create」→「3D Object」→「Plane」を選択してください。

f:id:nn_hokuson:20161208192116p:plain

カメラは平面を見下ろすように配置します。ヒエラルキービューからMain Cameraを選択し、インスペクタからPositionを(0, 7, -8)に、Rotationを(50, 0, 0)に設定してください。

f:id:nn_hokuson:20161208192228p:plain

テクスチャの設定

次に、絵を描くためのテクスチャをプロジェクトにインポートします。ここでは次のファイルを使いました。

f:id:nn_hokuson:20161208192247p:plain

テクスチャに絵を描くためにはテクスチャ自体の設定が必要です。プロジェクトビューでテクスチャを選択して、インスペクタから「Texture Type」を「Advanced」に設定して、「Read/Write Enabled」にチェックを入れます。

f:id:nn_hokuson:20161208192449p:plain

このテクスチャを先ほど配置したPlaneにドラッグ&ドロップして、マテリアルをアタッチします。Planeのシェーダは紙の質感が見えやすいようにUnlit/Textureを選択しておきましょう。

f:id:nn_hokuson:20161208192926p:plain

テクスチャの上半分を塗りつぶす

最後に、お絵かきの肝となるスクリプトの作成をしましょう。プロジェクトビューで右クリックし、「Create」→「C# Script」でスクリプトを作成し「PaintController」にリネームしてください。

とりあえずテクスチャの上半分を真っ黒に塗りつぶすスクリプトを書いてみましょう。

using UnityEngine;
using System.Collections;

public class PaintController : MonoBehaviour {

	Texture2D drawTexture ;
	Color[] buffer;

	void Start () {
		Texture2D mainTexture = (Texture2D) GetComponent<Renderer> ().material.mainTexture;
		Color[] pixels = mainTexture.GetPixels();

		buffer = new Color[pixels.Length];
		pixels.CopyTo (buffer, 0);

		// 画面上半分を塗りつぶす
		for(int x = 0; x < mainTexture.width; x++){
			for(int y = 0; y < mainTexture.height; y++){
				if( y < mainTexture.height / 2 ){
					buffer.SetValue (Color.black, x + 256 * y);
				}
			}
		}

		drawTexture = new Texture2D (mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
		drawTexture.filterMode = FilterMode.Point;
	}

	void Update () 
	{
		drawTexture.SetPixels (buffer);
		drawTexture.Apply();
		GetComponent<Renderer> ().material.mainTexture = drawTexture;
	}
}

 Startメソッド内では、現在表示しているテクスチャのピクセルをバッファ用の配列(buffer)にコピーしています。このバッファを更新することで画面上の見た目も更新されるように、Updateメソッドではbufferの配列をdrawTextureに設定したうえで、それをmainTextureにセットしています。

 作成したPaintControllerスクリプトをシーンビューの「Plane」にドラッグ&ドロップしてアタッチします。

f:id:nn_hokuson:20161208193222p:plain

実行結果は次のようになります。

f:id:nn_hokuson:20161208193554p:plain

マウスの軌跡を塗りつぶす

では、このスクリプトを書き換えてマウスの軌跡を黒く塗りつぶすように変更してみましょう。

using UnityEngine;
using System.Collections;

public class PixAccess : MonoBehaviour
 {
	Texture2D drawTexture ;
	Color[] buffer;

	void Start () {
		Texture2D mainTexture = (Texture2D) GetComponent<Renderer> ().material.mainTexture;
		Color[] pixels = mainTexture.GetPixels();

		buffer = new Color[pixels.Length];
		pixels.CopyTo (buffer, 0);

		drawTexture = new Texture2D (mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
		drawTexture.filterMode = FilterMode.Point;
	}

	public void Draw(Vector2 p)
	{
		buffer.SetValue (Color.black, (int)p.x + 256 * (int)p.y);
	}

	void Update () 
	{
		if (Input.GetMouseButton (0)) 
		{
			Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
			RaycastHit hit;
			if (Physics.Raycast (ray, out hit, 100.0f)) {
				Draw (hit.textureCoord * 256);
			}

			drawTexture.SetPixels (buffer);
			drawTexture.Apply ();
			GetComponent<Renderer> ().material.mainTexture = drawTexture;
		}
	}
}

 マウスの軌跡を塗りつぶすためには、マウスが乗っている平面の座標を知る必要があります。これにはUnityが提供してくれているRayの機能を使います。Rayを使えば、マウスから出たRayが平面と交差した点のuv座標を取得することができます。

f:id:nn_hokuson:20161208194745p:plain

得られる座標は 0 < u < 1、0 < v < 1なので、これをテクスチャのピクセル数に変換して、該当のピクセルを黒く塗りつぶしています。実行結果は次のとおりです。

f:id:nn_hokuson:20161208194805g:plain

ブラシの太さを太くする

最後にブラシの太さが1pxでは見にくいので、もう少しブラシを太くするスクリプトを紹介します。今回はDrawメソッドの中身だけを書き換えています。

	public void Draw(Vector2 p)
	{
		for (int x = 0; x < 256; x++){
			for (int y = 0; y < 256; y++){
				if ((p - new Vector2 (x, y)).magnitude < 5){
					buffer.SetValue (Color.black, x + 256 * y);
				}
			}
		}
	}

 先ほどのスクリプトではマウスが乗っている1ピクセルだけを書き換えていました。今回のスクリプトでは毎フレーム、テクスチャ上のすべてのピクセルをチェックして、マウスが乗っている座標からの距離が8以下なら黒く塗りつぶします。

f:id:nn_hokuson:20161208194433p:plain

実行結果は次のようになります。

f:id:nn_hokuson:20161208195013g:plain

まとめ

今回はテクスチャにお絵かきをする方法を紹介しました。直接テクスチャに書くのではなく、マスクに描画してシェーダで合成するともっときれいな表現が可能になる・・・気がします。

基本的なUnityの使い方は「Unity5の教科書」で解説しているので是非参考にしてみてくださいね!