Blender の UV データが入り組んでいる件

# 簡単な立体クイズ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/25b8ca73-0807-57c7-2948-2d18969d518b.png)

　デフォルトキューブがあります。当然ながら頂点は 8 個、面は 6 個あります。

```python
mesh = bpy.data.meshes['Cube']
for vert in mesh.vertices:
    print(vert.co)
```

```python
<Vector (1.0000, 1.0000, 1.0000)>
<Vector (1.0000, 1.0000, -1.0000)>
<Vector (1.0000, -1.0000, 1.0000)>
<Vector (1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, 1.0000, 1.0000)>
<Vector (-1.0000, 1.0000, -1.0000)>
<Vector (-1.0000, -1.0000, 1.0000)>
<Vector (-1.0000, -1.0000, -1.0000)>
```

　さて、このキューブの UV 頂点は何個あるでしょうか？

　頂点と1対1対応しているので、8個でしょうか。

　違います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/2876d548-a4c3-1fd1-16a0-b1260ef00ead.png)

　展開図にしてみるとわかりますが、繋ぎ目になっている部分だけ、展開図上では切り離されて数が増えます。

　まあこんなひっかけは予想済ですよね。正解は 14 個！

　**違います。**

# UV 頂点へのアクセス

　気になる正解の前に、まず UV 頂点のアクセスへの仕方について。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/25e10111-e19b-72e3-1901-b9dc1b59e719.png)

　Blender では、メッシュデータは「UVレイヤー」というデータを持っています。どのレイヤーの UV を使うのかを選択できます。正直、使い分けたことはないですし、エラーの温床にしかならないような気もしますが……。メッシュから`uv_layers`で`bpy.types.MeshUVLoopLayer`というデータへのリストにアクセスできます。（余談ながら、`bpy_prop_collection`という表示が出てきた時は、なんらかのリストだということを覚えておくと、API の発掘がしやすいかも）

```python
mesh = bpy.data.meshes['Cube']
layer = mesh.uv_layers[0]
# <bpy_collection[1], UVLoopLayers>
print(layer)
# <bpy_struct, MeshUVLoopLayer("UVMap") at 0x0000017152B3A208>
```

　[リファレンス](https://docs.blender.org/api/current/bpy.types.MeshUVLoopLayer.html?highlight=meshuvloop#bpy.types.MeshUVLoopLayer)を見ると、`data`という属性で`bpy.types.MeshUVLoop`のリストにアクセスできることがわかります。

```python 
uv_verts = layer.data
print(uv_verts)
#<bpy_collection[24], MeshUVLoopLayer.data>
```

　という訳で答えは 24 でした。本当かよ、ということで中身の座標も見ていきます。

```python 
for vert in uv_verts:
    print(vert.uv)
```

```python:console
<Vector (0.6250, 0.5000)>
<Vector (0.8750, 0.5000)>
<Vector (0.8750, 0.7500)>
<Vector (0.6250, 0.7500)>
<Vector (0.3750, 0.7500)>
<Vector (0.6250, 0.7500)>
<Vector (0.6250, 1.0000)>
<Vector (0.3750, 1.0000)>
<Vector (0.3750, 0.0000)>
<Vector (0.6250, 0.0000)>
<Vector (0.6250, 0.2500)>
<Vector (0.3750, 0.2500)>
<Vector (0.1250, 0.5000)>
<Vector (0.3750, 0.5000)>
<Vector (0.3750, 0.7500)>
<Vector (0.1250, 0.7500)>
<Vector (0.3750, 0.5000)>
<Vector (0.6250, 0.5000)>
<Vector (0.6250, 0.7500)>
<Vector (0.3750, 0.7500)>
<Vector (0.3750, 0.2500)>
<Vector (0.6250, 0.2500)>
<Vector (0.6250, 0.5000)>
<Vector (0.3750, 0.5000)>
```

　これを注意深く数えると（実際に数えなくていいです）、一部重複しているものがあることがわかります。先程の「14個」はこの、重複を除いたものと考えることができます。つまり、すべての面の4隅に、（例え座標が重複していようが）頂点のデータは設定されていたのでした。

　なぜこのようになっているのか？

　それは UV が常に連続であるとは限らない（非連続にもできる）からです。

　端的に説明すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/6033d9de-30f7-30f3-7556-054350e1b59a.png)

　こうやって切り離すことも可能にするためです（理論上は、全てのエッジにシームが入る可能性がある以上、すべての面が UV 上で分離する可能性はあります）。

# そもそも頂点は 8 個なのか

　こう考えると、当初の前提にあった、そもそも頂点は 8 個であるという認識も怪しくなってきます。実際に、`polygons`から`polygon`（面）のデータを辿ってみます。

