teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

ご提示のプロジェクトに合わせてスクリプトを改修

2018/11/08 12:05

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -77,4 +77,102 @@
77
77
 
78
78
  Normalがほぼ(0, 1, 0)で、Normal Varianceがほぼ(0, 0, 0)、DistanceとDistance Varianceがいずれもほぼ0ならメッシュに問題はなさそうなので、不具合の原因は他の部分にあると思われます。
79
79
  Normal、Distanceが上記と異なっていても、Normal Varianceがほぼ(0, 0, 0)、Distance Varianceがほぼ0ならシェーダーの修正で対応可能なはずです。
80
- Normal Variance、Distance Varianceが0から大きくずれているようですと、鏡が平面でない可能性が大きいです。その場合はモデルを修正する必要がありそうです...
80
+ Normal Variance、Distance Varianceが0から大きくずれているようですと、鏡が平面でない可能性が大きいです。その場合はモデルを修正する必要がありそうです...
81
+
82
+ #追記
83
+
84
+ プロジェクトファイルのご提示ありがとうございます。とても参考になりました。鏡のオブジェクトは「l2_slab」、メッシュは「_I_u_W_F_N」でよろしいでしょうか。
85
+
86
+ このメッシュは2つのサブメッシュから構成されており、鏡マテリアルの面も天井平面だけでなく側面も含んだ非平面のようでした。
87
+ 回答に追記した`MirrorMeshChecker`は、複数のサブメッシュを持たない平面メッシュを想定したものでしたので、正しく面の向き・位置を求めることができなかったようです。
88
+
89
+ さしあたり、下記のように`MirrorMeshChecker`に面法線が下方を向いている面だけを計算に加味するよう泥縄的改修を加えて実行してみたところ...
90
+
91
+ ```C#
92
+ using System.Collections.Generic;
93
+ using System.Linq;
94
+ using UnityEditor;
95
+ using UnityEngine;
96
+
97
+ public static class MirrorMeshChecker
98
+ {
99
+ [MenuItem("Utility/Check Mirror Mesh")]
100
+ public static void CheckMirrorMesh()
101
+ {
102
+ var mesh = Selection.activeObject as Mesh;
103
+ if (mesh == null)
104
+ {
105
+ return;
106
+ }
107
+
108
+ var subMeshCount = mesh.subMeshCount;
109
+ var vertices = mesh.vertices;
110
+ for (var k = 0; k < subMeshCount; k++)
111
+ {
112
+ var triangles = mesh.GetTriangles(k);
113
+ var faceCount = triangles.Length / 3;
114
+ var normals = new List<Vector3>();
115
+ var faceVertices = new HashSet<Vector3>();
116
+ for (var i = 0; i < faceCount; i++)
117
+ {
118
+ var j = i * 3;
119
+ var v0 = vertices[triangles[j]];
120
+ var v1 = vertices[triangles[j + 1]];
121
+ var v2 = vertices[triangles[j + 2]];
122
+ var n = Vector3.Cross(v1 - v0, v2 - v0).normalized;
123
+ if (Vector3.Dot(n, Vector3.down) < 0.9f)
124
+ {
125
+ continue;
126
+ }
127
+ normals.Add(n);
128
+ faceVertices.Add(v0);
129
+ faceVertices.Add(v1);
130
+ faceVertices.Add(v2);
131
+ }
132
+
133
+ if (normals.Count <= 0)
134
+ {
135
+ continue;
136
+ }
137
+ var normal = normals.Aggregate((sum, n) => sum + n).normalized;
138
+ var normalVariance = normals.Aggregate(
139
+ Vector3.zero,
140
+ (variance, n) =>
141
+ {
142
+ var d = n - normal;
143
+ return variance + Vector3.Scale(d, d);
144
+ });
145
+ var plane = new Plane(normal, Vector3.zero);
146
+ var distances = faceVertices.Select(v => plane.GetDistanceToPoint(v)).ToArray();
147
+ var distance = distances.Average();
148
+ var distanceVariance = distances.Aggregate(
149
+ 0.0f,
150
+ (variance, r) =>
151
+ {
152
+ var d = r - distance;
153
+ return variance + (d * d);
154
+ });
155
+ Debug.LogFormat("Submesh {0}:", k);
156
+ Debug.LogFormat("\tNormal:{0}", normal.ToString("F8"));
157
+ Debug.LogFormat("\tNormal Variance:{0}", normalVariance.ToString("F8"));
158
+ Debug.LogFormat("\tDistance:{0:F8}", distance);
159
+ Debug.LogFormat("\tDistance Variance:{0:F8}", distanceVariance);
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ 下図のように向きは(0, -1, 0)で位置は約-5.2、つまり地上5.2mの位置にある...という結果になりました。
166
+
167
+ ![コンソール](5ab4b9e58b5cb4f151839ef6f7bcce2c.png)
168
+
169
+ そこで、MirrorReflection.csの46、47行目を下記のように変更すると...
170
+
171
+ ```C#
172
+ Vector3 pos = transform.TransformPoint(new Vector3(0.0f, 5.2f, 0.0f));
173
+ Vector3 normal = -transform.up;
174
+ ```
175
+
176
+ 下図のように、天井に風景が映り込みました。
177
+
178
+ ![鏡天井](fdf04c6168639e433313f299024018d2.gif)

1

鏡面の向き・位置確認について追記

2018/11/08 12:05

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -9,4 +9,72 @@
9
9
  - 166行目の`reflectionCamera = go.camera;`を`reflectionCamera = go.GetComponent<Camera>();`にする
10
10
  - 170行目の`reflectionCamera.gameObject.AddComponent("FlareLayer");`を`reflectionCamera.gameObject.AddComponent<FlareLayer>();`にする
11
11
 
12
- 参考:[UnityのMirrorRefrectionによる鏡の表現 - Qiita](https://qiita.com/UnagiHuman/items/6fae8e52d9c5c73ce3b0)
12
+ 参考:[UnityのMirrorRefrectionによる鏡の表現 - Qiita](https://qiita.com/UnagiHuman/items/6fae8e52d9c5c73ce3b0)
13
+
14
+ #追記
15
+ メッシュの点検用スクリプトを作ってみました。
16
+ Editorフォルダを作って、中に下記スクリプトを入れ...
17
+ ```C#
18
+ using System.Linq;
19
+ using UnityEditor;
20
+ using UnityEngine;
21
+
22
+ public static class MirrorMeshChecker
23
+ {
24
+ [MenuItem("Utility/Check Mirror Mesh")]
25
+ public static void CheckMirrorMesh()
26
+ {
27
+ var mesh = Selection.activeObject as Mesh;
28
+ if (mesh == null)
29
+ {
30
+ return;
31
+ }
32
+
33
+ var vertices = mesh.vertices;
34
+ var triangles = mesh.triangles;
35
+ var faceCount = triangles.Length / 3;
36
+ var normals = new Vector3[faceCount];
37
+ for (var i = 0; i < faceCount; i++)
38
+ {
39
+ var j = i * 3;
40
+ var v0 = vertices[triangles[j]];
41
+ var v1 = vertices[triangles[j + 1]];
42
+ var v2 = vertices[triangles[j + 2]];
43
+ normals[i] = Vector3.Cross(v1 - v0, v2 - v0).normalized;
44
+ }
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 = vertices.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("Normal:{0}", normal.ToString("F8"));
65
+ Debug.LogFormat("Normal Variance:{0}", normalVariance.ToString("F8"));
66
+ Debug.LogFormat("Distance:{0:F8}", distance);
67
+ Debug.LogFormat("Distance Variance:{0:F8}", distanceVariance);
68
+ }
69
+ }
70
+ ```
71
+ 鏡メッシュを選択し...
72
+ ![選択](897b8d054ff2d4cdc1d55c37d6443458.png)
73
+ 「Utility」→「Check Mirror Mesh」を実行すると...
74
+ ![実行](2c50892bd64463a2d4c0c3a237bc3441.png)
75
+ コンソールに結果が表示されるかと思います。
76
+ ![結果](9310f62c4774161a9992eaabbc4f1fe6.png)
77
+
78
+ Normalがほぼ(0, 1, 0)で、Normal Varianceがほぼ(0, 0, 0)、DistanceとDistance Varianceがいずれもほぼ0ならメッシュに問題はなさそうなので、不具合の原因は他の部分にあると思われます。
79
+ Normal、Distanceが上記と異なっていても、Normal Varianceがほぼ(0, 0, 0)、Distance Varianceがほぼ0ならシェーダーの修正で対応可能なはずです。
80
+ Normal Variance、Distance Varianceが0から大きくずれているようですと、鏡が平面でない可能性が大きいです。その場合はモデルを修正する必要がありそうです...