kdenologue

たまに何か作ります。

Blenderのアドオン Fluent の処理を高速化した話

Blenderという有名なオープンソース 3Dモデリングツールがある.
最近バージョンが2.8に,なりやっと人間らしいUIを持つようになった.正直今までのは人間に難しすぎる.

ところで,Blender用のアドオンにFluentというのがある.
www.youtube.com

blendermarket.com

gumroad.com


なにかというと,ハードサーフェースモデリング(幾何学的でメカっぽいかっこいい物体をモデリングやつ)をしやすくするためのアドオンである.
基本的には画面中のオブジェクトに対してブール演算をしかけて穴を開けたりスライスしたりするというもの.
ブール演算をしかけるオブジェクトに対して配列やミラー,面取りなどの編集がサクッと出来る点と,クリック時にマウスの真下にある平面を編集平面として構築できる(=XYZ座標に対して斜めの面に対しても垂直に穴を開けたりできる)がいいところかしら.

ただ,まだ登場したばかりで機能もUIもちょっとこなれていない感じがある.(上の動画のチャンネル登録者数が2千いないところからして開発元の規模感もなんとなくわかりそうな気がする)
なんかかっこいいのつくれるのかなと,ちょっと気になったので買ってみたんです.1600円くらいだったし.
2/15に卒論発表もおわり,ちょっと使ってみるかと動かしてみたら,動作がやけに遅い状況があったので,パッチ出したという話.

ところで,使ってみた系の日本語の記事がヒットしないので,このアドオンの中に踏み込んだ日本語記事はこれが最初では.

改善した機能の概要

Fuent君,こんな感じで作業したい平面をクリックで指定できるんです.

f:id:kden:20190219010324p:plain
グリッド平面の例1
f:id:kden:20190219010439p:plain
グリッド平面の例2

このとき,構成する平面を含む矩形エリアをn分割するGrid Resolutionというのが指定できる.

f:id:kden:20190219010439p:plain
n=4
f:id:kden:20190219010552p:plain
n=7

このグリッドの点に編集中の図形をスナップさせて円や矩形を描画できるわけです.
f:id:kden:20190219010729p:plain

この点が増えれば増えるほど動作が遅くなるという問題があった.これを部分的に改善しました.

症例その1

先のデフォルトキューブ君をもう一度引き合いに出す.

f:id:kden:20190219010324p:plain
デフォルトキューブ君

画像では4分割されているが,これを10分割(=描画されるグリッド点の数が169個)になるとクソ重くなる.操作してから反映まで1secかかってるのではってくらい.
まず,たかが200個弱しか描画していないはずなのになんでこんなに遅いのだ?という興味が湧いたので,これを改善した.

問題点と解決

1. クリック時にマウス下にあるオブジェクトの△ポリゴンを取得,法線方向と頂点情報から作業平面を定義する
2. 対象の△ポリゴンをちょうど含むようにXYZ軸に沿った直方体の空間を作成する
3. 作成した直方体内部に,グリッド解像度に応じた数のグリッド点を仮配置する(グリッド点候補と呼ぶとする)
4. グリッド点候補から,作業平面上にあるグリッド点のみを取り出し,作業平面を構成するグリッド点とする

という手順で作業平面が構成される.

ここで,よくよく処理のログを吐かせてみると,やけに遅い状況ではなんと分割数の3乗に応じて描画する点の数が増えていたのである.
つまり,n=10のとき(外周も含めて)13^3=2197の点を描画していた.
そして,その症状は,上の画像の「グリッド平面の例1」では発生し,「"グリッド平面の例2」では発生しない.

原因は,上のプロセス 3 のところで,「対象の△ポリゴン」がXYZ軸どれかにほぼ直交する場合,つまり作成されたXYZ直方体が極薄の場合,
次のプロセス 3 で分割に利用される点がほぼ重なってしまう.
そして,プロセス 4 で全ての点が作業平面上に属すると判定されてしまい,結果描画する点数が減らなかった.

対処として,直方体が極薄(どれかの辺の長さがほぼ0)なら,その軸だけグリッドの分割数を1にしてあげる.

症例その2

さきの問題は解決したものの,依然として2000程度の四角形を描画するのに100ms以上かかっている状況はおかしい.根本的に描画にかかる処理が重いと予想.
もう一つ,作成されたグリッド点がマウスから近いとスナップする機能もあって,つまりマウスと各点との距離をマウスが移動するごとに計算している.これも,もしかしたら重くなるかも(3次元距離,回数2000で数百msはおかしいが)

問題と解決

これはシンプルで,GPUに四角形の描画処理を行わせるAPIを頂点毎に呼んでいたのが原因.なので,配列に描画する頂点位置を一旦保存して,実際に描画するAPIを叩くのは一回にまとめた.
これで2000頂点で150msほどかかっていた描画処理が10ms以下になった.やったね.

その他小さい話をつらつらと

  • なんとなく描画する頂点の情報をタプルで生成して += で連結させていったらクソ遅かった.素直に配列とappendでok
  • 頂点毎に立体座標を画面座標に変換するみたいな処理があって,要はMV変換みたいな行列演算なんだろうけど,そこも遅い 2000回回して20ms食われてる
  • 最近傍頂点探索の計算量が今はO(N)で,BlenderのKD-Treeってのを使うとO(logN)になっていいんだろうけど,それよりも↑の行列演算のほうがボトルネックなきがする
  • あと,素直にKD-Treeで実装すると立体空間内の点同士の距離を見る設計になるけど,これは画面上の点とはまたちょっと違う
  • ただ,ひとまずはグリッド座標を描画する部分はだいぶ良くなったんじゃないかなって.


先の問題点1はv1.0.2→v1.0.3 (2/18)への更新に反映してくれました.やったね.
f:id:kden:20190219180650p:plain

問題点2もv1.0.3→v1.0.4 (2/21) への更新に反映された.やったね.

ただ,これ以上の改善は↑のようにそもそも行列変換が遅そうという印象があって,あんまり突き詰める気にはならない.もともと卒論明けの土日の暇つぶし(暇ではないが)みたいなものだったし.


以上,動かしてから3,4日でだいぶ遊び倒したという話でした.楽しかった.
Discord見てる感じ,最近は日本語にも対応しようとしているらしいです.もっと動作が安定するといいな.


なんで買ったんだっけ? :thinking_face: