【Unity】SpriteRendererとMesh Renderの半透明描画順制御

# 概要
- Sprite Rendererと通常のMesh Rendererの描画順でハマったのでその備忘録と解決策です
- 解決策だけ知りたい方は[Mesh RendererにOrder In Layerを設定する](https://qiita.com/broken55/items/8431fd3d8d4d9bc04436#mesh-renderer%E3%81%ABorder-in-layer%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)まで飛んでください

# 半透明描画の描画順
## Mesh Renderer
まず下記の条件で調べます

- Apple:Render Queue=3000
- Boy:Render Queue=3000
- 位置関係：Boyの方がAppleより手前

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/48a4aad9-acec-59e0-a232-c25e8209c3d2.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/af489676-06ed-300e-103b-71429ba3bc98.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/6b6a6e05-e114-9c3b-1ea1-e3d90b5e265b.png)

この場合、Boyの方が手前として描画されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/48c44369-8755-5f3b-c07f-e7ff5a4a7e11.png)


次にAppleの`Render Queue`を+1して3001にします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/9d9a5ba4-7b06-cb26-eb6a-7ee6ac39a00c.png)

すると位置関係を無視して、AppleがBoyの前に描画されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/110d37c7-338e-da72-7fbf-10f4dd385868.png)

## Sprite Renderer
次にSprite Rendererの場合です

- Apple:Order In Layer=0
- Boy:Order In Layer=0
- 位置関係：Boyの方がAppleより手前

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/bb4e1e8c-d608-c445-6ff1-c890e02ab296.png)

この場合もBoyが手前として描画されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/6970cfc6-ab9a-9896-9266-0423b51732e7.png)

Appleの方の`Order In Layer`を1に変更します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/7fbbd7e3-812e-2719-c785-5a7aa5345e41.png)

この場合も位置関係を無視して、AppleがBoyの前に描画されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/b135466f-af64-16e6-6df3-f792acd5ac0b.png)

## Sprite RendererとMesh Rendererを組み合わせた場合
この2つを組み合わせた場合描画順は複雑になります
まず以下のように設定します

| 表示物| 表示方法 ||
|:-----------:|:------------:|:------------:|
|Apple|Sprite Renderer|Order In Layer=0|
|Boy|Sprite Renderer|Order In Layer=0|
|Car|Mesh Renderer|Render Queue=3000|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/d9fef0c6-e035-bb24-1fb9-39ee2ed0de51.png)

この場合は素直に手前から描画してくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/f8a59f01-5e35-e217-567c-cf7cf219f4f3.png)

次に一番奥にあるAppleのOrder In Layerを1に変更します

| 表示物| 表示方法 ||
|:-----------:|:------------:|:------------:|
|Apple|Sprite Renderer|**Order In Layer=1**|
|Boy|Sprite Renderer|Order In Layer=0|
|Car|Mesh Renderer|Render Queue=3000|

するとAppleはCarより手前に描画されるようになってしまいます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/b3e114ce-2b0f-a4a0-e171-ee79c86fb894.png)

このときCarの`Render Queue`を大きくしてもAppleより手前に描画されることはありません
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/a54f95fe-3196-8d2d-ad5d-6464c0ee4a3b.png)


次節で解決方法を紹介します

# Mesh RendererにOrder In Layerを設定する
Mesh Rendererにも実はOrder In Layerのパラメータが存在します
しかし、通常のGUIからは操作できないようになっています。
そこで、Editor拡張を追加することで操作を可能にします

```c#
using UnityEngine;
using UnityEditor;
using System.Linq;
using System;


[CustomEditor(typeof(MeshRenderer))]
public class MyMeshRendererInspector : Editor
{
    Editor defaultEditor;

    private void OnEnable()
    {
        this.defaultEditor = Editor.CreateEditor(targets, Type.GetType("UnityEditor.MeshRendererEditor, UnityEditor"));
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        EditorGUILayout.BeginHorizontal();

        // sorting order
        var sortOrderProperty = serializedObject.FindProperty("m_SortingOrder");
        sortOrderProperty.intValue = EditorGUILayout.IntField("Sort Order", sortOrderProperty.intValue);

        // sorting layer
        var layerIDProperty = serializedObject.FindProperty("m_SortingLayerID");
        var index = System.Array.FindIndex(SortingLayer.layers, layer => layer.id == layerIDProperty.intValue);
        index = EditorGUILayout.Popup(index, (from layer in SortingLayer.layers select layer.name).ToArray());
        layerIDProperty.intValue = SortingLayer.layers[index].id;

        EditorGUILayout.EndHorizontal();
        serializedObject.ApplyModifiedProperties();

        this.defaultEditor.OnInspectorGUI();
    }
}
```

ソースコードはこちらを参考にさせていただきました
[MeshRendererでSortingLayerIDやOrderInLayerを変更する拡張スクリプト](https://qiita.com/miikun109/items/dada342d23bf58cc879f)

このスクリプトをプロジェクト内に導入することでMesh RendererのOrder In Layerを設定することが可能になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/2e6daa98-d35e-c18f-5b97-f5e78e543acd.png)


この機能を使って、CarのOrder In Layerを設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/519fdae4-32e5-776c-0a73-fe5a6fbaf7e6.png)

| 表示物| 表示方法 ||
|:-----------:|:------------:|:------------:|
|Apple|Sprite Renderer|**Order In Layer=1**|
|Boy|Sprite Renderer|Order In Layer=0|
|Car|Mesh Renderer|Render Queue=3000<br> **Order In Layer=1**|

するとCarがAppleの手前に描画されるようになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/18cb98b7-7904-dae9-2c41-06a30fcfe8fb.png)

# まとめ
- 描画順制御は一度やりだすとあらゆるオブジェクトの描画順を管理しなければならないため、極力描画順制御しないつくりを目指すことをお勧めします
- 特に今回のようにSprite RendererとMesh Rendererが入り混じったシーンの場合、描画順制御の難易度が上がります