2枚板を膨らませたい時にはUV球を潰してclothで膨らませた方がICOを潰してやるよりも綺麗なシワができる。ただ、頂点部分に重さが集中するため、clothシミュレーションとしては嫌なモデル。ということで、頂点がおおむね均一に分布しつつも縦皺が綺麗に入るメッシュを切ってみた。


基本的なやりかた
縦皺が綺麗にはいるためには、赤道部分に真っ直ぐ経線が入ってるメッシュである必要がある。概ね円柱とか多角柱になる。それで均一にサクッと割れるものを考えると、立方体をsubdivideしたものが多分一番簡単。ということで立方体をsubdivideして、それを球にする事を考える。
blenderのToSphere(球状に変形)を使えば立方体を変換できるが、手作業もだるいので以下のスクリプトで生成する。
import bpy, math
def create_subdiv_ellipsoid(subdiv=(4, 3, 2), radius=(1, 1, 1)):
"""
subdiv: (subdiv_x, subdiv_y, subdiv_z)
radius: (radius_x, radius_y, radius_z)
分割数に応じたキューブの外側面を生成し、
各頂点を原点方向に正規化して各軸の半径をかけることで
楕円球状のメッシュを作成します。
"""
# 分割数と半径を各軸ごとに展開
sx, sy, sz = subdiv
rx, ry, rz = radius
verts = []
for i in range(sx + 1):
x = -0.5 + i / sx
for j in range(sy + 1):
y = -0.5 + j / sy
for k in range(sz + 1):
z = -0.5 + k / sz
# キューブ上の頂点から原点への距離
r = math.sqrt(x * x + y * y + z * z)
if r:
vx = rx * x / r
vy = ry * y / r
vz = rz * z / r
else:
vx, vy, vz = 0, 0, 0
verts.append((vx, vy, vz))
# 3次元グリッドのインデックスからリストのインデックスを返す補助関数
def idx(i, j, k):
return i * ((sy + 1) * (sz + 1)) + j * (sz + 1) + k
# キューブの各外面をリスト内包表記で生成
faces = []
faces += [(idx(0, j, k), idx(0, j + 1, k), idx(0, j + 1, k + 1), idx(0, j, k + 1))[::-1]
for j in range(sy) for k in range(sz)]
faces += [(idx(sx, j, k), idx(sx, j, k + 1), idx(sx, j + 1, k + 1), idx(sx, j + 1, k))[::-1]
for j in range(sy) for k in range(sz)]
faces += [(idx(i, 0, k), idx(i + 1, 0, k), idx(i + 1, 0, k + 1), idx(i, 0, k + 1))
for i in range(sx) for k in range(sz)]
faces += [(idx(i, sy, k), idx(i, sy, k + 1), idx(i + 1, sy, k + 1), idx(i + 1, sy, k))
for i in range(sx) for k in range(sz)]
faces += [(idx(i, j, 0), idx(i, j + 1, 0), idx(i + 1, j + 1, 0), idx(i + 1, j, 0))
for i in range(sx) for j in range(sy)]
faces += [(idx(i, j, sz), idx(i + 1, j, sz), idx(i + 1, j + 1, sz), idx(i, j + 1, sz))
for i in range(sx) for j in range(sy)]
# メッシュデータ作成とオブジェクトへのリンク
mesh = bpy.data.meshes.new("SubdivEllipsoid")
mesh.from_pydata(verts, [], faces)
mesh.update()
obj = bpy.data.objects.new("SubdivEllipsoid", mesh)
bpy.context.collection.objects.link(obj)
create_subdiv_ellipsoid((30,30,15), (5,5,0.1))
あとは以下の記事のように、clothシミュレーションかければいいが、四角メッシュの場合は注意点がある。
Shearの値をゼロにすると、メッシュ形状に引っ張られて、四角くなってしまう。したがって,shearに0.5ぐらいの小さな値を設定して、丸い形を維持出来る程度に制限を掛けてあげる必要がある。