[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 = @./grid.usd@ string name = "grid" asset thumbnail = @./thumbnail.png@ } prepend inherits = </__class__/grid> kind = "component" prepend payload = @./payload.usdc@ ) { float3[] extentsHint = [(-5, 0, -5), (5, 0, 5)] } class "__class__" { class "grid" { } } これらはComponent OutputのなかにあるropのOutput Processingにて、処理がされています。 ...

12月 12, 2024 · 3 分 · 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に移行 してくとこもあるみたいです。 ...

2月 28, 2024 · 4 分 · 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.GetStage() factor = husd.utils.convertFromMillimetersToCameraUnits(stage, 1.0) self.populateAttr(cam.CreateFocalLengthAttr(), self._node.parm('focal'), lambda value: value * factor) self.populateAttr(cam.CreateFocusDistanceAttr(), self._node.parm('focus')) self.populateAttr(cam.CreateFStopAttr(), self._node.parm('fstop')) self.populateAttr(cam.CreateShutterOpenAttr(), self._node.parm('shutter'), lambda value: value * -0.5) self.populateAttr(cam.CreateShutterCloseAttr(), self._node.parm('shutter'), lambda value: value * 0.5) self.populateAttr(cam.CreateClippingRangeAttr(), [self._node.parm('near'), self._node.parm('far')]) # Aperture is a bit more complicated aspect = float(self._node.parm('resy').eval()) / self._node.parm('resx').eval() win_size = self._node.parmTuple('winsize').eval() if proj == 'perspective': # Start by grabbing a few values we'll use to scale the attributes aperture = self._node.parm('aperture').eval() self.populateAttr(cam.CreateHorizontalApertureAttr(), self._node.parm('aperture'), lambda value: value * factor * win_size[0]) self.populateAttr(cam.CreateVerticalApertureAttr(), self._node.parm('aperture'), lambda value: value * aspect * factor * win_size[1]) self.populateAttr(cam.CreateHorizontalApertureOffsetAttr(), self._node.parmTuple('win'), lambda value: value[0] * aperture * factor) self.populateAttr(cam.CreateVerticalApertureOffsetAttr(), self._node.parmTuple('win'), lambda value: value[1] * aperture * aspect * factor) elif proj == 'ortho': # Start by grabbing a few values we'll use to scale the attributes sceneToMM = 1000 * hou.scaleToMKS("m1") orthowidth = self._node.parm('orthowidth').eval() self.populateAttr(cam.CreateHorizontalApertureAttr(), self._node.parm('orthowidth'), lambda value: value * sceneToMM * factor * win_size[0]) self.populateAttr(cam.CreateVerticalApertureAttr(), self._node.parm('orthowidth'), lambda value: value * aspect * sceneToMM * factor * win_size[1]) self.populateAttr(cam.CreateHorizontalApertureOffsetAttr(), self._node.parmTuple('win'), lambda value: value[0] * orthowidth * sceneToMM * factor) self.populateAttr(cam.CreateVerticalApertureOffsetAttr(), self._node.parmTuple('win'), lambda value: value[1] * orthowidth * sceneToMM * aspect * factor) def registerTranslators(manager): manager.registerTranslator('cam', CameraTranslator) このファイルを適切な場所にコピーしましょう。ファイル名は適当でOKです。$HOUDINIPATH/husdplugins/objtranslators/customCam.py ...

10月 5, 2023 · 2 分 · 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 さて、これらをどうやって全員に行き渡せるかですが、大きい会社ならランチャーがあると思うので、そこで設定してもいいです。 ...

4月 29, 2021 · 4 分 · 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でもう一度整えておしまいです。 ...

2月 12, 2019 · 1 分 · Shohei Okazaki

最近のお気に入り - 1 「右クリック」

