やること
- 球面上にランダムに頂点を作成します。
- Blenderで凸包を作ろうを使って、頂点から凸包を作ります。
- Blenderで隣り合う面に異なる色を割当(四色問題)を使って、凸包に色を割り当てます。
実行例
Pythonのコード
30個の頂点を球面上にランダムに作成し、凸包を作って色を割り当てます。
Scriptingワークスペースで新規作成してコピペして実行してください。
import bmesh
import bpy
import numpy as np
from mathutils import Vector
def rand_sphere(radius):
while True:
x = np.random.randn(3)
r = np.linalg.norm(x)
if r:
return x / r * radius
def add_vertex_on_sphere(n: int, radius: float = 1, name: str = ""):
"""球面上にランダムに頂点を作成し凸包にする
:param n: 頂点数
:param radius: 半径
:param name: 名前
"""
pts = [rand_sphere(radius) for _ in range(n)]
mesh = bpy.data.meshes.new(name=name or "Sphere")
mesh.from_pydata([Vector(pt) for pt in pts], [], [])
obj = bpy.data.objects.new(mesh.name, mesh)
bpy.context.scene.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.convex_hull()
bpy.ops.object.mode_set(mode="OBJECT")
return obj
def set_five_color(obj):
"""隣り合う面に異なる色を割当"""
colors = [
(1, 0.1, 0.1, 1),
(0.1, 0.2, 1, 1),
(0.8, 0.8, 0, 1),
(0, 0.8, 0.1, 1),
(0.8, 0.2, 0, 1),
]
bpy.context.view_layer.objects.active = obj
# 編集モード
bpy.ops.object.mode_set(mode="EDIT")
bm = bmesh.from_edit_mesh(obj.data)
# マテリアルのスロットを5つ用意
for _ in range(len(colors) - len(obj.material_slots)):
bpy.ops.object.material_slot_add()
# 5つのマテリアルを作成
for i, color in enumerate(colors):
material = f"M{i}"
mat = bpy.data.materials.get(material) or bpy.data.materials.new(name=material)
mat.use_nodes = True
mat.node_tree.nodes["Principled BSDF"].inputs["Base Color"].default_value = color
obj.active_material_index = i
obj.active_material = mat
# 面ごとに隣り合う面と異なるように、色を若番から割当
n = len(bm.faces)
res = [0] * n
dj = [[] for _ in range(n)] # 面ごとの禁止領域リスト
for edge in bm.edges:
if len(edge.link_faces) == 2:
i = edge.link_faces[0].index
j = edge.link_faces[1].index
dj[max(i, j)].append(min(i, j))
for i in range(n):
res[i] = ({1, 2, 3, 4, 5} - {res[j] for j in dj[i]}).pop()
# 色のマテリアルを面に設定
for face, i in zip(bm.faces, res):
if i:
obj.active_material_index = i - 1
bpy.ops.mesh.select_all(action="DESELECT")
face.select = True
bpy.ops.object.material_slot_assign()
bm.free()
# オブジェクトモード
bpy.ops.object.mode_set(mode="OBJECT")
if __name__ == "__main__":
obj = add_vertex_on_sphere(30)
set_five_color(obj)
以上