見出し画像

Procedural Hard Surface Design With Copernicus

この記事はHoudini Advent Calendar 2024 22日目の記事です


はじめに

Procedural DesignAkira Saitoです。
Houdini等を使用しロボットなどのメカデザインを自動で行う研究をしています。
今回は、Houdini 20.5でBeta実装されたCopernicusを使用して、メカディティールの生成を行ないました。
UV展開されたモデルをCopernicusに読み込み、そのモデルの立体情報を画像に変換(ラスタライズ)し、その情報を元にメカニカルなテクスチャを生成する過程を説明します。

動作環境

Houdini Indy Version 20.5.410(apple silicon)
macOS Sonoma バージョン14.6.1
MacBook Pro (16-inch, 2021)
プロセッサ Apple M1 Max
メモリ 64 GB

サンプルデータ

以下のファイルを参照しながら読み進めてみてください。

ラスタライズ後のパディングについて

本題に入る前に、UV展開されたオブジェクトに対して、そのUVを元にしたテクスチャ生成の準備工程であるラスタライズ後の処理について、注意すべき場所と私なりの改善点を紹介します。

Copernicusのチュートリアル等で紹介される、UVを元にしたラスタライズは以下の一連の流れで行われます。

  • SOP Importでのジオメトリの読み込み

  • Rasterize SetupでのUV形状に変換し元の位置情報は頂点attributerに格納

  • Rasterize Geometryで頂点アトリビュートを画像に

  • Extrapolate BoundariesでUV境界の拡張

問題と感じるのは、Extrapolate BoundariesでUV境界の拡張する部分。パディングとも呼ばれる処理で、UVアイランドの境界を拡張する事でミップマップ等で境界外の色がUVアイランド内部に染み出す不具合を解消するものです。

Test Geometry:Pig Headを例に元の位置情報をラスタライズした例で解説します。

COPネットワークの構成とパラメータ
Rasterize Geometryからの出力
Extrapolate Boundariesからの出力生成された画像は一見問題無いように見えます。
生成された画像をモデルに適応して確認してみます。
Preview Materialにジオメトリと生成された画像をbaseColorに接続し確認してみると、
UV境界が不連続になっている事が確認できます。
Extrapolate Boundariesのパラメーターを調整することで、
UV境界の不連続を解消する事ができます。

しかし、Extrapolate Boundariesのパラメータ調整だけでは制度に問題がある部分が出てきたので、私はVEXでラスタライズの時点でパディングの処理も行う事にしました。

VEXによるラスタライズとパディング

ラスタライズ時にパディングを行うメリットとしては、。画像とマスク情報のみでパディングを行うExtrapolate Boundariesと比べ、ジオメトリ情報にアクセスが可能と言う事です。
コードは極めてシンプルです。

orgPに、ジオメトリのポイントアトリビュートorgPを出力し、
maskに、UVアイランドの内外を判断するマスク情報を出力しています。
int prim;
vector uv;
//@Pが示す座標から最も近い位置のprimとuvを求める。
float dist = xyzdist(1,@P,prim,uv);
//primとuvから、元の形状の位置を求める
v@origP = primuv(1,'origP',prim,uv);

//0距離の場所をマスク情報として出力
if(dist==0)
{
    f@mask = 1;
}else{
    f@mask = 0;
}

パディングの距離を設定したいのであれば、distの値を参照する事で可能ですが、殆どの場合UVアイランドの隙間を全てパディングで埋めてしまっても問題がないので、今回は距離を加味していません。

パラメーターの調整の必要もなく安定したパディングが出来ました。

ラスタライズとパディングが無事できたので、メカのデザインの話を進めましょう。

やっぱりWorley Noiseは外せない

Worley Noiseを使うことで、メカニカルな印象のノイズを生成することが可能です。
Worley Noiseの詳しい解説は過去のアドベントカレンダーに投稿してあります。未読の方はそちらを参考にしてみてください。
Procedural Hard Surface ModelingのためのWorley noiseの実装
CopernicusにもWorley NoiseとWorley Noise 3Dが最初から用意されていますが、標準のWorleyノイズは、GLSLなどのシェーダ言語でよく使われるアルゴリズムを採用しているため、デザインの肝となる母点の詳細な制御が出来ません。

GLSLでのセルラーノイズに関しては
The Book of Shadersの解説が分かりやすいのでお勧めです。

そこで、過去にSOPでもWorley Noiseを自作したように、今回もCopernicusでWorley Noiseを自作していきます。

点群はどうするのか

この件に着手した頃は、Copernicusの学習が大きな目的でしたので、点群の生成もCopernicusだけでできないか検討しました。しかし、CopernicusのWrangleにはDetailランオーバーがなく、Pythonもないため、点群を生成し保持する処理が思いつきませんでした。早々にCopernicusだけで点群を生成するのは諦めましたが、点群そのものをCopernicusの外部から取り込むと利便性が失われるため、それだけは避けたかったので、Copernicus内の1ノードだけで点群の生成を行えるようにSOPを内包した仕組みを実装しました。

Copernicusのノードに入力されたgeometryを元に、点群を生成し、geometryとして出力する。

その機能を満たすサブネットの一層はこのようなものになります。
一層目にあるsop importの内部はこのようなものです。
先頭のCOP Networkで一層目の、
emitterという名のnullノードに接続されたジオメトリをSOP内に読み込みます。
その後、Scatter SOPで点群を生成し、
attribute wrangleで書くポイントにidアトリビュートを付加しています。

この構造は、標準のCopernicus HDAでも使われている構造で、Rasterize Setupも同様の構造です。Copernicus内でジオメトリに対して何かを行いたい場合はこの構造にすると良いでしょう。

ネットワーク全体

ネットワークの中央にWorley Noiseを生成するWrangleがあり、その右側に前処理、その左側に後処理が配置されています。
前処理としては、これまでに説明したラスタライズとパディングの部分と点群の生成があります。さらに、パディングの後に左右対称のデザインを生成するためにラスタライズされた位置情報を左右反転するWrangleが配置されています。

非常にシンプルなVEXです。この部分にノイズなどを入れれば複雑な形状を生成する事が可能です。

Worley Noise本体

Worley Noiseの実装wrangleで行います。
入力は3つ

  • ラスタライズされた位置情報(RGB)

  • メッシュ(ジオメトリの大きさを参照するため)(geometry)

  • 点群(geometry)

出力は2つ

  • 距離情報(float)

  • 母点情報(ID)

パラメーター

  • ノイズの種類(int)
    0:ユークリッド距離 F1
    1:ユークリッド距離 F2-F1
    2:マンハッタン距離
    3:チェビシェフ距離

コードが見切れていますが、worley noiseを生成するwrangleです。
int mode = chi('mode');

//母点の数
int seedNum = npoints(2);
//入力メッシュのサイズを求める
vector objSize = getbbox_size(1);
//マンハッタン距離での最長を仮設定
float maxDist = objSize.x + objSize.y + objSize.z;

float f1 = maxDist;
float f2 = maxDist;
//シード値
int id;
//ユークリッド距離 f1 f2
if(mode == 0|| mode == 1){
    int pt[] = nearpoints(2,v@pos,maxDist);
    vector p1 = point(2,'P',pt[0]);
    f1 = distance2(v@pos,p1);
    vector p2 = point(2,'P',pt[1]);
    f2 = distance2(v@pos,p2);
    
    id = point(2,'id',pt[0]);
    
}else if(mode == 2|| mode == 3){
    //全ての点群を巡回
    for(int i=0;i<seedNum;i++)
    {
        int tmpId = point(2,'id',i);  
        vector p1 = point(2,'P',i);
        vector v0 = p1 - v@pos;
        
        float tmpF1;
        
        if(mode ==2){
            //マンハッタン距離
            tmpF1 = abs(v0.x) + abs(v0.y) + abs(v0.z);
        }else{
            //チェビシェフ距離
            tmpF1 = max(abs(v0.x),abs(v0.y),abs(v0.z));    
        }
        if(tmpF1 < f1){
            f1 = tmpF1;
            id = tmpId;
        }
    }
}


