質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1539閲覧

UnityでMeshRenderを使用したオブジェクトのマテリアルを変更せずに、表示順をSortingLayerで変更したい

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2022/06/16 03:20

編集2022/06/20 00:56

前提

Unityでカメラからの距離に関係なく、複数のカメラを使わずに表示順を制御したいと調べたところ、SortingLayerを使うと実現できそうなのですが、MeshRenderのオブジェクトついて意図した表示になりません。

動作確認

まず、SortingLayerに「Front」を追加。以下のようにSprireRenderの画像を並べ、奥にある星の画像のSortingLayerを「Front」に変更しました。
すると、右の画像のように、カメラから見て奥にある星の画像が水色のてるてる坊主より手前に表示されるようになりました。ここまでは問題ありません。
イメージ説明

また、テキストについても確認してみます。星の画像のSortingLayerを「Default」に戻し、Canvasを使わないTextMeshProを星の奥にテキストを追加。
このTextMeshProのExtra SettingからSortingLayerを「Front」にすると、テキストが手前に表示されるようになりました。これも問題ありません。
イメージ説明

発生している問題

しかし、困ったのはここからです。
ヒエラルキを右クリックして、3Dから選択して作成するプリミティブなオブジェクト、MeshRenderで表示されているオブジェクトはSortingLayerの表示を無視してしまいます。
以下の画像はテキストのSortingLayerを「Front」のままですが、オブジェクトにテキストが隠れてしまっています。
イメージ説明

このMeshRendererを使用したオブジェクトはインスペクタでSortingLayerが表示されていないため、SortingLayerが反映されない(存在しない?)のかと思ったのですが、調べると以下のような変更方法についての記述が幾つか見つかります。
参考
https://tsubakit1.hateblo.jp/entry/2015/01/05/233000
https://qiita.com/miikun109/items/dada342d23bf58cc879f
https://hassakulab.com/knowledges/unity-renderer-order-between-sprite-and-mesh/

試したこと

参考にしたこちらのサイト:https://tsubakit1.hateblo.jp/entry/2015/01/05/233000
のスクリプトを元に、オブジェクトのSortingLayerを明示的にDefaultを指定して見たり、SortingLayerの設定でDefaultより小さいSortingLayerの追加、オブジェクトに設定したりしましたが、やはりオブジェクトの表示にはSortingLayerが反映されず、上記画像の位置関係であれば常に手前に表示されてしまいます。

SortingLayerを使用してMeshRenderを使ったオブジェクトの表示順を変更するにはどうすればよいのでしょうか。

頂いた追記・修正の依頼を元に補足

イメージ説明
Bongoさんの指摘を元にオブジェクトのマテリアルをFadeに変更したところ、上記のように実現することが出来ました。
しかし、この方法では既存の3Dモデルのアセットをすべてのマテリアルを変更しなければならず(それが最初から変えておくか、実行中に動的に変えるかはともかく)、手間が掛かったり、見た目が変わってしまう可能性があります。
ですので、今回作成したプリミティブなオブジェクトのように、マテリアルを変更せずに表示順の変更を実現したいです。

補足情報(FW/ツールのバージョンなど)

確認をしたunityのバージョンは2021.3.4f1です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2022/06/19 21:04

テラシュールブログさんの記事には、末尾に なお、この方法が使えるのは透明を使っている「スプライト」や「StandardShaderのTransparent/Fade」、「Transparentシェーダー云々」「パーティクルのシェーダー」です。要は透明を使っているシェーダーは描画順にコレを使ってるってだけの話です。 との注意書きがありますが、キューブのマテリアルは変更していますでしょうか。あるいは、マテリアルはデフォルトのままで描画順をコントロールしたい(その場合はおそらくキューブ以外...スプライトやTextMesh Proのマテリアルに手を加えることになる気配がします)ということでしょうか?
退会済みユーザー

退会済みユーザー

2022/06/20 01:01

質問、ありがとうございます。 テラシュールブログさんの記事の末尾は見落としていたので、マテリアルの変更について確認したところ実現したので、補足として追加させていただきました。 しかし、おっしゃっているようにマテリアルをデフォルト、あるいはそのアセットの元のまま変更せずに描画順を変更するのが実現したいことなので(タイトルも変更しました)、この方法では問題が解決しておらず、もし解決方法をご存じならば、ご教授いただければ幸いです。
guest

