Skip to content

Instantly share code, notes, and snippets.

@yamahigashi
Created March 16, 2015 08:39
Show Gist options
  • Save yamahigashi/5347b74a06d055e15384 to your computer and use it in GitHub Desktop.
Save yamahigashi/5347b74a06d055e15384 to your computer and use it in GitHub Desktop.
Auto duplicate animation clips at PostprocessModelImport #unity3d
import UnityEngine
import UnityEditor
import System
import System.IO
import System.Text.RegularExpressions
//--------------------------------------------------------------------------//
class Mot:
public name as string
public frame_in as single
public frame_out as single
public loop as bool
public def constructor( _name, _frame_in, _frame_out, _loop ):
self.name = _name
self.frame_in = _frame_in
self.frame_out = _frame_out
self.loop = _loop
public def ToString():
return "Mot: name:${self.name}, in: ${self.frame_in}, out: ${self.frame_out}, loop: ${self.loop}"
/*****************************************************************************
* FBXファイルをインポートした際、自動で
*
* ・インポートオプションの設定
* ・AnimationClip のファイルへの書き出し
*
* をおこないます
* **************************************************************************/
class AnimationAssetProcessor( AssetPostprocessor ):
def OnPostprocessModel( g as GameObject ):
im as ModelImporter = assetImporter
ap as string = assetPath
try:
AssetDatabase.StartAssetEditing()
setImportOptions( im )
setAnimations( im, g, ap )
copyAnimClips( im, g, ap )
AssetDatabase.WriteImportSettingsIfDirty( ap )
EditorApplication.SaveAssets()
AssetDatabase.Refresh()
except e:
Debug.LogError( "make anim error: " + e + "\n" + e.StackTrace )
# StartAssetEditing() をしたら必ずエラーを補足し StopAssetEditing() かけること
# さもないとエディタ無反応になる
AssetDatabase.StopAssetEditing()
def setImportOptions(im as ModelImporter):
im.generateAnimations = ModelImporterGenerateAnimations.GenerateAnimations #, UnityEditor.ModelImporterGenerateAnimations, GenerateAnimations
im.animationType = ModelImporterAnimationType.Generic #, UnityEditor.ModelImporterAnimationType, Generic
#im.bakeIK #, System.Boolean, false
#im.isBakeIKSupported #, System.Boolean, false
#im.isTangentImportSupported #, System.Boolean, true
#im.animationCompression #, UnityEditor.ModelImporterAnimationCompression, KeyframeRuduction
#im.animationRotationError #, System.Single, 0.5
#im.animationPositionError #, System.Single, 0.5
#im.animationScaleError #, System.Single, 0.5
#im.animationWrapMode #, UnityEngine.WrapMode, Default
#x im.animationType #, UnityEditor.ModelImporterAnimationType, Generic
#im.clipAnimations #, UnityEditor.ModelImporterClipAnimation[],
def setAnimations( im as ModelImporter, g as GameObject, ap as string ):
fname as string = Path.GetFileNameWithoutExtension( ap ).ToLower()
// テスト用の設定
mot1 = Mot( "mot1", 0.0, 14.0, false )
mot2 = Mot( "mot2", 15.0, 20.0, true )
mot3 = Mot( "mot3", 21.0, 30.0, false )
motions = ( mot1, mot2, mot3 )
//Debug.Log( "${ap}: アニメーションインポート 分割開始 --------" )
mica as (ModelImporterClipAnimation) = array( ModelImporterClipAnimation, motions.Length )
for i as int, m as Mot in enumerate( motions ):
clipName = fname + "${m.name}"
mica[i] = ModelImporterClipAnimation()
mica[i].takeName = clipName
mica[i].name = clipName
mica[i].firstFrame = m.frame_in
mica[i].lastFrame = m.frame_out
mica[i].loopTime = m.loop
im.clipAnimations = mica
//Debug.Log( "----- ${ap}: アニメーションインポート 分割終了" )
def copyAnimClips( im as ModelImporter, g as GameObject, ap as string ):
// FBXに含まれるアニメーションクリップ(複数)を .anim ファイルに書き出す
// mecanim(Animator) / Animation 両対応
// 必須コンポーネントの存否チェック
animator as Animator = g.GetComponent[of Animator]()
anim as Animation = g.GetComponent[of Animation]()
if anim == null and animator == null:
Debug.LogError( "Animation もしくは Animator Componentが見つからないです" )
#raise NotFoundAnimationOrAnimatorComponent #TODO: later
if animator != null:
_copyAnimatorClips( im, g, ap )
elif anim != null:
_copyAnimationClips( im, g, ap )
// ------------------------------------------------------------------------ //
// //
// ------------------------------------------------------------------------ //
private def _copyAnimationClips( im as ModelImporter, g as GameObject, ap as string ):
// Animation コンポーネント のクリップを複製
for x as AnimationClip in AnimationUtility.GetAnimationClips( g ):
animpath = _animpath( ap, x.name, "" )
_createClip( x, animpath )
private def _copyAnimatorClips( im as ModelImporter, g as GameObject, ap as string ):
// Animator コンポーネント のクリップを複製
// あまり良い方法と思えない・・・
// おそらく Import中メモリにのってる clip 拾いに行ってるんだと思う
all as (AnimationClip) = UnityEngine.Object.FindObjectsOfType( typeof(AnimationClip) )
for a as AnimationClip in all:
if isIgnoreClip( a ):
continue
animpath = _animpath( ap, a.name, "" )
_createClip( a, animpath )
// ------------------------------------------------------------------------ //
private static def _createClip( clip as AnimationClip, path as string ):
# verifying already exsits Anim Clip
asset = AssetDatabase.LoadAssetAtPath( path, AnimationClip )
if asset != null:
dst as AnimationClip = asset
else:
newPath as string = AssetDatabase.GenerateUniqueAssetPath( path )
dst = AnimationClip()
AssetDatabase.CreateAsset( dst, newPath )
EditorUtility.CopySerialized( clip, dst )
dst.name = clip.name
return dst
/* CopySerialized 知らなかった時代の名残
private static def _duplicateClip(src as AnimationClip, dst as AnimationClip):
for crv as AnimationClipCurveData in AnimationUtility.GetAllCurves(src, true):
ecb as EditorCurveBinding = EditorCurveBinding()
ecb.path = crv.path
ecb.type = crv.type
ecb.propertyName = crv.propertyName
AnimationUtility.SetEditorCurve( dst, ecb, crv.curve )
return dst
*/
// いい感じに anim ファイルの名前、パスを決定する
private static def _animpath(path as string, fname as string, postfix as string) as string:
folder as string = Path.GetDirectoryName(path)
if not postfix == "":
return Path.Combine(folder, "${fname}_${postfix}.anim")
else:
return Path.Combine(folder, "${fname}.anim")
// FBXをテキストとして読み、最終フレームを取得する
// バイナリfbx?そんなもの投げ捨てろ
private static def _getFBXFrameOut(path as string) as int:
st as StreamReader = StreamReader(path)
t as string = st.ReadToEnd()
st.Close()
re = Regex("KeyCount: ([0-9]+)", RegexOptions.Multiline)
m = re.Match(t)
if not m.Success:
return -1
res = m.Groups[1].Value
return int.Parse(res) - 1
private static def isIgnoreClip( c as AnimationClip ) as bool:
# インポート、複製する必要のあるクリップかどうか名前で判定
# __preview__ 外し
return true if string.IsNullOrEmpty( c.name )
return true if "__preview__" in c.name
return false
/* 全 ModelImporter のプロパティ列挙*/
#im.generateMaterials #, UnityEditor.ModelImporterGenerateMaterials, PerTexture
#im.importMaterials #, System.Boolean, true
#im.materialName #, UnityEditor.ModelImporterMaterialName, BasedOnTextureName
#im.materialSearch #, UnityEditor.ModelImporterMaterialSearch, RecursiveUp
#im.globalScale #, System.Single, 0
#im.isUseFileUnitsSupported #, System.Boolean, false
#im.useFileUnits #, System.Boolean, true
#im.addCollider #, System.Boolean, false
#im.normalSmoothingAngle #, System.Single, 60
#im.splitTangentsAcrossSeams #, System.Boolean, true
#im.swapUVChannels #, System.Boolean, true
#im.generateSecondaryUV #, System.Boolean, false
#im.secondaryUVAngleDistortion #, System.Single, 8
#im.secondaryUVAreaDistortion #, System.Single, 15
#im.secondaryUVHardAngle #, System.Single, 88
#im.secondaryUVPackMargin #, System.Single, 4
#im.generateAnimations #, UnityEditor.ModelImporterGenerateAnimations, GenerateAnimations
#im.transformPaths #, System.String[]
#im.referencedClips #, System.String[]
#im.isReadable #, System.Boolean, true
#im.optimizeMesh #, System.Boolean, true
#im.normalImportMode #, UnityEditor.ModelImporterTangentSpaceMode, Import
#im.tangentImportMode #, UnityEditor.ModelImporterTangentSpaceMode, Calculate
#im.bakeIK #, System.Boolean, false
#im.isBakeIKSupported #, System.Boolean, false
#im.isTangentImportSupported #, System.Boolean, true
#im.meshCompression #, UnityEditor.ModelImporterMeshCompression, Off
#im.animationCompression #, UnityEditor.ModelImporterAnimationCompression, KeyframeRuduction
#im.animationRotationError #, System.Single, 0.5
#im.animationPositionError #, System.Single, 0.5
#im.animationScaleError #, System.Single, 0.5
#im.animationWrapMode #, UnityEngine.WrapMode, Default
#im.animationType #, UnityEditor.ModelImporterAnimationType, Generic
#im.clipAnimations #, UnityEditor.ModelImporterClipAnimation[],
/* 以下は変更する必要ない
im.assetPath #, System.String,
im.assetTimeStamp #, System.UInt64,
im.userData #, System.String
im.name #, System.String
im.hideFlags #, UnityEngine.HideFlags, 0
*/
/* 以下はobsolute
#im.importedTakeInfos #, UnityEditor.TakeInfo[],
#im.reduceKeyframes #, System.Boolean
#im.splitAnimations #, System.Boolean
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment