Blender 스크립트로 분형 입체 모형 생성

Blender의 모델링 작업에도 어느 정도 습관이 있습니다. 보통 모델링뿐만 아니라 스크립트도 활용하고 싶어서 파이톤으로 분형 도형의 생성에 도전하고 싶습니다.
본 기사의 코드는 Blender 2.79a에서 버전 확인 작업을 수행했습니다.
스크립트로 이동하는 Blender
예를 들어 Blender의 텍스트 편집기에 다음 Python 코드를 붙이고 '실행 스크립트' 를 누르면 삼각형의 평면으로 구성된 대상을 생성합니다.
import bpy
import mathutils
# 初期化

verts = [mathutils.Vector([0,0,0]),
         mathutils.Vector([1,0,0]),
         mathutils.Vector([0,1,0])] #頂点のリスト
fIndexes = [[0,1,2]] #面のリスト
mesh = bpy.data.meshes.new('さんかく')
mesh.from_pydata(verts,[],fIndexes) #点と面の情報からメッシュを生成

obj = bpy.data.objects.new('さんかく', mesh) #メッシュ情報を新規オブジェクトに渡す
bpy.context.scene.objects.link(obj) #オブジェクトをシーン上にリンク

obj.select = True #作ったオブジェクトを選択状態に
정점 목록 verts에는 Blender 3D 뷰의 좌표 목록이 포함되어 있습니다.Vector 객체를 사용하여 좌표를 삽입합니다.
면 목록 fIndexes에는 면을 구성하는 정점 색인 목록(또는 원조)으로 구성된 목록이 나열됩니다.샘플에서verts의 0, 1, 2개의 삼각형을 만들고 싶어서 0, 1, 2로 구성된 목록은 1개로 구성된 목록을 정의했다.
이 정점 목록verts, 면 목록 fIndexes.from_pydata()에 망상물 제작 대상을 생성하는 느낌을 줍니다.
실행할 때의 인상은 바로 이렇다.

따라서 파이썬 스크립트에서 분형 그래픽을 만들 때 한 면을 이렇게 정의할 때마다 정점 목록에 좌표를 추가하여 이 점 집합에 대응하는 색인 목록을 면 목록에 추가하는 느낌으로 만든다.
이른바 분형
예컨대 그 근처에서 자라는 나무, 야채의 로망네스코처럼 그 녀석의 일부만 바라보면 그 녀석 자체의 구조가 그대로 드러나고 그 중 일부를 보면 같은 구조가 나오는데... 이런 느낌이 반복되는 걸 분형물이라고 한다.
이번에 한 것은 예에서 말한 것처럼 그렇게 복잡도가 높지 않지만 문자로만 표현하기는 어려우므로 도형을 결합시켜 제작 방법을 설명할 것이다.
삼각형으로 이루어진 분형
이번에는 정삼각형의 정점을 형성하는 데 다음과 같은 규칙을 반복해 분형을 만든다.
<생성 규칙>
정삼각형의 정점 P0, P1, P2의 경우
P3, P4, P5를 각각 P0-P1 사이, P1-P2 사이, P2-P0 사이의 중점
P6, P7, P8을 각각 P3-P4 사이, P4-P5 사이, P5-P3 사이의 중점,
P9을 P6, P7, P8과의 위치 관계로 정의하여 정사면체의 정점을 형성한다.
그림에서 보듯이 바로 이런 느낌이다.

위에 있는 그림도

한 번만 적용되는 이 규칙의 스티커는 분형할 수 없지만 이 P0에서 P9의 좌표 중에는 정삼각형을 형성하는 점도 있다.위에서 보듯이 그림의 파란색 글자에서 보듯이 원래 삼각형의 반축척 정삼각형은 3개, 6개의 축척이 더 생겼다.
이 9개의 삼각형에 대해 우리는 위에서 보여준'생성 규칙'을 차례로 정의할 것이다.
『생성 규칙』이 2단계에 적용되면 이렇게 됩니다.

9개의 삼각형 하나하나에 대해 각각 9개의 새로운 삼각형을 정의했기 때문에×9=81개의 삼각형으로 한 면을 만들었다.
이 생성 규칙을 반복하면 작은 가시가 촘촘하게 자란 분형을 만들 수 있다.
코드로 이걸 구현하면 이렇게 될 것 같은 느낌.
import bpy
import math
import mathutils
# 初期化

def normal(face): #法線ベクトル
    v1 = face[1] - face[0]
    v2 = face[2] - face[0]
    normal = v1.cross(v2)
    normal.normalize()#正規化
    return normal

def tetraFractal(level, face): #level: フラクタルの複雑度 face: フラクタル生成のターゲットとなる面
    if level <= 0:# 頂点と面の情報をリストに追加
        global idxV
        global verts
        global fIndexes

        verts.append(face[0])
        verts.append(face[1])
        verts.append(face[2])
        fIndexes.append((idxV,idxV+1,idxV+2))
        idxV += 3
    else: # 一つ下のレベルに分解
        pts = face[:] #p0~p2
        pts.append((pts[0] + pts[1])/2) #p3
        pts.append((pts[1] + pts[2])/2) #p4
        pts.append((pts[2] + pts[0])/2) #p5
        pts.append((pts[3] + pts[4])/2) #p6
        pts.append((pts[4] + pts[5])/2) #p7
        pts.append((pts[5] + pts[3])/2) #p8
        nrm = 0.5*math.sqrt(1/6.0)*(pts[0]-pts[1]).length * normal(face)
        pts.append((pts[0] + pts[1] + pts[2])/3 + nrm) #p9

        level -= 1 # 
        tetraFractal(level,[pts[0],pts[3],pts[5]])
        tetraFractal(level,[pts[1],pts[4],pts[3]])
        tetraFractal(level,[pts[2],pts[5],pts[4]])
        tetraFractal(level,[pts[3],pts[6],pts[8]])
        tetraFractal(level,[pts[4],pts[7],pts[6]])
        tetraFractal(level,[pts[5],pts[8],pts[7]])
        tetraFractal(level,[pts[6],pts[9],pts[8]])
        tetraFractal(level,[pts[6],pts[7],pts[9]])
        tetraFractal(level,[pts[7],pts[8],pts[9]])
#
# グローバル変数定義
#
verts = [] #頂点のリスト
idxV = 0 # 頂点のインデックス番号
fIndexes = [] #面のリスト
mesh = bpy.data.meshes.new('tetraFractal') #メッシュ情報

# フラクタルを作成する起点となる三角形の頂点座標
tetraV  = [mathutils.Vector([math.cos(0) , math.sin(0) , 0.0]),
     mathutils.Vector([math.cos(2*math.pi/3) , math.sin(2*math.pi/3), 0.0]),
     mathutils.Vector([math.cos(4*math.pi/3) , math.sin(4*math.pi/3), 0.0])
     ]
#
# メインルーチン
#
tetraFractal(4,tetraV)
mesh.from_pydata(verts,[],fIndexes) # 追加した点と面情報からメッシュを定義

obj = bpy.data.objects.new('tetraFractal', mesh) #メッシュ情報からオブジェクトを生成
bpy.context.scene.objects.link(obj)

obj.select = True
실행 결과:

이 코드를 간으로 하는 함수인tetraFractial()을 호출하여 정점 목록과 면 목록에 분형 도형을 구성하는 정점과 면의 정보를 계속 추가합니다.첫 번째 매개 변수 level에서 위에서 보여준 생성 규칙의 횟수를 입력하고face에는 삼각형 좌표를 나타내는 Vector 대상으로 구성된 목록을 추가합니다.
tetraFractial()의else문의 블록 안의ptt[0]~pts[9]에서 상기 설명에서 말한 P0~P9에 해당하는 좌표를 계산하여 넣는다.그리고 이 pts에서 위에서 설명한 9개의 삼각형의 좌표 조합을 골라서 그 삼각형에 대해tetraFractial 자신을 각각 호출한다.호출하기 전에 level을 낮추었기 때문에 최종 level은 0이 되고, 호출은 정점과 면의 정보를 목록에 추가하는 처리가 끝납니다.
위 코드의 "#분형의 시작점으로 삼은 삼각형 정점 좌표"섹션에서 삼각형의 좌표 테트라V를 정의하고 테트라Fractial을 호출하여 이 섹션을 다음과 같이 덮어쓰고 사면체를 구성하는 4개의 삼각형을 실행합니다.
# フラクタルを作成する起点となる四面体の頂点座標
tetraV  = [mathutils.Vector([math.cos(0) , math.sin(0) , 0.0]),
     mathutils.Vector([math.cos(2*math.pi/3) , math.sin(2*math.pi/3), 0.0]),
     mathutils.Vector([math.cos(4*math.pi/3) , math.sin(4*math.pi/3), 0.0]),
     mathutils.Vector([0, 0, -1*math.sqrt(2)])
     ]

# tetraVからなる四面体の面情報
tetraF = [[tetraV[0],tetraV[1],tetraV[2]],
        [tetraV[1],tetraV[0],tetraV[3]],
        [tetraV[2],tetraV[1],tetraV[3]],
        [tetraV[0],tetraV[2],tetraV[3]]]

#
# メインルーチン
#
for i in range(4):# 四面体をなす4つの三角形に対して実行
    tetraFractal(4,tetraF[i])
실행 결과:

손을 잡으면 굉장히 아픈 물체가 나오네요.
이 함수는 level의 값에 따라 계산량이 폭발적으로 증가하므로 주의해야 한다.현재 level은 4로 설정되어 있지만 7 정도면 자신의 환경에서 실행하는 데 2~3분 정도 걸리며 면을 만드는 수량도 보통이 아니다.규격과 메모리 용량을 상의한 후 level의 값을 설정하십시오.
보충 설명
예시 코드의 함수인tetraFractial()의 매개 변수face에서 Vector 대상은 이러한 느낌으로 가감법과 정수배를 계산할 수 있다.

만약 두 좌표 사이의 차이를 계산하고length 방법을 호출한다면 거리도 계산할 수 있다.

또한'생성 규칙'에서 P9의 좌표를 계산하기 위해서는 p0~p2로 구성된 삼각형 평면과 수직의 법선 벡터를 계산해야 하기 때문에 외적을 사용하여 정의한다.다음 섹션.
def normal(face): #法線ベクトル
    v1 = face[1] - face[0]
    v2 = face[2] - face[0]
    normal = v1.cross(v2)
    normal.normalize()#正規化
    return normal
네 번째 줄의 v1.cross(v2)는 외적 v1×v2를 계산하는 중입니다.
다섯 번째 줄의normalize 귀일화, 즉 길이가 1과 일치하는 것이다.
그림에서 보듯이 바로 이런 느낌이다.

이렇게 하면 법선의 벡터를 구할 수 있고 적당한 길이로 몇 배를 정한 다음에 삼각형 중앙의 좌표를 더하면 P9을 구할 수 있다.이 부분이죠?
nrm = 0.5*math.sqrt(1/6.0)*(pts[0]-pts[1]).length * normal(face)
pts.append((pts[0] + pts[1] + pts[2])/3 + nrm) #p9
참고 자료
공식 참조
Math Types & Utilities (mathutils)
https://docs.blender.org/api/current/mathutils.html
분형
잡다한 과학 노트-분형의 이야기-
https://hr-inoue.net/zscience/topics/fractal/fractal.html
해설--분형ImaginaryCube--
https://www.i.h.kyoto-u.ac.jp/users/tsuiki/cfractal/kaisetu.html

좋은 웹페이지 즐겨찾기