回答2

0

ベストアンサー

ご質問者さんの懸念はもっともだと思います。不透明オブジェクト用のシェーダーを全部透明用に作り替えるのはかなり手間がかかりそうですし、前後関係を正確に表現できなくなって「半透明になるオブジェクトの描画順がぐちゃぐちゃになる問題の解決法 - プログラミング関連の覚え書き集」の冒頭にある図のような不具合を起こしてしまうかもしれません。

最初から透明キューで描画されるように意図されたMeshRenderer(描画モードがFadeに設定されているものなど)であればテラシュールブログさんのSortingLayerを使うのがいいかと思います。
一方、今回のキューブのように不透明なオブジェクトの場合はソーティングレイヤーを設定しても効果を発揮しないため、SortingLayerは削除してかまわないでしょう(残しておいても動作に影響はないだろうとは思いますが...)。
その上で、追記依頼欄で申し上げた「スプライトやTextMesh Proのマテリアルに手を加えることになる気配がします」とはちょっと異なるアプローチになってしまいすみませんが、以下のような作戦を考えてみました。

まず、特に対策を行っていない状態でご質問者さんのシーンをまねて下図のようにシーンをセットアップしました。カメラから見て遠くから順にTextMesh Pro、星のスプライト、キューブが並んでいます。
キューブのマテリアルはDefault-Materialのままですので、通常どおり不透明キューで描画されます。TextMesh Proのソーティングレイヤーは前面描画用の「Front」に変更していますが、ご質問者さんがお示しいただいた図と同様に星よりも前面、キューブよりも背面に描画されています。

図1

Frame Debuggerで描画過程を確認してみますと、まず不透明キューでキューブが描画され、引き続き透明キューでのソーティングレイヤーの設定に従い先に星、次にテキストが描画されています。

図2

キューブより後に描画される透明キューオブジェクトがキューブの背後に隠れることができるのはデプステストのおかげですが、今回のような強制的に前面に描画させたいケースでは逆に邪魔になってしまうでしょう。追記依頼欄の「マテリアルに手を加える」というのは、スプライトやTextMesh Proのマテリアルをデプステストを行わないタイプに改造することを想定していたのですが、それもわりと面倒そうだと思い直しまして、代わりに「不透明オブジェクトより前面に出したいオブジェクトの描画に入る前に、デプスバッファを最遠点で塗りつぶす」という方針に変更しました。

まず下記のようなデプス塗りつぶしシェーダーを作成しました。ファークリップ面いっぱいに四角形を描きますが、「デプステストは常に通過」「デプスを書き込む」「カラーバッファへの書き込みは行わない」と設定することで、目には見えませんがデプスを最深値に書き換える挙動をさせています。
なお、シェーダーがビルド時に除外されないようにするにはAlways Included Shadersのリストに追加しておく必要があるかもしれません。

ShaderLab

1Shader "Effect/DepthEraser" 2{ 3 Properties 4 { 5 } 6 SubShader 7 { 8 Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } 9 10 Cull Off 11 ZWrite On 12 ZTest Always 13 ColorMask 0 14 15 Pass 16 { 17 CGPROGRAM 18 #pragma vertex vert 19 #pragma fragment frag 20 21 #include "UnityCG.cginc" 22 23 float4 vert(float4 vertex : POSITION) : SV_POSITION 24 { 25 return float4(vertex.xy, 1.0 - saturate(UNITY_NEAR_CLIP_VALUE), 1.0); 26 } 27 28 fixed4 frag() : SV_Target 29 { 30 return 0.0; 31 } 32 ENDCG 33 } 34 } 35}

そして塗りつぶしオブジェクト用スクリプトを用意しました。

C#

1using UnityEngine; 2#if UNITY_EDITOR 3using UnityEditor; 4#endif 5 6[ExecuteAlways] 7public class DepthEraser : MonoBehaviour 8{ 9 private const string DepthEraserShaderName = "Effect/DepthEraser"; 10 private static Shader depthEraserShader; 11 12 // レイヤー名の選択にはテラシュールブログさんのSortingLayerAttributeを使いました 13 // Set Sorting Layer 14 // Copyright (c) 2014 Tatsuhiko Yamamura 15 // Released under the MIT license 16 // http://opensource.org/licenses/mit-license.php 17 [SortingLayer] public string sortingLayer = "Default"; 18 public int orderInLayer; 19 20 private Material material; 21 private Mesh mesh; 22 private MeshFilter meshFilter; 23 private MeshRenderer meshRenderer; 24 private int previousOrderInLayer = int.MaxValue; 25 private string previousSortingLayer; 26 27 private void Update() 28 { 29 if (depthEraserShader == null) 30 { 31 depthEraserShader = Shader.Find(DepthEraserShaderName); 32 if (depthEraserShader == null) 33 { 34 Debug.LogError($"{DepthEraserShaderName} not found."); 35 this.enabled = false; 36 return; 37 } 38 } 39 40 if (this.material == null) 41 { 42 this.material = new Material(depthEraserShader) 43 { 44 name = "DepthEraser", 45 hideFlags = HideFlags.HideAndDontSave 46 }; 47 } 48 49 if (this.mesh == null) 50 { 51 this.mesh = new Mesh 52 { 53 name = "DepthEraser", 54 hideFlags = HideFlags.HideAndDontSave, 55 vertices = new[] 56 { 57 new Vector3(-1.0f, -1.0f, 0.0f), 58 new Vector3(-1.0f, 1.0f, 0.0f), 59 new Vector3(1.0f, -1.0f, 0.0f), 60 new Vector3(1.0f, 1.0f, 0.0f) 61 }, 62 triangles = new[] 63 { 64 0, 1, 2, 65 3, 2, 1 66 } 67 }; 68 } 69 70 if (this.meshFilter == null) 71 { 72 this.meshFilter = this.gameObject.AddComponent<MeshFilter>(); 73 this.meshFilter!.hideFlags = HideFlags.HideAndDontSave; 74 this.meshFilter!.sharedMesh = this.mesh; 75 } 76 77 if (this.meshRenderer == null) 78 { 79 this.meshRenderer = this.gameObject.AddComponent<MeshRenderer>(); 80 this.meshRenderer!.hideFlags = HideFlags.HideAndDontSave; 81 this.meshRenderer!.sharedMaterial = this.material; 82 } 83 84 this.meshRenderer!.bounds = new Bounds( 85 Vector3.zero, 86 new Vector3(Mathf.Infinity, Mathf.Infinity, Mathf.Infinity)); 87 if (this.orderInLayer != this.previousOrderInLayer) 88 { 89 this.previousOrderInLayer = this.orderInLayer; 90 this.meshRenderer.sortingOrder = this.orderInLayer; 91 } 92 93 if (this.sortingLayer != this.previousSortingLayer) 94 { 95 this.previousSortingLayer = this.sortingLayer; 96 this.meshRenderer.sortingLayerName = this.sortingLayer; 97 } 98 } 99 100 private void OnDestroy() 101 { 102 if (Application.isPlaying) 103 { 104 Destroy(this.material); 105 Destroy(this.mesh); 106 } 107 else 108 { 109 DestroyImmediate(this.material); 110 DestroyImmediate(this.mesh); 111 } 112 } 113 114 #if UNITY_EDITOR 115 [MenuItem("GameObject/Depth Eraser", false, 11)] 116 public static void Create() 117 { 118 var eraserObject = new GameObject("Depth Eraser"); 119 Undo.RegisterCreatedObjectUndo(eraserObject, "Create Depth Eraser"); 120 Undo.AddComponent<DepthEraser>(eraserObject); 121 } 122 #endif 123}

「GameObject」→「Depth Eraser」でオブジェクトを作成し、Sorting LayerとOrder In Layerを最前面にしたいオブジェクトより手前になるようにします。さしあたりSorting LayerはFront、Order In Layerは-1としました。

図3

その結果、TextMesh Proの描画前にデプス塗りつぶし用の見えないオブジェクトが描画され、TextMesh Proがキューブに遮られなくなりました。

図4

投稿2022/06/21 10:32

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Bongoさんの方法はすべてが理解できているわけではないのですが、解決することが出来ました。

投稿2022/06/25 02:35

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問