こんにちはトイロジックのプログラマーYです。業務では主にツール関連の整備を行っています。その中でメッシュをゲームに読み込むデータとして適切なものに変換することがあります。C++等のプログラムを用いて変換することも多いですが、メッシュを触るのはDCCツールを使用するのがやっぱり便利です。

本記事ではPythonを用いてのメッシュのポリゴン削減の例としてHoudiniとBlenderの2つのパターンを紹介しようと思います。以下のメッシュを使用してポリゴン数を半分にしていきます。

使用しているバージョンは下記の通りです。

  • Houdini 19.0.531
  • Blender 3.2.0

Houdiniの例

Houdiniはノードでネットワークを組んでデータを処理するプロシージャルなDCCツールです。Houdiniの実行ファイル(.exe)があるディレクトリにhython.exeという名前でPythonの実行ファイルがあるのでコマンドラインから使用する場合はこちらを使用します。

ノードネットワークをPythonスクリプトを用いて組んでいきます。この例では使いませんが複雑なネットワークを組む場合は事前にHDA(Houdini Digital Asset)という形式でノードをまとめておいてスクリプトからは1つのノードとして扱います。

ポリゴンを削減するにはPolyReduceというノードを使用します。以下サンプルコードです。

# houdini_script.py

import hou

# 入力ファイル、出力ファイルを設定 
input_file = 'toylo.obj'
output_file = 'houdini_reduction_toylo.obj'

# ノードを組むためのワークノードを追加 
work_node = hou.node('/obj').createNode('geo', 'WORK')

# 入力ファイルを読み込むノードを追加
input_file_node = work_node.createNode('file', 'input_file')
input_file_node.parm('file').set(input_file)

# ポリゴン削減のためのノードを追加
polyreduce_node = work_node.createNode('polyreduce::2.0', 'polyreduce')
polyreduce_node.parm('percentage').set(50.0)

# 入力ノードとポリゴン削減ノードを接続
polyreduce_node.setInput(0, input_file_node, 0)

# 出力のためのノードを追加
output_file_node = work_node.createNode('file', 'output_file')
output_file_node.parm('filemode').set('write')
output_file_node.parm('file').set(output_file)

# ポリゴン削減ノードと出力ノードを接続
output_file_node.setInput(0, polyreduce_node, 0)

# 出力ノードをクックしてポリゴン削減したファイルを出力
output_file_node.cook(force=True)

# デバッグのためのプロジェクト保存 
# work_node.layoutChildren()
# hou.hipFile.save('mesh_reduction.hip')

実行はhython.exe houdini_script.pyで行います。

元メッシュと生成されたメッシュを並べると以下のようになります。

最後の2行のコメントアウトを外すことでHoudiniのプロジェクトファイルを保存することが出来ます。スクリプトが正しく記述できているかの確認に便利です。また通常のPythonスクリプトと同じように使うことが出来るため入出力ファイルやノードのパラメータをコマンドライン引数から取得することでスクリプトを使いまわせるようになります。

Blenderの例

Blenderは無料で使えるオープンソースのDCCツールです。Pythonの実行ファイルもインストールディレクトリに含まれていますがblender.exeからpythonスクリプトを実行します。Blenderでのスクリプトは手動で操作した手順をスクリプトに置きなおすという側面が強いです。

ポリゴンを削減するにはDecimateというモディファイアを使用します。以下サンプルコードです。

# blender_script.py

import bpy

# 入力ファイル、出力ファイルを設定 
input_file = 'toylo.obj'
output_file = 'blender_reduction_toylo.obj'

# デフォルトで入っているオブジェクトを削除 
for obj in bpy.context.scene.objects:
    bpy.data.objects.remove(obj)

# 入力ファイルを読み込み 
bpy.ops.import_scene.obj(
    filepath=input_file 
)

# 読み込んだオブジェクトを選択 
obj = bpy.context.scene.objects[0]
bpy.context.view_layer.objects.active = obj

# Decimateモディファイアを設定 
bpy.ops.object.modifier_add(type='DECIMATE')
bpy.context.object.modifiers['Decimate'].ratio = 0.5

# ファイルを出力 
bpy.ops.export_scene.obj(
    filepath=output_file,
    use_materials=False
)

実行はblender.exe --background --python blender_script.pyで行います。
--backgroundを外すことでBlenderのGUIが立ち上がりスクリプト終了時点での状態を確認することが出来ます。

元メッシュと生成されたメッシュを並べると以下のようになります。

Houdiniと異なり引数からパラメータを渡すことが出来ないためスクリプトを使いまわせるようにするには、スクリプトから外部の設定ファイルを読みに行く、スクリプト自体を別のプログラムから生成する等の一工夫が必要になります。

最後に

本記事ではHoudiniBlenderの2つのDCCツールをPythonを用いてコマンドラインから動かす方法をご紹介しました。

  • Houdiniは複雑なネットワークを組んで様々な処理を実行するのに適しています。
  • Blenderは無料でライセンスを気にせずに実行することができ、また最近ではGeometryノードの登場で出来ることも増えてきています。

用途に合わせて適切なツールを選択することでより良いワークフローを構築できると思います。この記事がどなたかの参考になれば幸いです。ここまで読んでいただきありがとうございました!

著者紹介 Y
2011年にトイロジック新卒入社。いくつかのプロジェクトでUI制作を経験、現在はライブラリ班でツール業務を担当。

トイロジックでは現在、一緒に働くプログラマーを募集しています。

不明点などもお気軽にお問い合わせくださいフルリモート採用も行っております、ご応募お待ちしております!