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

回答編集履歴

3

枠線が細くなる問題について追記

2018/06/03 22:01

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -119,4 +119,129 @@
119
119
  toFill.AddUIVertexTriangleStream(this.vertices);
120
120
  }
121
121
  }
122
- ```
122
+ ```
123
+
124
+ ### 枠線が細く見えることについて追記
125
+ 確かに傾き量を大きくすると、枠線が細く見えてしまうのは気になりますね。
126
+ なんとかして9スライスの区切り位置をずらしてやる必要があるかと思います。あまりエレガントではないですが、ずらし機能を追加してみました。
127
+
128
+ 元のスプライトは9つの四角形が並んだ36個の頂点からなり、これがGetUIVertexStreamを通った後は一つの四角形が2つの三角形になって頂点数は54個になるようです。このうち、コード中の`SliceOffsetV0Indices`に示した18頂点が下側のスライス区切り位置に、`SliceOffsetV1Indices`に示した18頂点が上側のスライス区切り位置に相当するようなので、これらを見た目がよくなるようY座標を調節できるようにしてみました。
129
+
130
+ 私のコードはスキュー行列方式のままですが、ご質問者さんの方式でも使える方法かと思います。
131
+
132
+ SkewedImage改変版
133
+ ```C#
134
+ using System.Collections.Generic;
135
+ using UnityEngine;
136
+ using UnityEngine.UI;
137
+
138
+ public class SkewedImage : Image
139
+ {
140
+ // スライス区切り位置に相当する頂点のインデックスの表
141
+ private static readonly int[] SliceOffsetV0Indices =
142
+ {
143
+ 1, 2, 3, 6, 10, 11,
144
+ 19, 20, 21, 24, 28, 29,
145
+ 37, 38, 39, 42, 46, 47
146
+ };
147
+ private static readonly int[] SliceOffsetV1Indices =
148
+ {
149
+ 7, 8, 9, 12, 16, 17,
150
+ 25, 26, 27, 30, 34, 35,
151
+ 43, 44, 45, 48, 52, 53
152
+ };
153
+
154
+ public Vector2 Skew;
155
+
156
+ // スライス区切り座標のずらし量
157
+ public Vector2 SliceOffsetV;
158
+
159
+ private List<UIVertex> vertices;
160
+
161
+ protected override void OnPopulateMesh(VertexHelper toFill)
162
+ {
163
+ base.OnPopulateMesh(toFill);
164
+ if (this.vertices == null)
165
+ {
166
+ this.vertices = new List<UIVertex>();
167
+ }
168
+ toFill.GetUIVertexStream(this.vertices);
169
+ var vertexCount = this.vertices.Count;
170
+ var skewMatrix = Matrix4x4.identity;
171
+ skewMatrix.m01 = this.Skew.x;
172
+ skewMatrix.m10 = this.Skew.y;
173
+
174
+ // スライス区切りインデックス表を参照するためのインデックス
175
+ var sV0 = 0;
176
+ var sV1 = 0;
177
+
178
+ for (var i = 0; i < vertexCount; i++)
179
+ {
180
+ var v = this.vertices[i];
181
+ v.position = skewMatrix.MultiplyPoint3x4(v.position);
182
+
183
+ // iがスライス区切りインデックス表に載っていれば、Y座標をずらす
184
+ if (i == SliceOffsetV0Indices[sV0])
185
+ {
186
+ // 第1のスライス区切り位置をずらす
187
+ v.position.y += this.SliceOffsetV.x;
188
+ sV0 = Mathf.Min(sV0 + 1, SliceOffsetV0Indices.Length - 1);
189
+ }
190
+ else if (i == SliceOffsetV1Indices[sV1])
191
+ {
192
+ // 第2のスライス区切り位置をずらす
193
+ v.position.y += this.SliceOffsetV.y;
194
+ sV1 = Mathf.Min(sV1 + 1, SliceOffsetV1Indices.Length - 1);
195
+ }
196
+
197
+ this.vertices[i] = v;
198
+ }
199
+
200
+ toFill.Clear();
201
+ toFill.AddUIVertexTriangleStream(this.vertices);
202
+ }
203
+ }
204
+ ```
205
+
206
+ SkewedImageEditor改変版
207
+ ```C#
208
+ using UnityEditor;
209
+ using UnityEditor.UI;
210
+ using UnityEngine;
211
+
212
+ [CustomEditor(typeof(SkewedImage), true)]
213
+ [CanEditMultipleObjects]
214
+ public class SkewedImageEditor : ImageEditor
215
+ {
216
+ public override void OnInspectorGUI()
217
+ {
218
+ base.OnInspectorGUI();
219
+ var targetSkewedImage = this.target as SkewedImage;
220
+ if (targetSkewedImage != null)
221
+ {
222
+ var prevSkew = targetSkewedImage.Skew;
223
+ var newSkew = EditorGUILayout.Vector2Field("Skew", prevSkew);
224
+ var dirty = false;
225
+ if (newSkew != prevSkew)
226
+ {
227
+ targetSkewedImage.Skew = newSkew;
228
+ dirty = true;
229
+ }
230
+ var prevSliceOffsetV = targetSkewedImage.SliceOffsetV;
231
+ var newSliceOffsetV = EditorGUILayout.Vector2Field("Vertical Slice Offset", prevSliceOffsetV);
232
+ if (newSliceOffsetV != prevSliceOffsetV)
233
+ {
234
+ targetSkewedImage.SliceOffsetV = newSliceOffsetV;
235
+ dirty = true;
236
+ }
237
+ if (dirty)
238
+ {
239
+ targetSkewedImage.SetVerticesDirty();
240
+ }
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ 動かした様子
247
+ ![プレビュー](272972b5862c893efe1d3ff3b9a33841.gif)

2

GetUIVertexStream版コードを追記

2018/06/03 22:01

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -72,4 +72,51 @@
72
72
  プライベートフィールドへの直接アクセスをせずにやるとなると、自前で9スライス機能を持つコンポーネントを作ることになるでしょうかね。
73
73
  Imageのコードを改造する手もあるかもしれませんが、Unity Technologiesの公開しているコードは自由に改造していいわけではないらしいので、そちらは控えておいた方がよさそうです。
74
74
 
75
- ※ご質問者さんのおっしゃる「台形」というのは、ご提示の図を見て[平行四辺形](https://ja.wikipedia.org/wiki/%E5%B9%B3%E8%A1%8C%E5%9B%9B%E8%BE%BA%E5%BD%A2)のことだろうと勝手に解釈してしまいましたが、任意の[台形](https://ja.wikipedia.org/wiki/%E5%8F%B0%E5%BD%A2)(平行でない対辺があるかもしれない)でないとまずかったでしょうか?
75
+ ※ご質問者さんのおっしゃる「台形」というのは、ご提示の図を見て[平行四辺形](https://ja.wikipedia.org/wiki/%E5%B9%B3%E8%A1%8C%E5%9B%9B%E8%BE%BA%E5%BD%A2)のことだろうと勝手に解釈してしまいましたが、任意の[台形](https://ja.wikipedia.org/wiki/%E5%8F%B0%E5%BD%A2)(平行でない対辺があるかもしれない)でないとまずかったでしょうか?
76
+
77
+ ### 追記
78
+ どうやらGetUIVertexStreamを使っても問題なさそうでした。計算量・メモリ消費量は少し増えそうですが(わずかな増加なので大したことはないでしょう)、こっちの方がまともなやり方のように思います。
79
+ ```C#
80
+ using System.Collections.Generic;
81
+ using UnityEngine;
82
+ using UnityEngine.UI;
83
+
84
+ public class SkewedImage : Image
85
+ {
86
+ public Vector2 Skew; // 水平・垂直スキューのタンジェント...たとえば(0, 1)とすると、X成分の増加に傾き1で比例してYも増加する→X軸が45°傾く
87
+
88
+ private List<UIVertex> vertices;
89
+
90
+ protected override void OnPopulateMesh(VertexHelper toFill)
91
+ {
92
+ // 本来のImageの頂点を作成させる
93
+ base.OnPopulateMesh(toFill);
94
+
95
+ // Imageが作成した頂点をまともな方法で取得
96
+ // どうやらメッシュがインデックス付きからインデックスなしに変わってしまう?
97
+ // UI用オブジェクトなら、インデックスなしメッシュでもさほど頂点数は増えないだろうと期待する
98
+ if (this.vertices == null)
99
+ {
100
+ this.vertices = new List<UIVertex>();
101
+ }
102
+ toFill.GetUIVertexStream(this.vertices);
103
+ var vertexCount = this.vertices.Count;
104
+
105
+ // スキュー変換行列を作成
106
+ var skewMatrix = Matrix4x4.identity;
107
+ skewMatrix.m01 = this.Skew.x;
108
+ skewMatrix.m10 = this.Skew.y;
109
+
110
+ // スキュー変換適用後の頂点でメッシュを置き換える
111
+ // せっかくImageが作ったメッシュを破棄してしまっている気がするが、こちらの方が正当なやり方かもしれない
112
+ for (var i = 0; i < vertexCount; i++)
113
+ {
114
+ var v = this.vertices[i];
115
+ v.position = skewMatrix.MultiplyPoint3x4(v.position); // 平行四辺形変形ならMultiplyPoint3x4で対応可能なので、こっちを使った方が少し高速?
116
+ this.vertices[i] = v;
117
+ }
118
+ toFill.Clear();
119
+ toFill.AddUIVertexTriangleStream(this.vertices);
120
+ }
121
+ }
122
+ ```

1

誤字を修正

2018/06/02 21:10

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -72,4 +72,4 @@
72
72
  プライベートフィールドへの直接アクセスをせずにやるとなると、自前で9スライス機能を持つコンポーネントを作ることになるでしょうかね。
73
73
  Imageのコードを改造する手もあるかもしれませんが、Unity Technologiesの公開しているコードは自由に改造していいわけではないらしいので、そちらは控えておいた方がよさそうです。
74
74
 
75
- ※ご質問者さんのおっしゃる「台形」というのは、ご提示の図を見て[平行四辺形](https://ja.wikipedia.org/wiki/%E5%B9%B3%E8%A1%8C%E5%9B%9B%E8%BE%BA%E5%BD%A2)のことだろうと勝手に解釈してしまいましたが、任意の[台形](https://ja.wikipedia.org/wiki/%E5%8F%B0%E5%BD%A2)(行でない対辺があるかもしれない)でないとまずかったでしょうか?
75
+ ※ご質問者さんのおっしゃる「台形」というのは、ご提示の図を見て[平行四辺形](https://ja.wikipedia.org/wiki/%E5%B9%B3%E8%A1%8C%E5%9B%9B%E8%BE%BA%E5%BD%A2)のことだろうと勝手に解釈してしまいましたが、任意の[台形](https://ja.wikipedia.org/wiki/%E5%8F%B0%E5%BD%A2)(行でない対辺があるかもしれない)でないとまずかったでしょうか?