```python
for face in mesh.polygons:
    print(face)
```

```python:output
<bpy_struct, MeshPolygon at 0x0000017152BB0458>
<bpy_struct, MeshPolygon at 0x0000017152BB0464>
<bpy_struct, MeshPolygon at 0x0000017152BB0470>
<bpy_struct, MeshPolygon at 0x0000017152BB047C>
<bpy_struct, MeshPolygon at 0x0000017152BB0488>
<bpy_struct, MeshPolygon at 0x0000017152BB0494>
```

 6 枚あります。これはさすがに異論の余地はないと思います。これにはそれぞれ`loop_start`と`loop_total`という属性があります。ループ開始の頂点番号とループ長とかと思いきや、ちょっと違います。

```python
for face in mesh.polygons:
    print(face.loop_start,face.loop_total)
```

```python:output
0 4
4 4
8 4
12 4
16 4
20 4
```

　各面ごとに、4 つずつ番号が増えていくことがわかります。頂点は 8 個しかないのに！　ここを詳しく見ていくために、`vertices`という別の属性を見ていきます。

```python
for face in mesh.polygons:
    print(*face.vertices)
```

```python:output
0 4 6 2
3 2 6 7
7 6 4 5
5 1 3 7
1 0 2 3
5 4 0 1
```

　ここでやっと頂点番号らしきものが出てきました。座標を確認してみます。（`*`については[Pythonでタプルやリストをアンパック（複数の変数に展開して代入）](https://note.nkmk.me/python-tuple-list-unpack/)を参考）

```python
vertices = mesh.vertices

for face in mesh.polygons:
    for vert in face.vertices:
        print(vertices[vert].co)
```

```python:output
<Vector (1.0000, 1.0000, 1.0000)>
<Vector (-1.0000, 1.0000, 1.0000)>
<Vector (-1.0000, -1.0000, 1.0000)>
<Vector (1.0000, -1.0000, 1.0000)>
<Vector (1.0000, -1.0000, -1.0000)>
<Vector (1.0000, -1.0000, 1.0000)>
<Vector (-1.0000, -1.0000, 1.0000)>
<Vector (-1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, -1.0000, 1.0000)>
<Vector (-1.0000, 1.0000, 1.0000)>
<Vector (-1.0000, 1.0000, -1.0000)>
<Vector (-1.0000, 1.0000, -1.0000)>
<Vector (1.0000, 1.0000, -1.0000)>
<Vector (1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, -1.0000, -1.0000)>
<Vector (1.0000, 1.0000, -1.0000)>
<Vector (1.0000, 1.0000, 1.0000)>
<Vector (1.0000, -1.0000, 1.0000)>
<Vector (1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, 1.0000, -1.0000)>
<Vector (-1.0000, 1.0000, 1.0000)>
<Vector (1.0000, 1.0000, 1.0000)>
<Vector (1.0000, 1.0000, -1.0000)>
```

　座標は 8 種類しかないですが、頂点のデータとしては 24 個あることがわかります。UV 座標の時は 14 種類まで重複していました。

# 結論

　面が存在する以上、データ上の頂点（`bpy.types.MeshPolygon`）はそれを囲む頂点の数（多くの場合は 3 か 4）だけ存在します。それらの3次元空間上の位置はいわゆる「頂点」（`bpy.types.MeshVertex`）として存在しますが、複数の`MeshPolygon`から同一の`MeshVertex`が指定されることもあります。というか、ポリゴンは普通つながっているので、そちらの方が圧倒的に多いです。

「頂点」の考え方によりますが、デフォルトキューブの頂点は 8 個ではなく、24 個だが 8 種類である、といった方が適切なのかもしれません。（例えば、頂点カラーは面が繋がっていても、接する面によって違う色に塗ることもできます）

　また、UV マップ上の 2 次元空間上の位置は`MeshUVLoop`の中の`uv`という属性で管理されています。どの（3次元空間の）点がどの（UV マップ上の）点に対応するかは、MeshPolygon で示されたループの通りに記述されており、この対応関係が 3 次元空間のメッシュと 2 次元の UV マップをつなぐ、画像テクスチャの重要な部分となります。

# おまけ

　これらのことがわかると、3D ビューで頂点を選択するだけではなぜ UV マップに点が選択されないのかもわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/f2816fb8-2302-fd30-48ea-73f2ab1e4d60.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/cf987573-45bc-c22d-db63-29359ad9d04d.png)
（面を選択して、初めて UV マップ上で選択した部分が現れる）

　空間上の 1 つの頂点に対して複数の UV 点が対応している可能性があるので、特定できないためです。面で選択すればそのような曖昧性はなくなるので、UV マップに即座に対応する部分が現れます。