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

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

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

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

Q&A

解決済

2回答

1376閲覧

unityの鏡面表現にリフレクションプローブを使っていますが、うまく映り込みしません。

pin03

総合スコア23

Unity

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

0グッド

0クリップ

投稿2018/11/05 03:08

unityにて、建物の天井を鏡面にするためにリフレクションプローブを使っています。
天井は平らなのですが、上から見た時の形状は四角ではなく複雑な形をしています。

鏡面っぽくはなっています。しかし、映り込みが明らかにずれていたりして違和感があります。
自然に映るようにするための方法を試しましたが、その条件の一つとして、プローブの効果範囲(黄色い線で表示される)を対象のオブジェクトにピッタリ合わせないとならないようです。

天井の輪郭は複雑なので、うまくいきませんでした。
どのような方法であれば正確な映り込みを実現できるのでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

縁が複雑な形であっても、反射面が平面ならば、反射像を別途レンダリングして鏡面に投影するテクニックが使えるのではないかと思います。
MirrorReflection4 - Unify Community Wikiを試してみたところ、下図のように天井に不定形の鏡を設置することができました。

鏡

コードについては、2018.2.14f1でも少し修正するだけで動作しました。
MirrorReflection.csの...

  • 166行目のreflectionCamera = go.camera;reflectionCamera = go.GetComponent<Camera>();にする
  • 170行目のreflectionCamera.gameObject.AddComponent("FlareLayer");reflectionCamera.gameObject.AddComponent<FlareLayer>();にする

参考:UnityのMirrorRefrectionによる鏡の表現 - Qiita

#追記
メッシュの点検用スクリプトを作ってみました。
Editorフォルダを作って、中に下記スクリプトを入れ...

C#

1using System.Linq; 2using UnityEditor; 3using UnityEngine; 4 5public static class MirrorMeshChecker 6{ 7 [MenuItem("Utility/Check Mirror Mesh")] 8 public static void CheckMirrorMesh() 9 { 10 var mesh = Selection.activeObject as Mesh; 11 if (mesh == null) 12 { 13 return; 14 } 15 16 var vertices = mesh.vertices; 17 var triangles = mesh.triangles; 18 var faceCount = triangles.Length / 3; 19 var normals = new Vector3[faceCount]; 20 for (var i = 0; i < faceCount; i++) 21 { 22 var j = i * 3; 23 var v0 = vertices[triangles[j]]; 24 var v1 = vertices[triangles[j + 1]]; 25 var v2 = vertices[triangles[j + 2]]; 26 normals[i] = Vector3.Cross(v1 - v0, v2 - v0).normalized; 27 } 28 29 var normal = normals.Aggregate((sum, n) => sum + n).normalized; 30 var normalVariance = normals.Aggregate( 31 Vector3.zero, 32 (variance, n) => 33 { 34 var d = n - normal; 35 return variance + Vector3.Scale(d, d); 36 }); 37 var plane = new Plane(normal, Vector3.zero); 38 var distances = vertices.Select(v => plane.GetDistanceToPoint(v)).ToArray(); 39 var distance = distances.Average(); 40 var distanceVariance = distances.Aggregate( 41 0.0f, 42 (variance, r) => 43 { 44 var d = r - distance; 45 return variance + (d * d); 46 }); 47 Debug.LogFormat("Normal:{0}", normal.ToString("F8")); 48 Debug.LogFormat("Normal Variance:{0}", normalVariance.ToString("F8")); 49 Debug.LogFormat("Distance:{0:F8}", distance); 50 Debug.LogFormat("Distance Variance:{0:F8}", distanceVariance); 51 } 52}

鏡メッシュを選択し...
選択
「Utility」→「Check Mirror Mesh」を実行すると...
実行
コンソールに結果が表示されるかと思います。
結果