test 大したことじゃないけど、最近のお気に入りを紹介するコーナ。 第一弾は右クリック。 FXを作ってく上で、僕には2大裏テーマというものがあります。それは 「キーフレームを極力打たない」と「手の挙動範囲を極力少なくする」 です。今回は後者のために、必要なカスタマイズです。 ノードのプリセットに入れればいいじゃんと言う人もいるかもしれないですが、あれはパラメータの並び順や位置のレイアウトも記憶しています。Houdiniはバージョンが変わると、パラメータのレイアウトが変わることなんてことは当たり前なので、バージョンごとにプリセットを更新する必要があり非常にめんどいのです。といわけで右クリックのメニューにサポートツールを追加して効率化を図っています。 メニューの追加の仕方ですが、 ノードを右クリックした時にメニューを追加するには、OPmenu.xmlを編集します。 パラメータを右クリックした時にメニューを追加するには、PRAMmenu.xmlを編集します。 基本的には、ここに書いてあるんで、読めばわかります。 http://www.sidefx.com/docs/houdini/basics/config_menus.html お題として、先日パベルさんのセミナーでDescriptive Parmの表示の仕方を習ったので、これをパラメータの右クリックに追加してみましょう。 Descriptive Parmとは、File Sopなどにある、Network View上でノードの名前の下にあるやつです。 これを、表示されてないノードにも表示させるようにします。これで、いちいちノードを選択してパラメータを見なくても、重要なパラメータの値がNetwork View上で確認できるようになります。しかし、そのパラメータが何かのノードとリンクして、そのノードはクソ重い処理をしなければならないのなら、この値を表示するために、毎回時間がかかってしまうので、気をつけてください。 最初に、Pythonでどうやるか確認しましょう。ヘルプを見るとノードのUserDataを変更すれば、いいようです。 http://www.sidefx.com/docs/houdini/network/badges.html#textbadges 上の添付のようにMountainSopのElement Sizeを、Network Viewに表示させるには、Pythonはこんな感じ。 node = hou.node('/obj/geo1/mountain1') parm_name = 'elementsize' node.setUserData("descriptiveparm", parm_name) ノードと、Descriptive Parmになるパラメータの名前が必要ですね。 必要なものがわかったので、実際の作業に入りましょう。まずはPythonファイルを作ります。ここでは、changeDescriptiveParm.pyという名前にして、Houdiniがインポートできる場所に保存します。 import hou def doit(parms,type): parm = parms[0] parm_name = parm.name() node = parm.node() if type == "clear" parm_name = "" node.setUserData("descriptiveparm", parm_name)) 現在、右クリックしているパラメータが何かはparms=kwargs["parms"]で取得します。parmsとあるとおり、リストとして値が返ってきます。選択してるパラメータは1つなので、parm = parms[0]。パラメータからノードの情報を得るには、単純にparm.node()。これで、必要な情報はすべて取得できたことになります。 Descriptive Parmをクリアしたい時もあるので、parm_nameを空にして、それを可能にしておきます。 ...

3月 6, 2018 · 1 分 · Shohei Okazaki

[Deadline] Add Extra Version

時々、悩んでる人がいたので、Deadlineネタを1つ。 どんなソフトでも、マイナーアップデートは簡単にできますが、メジャーアップデートは、プロジェクトの兼ね合いや自社Plugin/Toolの影響で、そうは容易くできません。アップグレードの金を出すのに渋って更新してないのでなく、ただ単にめんどくさいという理由で更新されてなかったら、担当者のケツを蹴っ飛ばして更新してもらいましょう。 いろんな理由でDeadlineのバージョンが古すぎて、最新のHoudiniのバージョン使用できないという人もいるでしょう。今回は、そんな人向けへの裏ワザを紹介します。 ※この記事は、Deadline Client Version: 9.0.6.1の元、作成しています。 Configure Plugins まずは、 Configure Pluginsに任意のバージョンを追加して、Pathをセットできるようにしましょう。 以下のファイルを探しだして、[Houdini16_Hython_Executable]の次に追加します。 $DEADLINE_REPOSITORY/plugins/Houdini/houdini.param [Houdini17_Hython_Executable] Label=Houdini 17 Hython Executable Category=Render Executables CategoryOrder=0 Type=multilinemultifilename Index=8 Default=C:\Program Files\Side Effects Software\Houdini 17.0.000\bin\Hython.exe;C:\Program Files (x86)\Side Effects Software\Houdini 17.0.000\bin\Hython.exe;/Applications/Houdini/Houdini17.0.000/Frameworks/Houdini.framework/Versions/17.0.000/Resources/bin/hython Description=The path to the hython executable. It can be found in the Houdini bin folder. そうすると、Configure Pluginsをみてみると追加されています。簡単ですね。各自インストールフォルダを指定してあげてください。 Distribute Sim使う人は、Sim Trackerも追加しときましょう。(HQueue使う人ってどれくらいるんだろう?使わないよね?) Buildを指定したいなら、Houdini16.5.123_Hython_Executableみたいに作ることも可能です。 Mantraも同じ要領でやればできます。 Houdini Submission Submission WindowのVersion指定メニューに、任意のバージョンを足すには、以下のpythonを変更します。 $DEADLINE_REPOSITORY/scripts/Submission/HoudiniSubmission.py 以下のラインを探しだして、任意のバージョンを追加してください。 scriptDialog.AddComboControlToGrid("VersionBox","ComboControl","14",("9","10","11","12","13","14","15","16","17",), 5, 1) これだけです。 Deadlineは結構いいよ 以上の手順を踏めば、投げられるようになったと思いますが、 Deadlineはバッチ処理をする前に、いくつかのプロセスを処理してるので、あまりにも古いバージョンを使用してる場合は、ノードのパラメータ名が変わっていたり、対応してないかもしれません。 そんな時は、$DEADLINE_REPOSITORY/plugins/Houdini/hrender_dl.pyをなんとかなります。 ...

9月 13, 2017 · 1 分 · Shohei Okazaki

Kill Houdini

今回の話は、Linuxユーザのためだけですので、あしからず。 なにか間違った値を入れてしまったりして、メモリが右肩上がりに上昇し、メモリをフルに使いきり、パソコンが動かなくなるということは、時々あるでしょう。会社のマシンは128GBですが、まれになります。 そんなときは、 CUIモードで対処したり、同僚のマシンから操作してもらったり、泣く泣く電源を落としたりと、みなさんもこんな経験はたくさんあるでしょう。 残念ながら、いろいろセーブしてなくて、「ごめんなさい」を連呼しながらEscを連打しても、ダメなときはダメです。 そうなる前に、問題のプロセスを強制的に終了させましょう。 というわけで、今回はBashを調べてみました。基本Linuxで仕事してますが、Bashやコマンドは避けてきたので、何か間違ってる点や、もっといい方法がありましたら教えてください。 プロセス一覧から探しだして、kill まずは、ベーシック。 プロセスを表示するコマンドはps。 みなさんは、どういうオプション使っているかはわかりませんが、自分はいつもこれ ps aux 端末内外のプロセスを表示して、CPUとメモリの使用量も表示させる。 さらに、Houdiniのプロセスだけを表示させる ps aux | grep houdini-bin 表示された結果から、見つけた対象のプロセスIDを殺す。 kill -SEGV 123456 このSEGVは、ホント助かりますよね。Windowsにはないらしいですが、可哀想に。 これで、プロセスが死に、$houdini_tmpのなかに、シーンファイルが、保存される。まっ、たまに保存が失敗することがありますが。 さて、ここまでは普通の手順。もう少し、賢くやってみましょう。 すべてのHoudiniプロセスを、kill まずは、今あるHoudiniのプロセスすべてをKillします。 kill -SEGV `ps aux | grep [h]oudini-bin | tr -s ' ' | cut -d ' ' -f 2` houdini-binは、houdiniの立ち上げ方によって、名前変わるので、各自変えてください。ちなみにhoudini-bin はターミナルで、houdini_sourceをセットし、houdiniとタイプし起動したら、そうなります。 なので、それらを考慮するなら、複数指定しときましょう grep -e [h]oudini-bin -e [h]indie-bin []を使う理由は、プロセスにgrep自身が表示されないようにするためです。 ps aux | grep [h]oudini-bin 実行すると、こんな感じのものが返ってくると思います。 shohei 9042 4.7 1.5 5985364 2067844 ? Ssl 10:54 11:17 /opt/hfs16.0/bin/houdini-bin shohei 24231 0.4 0.4 1385564 544956 ? Ssl Jun05 11:00 /opt/hfs16.0/bin/houdini-bin 分かりづらいかもしれせんが、連続したスペースがあります。これだと不便です。 ...

6月 19, 2017 · 2 分 · Shohei Okazaki

H16についてのメモ

New Network Editor さて、賛否両論ありそうなこれ。見た目は可愛くなりましたね。 そして描画速度も速くなりました。Pythonでノードを何千と作ったり、AlembicのHierarchyを保持して展開するときなど、大きな差が出そうです。 あのノードの形、可愛くないから使いたくないとか、デフォルトを変えたいって人はいるでしょう。僕はノードを組む上での自分なりのルールがあるためノードの色が最初から付いているのは非常に不便でデフォルトを変更してます。 そこで、どうやってカスタマイズするかを紹介します。 書き方は、インストール先の$HFS/houdini/OPcustomizeに記述されてるので覗いてみてください。 Sample 文頭がopdefaultcolorで始まるのが色の設定。 文頭がopdefaultshapeで始まるのが形の設定。 では、$HOME/houdini16.0/OPcustomizeというテキストを作って編集してみましょう。 まず形から変更してみましょう。 SopのMergeを丸にするには opdefaultshape Sop merge circle 形の種類ってヘルプのどこかに書いてあるんですかね?5分位探してなかったのであきらめました。 そこでPythonで選択したのノードの形を取得してみます。 import hou n = hou.selectedNodes()[0] ns = n.userData('nodeshape') ds = n.type().defaultShape() print(ns, ds) userDataに入ってるのは、NetworkViewで変えた形で、defaultShapeは名の通りです。 続いて色です。個人的に勝手にノードに色がつくのはうっとおしかったため、すべての色の設定をクリアしました。 opdefaultcolor -c これで、Houdini Pathの順番で、このファイルより前で設定されたopdefaultcolorはClearされます。 形の設定をクリアするには、同じく-cです opdefaultshape -c 色をつけるには opdefaultcolor Sop rop_geometry 'RGB 0.451 0.369 0.796' ノードの名称、色とか形を調べるのはメンドイんで、ノードを選択して実行すれば分かるようにして、作業しました。 import hou ns = hou.selectedNodes() for n in ns: nn = n.type().nameWithCategory() cd = n.color() ds = n.type().defaultShape() us = n.userData('nodeshape') print( "Name:%s, Color:%s, Defalut Shape:%s, User Shape:%s" % (nn, cd, ds, us) ) なんで、こんなことをしたかというと、例えば、チーム内で「このノードの色はこういう条件の時のみ使用しよう。」とか「このノードの形は書き出しを意味する。」とか決めておけば、他の人の複雑なシーンファイルを渡されても、どのノードが重要なのかとか何をしてるのか、わかりやすくなっておすすめです。 ...

3月 29, 2017 · 1 分 · Shohei Okazaki

Wrangleを使おう 3 - Replace ForLoop

test 久しぶりのWrangle回です。 個人的にHoudiniにおいて、よく使う必需ノードは、For LoopとAttribute Promoteです。これらがないと仕事ができません。もちろんWrangleも絶対使います。 特にFor LoopはHoudiniを象徴するようなノードだと勝手に思ってます。ある処理を考え、それを他のものにも同様な処理を施す。まさにProceduralに作業する上で必要不可欠なものです。 しかし!ForLoopは処理に時間がかる時が大半です。なぜなら、 すべてのノードがマルチスレッド処理されるわけではありませんし、1つ1つのピースやグループを同時にではなく、順番に処理するため遅くなってしまいます 。 シンプルな例を元に解説していきます。 Sample File : wrangle_03.hiplc (15.5.607 linux-x86_64-gcc4.8) Voronoiで割った1つ1つのピースのサイズを測ろうと思います。あまりにも小さいピースはSimulationに参加させない様にさせるとか、大きいやつはもう一回砕こうとかで使うことがありますね。 ピースのサイズを求めるために、まずMeasureで個々のPrimitiveの面積か体積を測ります。続いて、For Loopで各ピースごとが持っている各Primitive面積の総和を出します。これが、ピースのサイズとなります。 本題です。Wrangleでやってみます。 nuniqueval() uniqueval() findattribvalcount() findattribval() この関数がミソなんでHelpは読んでください。 string piece_attr = "name"; int num_piece_attr = nuniqueval(@OpInput1, "prim", piece_attr); addattrib(0,"prim","area_sum",0.0); for(int i = 0; i < num_piece_attr; i++){ string uq_val = uniqueval(@OpInput1, "prim", piece_attr,i); int num_prim_piece = findattribvalcount(@OpInput1, "prim", piece_attr,uq_val); int prim_piece,ii =0; float per_area,area_sum =0.0; for(ii=0; ii< num_prim_piece; ii++){ prim_piece = findattribval(@OpInput1,"prim",piece_attr,uq_val,ii); per_area = prim(0,"area",prim_piece); area_sum += per_area; } for(ii=0; ii< num_prim_piece; ii++){ prim_piece = findattribval(@OpInput1,"prim",piece_attr,uq_val,ii); setattrib(0, "prim", "area_sum", prim_piece, 0, area_sum, "set"); } } For Loopでやった処理を分解しながら説明していきます。Run OverはDetailです。 ...

12月 10, 2016 · 1 分 · Shohei Okazaki