【Unity基礎】オブジェクトを使わずMeshだけで描画する方法。Graphics.DrawMesh

# はじめに
こんにちは、かき氷です。
見やすさを考えているといつの間にか結局最初の方が良かったとなるタイプの人いますよね。私です。
今回は**Meshだけを描画する方法**を紹介します。

:::note warn
**UnityEngine.Meshの基礎的な部分の紹介**です。基礎を終えた方には復習になる内容となっています。
:::

# Meshって何？
Meshというのは、 **三角形**です。
この三角形を自在に変え、何個も組み合わせることで、立体的な形が作られています。

![スクリーンショット 2024-12-20 10.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/38ec0d31-da44-1375-4dfb-15051aabd6e4.png)

↑これがMesh一つだけの状態

↓Meshを大量に繋げた状態
![mesh.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/7ee0ff23-39ab-477b-9f8f-55e68a868307.jpeg)　全部三角形！
引用：wikipedia
## Graphics.DrawMesh
Meshの描画には、**Graphics.DrawMesh**を使います。
必要な要素・省略可能な要素ともに数が多いので紹介します。
```drawMeshScript.cs
Graphics.DrawMesh(Mesh,Matrix4x4,Material,layer,Camera,submeshIndex,MaterialPropertyBlock,castShadows,receiveShadows,useLightProbes,Transform probeAnchor);
```
### Graphics.DrawMeshに必要な要素
#### 必須要素
| 順         | 要素　       | 概要　　　　|
|:-----------|:------------|:-------------|
| 0          | Mesh                  | 描画するMeshの頂点座標|
| 1          | Vector3 position      | 描画をする位置※1|
| 2          | Quaternion rotation   | Meshの向く方向|
| 3          | Material              | Meshに適応するmaterial|
| 4          | layer                 | Meshを描画するレイヤー※2|

#### オプション
| 順         | 要素　       | 概要　　　　|
|:-----------|:------------|:-------------|
| 5          | camera                | Meshが表示されるカメラ|
| 6          | submeshIndex(int型)    |特定のサブメッシュ|
| 7          | MaterialPropertyBlock | マテリアルを動的に変化させる場合に適応する|
| 8          | 影を落とす(bool型)      | 説明なし|
| 9          | 影を受ける(bool型)      | 説明なし |
| 10         | 光の効果を受ける(bool型) | 光の色や明るさを受ける場合適応する※3|

※1　この座標を中心に、Meshの座標が適応される。
(Meshのxが100で、座標xが500の場合、Meshは600の位置に置かれる)
※2　レイヤーにあまりこだわりがないなら、0で良い。
※3　赤色の光を受けると、キャラクターやオブジェクトが赤みがかるなど。

# Meshを描画する
ではMeshを描画していきましょう。
Meshは、**3つの座標から三角形を描画します**

![スクリーンショット 2024-12-20 11.27.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/67a9f72f-eb5d-5575-665c-02f134d86f08.png)

今回は上記した**三角形を描画するコード**です。
最もわかりやすく書ける(多分)**Matrix4x4.TRS**を使った方法で書いています。

:::note warn
今回のコードの**Graphics.DrawMeshは必須要素のみ**です。
:::

```DrawMeshScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawMeshScript : MonoBehaviour
{
    private Mesh mesh;
    
    public Material material;
    
    void Start()
    {
        mesh = new Mesh();
        
        mesh.vertices = new Vector3[] {
            new Vector3(0, 0, 0),
            new Vector3(100, 0, 0),
            new Vector3(0, 100, 0),
        };

        mesh.triangles = new int[] { 0, 1, 2};
    }
    private void Update() 
    {
        Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0,0,-10), Quaternion.Euler(0, 0, 0), Vector3.one);

        Graphics.DrawMesh(mesh, matrix, material, 0);
    }

}
```
では解説していきます。

```DrawMeshScript.cs
mesh = new Mesh();
```
ここでは、まず「mesh = new Mesh();」でMesh型の変数に頂点座標を書き込める状態にしています。

```DrawMeshScript.cs 
mesh.vertices = new Vector3[] {
    new Vector3(0, 0, 0),
    new Vector3(100, 0, 0),
    new Vector3(0, 100, 0),
};
```
次に、設計図となるMeshの頂点座標を入れています。

```DrawMeshScript.cs 
mesh.triangles = new int[] { 0, 1, 2};
```
ここで、先ほど入れた頂点座標を使い、一つの三角形として保存しています。
****
```DrawMeshScript.cs
Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0,0,-10), Quaternion.Euler(0, 180, 0), Vector3.one);

Graphics.DrawMesh(mesh, matrix, material, 0);
```
描画のコードです。

:::note warn
描画は**一度すればそのまま残るわけではないので、毎フレーム必要です。
Updateに入れましょう**
:::
では、**Matrix4x4.TRS**の解説をしていきます。
```DrawMeshScript.cs
Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0,0,-10), Quaternion.Euler(0, 0, 0), Vector3.one);
```

Matrix4x4.TRSは、
**位置(transform)・回転(rotation)・拡大縮小(scale)を同時に管理・保存ができる型**
です。

これを使って、Graphics.DrawMeshに必要な情報の半分を一つに抑えています。
```DrawMeshScript.cs
Graphics.DrawMesh(mesh, matrix, material, 0);
```
最後です。今までに設定した情報を入れて、描画します。
左から、Mesh・Matrix4x4の座標情報・マテリアル・レイヤーです。

これで完成！
### それでは実行してみましょう！
![スクリーンショット 2024-12-20 13.38.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/21cffab0-69c8-eed3-e506-44b720aa2085.png)
**...あれ？**

何も映らなかったのではないでしょうか。これは、
### Meshは裏側の描画がない
というのが原因です。
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/10232ef5-5f0e-d289-7c95-1c5a1479796c.gif)
このように、裏側を見ると、**Meshが消えます。**
## 解決策
この問題の解決方法はいくつかありますが、二つ紹介します。

### 1.Shaderに直接書き込む
描画の根元にあるShaderというところに、裏側も描写させるコードを書く解決策です。
しかし、**難易度が高く、処理が増えてしまうデメリットがあります。**

### **2.回転させる**
無難ですが、最も簡単な解決策です。
デメリットは、は逆さになるので座標の計算をする場合ややこしくなることです。
****
今回は、**回転を使って解決**させます。
```DrawMeshScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawMeshScript : MonoBehaviour
{
    private Mesh mesh;
    
    public Material material;
    
    void Start()
    {
        mesh = new Mesh();
        
        mesh.vertices = new Vector3[] {
            new Vector3(0, 0, 0),
            new Vector3(100, 0, 0),
            new Vector3(0, 100, 0),
        };

        mesh.triangles = new int[] { 0, 1, 2};
    }
    private void Update() 
    {
        Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0,0,-10), Quaternion.Euler(0, 180, 0), Vector3.one);

        Graphics.DrawMesh(mesh, matrix, material, 0);
    }

}
```
### 変更点
```DrawMeshScript.cs
Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0,0,-10), Quaternion.Euler(0, 180, 0), Vector3.one);
```
非常に単純で、Y軸の回転を180に変更しました。
### 実行
![スクリーンショット 2024-12-20 10.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965351/38ec0d31-da44-1375-4dfb-15051aabd6e4.png)
無事表示されました！

# 最後に
初記事に少しワクワクしていました。
今回はGraphics.DrawMeshを使ったMeshだけの描画を紹介しました。
基礎的な部分のみの紹介だったため、Graphics.DrawMeshの大半の部分には触れられていません。是非、Meshを深く触ってみてください。