Normalがほぼ(0, 1, 0)で、Normal Varianceがほぼ(0, 0, 0)、DistanceとDistance Varianceがいずれもほぼ0ならメッシュに問題はなさそうなので、不具合の原因は他の部分にあると思われます。
Normal、Distanceが上記と異なっていても、Normal Varianceがほぼ(0, 0, 0)、Distance Varianceがほぼ0ならシェーダーの修正で対応可能なはずです。
Normal Variance、Distance Varianceが0から大きくずれているようですと、鏡が平面でない可能性が大きいです。その場合はモデルを修正する必要がありそうです...

#追記

プロジェクトファイルのご提示ありがとうございます。とても参考になりました。鏡のオブジェクトは「l2_slab」、メッシュは「_I_u_W_F_N」でよろしいでしょうか。

このメッシュは2つのサブメッシュから構成されており、鏡マテリアルの面も天井平面だけでなく側面も含んだ非平面のようでした。
回答に追記したMirrorMeshCheckerは、複数のサブメッシュを持たない平面メッシュを想定したものでしたので、正しく面の向き・位置を求めることができなかったようです。

さしあたり、下記のようにMirrorMeshCheckerに面法線が下方を向いている面だけを計算に加味するよう泥縄的改修を加えて実行してみたところ...

C#

1using System.Collections.Generic; 2using System.Linq; 3using UnityEditor; 4using UnityEngine; 5 6public static class MirrorMeshChecker 7{ 8 [MenuItem("Utility/Check Mirror Mesh")] 9 public static void CheckMirrorMesh() 10 { 11 var mesh = Selection.activeObject as Mesh; 12 if (mesh == null) 13 { 14 return; 15 } 16 17 var subMeshCount = mesh.subMeshCount; 18 var vertices = mesh.vertices; 19 for (var k = 0; k < subMeshCount; k++) 20 { 21 var triangles = mesh.GetTriangles(k); 22 var faceCount = triangles.Length / 3; 23 var normals = new List<Vector3>(); 24 var faceVertices = new HashSet<Vector3>(); 25 for (var i = 0; i < faceCount; i++) 26 { 27 var j = i * 3; 28 var v0 = vertices[triangles[j]]; 29 var v1 = vertices[triangles[j + 1]]; 30 var v2 = vertices[triangles[j + 2]]; 31 var n = Vector3.Cross(v1 - v0, v2 - v0).normalized; 32 if (Vector3.Dot(n, Vector3.down) < 0.9f) 33 { 34 continue; 35 } 36 normals.Add(n); 37 faceVertices.Add(v0); 38 faceVertices.Add(v1); 39 faceVertices.Add(v2); 40 } 41 42 if (normals.Count <= 0) 43 { 44 continue; 45 } 46 var normal = normals.Aggregate((sum, n) => sum + n).normalized; 47 var normalVariance = normals.Aggregate( 48 Vector3.zero, 49 (variance, n) => 50 { 51 var d = n - normal; 52 return variance + Vector3.Scale(d, d); 53 }); 54 var plane = new Plane(normal, Vector3.zero); 55 var distances = faceVertices.Select(v => plane.GetDistanceToPoint(v)).ToArray(); 56 var distance = distances.Average(); 57 var distanceVariance = distances.Aggregate( 58 0.0f, 59 (variance, r) => 60 { 61 var d = r - distance; 62 return variance + (d * d); 63 }); 64 Debug.LogFormat("Submesh {0}:", k); 65 Debug.LogFormat("\tNormal:{0}", normal.ToString("F8")); 66 Debug.LogFormat("\tNormal Variance:{0}", normalVariance.ToString("F8")); 67 Debug.LogFormat("\tDistance:{0:F8}", distance); 68 Debug.LogFormat("\tDistance Variance:{0:F8}", distanceVariance); 69 } 70 } 71}

下図のように向きは(0, -1, 0)で位置は約-5.2、つまり地上5.2mの位置にある...という結果になりました。

コンソール

そこで、MirrorReflection.csの46、47行目を下記のように変更すると...

C#

1 Vector3 pos = transform.TransformPoint(new Vector3(0.0f, 5.2f, 0.0f)); 2 Vector3 normal = -transform.up;

下図のように、天井に風景が映り込みました。

鏡天井

投稿2018/11/05 13:13

編集2018/11/08 12:05
Bongo

総合スコア10807

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

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

pin03

2018/11/07 06:28

ありがとうございます!試してみます
pin03

2018/11/07 07:48

貼っていただいた方法で試したのですが、灰色一色になってしましました。。 どこかでやり方を間違っているのだと思いますが、どこが間違いなのかわかりません。。 以下の手順で作成しましたが、間違いはありますでしょうか。。 ①プロジェクトにて新規マテリアルを作成 ②マテリアルを天井に使用する ③プロジェクトにて「Create」→「Shader」→「Standard Surface Shader」を作成 ④③に貼ってもらったサイトに従ってコードをペースト ⑤マテリアルのインスペクターにて「Shader」を「FX/Mirror Reflection」に ⑥プロジェクトにて「Create」→「C#Script」を作成 ⑦⑥にコードをコピーペースト&調整してもらった部分の修正(166行目と170行目) ⑧⑥をオブジェクトにアタッチ ⑨オブジェクトのレイヤーをwaterにする 以上です。 関係あるかわかりませんが 今作っているのもに動的なものはないので全てstaticにしています。。
Bongo

2018/11/07 08:39

鏡モデルの、反射面の位置と向きはどうなっているでしょうか? 今回のマテリアルの場合、反射面の向きはY軸+方向で、位置はオブジェクト原点を通過するようにモデリングされていないと、うまく反射してくれないはずです。 もしポリゴンメッシュの方を修正するのは困難でしたら、逆にシェーダーコードの中の反射面位置・向きをメッシュに合わせて修正することも可能かと思います。
pin03

2018/11/07 12:00

反射面の位置と向きというのは、天井(鏡)のオブジェクトを選択したときに「インスペクター」の「Transform」に出てくる数値のことですか?もしそうならスケールだけが全て1になっており、他は全て0になっています。(鏡だけでなくすべてのオブジェクトがその数値になっています。) もしその数値でなければ、どこで確認できるのか教えていただきたいです。(初心者でいろいろわからず申し訳ありません。。)
Bongo

2018/11/07 13:28

Transformが既定値の状態で天井用鏡として正常に使える状態である...ということは、反射面が真下を向いているのかもしれませんね... メッシュの面の向きと位置を点検するスクリプトを追記しましたので、念のためご確認ください。どのような結果になるでしょうか?
pin03

2018/11/08 01:18

スクリプトまで作成いただきありがとうございます。。 このような結果になりました Distance Variance:7915765.00000000 UnityEngine.Debug:LogFormat(String, Object[]) MirrorMeshChecker:CheckMirrorMesh() (at Assets/Editor/NewBehaviourScript.cs:50) NormalとDistance、Normal Varianceが出てきませんが Distance Varianceの値が大きいので鏡が平面ではないのでしょうか。。 モデルはformZというモデリングソフトで作成し、3ds形式でunityに読み込みました。
Bongo

2018/11/08 03:10

