XGen による毛髪や、体毛、毛皮のレンダリングに関するガイドライン

Unreal Engine 4 で使用するために、グルームを Alembic ファイルとしてエクスポートするためのガイドラインを説明します。

Windows
MacOS
Linux

このガイドでは、「Alembic for Grooms 」のドキュメントで概説されているサポートされた属性のセットを使用して Unreal Engine にインポートを行うために、Maya の「従来の XGen ヘア作成システム 」からインポートするグルームを設定する方法を説明します。

このガイドのアセット作成には、Maya 2018.6 を使用しました。

レガシー XGen の記述を変換する

ガイドを NURBS カーブへ変換する

以下の手順を使って、転送するガイドと一致するカーブを保存するためにグルームのガイドをカーブに変換します。

  1. Maya のメニューセットを [Modeling (モデリング)] に設定すると、正しいメニュー オプションが使用可能になります。

    MenuSetSelection.png

  2. メインメニューから [Generate (作成)] のドロップダウンをクリックし、 [XGen Editor (XGen エディタ)] を選択します。

  3. [XGen] ウィンドウで、[Utilities (ユーティリティ)] タブから [Guides to Curves (カーブの操作)] を選択します。

    XGen_Utilities.png

  4. [Create Curves (カーブを作成)] をクリックします。

完了すると、グルームの出力は次のようになります。

GuidesToNurbsCurvesOutput.png

グルームを XGen Interactive Groom に変換する

従来の XGen Description を使用している場合、グルームを XGen Interactive Groom に変換する必要があります。これを行うには、次のいずれかの方法を実行します。

  1. XGen Description ノードを選択します。

    XGenDescriptionNodes.png

  2. [Modeling (モデリング)] メニュー セットで、メイン メニューから、[Generate (作成)] ドロップダウンをクリックし、[Convert to Interactive Groom] を選択します。

    XGenInteractiveGroom.png

スプライン記述を NURBS カーブへエクスポートする

次の手順に従って選択したスプライン記述を、NURBS カーブとして補間されたヘアをインポートすることができる Alembic ファイルでエクスポートします。

  1. XGen Spline Description ノードを選択し、[Modeling (モデリング)] メニュー セットで、メイン メニューから、[Generate (作成)] ドロップダウンをクリックします。リストから [Cache (キャッシュ)] > [Export Cache (キャッシュをエクスポート)] を選択します。

    SplineDescToNurbsCurve_ExportCache.png

  2. [Export Cache (キャッシュをエクスポート)] ウィンドウで、以下を設定します。

    • [Cache Time Frame (キャッシュのタイムフレーム)]: [Current Frame (現在のフレーム)] に設定

    • [Multiple Transforms (複数のトランフォーム)]:Disabled (無効)

    • [Write Final Width (最終的な幅を書き込み)]:Enabled (有効)

    SplineDescToNurbsCurve_ExportCacheWindow.png

  3. ファイルに名前を付け、ファイル タイプとして [Alembic] を選択します。

    SplineDescToNurbsCurve_ExportCacheFile.png

  4. [Export (エクスポート)] をクリックします

  5. [File] メニューを使って [Import] を選択します。[Import] ウィンドウが開いて、Alembic ('.abc') ファイルを選んでシーンにインポートすることができます。

    SplineDescToNurbsCurve_ImportAlembic.png

インポートすると、XGen Spline Description は、Alembic ファイルとしてエクスポートされ、補間されたヘアを NURBS カーブとして取り込むためにインポートされます。

SplineDescToNurbsCurve_Output.png

属性を作成する

ID 属性を作成する

補間されたヘアは、1 つ以上のグループでエクスポートできます。これらのグループは、固有マテリアル割り当てのために Unreal Engine で認識されます。

グループ ID 属性を作成するときは、次のスクリプトを使用します。

from maya import cmds

attr_name = 'groom_group_id'

# NOTE: change the following names to reflect your node's scene.
groups = ['hair_brows_splineDescription1|SplineGrp0', 'hair_lashes_splineDescription1|SplineGrp0', 'hair_head_splineDescription1|SplineGrp0']

for groom_group_id, group_name in enumerate(groups):

    # get curves under xgGroom
    curves = cmds.listRelatives(group_name, ad=True, type='nurbsCurve')

    # tag group with group id
    cmds.addAttr(group_name, longName=attr_name, attributeType='short', defaultValue=groom_group_id, keyable=True)

    # add attribute scope
    # forces Maya's alembic to export data as GeometryScope::kConstantScope
    cmds.addAttr(group_name, longName='{}_AbcGeomScope'.format(attr_name), dataType='string', keyable=True)
    cmds.setAttr('{}.{}_AbcGeomScope'.format(group_name, attr_name), 'con', type='string')

