LoginSignup
0
0

Blenderで球面上の頂点から凸包を作り色を割り当てよう

Last updated at Posted at 2022-01-10

やること

実行例

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)

参考:BlenderでPythonを実行する方法

以上

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0