はじめに
今回開発を試みるのは、平面上に色をPixelで配置する従来のお絵かきアプリではなく、Voxelを積み重ねるようにして立体的なお絵かきを実現するアプリである。
立体的に盛り上がった絵具の質感やキャンバスの凹凸、ひいては絵具同士の混ざり合いなど平面上では表現しきれない質感をVoxelで実現したい。
そこでまずは「クリックした場所にボクセルを置く」「積み重ねる」ができるだけの最小限のスクリプト作成を目標とした。
環境
Unity6.6 + VSCode
スクリプト
- Unityで新しい3Dプロジェクトを作成
- 画面上に Plane(キャンバス)を設置
- 作成された Plane を選択し、画面右の Inspector ウィンドウにある Tagをクリック
- Add Tag... を選び、+ ボタンを押して Ground という名前のタグを追加して保存
- 再度 Plane を選択し、Tag を Ground に変更
- GameObject ➔ 3D Object ➔ Cube を作成
- 画面下の Project ウィンドウの空きスペースに、画面上の Cube をドラッグ&ドロップし、アイコンが青色に変わり「プレハブ(元データ)」化される
- 画面上の(Hierarchyにある)Cube は不要になるので右クリックして削除
- GameObject ➔ Create Empty で空のオブジェクトを作成し、名前を VoxelManager に設定
- VoxelManager に作成した VoxelPainter.cs をドラッグ&ドロップしてアタッチ
- VoxelManager の Inspector に Voxel Prefab という項目があるので、先ほど作成したCubeをそこにドラッグ&ドロップしてセット
- VoxelPainter.cs には以下のコードを入力
VoxelPainter.cs
using UnityEngine;
using UnityEngine.InputSystem; // 新しいInput Systemを使用
public class VoxelPainter : MonoBehaviour
{
[Header("設定")]
public GameObject voxelPrefab; // 配置するボクセルのプレハブ(Cube)
public float voxelSize = 1.0f; // ボクセルのサイズ
void Update()
{
// マウスが接続されていない場合は処理しない
if (Mouse.current == null) return;
// マウス左クリックでボクセルを設置
if (Mouse.current.leftButton.wasPressedThisFrame)
{
PlaceVoxel();
}
// マウス右クリックでボクセルを削除(彫る)
else if (Mouse.current.rightButton.wasPressedThisFrame)
{
RemoveVoxel();
}
}
void PlaceVoxel()
{
// 現在のマウス座標を取得
Vector2 mousePos = Mouse.current.position.ReadValue();
Ray ray = Camera.main.ScreenPointToRay(mousePos);
if (Physics.Raycast(ray, out RaycastHit hit))
{
// クリックした面(法線)の方向に1マスずらした位置を計算
Vector3 targetPosition = hit.point + (hit.normal * (voxelSize * 0.5f));
// グリッド(1.0刻み)にスナップさせる
Vector3 gridPosition = new Vector3(
Mathf.Floor(targetPosition.x / voxelSize) * voxelSize + (voxelSize * 0.5f),
Mathf.Floor(targetPosition.y / voxelSize) * voxelSize + (voxelSize * 0.5f),
Mathf.Floor(targetPosition.z / voxelSize) * voxelSize + (voxelSize * 0.5f)
);
// ボクセルを生成
Instantiate(voxelPrefab, gridPosition, Quaternion.identity);
}
}
void RemoveVoxel()
{
Vector2 mousePos = Mouse.current.position.ReadValue();
Ray ray = Camera.main.ScreenPointToRay(mousePos);
if (Physics.Raycast(ray, out RaycastHit hit))
{
// クリックした対象がPlane(キャンバス)でなければ削除
if (hit.collider.gameObject.tag != "Ground")
{
Destroy(hit.collider.gameObject);
}
}
}
}
結果
白いキャンバスに白いボクセルを一つずつ積み上げるごく基本的な動作ではあったものの、立体を自由に作成することに成功した。
感覚的には真っ白なマイクラをしているような気分だ。
今後はカラーパレット、光と影の調整、カメラ操作の導入を順次試みる。
アプリケーションの名称
このお絵かきアプリは ReliefCanvas Morie として今後のプロジェクトを進めていく。
平面から立体が浮き出る「浮き彫り(レリーフ)」絵画と、「盛る絵(盛り絵)」から取ったシンプルで覚えやすい名称を組み合わせて命名した。