Distance Varianceしか出ませんでしたか?コンソールの設定の問題でしょうか... ログファイルに出力結果が残っていれば、コンソールのメニューにある「Open Editor Log」から読めるかもしれません(参考: https://gametukurikata.com/basic/console )。 モデルの位置・向きの件ですが、少なくともDistance Varianceの結果だけ見ると、モデルの修正が必要かもしれませんね。 Unityウィンドウ上部の操作モード切り替えボタンが「Pivot」「Local」の状態でシーン上の鏡オブジェクトを選択すると、オブジェクトの中心からローカルXYZ軸の方向に3色の矢印が表示されるかと思います。この矢印がどの点からどの方向に生えているかが肝心なのですが、画像などでご説明いただけますか? とはいえ、画像ではうまく状況を判断できる自信がないため、できればその鏡モデルファイルをどこかにアップロードしていただけるとありがたいのですが...
pin03

2018/11/08 05:06

ギズモードしたの「Pivot」「Local」を確認しましたが 矢印が反射したい対象物のある方向と逆をむいていましたがこれが原因でしょうか···モデリングソフトではそのような方向があることも知らずモデリングしているのですが、その矢印の方向は何を基準に決まっているのでしょう。。 データをダウンロードできるようにしました。 http://xfs.jp/0MXaC1
Bongo

2018/11/08 12:17

ご提示ありがとうございます。スクリプトの書き換え案を追記しました。 おっしゃる通り、鏡にしたい天井面が下を向いていたのが原因のようですね。矢印の向きについては、モデリングソフトや書き出し時の設定によって変わってくるでしょうから一概には言いにくいところもあります... 基準となる原点(Unity上で矢印が生える位置)は大抵のモデリングソフトにおける座標系の原点になるでしょうが、どの方角がX、Y、Zになるかは様々だと思います。モデリングソフトで単純な形状を作ってUnityに読み込ませてみて、方角の対応付けを調べるのが順当な手段ではないでしょうか。
pin03

2018/11/09 01:36

重いデータを送ってしまいすみませんでした。。 コードを変更したところ、送っていただいた画像のように正しく反射されるようになりました! また、なぜ反射されなかったのもわかりやすく解説いただき、理解することができました。 平面であることが前提と最初の回答に記載がありましたね。。 この件に関しては本当にとても困っていたので、たいへん助かりました。 親切丁寧な回答に感謝申し上げます。
Bongo

2018/11/09 01:55

お役に立てましたようでなによりです。 今さらですが、MirrorMeshCheckerの中で「Variance」という単語をいくつか使っていましたが、見返してみると用語がちょっと不適切でした。 データ数で割るのを忘れていたため「分散」というより「偏差平方和」でしたね。もはやMirrorMeshCheckerは用済みかと思いますが、一応お詫びします...
pin03

2018/11/09 02:10

とんでもありません。プログラミングは本当に最近始めたばかりで全く気が付きませんでした。。 重ねてお聞きして申し訳ないのですが、 このミラー天井の反射率を下げて白くしたりするのもプログラミングの領域になるのでしょうか?
Bongo

2018/11/09 03:01

その辺のカスタマイズは、Mirror.shaderの方を編集することになりますね。 「UnityのMirrorRefrectionによる鏡の表現 - Qiita」のサイト内の図では、反射像が薄暗くなっています。この程度でしたらマテリアルの「Base (RGB)」に適当なテクスチャをセットするだけで可能ですが、現状では反射像を暗くする方向にしか対応できませんので、より白っぽくしたいとか、つるつるに磨かれた石のようないくらか陰影のある見た目にしたいといった場合はMirror.shaderの改造が必要になるでしょう。
pin03

2018/11/09 04:33

シェーダーによる調整になるのですね。 やってみようと思います。 いろいろ教えていただきありがとうございました!
guest

0

Unityは使ったことがないですが、見た感じParallax-Corrected Cubemapのような技法で鏡面反射を表現する仕組みですかね。
これは鏡に映る対象が直方体の面に一致しているときのみ正しい結果が出ます。
その代わり曲面や無数の向きの違う鏡面を軽い処理で扱えます。
使う鏡面が1枚の平面なら必要ありません。Bongoさんの回答の手法が適切です。
天井の輪郭が複雑というのは部屋の壁も不定形でしょうか。でしたら対象を部屋に合わせられないのでどうやってもずれます。

投稿2018/11/06 01:20

ikadzuchi

総合スコア3047

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

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

pin03

2018/11/07 06:28

回答ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問