ガイド属性を作成する

グルーミングのガイド属性を作成するとき、ガイド とタグ付けされたカーブのみが、Unreal Engine でのシミュレーションに使用されます。Alembic ファイルにガイドが指定されていない場合、補間されたヘアのパーセンテージは、UE4 へのインポート プロセス中にガイドとして内部でタグ付けされます。

ガイドなしでグルームをインポートする場合、「ガイド」とタグ付けされた補間されたヘアの割合は、「[Groom Import Options (グルームのインポートオプション)(Engine/HairRendering/Reference)」で設定できます。デフォルトでは、ヘア数の 10% のみがガイドとして使用されます。

ガイド属性を作成するときは、次のスクリプトを使用します。

from maya import cmds

attr_name = 'groom_guide'

# get curves under xgGroom
curves = cmds.listRelatives('xgGroom', ad=True, type='nurbsCurve')

# create new group
guides_group = cmds.createNode('transform', name='guides')

# tag group as groom_guide
cmds.addAttr(guides_group, longName=attr_name, attributeType='short', defaultValue=1, keyable=True)

# forces Maya's alembic to export curves as one group.
cmds.addAttr(guides_group, longName='riCurves', attributeType='bool', defaultValue=1, keyable=True)

# add attribute scope
# forces Maya's alembic to export data as GeometryScope::kConstantScope
cmds.addAttr(guides_group, longName='{}_AbcGeomScope'.format(attr_name), dataType='string', keyable=True)
cmds.setAttr('{}.{}_AbcGeomScope'.format(guides_group, attr_name), 'con', type='string')

# parent curves under guides group
for curve in curves:
    cmds.parent(curve, guides_group, shape=True, relative=True)

Maya から Alembic にエクスポートする

  1. Maya で、エクスポートするガイドと Group_ID カーブを選択します。

    各ノードには固有の名前が必要です。

  2. [Modeling (モデリング)] メニューセットで、メイン メニューから [Cache (キャッシュ)] ドロップダウンをクリックし、[Alembic Cache] > [Export Selection to Alembic] を選択します。

    ExportToAlembic_ExportSelection.png

  3. [Export Selection (選択範囲をエクスポート)] ウィンドウの [General Options (全般オプション)] カテゴリで、[Cache time range (キャッシュ時間の範囲)][Current Frame (現在のフレーム)] に設定します

    ExportToAlembic_ExportSelection_CurrentFrame.png

  4. 次に、[Attributes (属性)] カテゴリの下で、リストに追加する [Attributes (属性)] の名前を入力し、[Add (追加)] ボタンをクリックします。次のスキーマ属性を追加してください。

    ExportToAlembic_ExportSelection_AddAttributes.png

    • groom_group_id

    • groom_guide

  5. [File name (ファイル名)] テキストボックスでファイルに名前を付け、[Files of type (ファイルの種類)][Alembic] に設定します。

    ExportToAlembic_ExportSelection_FileNameType.png

  6. [Export Selection (選択範囲をエクスポート)] ボタンをクリックします。

テクスチャを毛髪の UV に適用する

以下の手順およびスクリプトを使うと、Unreal Engine へエクスポートが可能な独自の XGen による毛髪を設定し、適用したテクスチャを 1 本ごとの髪に表現するのに有用です。

  1. Maya の [Modeling] メニューから、[Generate (生成)] > [Create Interactive Groom Splines (インタラクティブ グルーム スプラインを作成)] の順に選択します。

    HairUV_XGen.png

  2. ガイドを作成し、プロジェクト用に自由に髪にブラシをかけることができます。準備ができたら、オプションから [Generate] > [Cache] > [Create New Cache (キャッシュを新規作成)] の順に選択してカーブを Alembic Cache としてエクスポートします。

    HairUV_2_XGen.png

  3. XGen による毛髪を非表示にするか削除して取り除きます。ソースメッシュのあるエクスポートした髪のカーブを Maya シーンに再インポートします。

    HairUV_3_XGen.png

  4. 使用したいるシーンによって、最上のカーブ (この例では SplineGrp0) を親に持つ数千ものスプライン カーブができます。以下の Python スクリプトを編集して、以下の値をプロジェクトの値に置き換えます。

    • export_directory

    • hair_file

    • curve_top_group

    • uv_mesh

    以下のスクリプトは こちら からダウンロードできます。

    from maya import cmds
    from maya import OpenMaya
    import os
    
    def create_root_uv_attribute(curves_group, mesh_node, uv_set='map1'):
        '''
        Create "groom_root_uv" attribute on group of curves.
        '''
    
        # check curves group
        if not cmds.objExists(curves_group):
            raise RuntimeError('Group not found: "{}"'.format(curves_group))
    
        # get curves in group
        curve_shapes = cmds.listRelatives(curves_group, shapes=True, noIntermediate=True)
        curve_shapes = cmds.ls(curve_shapes, type='nurbsCurve')
        if not curve_shapes:
            raise RuntimeError('Invalid curves group.No nurbs-curves found in group.')
        else:
            print "found curves"
            print curve_shapes
    
        # get curve roots
        points = list()
        for curve_shape in curve_shapes:
            point = cmds.pointPosition('{}.cv[0]'.format(curve_shape), world=True)
            points.append(point)
    
        # get uvs
        values = list()
        uvs = find_closest_uv_point(points, mesh_node, uv_set=uv_set)
        for u, v in uvs:
            values.append([u, v, 0])
            #print (str(u) + " , " + str(v)  )
    
        # create attribute
        name = 'groom_root_uv'
        cmds.addAttr(curves_group, ln=name, dt='vectorArray')
        cmds.addAttr(curves_group, ln='{}_AbcGeomScope'.format(name), dt='string')
        cmds.addAttr(curves_group, ln='{}_AbcType'.format(name), dt='string')
    
        cmds.setAttr('{}.{}'.format(curves_group, name), len(values), *values, type='vectorArray')
        cmds.setAttr('{}.{}_AbcGeomScope'.format(curves_group, name), 'uni', type='string')
        cmds.setAttr('{}.{}_AbcType'.format(curves_group, name), 'vector2', type='string')
    
        return uvs
    
    def find_closest_uv_point(points, mesh_node, uv_set='map1'):
        '''
        Find mesh UV-coordinates at given points.
        '''
    
        # check mesh
        if not cmds.objExists(mesh_node):
            raise RuntimeError('Node not found: "{}"'.format(mesh_node))
    
        # check uv_set
        uv_sets = cmds.polyUVSet(mesh_node, q=True, allUVSets=True)
        if uv_set not in uv_sets:
            raise RuntimeError('Invalid uv_set provided: "{}"'.format(uv_set))
    
        # get mesh as dag-path
        selection_list = OpenMaya.MSelectionList()
        selection_list.add(mesh_node)
    
        mesh_dagpath = OpenMaya.MDagPath()
        selection_list.getDagPath(0, mesh_dagpath)
        mesh_dagpath.extendToShape()
    
        # get mesh function set
        fn_mesh = OpenMaya.MFnMesh(mesh_dagpath)
    
        uvs = list()
        for i in range(len(points)):
    
            script_util = OpenMaya.MScriptUtil()
            script_util.createFromDouble(0.0, 0.0)
            uv_point = script_util.asFloat2Ptr()
    
            point = OpenMaya.MPoint(*points[i])
            fn_mesh.getUVAtPoint(point, uv_point, OpenMaya.MSpace.kWorld, uv_set)
    
            u = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_point, 0, 0)
            v = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_point, 0, 1)
    
            uvs.append((u, v))
    
        return uvs
    
    def abc_export(filepath, node=None, start_frame=1, end_frame=1, data_format='otawa', uv_write=True):
    
        job_command = '-frameRange {} {} '.format(start_frame, end_frame)
        job_command += '-dataFormat {} '.format(data_format)
    
        job_command += '-attr groom_root_uv '
    
        if uv_write:
            job_command += '-uvWrite '
    
        job_command += '-root {} '.format(node)   
    
        job_command += '-file {} '.format(filepath) 
    
        cmds.AbcExport(verbose=True, j=job_command)
    
    def main():
    
        export_directory = 'D:/Dev/Ref'
        hair_file = os.path.join(export_directory, 'hair_export.abc')
        curve_top_group= 'description1|SplineGrp0'
        uv_mesh='pPlane1'
    
        create_root_uv_attribute( curve_top_group , uv_mesh)
        abc_export(hair_file, curve_top_group)
    
    main()
  5. 変更した値でスクリプトを Maya で実行します。新しい Alembic ('.abc') ファイルが生成されます。このファイルは Unreal Engine へインポートすることができます。

  6. Unreal Engine で、Hair シェーディング モデルを使って新しいマテリアルを作成します。マテリアル グラフで Hair Attributes 表現式を追加して Root UV を Texture Sample の UV 入力へつなぎます。

    HairUV_4_XGen.png

  7. インポートした髪の Alembic ファイルをコンテンツ ブラウザからレベルにドラッグし、ヘア マテリアルをそれに割り当てます。最終的には以下に示す画像のような結果となります。

    レベルの髪の Alembic ファイルの幅が 0 より大きいことを確認してください。

    HairUV_5_XGen.png

Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback