株式会社デジタル・フロンティア-Digital Frontier

Header

Main

  • TOP
  • DF TALK
  • 【Unity】 UnityでのFBXのImportについて

【Unity】 UnityでのFBXのImportについて

2017/6/26

Tag:

皆様お久しぶりです、開発の辻です。

最近はひたすらパイプラインの開発をしていますが、今回もUnityネタです。
ただ今回はShaderに関してではなく、以前映像で使用する為に調べたFBXのImport回り(とちょっとした設定)について書いていきます。

    ※注: 検証していた時の環境は5.4なので、少し古い可能性があります。2017になるといくつか変更・改善されているかもしれません。比較検証出来た箇所に関してはその旨を記述してあります。


目次


MayaのカメラのImportについて

UnityはFBXのImportに対応しています。基本的にモデルやアニメーションはFBXで読み込むことになりますが、カメラのFoVやnear/farClipといった情報はImportすることが出来ません。
……出来ませんでしたが、2017を見てみたらimportセッティングが増えてました。

2017_importSetting

Importして配置すると、以前はtransformだけ来るようになっていたのが、カメラとして置かれるようになってました。
nearとfarはkeyを打っても反応しませんでしたが、AoV(Unity上ではFoV)は来るようになっているみたいです。
ただ、そのままではMaya側と値が一致しないので、Maya側の設定かScriptで対応する必要がありそうです。これに関してはまだ検証出来てませんので、今回紹介する方法は別の方法です。あしからず…

さておき、では以前はどうしていたのかというと、ユニティ・テクノロジーズ・ジャパンの方が公開されている以下のSlideを参考にして、カメラ情報をlocatorにbakeしそれを出力して使用していました。

Mayaカメラデータunityインストール
この方法は新しい環境でも引き続き使えるのですが、FilmApertureだけ注意が必要なのでここではその旨について書いていきます。

Slide内で行われているFoV(AoV)算出には、画角を水平/垂直どちらで扱うかによって結果が変わってしまいます。
弊社の場合、カメラのFoVは基本的に水平画角(Horizontal)基準で扱ってます。
ソフトによっては水平画角固定の場合もあるそうなので、弊社だけでなく映像業界としてはこちらが一般的なのではないでしょうか。

一方、Unity側では垂直画角(Vertical)基準です。これに関してはスクリプトのドキュメントに、CameraのfieldOfViewについての記述があります。
理由は知らないのですが、スマフォのゲームだと縦の画面が多いからなのかもしれませんね。
SlideのExpressionも、cameraのverticalFilmApertureを使用しています。(Slideの16ページ参照)

ですので、もし水平画角のカメラをUnityに持って行きたい場合は、Unity側で水平画角を垂直画角に直す必要があります。

カメラの設定を変更するのでもいいですが、うっかり設定し忘れとかあると大変ですのでScript側で吸収しましょう。
Slideで紹介されているAttributeのマッピング処理を少し変更して以下のようにします。

using UnityEngine;
using System.Collections;

public class CameraAttributeMapper : MonoBehaviour {

	Camera renderCamera;

	public bool  nearFarEdit = false;
	public float nearClip    = 0.1f;
	public float farClip     = 10000.0f;

	void Awake()
	{
		renderCamera = GetComponentInChildren<Camera>();
	}

	void LateUpdate()
	{
		//Attribute mapping
		if(nearFarEdit)
		{
			renderCamera.nearClipPlane = nearClip;
			renderCamera.farClipPlane  = farClip;
		}
		else
		{
			renderCamera.nearClipPlane = transform.localScale.x;
			renderCamera.farClipPlane  = transform.localScale.y;
		}
        //Mayaカメラの水平画角を取得
		float horizontalAoV        = transform.localScale.z;
        //現在の画面の、横に対する縦の比率を取得
		float aspectRatio          = (float)Screen.height / (float)Screen.width;
        //horizontalAoVを一度タンジェントの値に戻してから画面比を掛ける
		float AoV                  = Mathf.Atan(Mathf.Tan(horizontalAoV / (2.0f*57.29578f))*aspectRatio)*2.0f*57.29578f;

		renderCamera.fieldOfView = AoV;
	}
}

nearFarEditは、nearとfarをUnity上で弄りたいという場合がありそうだったので付けているフラグです。不要であれば消しても問題ありません。

上のScriptに対応している、Maya上のカメラから諸々設定したlocatorを生成するMayaのPythonScriptも紹介します。
先ほど紹介したSlideで紹介されている内容の画角回りを変更しつつ手順をまとめて書いたもので、
新規にロケーターを生成し、入力されたカメラに対してのconstraintからExpressionの生成、Animationのbakeまでやります。
このScriptで生成するExpressionは、horizontalFilmApertureを使用するようになっています

import sys
import maya.cmds as cmds
from string import Template

# Expression用のTemplate
NEAR_CLIP_TEMPLATE = """float $$near_clip_plane;
$$near_clip_plane = ${camera_shape}.nearClipPlane;
${locator}.scaleX = $$near_clip_plane;"""

FAR_CLIP_TEMPLATE = """float $$far_clip_plane;
$$far_clip_plane = ${camera_shape}.farClipPlane;
${locator}.scaleY = $$far_clip_plane;"""

AOV_TEMPLATE = """float $$focal_length;
float $$film_aperture;
float $$AoV;
$$focal_length = ${camera_shape}.focalLength;
$$film_aperture = ${camera_shape}.horizontalFilmAperture;
$$AoV = atan(($$film_aperture*0.5)/($$focal_length*0.03937)) * 2.0 * 57.29578;
${locator}.scaleZ = $$AoV;
"""

TEMPLATE_SOURCES = [NEAR_CLIP_TEMPLATE,
                    FAR_CLIP_TEMPLATE,
                    AOV_TEMPLATE]

def _make_locator_constraint(target, source):
    """targetに設定したtransformに対して、
       sourceがpointとrotateでConstraintし、結果のNodeを返します
       scaleはnearClip、farClip、Aovを詰める為設定しません
    """
    node_list = []
    node_list.append(cmds.pointConstraint(target, source))
    node_list.append(cmds.orientConstraint(target, source))
    return node_list

def _set_locator_expression(camera_shape, locator):
    """TemplateからExpression文字列を生成して、登録します
    @param[in] camera_shape  Expressionで参照するcameraのShape
    @param[in] locator       Expressionを設定するlocator
    """
    for template_src in TEMPLATE_SOURCES:
        template = Template(template_src)
        expression = template.substitute(camera_shape=camera_shape,
                                         locator=locator)
        cmds.expression(s=expression)

def make_unity_camera_locator(camera_transform, start_frame, end_frame):
    """UnityのCameraのAnimationに必要な情報を設定したLocatorを返す
    @param[in] camera_transform Locatorに情報を設定するCameraのtransform名
    @param[in] start_frame      Animationの開始Frame
    @param[in] end_frame        Animationの終了Frame
    @return Unityで必要なCamera情報を持ったLocator
    """
    camera_shape = cmds.listRelatives(camera_transform)[0]
    locator_name = camera_transform + "_locator"
    locator = cmds.spaceLocator(name=locator_name)[0]

    # ConstraintNodeを後の削除用に受け取る
    constraint_nodes = _make_locator_constraint(camera_transform, locator)

    # expression設定
    _set_locator_expression(camera_shape, locator)
    cmds.bakeResults(t=(start_frame, end_frame))

    # 不要になったConstraintNodeを削除
    for node in constraint_nodes:
        cmds.delete(node)
    cmds.select(locator)
    return locator

使う場合はimportするなり、MayaのscriptEditorに貼り付けるなりして、
make_unity_camera_locator関数にlocatorの名前文字列、スタートフレーム、エンドフレームを入れて呼び出してください。
戻り値がlocatorの名前なので、そのままfbx出力するscriptとかに投げて使うと便利かもしれません。

その他細かい点では、Unity上の1は 1m なので、near/farのサイズ(特にnear)には気をつける必要があります。
Maya上でnearを10に設定するとキャラがカメラに寄った時にnearの範囲から手前にはみ出してしまいます。


ModelとAnimationのImport設定について

UnityはFBXをImportする際の処理をScriptでフックすることが出来ます。defaultの設定だと不都合がある場合はここでいじります。
sampleは以下のような感じ。

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Text.RegularExpressions;

public class FBXImportSetting : AssetPostprocessor{
	void OnPreprocessModel()
	{
		var importer = assetImporter as ModelImporter;
		string name = importer.assetPath.ToLower();

		Regex filename_regex = new Regex(".fbx$");
		Match match = filename_regex.Match(name);
        //fbxの場合だけimporterの設定を変更
		if(match.Success)
		{
			//fbxのMaterial読み込み設定をImpoertしたMaterialの名前に変更
			importer.materialName = ModelImporterMaterialName.BasedOnMaterialName;
			//Animationのkeyframe圧縮を行わないよう変更
			importer.animationCompression = ModelImporterAnimationCompression.Off;
		}
	}
}

これを記述したファイルをProject内にEditorディレクトリを作成し、その下に配置するとImportの設定を変える事ができます。
ファイルはFBXImportSetting.csという名前で保存してます

editor

AssetPostprocesserとmodelImporterに関しては以下のドキュメントを参照してください。
AssetPostprocesserのdocument
modelImporterのdocument

例として今回変更しているのはFBXでMaterial付きのModelをImportする際のMaterialの名称設定と、Animationの圧縮設定に関してです。

MaterialのImport設定の変更

Materialは、Maya側で設定したMaterialの名前を使用するように設定しています。これはMaya側で設定したのをそのまま持って来る為です。

ModelをImportすると、Importしたディレクトリの下にMaterialsというディレクトリが出来て、
その中にUnity側の標準Material(正確には標準のShaderが設定されたMaterial)が生成されます。

生成処理は同ディレクトリに既に同名のMaterialがあるとSkipされ、既にあるMaterialが使われるようになるため、
最初に生成されたMaterialでルックを作っておけば、Modelのバージョンが上がって再度Importとなった時に、Materialをアサインしなおす手間が省けます。
Modelを読み込む度にMaterial割り当てていたら面倒ですよね。

文章だけだと分かりづらいので画像も用意しました。
まずはMaya上でdefaultのlambert1を当てた適当なsphereをUnityにImportします。

lambert_1

modelというディレクトリの下にImportしたので、modelの下にMaterialsディレクトリが出来、Lambert1という名称のMaterialが生成されます。

materials_1

次に生成されたlambert1のMaterialのalbedoを弄って真っ赤にします。

albed_red

その後、同様にlambert1のあたったConeをImportします。

lambert_cone

すると、既にlambert1が存在するため、新たにMaterialは生成されず、既にあるMaterialが設定された状態で読み込まれます。
サムネの色はImportした時のMaterialのdiffuseColorのようですね(Unity上ではAlbedoですが)

先程も書きましたが、注意点として同名のMaterialがあるか判定してくれるのは同じディレクトリにImportした場合だけです。
以下は別ディレクトリを作ってConeをImportした時の画像です。othermodelディレクトリの下にもMaterialsが作られています。

otherModel

AnimationのImport設定の変更について

Animationの設定にはAnim. CompressionというAnimationの圧縮に関する設定があります。

anim_compression

ドキュメントはこちら

上記のドキュメントにある通り、圧縮した方がパフォーマンスが上がります。ドキュメントでは非圧縮を推奨していませんが、圧縮を有効にした際にMaya上のAnimationの結果と一致しなくなる場合があったため、映像製作の場合にはOffにするのが良いのではないでしょうか。

ちなみに先ほど紹介したLocator生成のScriptで作ったLocatorのAnimationを圧縮すると、Animationビュー上の表示が以下のようになり、

key_frame_reduction

圧縮設定をOffにすると以下のようになります

key_frame_reduction_off

圧縮した方がパフォーマンスは上がるので、遠景で大量に動くモブのAnimation等に使っていく感じでしょうか。

Projectの解像度の設定について

Importとは関係ないですが、Projectの解像度の設定についても書いておきます。大したことでは無いのですが自分で探した時に分かりづらかったので…

resolution

終わりに

先日開催していたUnite2017TokyoでもUnityを使った映像製作事例が発表されていましたし、
最近はゲームエンジンを使用したリアルタイム映像制作の今後の広がりを感じられて楽しみです。

標準機能だと映像で使うのはちょっと厳しげな印象のあったUnityですが、
2017からtimelineがようやく使えるようになりますし、postEffectのクオリティも上がってきており必要な機能は実装されて来ている印象です。

今回の内容はFBXのImport回りとちょっとした設定の話がメインでしたが、
実際に映像を作るにはモデルを読み込んでアニメーションするだけでなく、レンダリングまでのフローがなければなりません。

僕もまだまだ勉強中ですので、その辺のネタはまたある程度わかってきたら記事にしようかなと思います。

ここまで読んで頂きありがとうございました。何か一つでも皆様のプラスになれば幸いです。


※免責事項※
本記事内で公開している全ての手法・コードの有用性、安全性について、当方は一切の保証を与えるものではありません。
これらのコードを使用したことによって引き起こる直接的、間接的な損害に対し、当方は一切責任を負うものではありません。
自己責任でご使用ください。

Pocket

コメント

コメントはありません

コメントフォーム

コメントは承認制ですので、即時に反映されません。ご了承ください。

*