[PDG] Gathering USD Files

皆さんはアウトソーシング先や他のベンダー会社にデータを共有する際、どのような手法を取っていますか? Houdiniならキャッシュやテクスチャをシーンファイルがある同じ階層に置いて、それぞれのファイルパスを$HIP始まりにする。もしくはLocal Variables $JOBを用いてファイルの保存場所を指定し、異なる環境で開いた際には作業者が変数の値を更新するのが一般的です。 Nukeにおいては、Nukepediaや社内で開発したGathering toolを利用して、シーン内のRead/Writeノードが参照するファイルパスのデータを他の場所にコピーし、それらのノードのファイルパスを相対パスに変更することが多いです。 では、USDを使う場合はどのように対応すればよいでしょうか?今回はPDGを使った話をしていきます。 Sample File(20.5.410 py3.11): https://drive.google.com/file/d/1pkv1pYyNRrdOpoF50qxvsBc3HxAFyi5r/view?usp=drive_link USDアセット作成 まずSolarisで簡単なデータを作るとこから始めます。 もうUSDは日本以外のとこではスタンダードになったと言っても過言ではないフォーマットです。ですので、簡単な説明は省きます。 アセットを作ったことがない人は、このチュートリアルを見てください。 https://www.sidefx.com/tutorials/usd-asset-building-with-solaris/ Component まずCompoent Builderを使って、2つのComponent、GridとVariantをもったRocksをつくります。 Component Outputの出力先を、今後の説明を分かりやすくするために以下のように変更しておきます。 それぞれ、Save to Diskを押して、USDを作成します。 $HIP/usd/components/`chs("name")`/v001/`chs("filename")` 保存先を見てみると、このようなフォルダ構造になっているかと思います。 └── usd/ └── components/ └── grid/ └── v001/ └── grid.usd └── geo.usdc └── mtl.usdc └── payload.usdc └── textures/ └── bricks001_basecolor.png └── rocks/ └── v001/ └── rocks.usd └── geo.usdc └── mtl.usdc └── payload.usdc Gridはテクスチャは持っており、そのテクスチャは$HIP/texturesに保存してありましたが、usdが保存されているtexturesフォルダにコピーされています。 そして、GridというComponentのUsdを読み込んでみると、テクスチャパスは@./textures/bricks001_basecolor.png@になっています。絶対パスではなくでなく、相対パスになっています。 Referenceで読み込んでるgrid.usdの中身にも相対パスが使われています #usda 1.0 ( defaultPrim = "grid" framesPerSecond = 24 metersPerUnit = 1 timeCodesPerSecond = 24 upAxis = "Y" ) def Xform "grid" ( prepend apiSchemas = ["GeomModelAPI"] assetInfo = { asset identifier = @....

<span title='2024-12-12 00:00:00 +0000 UTC'>12月 12, 2024</span>&nbsp;·&nbsp;3 分&nbsp;·&nbsp;Shohei Okazaki

[Linux] 101

Windows vs Linux Googleで「Houdini Windows vs Linux」と調べればいろいろな検証結果がでてきます。 例えば杉村さんのBlogには、シミュレーションの比較があります。 Linux vs Windows10パフォーマンス対決その1|スギムラ マサヤ(sugiggy) またこちらの動画はMantraとKarmaのレンダリング比較してくれてます。 10%ー30%はLinuxのほうが速いですね。 にしてもKarmaの速度に大きな差があるのは驚きですね! Linuxディストリビューション Linuxディストリビューションとは、ハードウェアとソフトウェアの間の通信を管理し、システムリソースを効率的に配分してくれるLinuxカーネルに加えて、ソフトウェアやユーティリティ、ユーザーインターフェースなどが組み込まれている、Linuxベースのオペレーティングシステムのバリエーションやバージョンのこと。 ユーザーフレンドリーなUbuntuやLinux Mint、企業向けのRed Hat Enterprise Linux、高度なユーザー向けのArch Linuxなど、多種多様なバリエーションがあります。 VFX/CG業界ではCentOSが主流 でした。しかし CentOSが2024年6月30日にサポート終了 になる、つまりアップデートやセキュリティパッチの更新がなくなることが発表されました。 ですのでCentOSを使ってた会社は Rockyに移行 してくとこもあるみたいです。 ディストリビューション 特徴 Ubuntu ユーザーフレンドリーで初心者におすすめ。広範なソフトウェアサポート。 Debian 安定性とセキュリティに重点を置いている。多くのディストリビューションのベース。 Fedora 最新のテクノロジーを早期に採用。Red Hatによって支援されている。 CentOS Red Hat Enterprise Linuxをベースにした企業向けの無料ディストリビューション。 Arch Linux シンプルさとユーザーによる細かなカスタマイズを重視。 Linux Mint Ubuntuをベースに、使いやすさと美しいデスクトップ環境を提供。 Rocky Linux CentOSの代替として開発された、企業向けの安定したディストリビューション。 AlmaLinux CentOSの終了に伴い、そのコミュニティによって作成された無料のエンタープライズ級Linuxディストリビューション。 どのディストリビューションを選ぶかは、まず各ソフトのシステム要件をみてみましょう。 Houdini: https://www.sidefx.com/ja/Support/system-requirements Nuke: https://www.foundry.com/products/nuke-family/requirements Unreal Engine: https://docs.unrealengine.com/5.3/en-US/hardware-and-software-specifications-for-unreal-engine/ Blender: https://blender.org/download/requirements/ Maya: https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/System-Requirements-for-Autodesk-Maya-2024.html やはりRockyを推していってますね。 Mintをインストール! Mintな理由 上記でVFX業界の主流はCentOSからRockyへ、ソフトウェアの対応もRockyに移行してるみたいなのに、なんでMintなのと思われるでしょう。 CentOSやRockyはRedHat系といわれますが、これらは初心者には難しいです。私自身も自宅でCentやFedoraを使ったことがありますが、かなり苦労しました。...

