夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Blenderで選択した頂点をある平面座標上に並び替える

本日はBlender枠です。

Blenderモデリングをしていると、次の画像のように頂点の位置にばらつきがあり面としてぼこぼこして見えることがあります。

こういった場合はSキー+Zキー+0を選択し、Z軸に対してスケールを0して歪みをなくしています。

 しかし次のようなモデルの場合は軸がワールド軸と異なるため先ほどのような手法が使えません。

このような場合は3つの頂点から平面を検出して、ほかの頂点を合わせることで実現できそうです。

〇3つの頂点から平面を検出する

まずは3つの頂点から平面を検知します。

Pythonコードは以下になります。

import bpy

# アクティブなオブジェクトを取得
obj = bpy.context.active_object

# オブジェクトがメッシュであることを確認
if obj.type == 'MESH':

  # 選択中の頂点を取得
  selected_verts = [v for v in obj.data.vertices if v.select]

  # 選択中の頂点の座標を取得して出力
  for vert in selected_verts:
      print("頂点座標:", vert.co)

こちらを実行するとConsoleに選択中の頂点の座標が出力されます。

ではこの3つの座標を使用して構成される面の方程式を求めます。

面の方程式を求めるには次の手段に従います。

①これらの頂点を通る2つのベクトルを計算します。

②これらのベクトルの外積を求めて、面の法線ベクトルを取得します。

③法線ベクトルと頂点のうちのどれかを使って、面の方程式を構築します

これをコードに落とし込むと次のようになります。

import bpy
import mathutils

def calculate_face_equation():
    # 現在のアクティブなオブジェクトを取得
    obj = bpy.context.active_object

    # 編集モードでなければ編集モードに切り替える
    bpy.ops.object.mode_set(mode='EDIT')

    # 選択中の頂点を取得
    selected_verts = [v for v in obj.data.vertices if v.select]

    # 選択された3つの頂点の座標を取得
    if len(selected_verts) == 3:
        v1 = selected_verts[0].co
        v2 = selected_verts[1].co
        v3 = selected_verts[2].co

    # 2つのベクトルを計算
    vec1 = v2 - v1
    vec2 = v3 - v1

    # 外積を計算して法線ベクトルを求める
    normal = vec1.cross(vec2).normalized()

    # 面の方程式を構築
    # 一般的な面の方程式は、Ax + By + Cz + D = 0 です。
    D = -normal.dot(v1)

    # 構築した面の方程式を出力
    print("面の方程式: {}x + {}y + {}z + {} = 0".format(normal.x, normal.y, normal.z, D))

    # 編集モードを終了してオブジェクトモードに戻る
    bpy.ops.object.mode_set(mode='OBJECT')

# 関数を呼び出して面の方程式を計算
calculate_face_equation()

これによって面の方程式を求めることができました。

〇面の方程式に合うように頂点座標を動かす

では、求めることができた面の方程式に合うように頂点の座標を動かします。

具体的にはZ軸座標を動かしていきます。(のちにX、Y座標も任意に設定できるようにするつもりです。)

これを行うコードは次のようになります。

import bpy
import mathutils

# 面の方程式の係数
a = 
b = 
c = 
d = 

# 選択されたオブジェクトとその頂点を取得
obj = bpy.context.active_object
vertices = [v.co for v in obj.data.vertices if v.select]

# 選択された頂点のZ座標を調整
for vertex in vertices:
    x = vertex.x
    y = vertex.y
    z = vertex.z
    
    # 面の方程式に代入してZ座標を計算
    new_z = (-d - a * x - b * y) / c
    
    # 新しいZ座標を設定
    vertex.z = new_z

# 頂点の座標を更新
for i, vertex in enumerate(vertices):
    obj.data.vertices[i].co = vertex

ここで面の方程式の係数とはAx + By + Cz + D = dに相当します。

先の方程式の例では0,0.468483....,-0.8876...,10.23102813....,0がそれぞれ相当します。

編集モードで頂点を選択しオブジェクトモードの状態で実行することで面の方程式に合わせて頂点が配置されるようになります。

本日は以上です。