記事の目次

    みなさんこんにちは。最近、今更ながら3Dプリンタ欲しい欲しい病にかかっています。プログラムとかCGとか、実体のないものばかりを扱っていると無性に手で触れるものでガッシャンガッシャンやりたくなるのですよね。本当は金属加工とか鋳造とかやりたいのですが、さすがにそれはスペースや安全性の問題で実現できなさそうです。残念無念......

    TEXT_痴山紘史 / Hiroshi Chiyama(日本CGサービス
    EDIT_尾形美幸 / Miyuki Ogata(CGWORLD)

    アセットの管理方法について考える

    今回は、クラウド環境上でのアセット管理について考えていきます。

    クラウド環境上でデータを処理するということは、ローカル環境とクラウド環境の2ヶ所にデータを置くことになります。このとき、データがきちんと管理できていないと、ローカル環境にあるファイルが更新されているのにクラウド環境が更新されていない、もしくはその逆といったことが起きてしまい、処理を実行する環境(最悪の場合、各インスタンス)によって結果が異なるという問題が起きてしまいます。こうなると問題解決にばかり時間を取られてしまい、何のためにクラウド環境を使用しているのかわからなくなってしまいます。

    この問題を解決する最も単純な方法は、処理を行う度に全てのデータをクラウド環境に転送することです。必要な全てのデータを都度転送することで、環境ごとにデータが異なってしまうという問題が起きなくなります。この方法の問題点は毎回同じだけの転送時間がかかってしまうということです。

    都度全部転送はめんどくさいなぁ......ということで、次に候補に挙がるのが前回(第19回)も言及した、社内と社外で常に同期をとっておく方法です。似たようなケースで、複数の会社を跨いで仕事を行うときのデータ共有手段としても検討されることが多いです。ユーザーは一切何も考えなくてよく、同期システムがいい感じに対応してくれて万歳......となればいいのですが、転送時間によるタイムラグや複数の場所で同じファイルが更新されてしまった場合の対応を考える必要があるため、なかなか一筋縄ではいかないです。また、まちがってリリースしたデータも共有されてしまうため、その転送時間が大きなロスになってしまいます。アセットを共有フォルダに置いた後に見直したら、テクスチャがまちがっていて、何度かファイルのコピーを繰り返したり、誰にもわからないだろうと思ってコッソリと共有データを上書きしたりした経験のある人も多いでしょう。

    さてさてどうする~??となって救世主の如く現れるのがバージョン管理システムです。映像・ゲーム関連では未だに Subversion(SVN)を使用することが多いようです。SVNはテキストベースのデータの扱いをメインにしており、バイナリデータを扱うことには向いていない上に、ソフトウェアとしても古いので、何で未だに使っているのかちょっと私にはわからないです。お金のあるところはHelix(旧名・Perforce)を使用しているようです。バージョン管理システムを使用すると、バイナリデータの扱いが大きな負荷になってしまうことが多く、インフラにそれなりの投資が必要となります。CEDEC2019でも、スクウェア・エニックスのセッションでPerforceを使用した事例が紹介されていて、最終的には二度ほどサーバの増強をすることで解決したというお話があったと記憶しています。

    また、バージョン管理システムを使用しても解決できないのが、複数のバージョンのバイナリデータを同時に確認するのが難しいという問題です。テキストデータであればバージョン間のちがいを目で確認できますが、バイナリデータの場合はアプリケーションで開く必要があるため、ディスク上に実体として存在する必要があります。これは既存のバージョン管理システムの思想と相性が悪いため、なかなか悩ましいところです。また、バージョン管理システムに登録されたファイルを全て共有することも、データ量の多さによって各種問題が引き起こされる原因になりがちです。そもそも、バージョン管理システムの場合、普通は作業環境ごとにデータをコピーして手元に置いて作業することを想定しているので、チームで巨大なデータを共有して作業を進めるという使い方との相性がとても悪いです。

    これらの問題をある程度解決しつつ、巨大なバイナリデータを扱うためのしくみとしてGit-LFSもあるので、これを上手く活用しているところもあるのではないかと思います。

    ここまでくるとめんどくさくなって「もうクラウドとかメンドイし、いいかな......」っていう気になってきますね :-)。でも、これって実は普段仕事をしていても常につきまとってくる問題なのですよね。今回は、前回の内容をベースに、ある程度簡単に実現できる方法を考えます。

    アセット管理ルールを決める

    前回決めたルールを元に、アセット管理ルールを決めます。

    前回、ローカルの作業環境とAWS上のインスタンスの両方に/gsディレクトリを用意し、ローカル環境の場合は/gsはローカルのファイルサーバを参照し、インスタンスではS3上のデータをs3fsでマウントするようにしました。また、ローカル環境ではS3上のデータをs3fsで/s3fsディレクトリにマウントしています。

    さらに、アセットの管理ルールを詰めていきます。

    プロジェクト共通で使用するファイルは/gs/assets/(アセット名)/revXXX以下に置きます。revXXXはrev001, rev002, ......と続く連番で、アセットが更新されると新しいリビジョンの中に完全なアセットのファイルが格納されます。この時、一度作成されたリビジョンの中身は絶対に変更しないようにします。ツールを使用して配置を行うのであれば、配置後に読み取り専用に変更することも簡単にできます。

    クラウドとのファイルの同期はリビジョン単位で行います。ジョブ投入時に必要なファイルをリストアップし、もし/s3fs以下にあるファイルで、かつファイルの属するリビジョンディレクトリがなければファイルを転送するようにします。

    ユーザーの作業領域は/gs/work以下とします。ここにあるファイルは、必要なものをリストアップした上で転送するようにします。

    計算結果も/gs/work以下に格納するようにします。

    ここまでの内容を図にまとめてみました。


    これくらいなら混乱も少なくローカル環境とクラウド環境でデータを共有できそうです。

    アセットの用意

    アセットは以前から使用しているAnimator Starter Pack(For Short Films or Animations)Final 6.0.0 for Maya(※リンク切れ)を使用します。このアセットは無料で使用できるということで重宝していたのですが、Highend3D.comの閉鎖にともない入手できなくなってしまったようです。残念無念......

    事前に変換した.usdファイルを/gs/assets以下に配置し、Mayaから出力したレイアウト用.usdファイルが参照します(これも/gs/assets以下に配置する)。Gafferはレイアウト用.usdファイルを参照してレンダリングを行います。

    例えば、/gs/assets以下はこのようになります。

    [neo@matrix assets]$ ls /gs/assets
    ActingStage         Building6_House        ParkEntrance_PayStation
    ActingStageV2       Building7_House        PhoneBooth
    AwningBase          Building8_House        PlantedTree
    AwningBaseV2        Building9_House        plasticCrate
    BenchV1             Building_Apartment_1   Playground_Equiptment
    BenchV2             Building_Apartment_2   PoliceCar
    BenchV3             Building_SignV1        Raft
    BenchV4             Bushel                 RetainingWall
    BrickPattern1       CafeV1                 RetentionWallv1
    BrickPattern2       CafeV2                 Shingles
    BrickPattern3       Chinmey                ShinglesV2
    BrickPattern4       Cone                   SideWalk_Peice1
    BrickPattern5       CrateV1                SmallPieces
    Building10_House    CrateV2                Steps1
    Building10V2_House  cube                   StopLight
    Building10V3_House  Door1                  test
    Building11_House    DrinkStand1            TextForSigns
    Building11v2_House  FamilyCar              TrainTracksV1
    Building11v3_House  FamilyCarv2            TrashCan
    Building12_House    FamilyCar_WithLuggage  Tree1
    Building13_House    FamilyVan              Tree2
    Building14_House    FamWagon               Tree3
    Building14v2_House  Fiat1500               Tree4
    Building15_House    FireHydrant            VentV1
    Building15v2_House  GrassSectional_1       WindowWoodv1
    Building16_House    Headstone1             WindowWoodv2
    Building16v2_House  Headstone2             WoddenFence
    Building17_House    Headstone3             WoodenBarrel
    Building17v2_House  IceChest               WoodenBarrelV2
    Building18_House    IceCreamTruck          WoodenWheel
    Building1_House     IPhoneRig              WoodFloorV1
    Building3_House     IVY_basic              WoodFloorV2
    Building4_House     Lightpost              WoodFloorV3
    Building5_House     Lockers                WoodSign1
    Building5v2_House   PappyTruck             ZooPictureSign
    [neo@matrix assets]$ ls /gs/assets/Fiat1500/rev001/
    Fiat1500.abc  Fiat1500.usd
    [neo@matrix assets]$ ls /s3fs/
    foobar  Kitchen_set  render  work
    

    当然のこととして、ローカル環境にアセットを用意しただけなので、S3上にはファイルが存在しません。

    次ページ:
    必用なファイルのリストアップ

    [[SplitPage]]

    必用なファイルのリストアップ

    Gafferの.gfrファイルと.usdファイルを調べて、中で使用されている外部データをリストアップします。gafferは引数によって動作モードが変わり、cliではpythonコンソールを使用することができます。例えば、以下のようにして.gfrファイルを読んでノードをリストアップすることができます。

    [neo@matrix HTCondor]$ /opt/gaffer-0.54.1.0-linux/bin/gaffer cli
    >>> import Gaffer
    >>> script = Gaffer.ScriptNode()
    >>> script['fileName'].setValue('/home/neo/Documents/HTCondor/layout_Arnold.gfr')
    >>> script.load()
    >>> for node in script.children(Gaffer.Node):
    >>>     print(node)
    

    また、cliの代わりにpythonを指定するとpythonスクリプトファイルを実行できるので、これを使用します。

    とりあえずざっくりと、.gfrファイルと中で読んでいる.usdファイルを解析して関連するファイルをリストアップします。.usdファイルは本連載の第4回で生成したものを使用して、必要最低限の処理でアセットをリストアップします。

    今回はこのようなコードにしました。

    [neo@matrix neo]$ cat gfrAnalyzer.py
    import sys
    import re
    
    import Gaffer
    import GafferScene
    
    
    def listupUSDAssets(path):
        ret = []
    
        fp = open(path)
        for l in fp.readlines():
            m = re.search('references = @([^@]+)@', l)
            if m is None:
                continue
    
            ret.append(m.group(1))
    
        return ret
    
    
    def analyze(path):
        script = Gaffer.ScriptNode()
        script['fileName'].setValue(sceneFileName)
        script.load()
    
        ret = []
        for node in script.children(Gaffer.Node):
            if node.__class__ == GafferScene.SceneReader:
                fileName = node['fileName'].getValue()
                ret.append(fileName)
                ret.extend(listupUSDAssets(fileName))
    
            if node.__class__ == Gaffer.Reference:
                ret.append(node.fileName())
    
        return ret
    
    
    if __name__ == '__main__':
        sceneFileName = sys.argv[1]
        files = analyze(sceneFileName)
        files = list(set(files))
        files.sort()
    
        for f in files:
            print(f)
    
    [neo@matrix neo]$
    

    これを実行します。

    [neo@matrix neo]$ ~/gaffer.sh python gfrAnalyzer.py layout_Arnold.gfr
    /gs/assets/BenchV1/rev001/BenchV1.usd
    /gs/assets/BrickPattern1/rev001/BrickPattern1.usd
    /gs/assets/Building10_House/rev001/Building10_House.usd
    /gs/assets/FamilyCar/rev001/FamilyCar.usd
    /gs/assets/Tree3/rev001/Tree3.usd
    /gs/work/neo/gaffer/projects/default/references/Bench.grf
    /gs/work/neo/gaffer/projects/default/references/BrickPattern.grf
    /gs/work/neo/gaffer/projects/default/references/FamilyCar.grf
    /gs/work/neo/gaffer/projects/default/references/Hotel.grf
    /gs/work/neo/gaffer/projects/default/references/Tree.grf
    /gs/work/neo/layout.usd
    [neo@matrix neo]$
    

    .gfrファイル中で読んでいる.usdファイルと、さらにその中で読んでいるアセット、それからlookdevに使用した.grfファイルがリストアップされています。ここまでくれば、後は前回の方法と組み合わせてクラウド環境でのレンダリングまでできるでしょう。ここから先はこれまでやってきたことの繰り返しになりますし、環境や要望によって詰めていく内容が異なってくるので言及しません。

    皆さん各自工夫していただけたらと思います。

    まとめ

    これで、本連載のクラウド編は一区切りとなります。おつかれさまでした。次回以降、2回ほどクラウドを絡めた番外編を挟み、5月から新章に突入できればいいかなと考えています。今後も引き続きよろしくお願いします。



    第21回の公開は、2020年3月を予定しております。

    プロフィール

    • 痴山紘史
      日本CGサービス(JCGS) 代表

      大学卒業後、株式会社IMAGICA入社。放送局向けリアルタイムCGシステムの構築・運用に携わる。その後、株式会社リンクス・デジワークスにて映画・ゲームなどの映像制作に携わる。2010年独立、現職。映像制作プロダクション向けのパイプラインの開発と提供を行なっている。新人パパ。娘かわいい。
      @chiyama