<span title='2024-02-28 00:00:00 +0000 UTC'>2月 28, 2024</span>&nbsp;·&nbsp;4 分&nbsp;·&nbsp;Shohei Okazaki

[Solaris] HDAカメラのインポート

問題 SolarisにSceneImportLOPでカメラをインポートする際、自前のHDAカメラをインポートしようとするとワーニングがでてインポートできません。 (自前のカメラとはこういうHDAです) 以下のようなワーニングが表示されます。これはおそらく19.5以降でしか表示されないかもしれません。 解決策 まずは言われた通り、リンクに飛びましょう。 以下のような記述が冒頭にありますね。カスタムノードをLOPに読み込むにはなにか作業が必要なようですね。 Scene Import LOPが特定のHoudiniオブジェクトノードタイプをUSDに変換する方法をカスタマイズすることができます。 これは、特にカスタムノードタイプ(例えば、プロプライエタリなレンダラー関係のライトタイプやカメラタイプ)の変換に役立ちます。 その後を読み続けると色々Pythonやら書いてありますね。でもちょっと長いので無視します。 Houdiniはカスタムできるものについては、インストールフォルダにだいたいのものがバイナリになっていない状態で保存されてるので、それをコピーしてから始めるのが最短の道です。ということで以下のファイルを見てみましょう。 インストールフォルダ/houdini/husdplugins/objtranslators/cam.py import hou import husd from pxr import UsdGeom class CameraTranslator(husd.objtranslator.Translator): def shouldTranslateNode(self): return True def primType(self): return 'Camera' def populatePrim(self, prim, referenced_node_prim_paths, force_active): super(CameraTranslator, self).populatePrim(prim, referenced_node_prim_paths, force_active) cam = UsdGeom.Camera(prim) proj = self._node.parm('projection').evalAsString() if proj == 'perspective': cam.CreateProjectionAttr('perspective') elif proj == 'ortho': cam.CreateProjectionAttr('orthographic') # A few of the parameters need to be converted into 1/10 scene unit space stage = prim....

<span title='2023-10-05 09:27:07 +0900 +0900'>10月 5, 2023</span>&nbsp;·&nbsp;2 分&nbsp;·&nbsp;Shohei Okazaki

Houdini Workflowについて

いままで何回もHoudini Workflowをつくってきたので、どんなことをやっているか紹介したいと思います。 小規模な会社にいるからとか個人でやってるから、そんなの必要ないと考える人もいるかもしれませんが、そうは思いません。数人の会社で働いたことがありますが、確実にワークフローが少しでもないと良いパフォーマンスを出すことをできません。 大規模な会社には専任のTDがいてパイプラインがしっかりあり、色々便利なこともあります。反面、大きくなりすぎた会社ほど、やる気のない人や老害がたまり自由度がなくなり最新の流れにもついていけなくなったり、ワークフローを作るのに大工事したり、パイプラインにも手をいれなければいけないみたいなことも起こってしまいます。小規模だとパイプラインを作るのは難しいですが、ワークフローは自分たちの好きに作りやすいです。自分たちにあったものを構築できれば、小回りがきいて大きな所に負けないワークフローを構築しアドバンテージにすることも出来ます。 ワークフローは、TDの人やスクリプトをかける人が作るものだと考えるでしょうが、実際に作業するアーティスト主導で構築するべきです。なぜならそのワークフローを使うのは作業者であり、なにが必要なのかを知ってるのは作業者であるアーティストだからです。 パイプライン? ワークフロー? そもそもパイプラインとワークフローの違いはなんなんでしょうか? パイプラインは、別部署へのデータを送る時、たとえばアセットデータやアニメーションデータやレンダーイメージのパブリッシュなど です。決められた場所かつ安全な場所にパブリッシュしたり、決まったフォーマットに変換したりします。また、ファイルの命名規則やチェック方法やShotgunとの連携もこちらの役割です。 ワークフローは、アーティストがショット作業をする時に必要なルール・ツール を用意しておくことです。 パイプラインはTDが担当しますが、ワークフローは出来る限りそのツールや流れを熟知した人が作るのに携わるのが良いと思います。そしてFXはPythonは書けて当たり前なので、TDにお前らどうせ自分たちで出来るからとか言われ、他の部署を先にやってからと後回しにされがちです。 目的 まずは何のためにワークフローを作るかの目的をしかっり決めましょう。 私はいつもアーティストが絵作りだけに集中できる環境を作ることを目的にし、できるかぎりのことをするようにしています。 何を基準にツールやルールを作るかというと、基本この2つをベースに考えます。 ヒューマンエラーをなくす 毎回同じことをしたくない 代表格は、キャッシュやレンダーの出力先を毎回入力することです。これはもはや人間のやることではありません。 チームで新しくワークフローを作る場合は、みんなの意見を聞いて不便なことや要望を洗い出してあげることも大事です。 チームにジュニアレベルの人やHoudiniに詳しくない人がいるとしたら、色んなレベルの人にもスムーズにいくルールを考える必要があるかもしれません。 環境変数 まずプロジェクト固有の変数について考えましょう。変数は、 プロジェクト全体に適用されるグローバル変数と、シーケンスやショットごとに値が変わるローカル変数にわけられます。 プロジェクト名やシーケンス名を定義しとくとフォルダの移動やアウトプット先を決めるのが楽になります。ただこの変数はパイプラインとして設定されてることが多いです。小規模な会社や個人では自身で設定してもいいと思います。これらを設定することによってどういうことが出来るかはあとで説明します。 PROJ = 'BurningProj' 他のソフトからAlembic等でデータを持ってきた時、シーンスケールを正しくしてあげる必要があります。なぜなら、Houdiniのシミュレーション系ノードのデフォルト値は、1Grid=1mを前提として値が設定されています。これにあわせてやるのが一番良いです。 大抵の場合はインポートしたものを0.1倍か0.01倍すればいいでしょうが、海外のクライアントからもらったデータはメートルでなくインチで作業してる場合があります。その場合は39.37で割る必要があります。覚えたくないですよね。なので、コレも変数にしておきましょう。 SCALE_FACTOR = 10 他には、レンダーサイズも変数にしてもいいかもしれません。 RENDER_RES_X=1920 RENDER_RES_Y=960 また、WinodwsやLinuxのプラットフォームが混在してる場合、マウントするところを変数にしたとき、少し便利になります。どいうことかというとWindowsはZ:/proj/BuringProjがLinuxでは/proj/BuringProjの場合、$PROJ_ROOT/BuringProjという書き方に統一できます。協力会社によってはクライアントと同じドライブレターが使えないときは、協力会社に$PROJ_ROOTをX:/good_client/A_Inc/projみたいに設定してもらえれば、フォルダ構造を維持したままシーンファイルを渡せば、別の環境でもシーンを容易に再現できる可能性が高まります。 PROJ_ROOT = 'Z:/proj' 日本でもNetflixの仕事が増えてきたせいか、やっとColorMangementが浸透してきましたね。Houdiniも他のソフト同様、OCIOの環境変数を設定してあげる必要があります。ACTIVE_VIEWSはなくてもいいです。VFXではシーケンスやショットごとでLutが違う場合があるので、OCIO_ACTIVE_VIEWSを変動出来るようにしてもいいかと思います。 OCIO='/proj/BurninigProj/tools/OCIO/will_be_beautiful.ocio' OCIO_ACTIVE_VIEWS='Rec.709' ローカル変数の代表は、シーケンスとショット番号、フレームレンジとかでしょうか。 SEQ = 'seq_01' SHOT = 'shot_003' P_START = 1001 P_END = 1032 さて、これらをどうやって全員に行き渡せるかですが、大きい会社ならランチャーがあると思うので、そこで設定してもいいです。 小さい会社や個人の場合は、パッケージを使うといいでしょう。 https://www.sidefx.com/ja/docs/houdini/ref/plugins.html たとえば/proj/BurningProj/tools/houdiniというフォルダの中にプロジェクトのHDAやスクリプトを置き変数を定義するとします。 /proj/BurningProj └── tools └── houdini └── otls └── packages └── scripts └── toolbar └── maya └── nuke まずメインのパッケージを作ります。これをpackagesフォルダのBurningProj....

<span title='2021-04-29 12:27:07 +0900 +0900'>4月 29, 2021</span>&nbsp;·&nbsp;4 分&nbsp;·&nbsp;Shohei Okazaki

FX的 Height Fieldの使い方

今回は、Height Fieldです。 FXは、Height Fieldの恩恵は、あまりないと思いますが、個人的なFX的使い方を紹介します。 サンプルファイルです。17.0.459で作成。 Download Terrain Object Height Filedの実装にともないTerrain Object DOPにUse Heightfiledというオプションが追加されました。 今までは、Particleと地面の詳細なコリジョン結果を得るには、このノードのVolumeに変換する所のオプションにてDivisionSizeをあげて高解像度にするか、StaticObjectをつかってSurface Collisionを使用したりしてました。どちらも、軽いものではありませんね。 Height Filedは、どこかの軸が2000を超えてもなんてことありません。普通のVolumeのならめっちゃ重いですよね。これを使うなんて、さすがSideFX。 さて実際の使い方は、Environment Modeler等が作ってくれた地形等を読み込み、HeightField ProjectでHeightFiledに変換します。 シミュレーションの範囲を決めて、より効率的に作業するならHeightField Cropを使いましょう。 小さな石とかデブリがあったら、それごとProjectionしても、そこそこ使えます。 え、Displacement・Bumpを使ってたらどうするんだって? Point CloudでUVを持ってきて、Textureをインポートして、 足し算。 それだとNormal考慮してないってか。インポートしたGeometryをSubdivisionをめっちゃかけて、SopでDisplacementするしかないですかね。 Packでコレ使うと、めっちゃ重いからVolume Collision使わないで、普通にBulletでConcaveにしたほうが良いです。 Boolean Cutter 続いては、別の使い方の紹介。BooleanのShatterに使ってみましょう。 そもそもBooleanを使う時の重要な点は、如何にエラーのないGeometryを作り出しレンダリングできるようにするかです。「エラー」とはManifold Topologyになっていないものが生成されたり、Alembicを使って他のツールにGeometryとしてインポートするときに起こりうる問題の要因のことを指します。Houdini内で完結する場合は、これらの問題があっても気にせずレンダリングできることが多々です。 なぜBooleanに使うのか?それはHeightFiledの特徴が気に入ったからです。 特徴1:軽い 前述した通り挙動が軽いです。破壊の断面はディティールが欲しくなります。通常だったら、面を細かく分割してPointにNoiseをかけたりしますが、結構動作重いです。軽いは良いです。 特徴2:Topology HeightFieldをPolygonにコンバートして、それをDisplacementした方向からTopoloyを見ると綺麗な格子状になっています。 エラーTopologyを最も生成しやすい要因は、このNoiseのカッターを作ってる時です。GeometryのPointsに対して、強いNoiseをかけると、自身の面と干渉してしまいます。これは、あまり良くないです。 そして、綺麗なTopologyということは、ここからUVが作りやすいです。 それでは、実際の手順の説明です。 基本的には普通よくあるやつと似てます。Point作ってHeightFiledのGridをコピーしてNoiseをかけます。 Noiseをかける前に対象Geometryより少し大きめなBoundigBoxを使ってCropしてあげれば、より効率が良くなります。 続いて、HeightFiledをMeshにコンバートし、UV ProjectでDisplacement方向からUVを転写。UV Layoutで一度整えます。このままだと高さが考慮されていないので、heightというPointAttrを使ってUVを調整します。 Wrangleで縦横比をheihgtで乗算 vector bsize = getbbox_size(0); float mult= bsize[0]/bsize[2]; @uv.y = point(0,"height",@ptnum)*mult; 最後に、UV Layoutでもう一度整えておしまいです。 Cutterの用意ができたら、あとは通常通りBooleanでShatterしましょう。 その後は、Normal入れたり、 Non-Manifoldを取り除くために、CleanかPolyDoctorで治しときましょう。エラーは出るときは出ます。 ここまでUVがあれば、ModelerやLookDevにTexture・Shaderを作ってもらうために壊したものを戻しても、文句は言われないでしょう。きっと。 ということで、今回は本来の用途とは違った使い方の紹介でした。 他にも、こんな風に本来の目的とは違う使ってるよって方いましたら、ぜひ教えてください。

<span title='2019-02-12 09:30:42 +0900 +0900'>2月 12, 2019</span>&nbsp;·&nbsp;1 分&nbsp;·&nbsp;Shohei Okazaki