i@id = id;


if(mode == 0){
    f@dist = f1;
}else if(mode == 1){
    f@dist = f2-f1;
}else{
    f@dist = f1;
}

VEXコードです。アルゴリズムや数式の解説は
Procedural Hard Surface ModelingのためのWorley noiseの実装 を参考にしてください。

後処理

Worley Noiseによって生成された距離情報は、各母点からの距離が設定されているので、そのままでは使いづらいことが多いです。最小距離を0、最大距離を1に変換する正規化を行います。

Statisticsで求められた最小値、最大値を元に距離を正規化

Statistics 求められた最小値と最大値を用いてWrangleで正規化を行います。
シンプルなVEXで正規化を行うことが可能です。

サブネットにまとめる

利便性を上げるためにサブネット化します。
入力は1つ

  • UVが設定されたメッシュ(geometry)

出力は2つ

  • 距離情報(float)

  • 母点情報(ID)

パラメーターは

  • mode(worley noiseのパターンを設定) 
    worley ノイズを生成するwrangleから参照します
    0:Euclidean(F1)
    1:Euclidean(F2-F1)
    2:Manhattan
    3:Chebyshev

点群を配置するScatter SOPから以下をパブリッシュ

  • Force Total Count

  • Global Seed

  • Relax Iterations

メカディティールの生成

ネットワーク全体

完成したWorley noiseのサブネットを使用した
メカディティール生成のCopernicusネットワーク全体。

距離情報を高さ情報に変換

Worley Noiseを生成し、その距離情報をremapを使用し高さ情報に変換します。

ノーマルマップの生成

Height To Normalを使用し、高さ情報をノーマルマップに変換します。

ベースカラーの生成

ID to MaskのKeep By Chanceを使用し、色の塗り分けマスクを生成。
Height To Ambient Occlusionを使用しAOを生成。
(UV境界に不連続が出てしまうが今回は目を瞑る)

各要素をBlendを使用し合成。

モデルにテクスチャを設定し確認

Preview Materialを使用して、生成されたテクスチャの確認

Worley Noiseの種類

ユークリッド距離(F1)

ユークリッド距離(F2-F1)

マンハッタン距離

チェビシェフ距離

作例紹介

元々メカニカルな印象のTest Geometry:Electraを生成テクスチャだけでディティールアップ
注意:Test Geometry:Electraの初期のUVは裏返っていたり密度が不均一なので、UV Unwrap等でUVを作り直しましょう。

入力ジオメトリ Test Geometry:Electra
ベースカラーとノーマルマップのみで印象が変わる。
複数のWorley NoiseやStamp Pointによるディティール配置を加えて
Worley Noiseに入力する座標情報にノイズを加え有機的な印象に
位置情報をシンメトリにするWrangleでノイズを加えています。

まとめ

現時点でのCopernicusは、

  • まだBetaなので、今後仕様が変わる可能性があるので注意。

  • Pythonノードが無い。

  • Wrangleのランオーバーはピクセル単位のみ。

  • パディングには注意が必要。

  • PBRに必要な複数のテクスチャをまとめて操作するのが難しい。

  • SOP Importとcopnet SOPを使う事で、
    Copernicus内のGeometryを編集する事ができる。

  • Mac Apple Silliconは、Vulkanが未対応なのでView Portがしょぼい…

気になる点を挙げてみましたが、2Dと3Dを行き来できるワークフローが非常に優れており、様々な表現が可能になりました。この部分が肝であり、どこまでを3Dで、どこから2Dで行うかを判断するセンスが求められる部分でもあると考えられます。今回は触れませんでしたが、OpenCLを使うことで、高速化や複雑な処理も可能になると思うので、今後色々と試していきたいと思います。

それでは、皆様、良いクリスマスを。


いいなと思ったら応援しよう!