Last active
July 17, 2018 20:39
-
-
Save FleshMobProductions/a5497f2e705a22b2ce4e4a0f0bcf612a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor; | |
using System.IO; | |
using System; | |
namespace TF2018.UI | |
{ | |
/// <summary> | |
/// Will copy the import data from a reference model to all animations in a specific folder | |
///- files have to be of type fbx | |
///- The importer will iterate over every animation that has the name "SmashAnimations" in the path, so it is recommended to have a separate folder for that. | |
///- The importer will search a reference model in the same folder as the currently imported animation asset.The reference model has to have "MainAvatar" in the name | |
///- The referenced avatar definition has to be in a model file with the name "ModelReference" in it. this model is excluded from the import processing. | |
///- In your "MainAvatar" animation/model, set the rig to type "Humanoid", check "Copy from other Avatar" and select as source the avatar from the "ModelReference" model. | |
///- all relevant properties of the reference model importer are copied to the importer of the animation | |
///- some animation clip settings from the first animation clip in the reference model are copied to all animation clips of the other animations | |
/// | |
/// Problems: | |
/// Script execution throws errors in the Editor: Assertion failed: TLS Allocator ALLOC_TEMP_THREAD, underlying allocator ALLOC_TEMP_THREAD has unfreed allocations, size 454 | |
/// changing the name of the importer probably has no effect, so in future versions I'd need another way to check if an animation was already processed | |
/// </summary> | |
public class UnityAnimationSettingCopyPostprocessor : AssetPostprocessor | |
{ | |
private static readonly string requiredAssetPathContent = "smashanimations"; | |
private static readonly string mainAvatarContent = "mainavatar"; | |
private static readonly string excludedModelname = "modelreference"; | |
private static readonly string doneAnimationSubfix = "_done"; | |
void OnPreprocessModel() | |
{ | |
//OnPreprocesModelOrAnimation(); | |
} | |
/// <summary> | |
/// Apply settings to the asset importer here! | |
/// </summary> | |
void OnPreprocessAnimation() | |
{ | |
OnPreprocesModelOrAnimation(); | |
} | |
/// <summary> | |
/// Processes fbx files, checks if they are in a path whose lower case conversion contains "smashanimations" | |
/// and edits all ModelImporters for them, except for files with the name "modelreference" or "mainavatar" in their lower case paths | |
/// </summary> | |
private void OnPreprocesModelOrAnimation() | |
{ | |
string animationPath = assetPath; | |
try | |
{ | |
string animationPathLower = animationPath.ToLower(); | |
Debug.Log("Process animation " + animationPath); | |
//don't include the reference model | |
if (animationPathLower.Contains(".fbx") && animationPathLower.Contains(requiredAssetPathContent) && !IsModelPathMainAvatar(animationPath) && !animationPathLower.Contains(excludedModelname)) | |
{ | |
ModelImporter importer = (ModelImporter)assetImporter; | |
if (importer.name.EndsWith(doneAnimationSubfix)) | |
{ | |
return; | |
} | |
string sourceModelPath = GetMainAvatarModelPathForFile(animationPath); | |
if (string.IsNullOrEmpty(sourceModelPath)) | |
{ | |
Debug.LogError(string.Format("SmashFbxAnimationImporter: no reference avatar fbx found for animation at path {0}", animationPath)); | |
return; | |
} | |
ModelImporter referenceImporter = AssetImporter.GetAtPath(sourceModelPath) as ModelImporter; | |
if (referenceImporter == null) | |
{ | |
Debug.LogError(string.Format("SmashFbxAnimationImporter: reference model importer for path {0} is null", animationPath)); | |
return; | |
} | |
CopyModelImporterSettings(importer, referenceImporter); | |
//after everything is done, we can mark our importer in a way: | |
importer.name = importer.name + doneAnimationSubfix; | |
//importer.SaveAndReimport(); //this would cause an endless loop, importer is saved automatically | |
AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError("SmashAnimationPostprocessor: something went wrong while processing animation " + animationPath + ". Error: " + e.ToString()); | |
} | |
} | |
/// <summary> | |
/// Copies important settings from the referenceImporter to the importer | |
/// Animation clip settings are copied from the first clip in the referenceImporter and applied to all clips in the importer | |
/// </summary> | |
/// <param name="importer">ModelImporter attributes are copied to</param> | |
/// <param name="referenceImporter">ModelImporter attributes are copied from</param> | |
private void CopyModelImporterSettings(ModelImporter importer, ModelImporter referenceImporter) | |
{ | |
//Model tab | |
importer.globalScale = referenceImporter.globalScale; | |
importer.useFileScale = referenceImporter.useFileScale; | |
importer.meshCompression = referenceImporter.meshCompression; | |
importer.isReadable = referenceImporter.isReadable; | |
importer.optimizeMesh = referenceImporter.optimizeMesh; | |
importer.importBlendShapes = referenceImporter.importBlendShapes; | |
importer.keepQuads = referenceImporter.keepQuads; | |
importer.indexFormat = referenceImporter.indexFormat; | |
importer.weldVertices = referenceImporter.weldVertices; | |
importer.importVisibility = referenceImporter.importVisibility; | |
importer.importCameras = referenceImporter.importCameras; | |
importer.importLights = referenceImporter.importLights; | |
importer.preserveHierarchy = referenceImporter.preserveHierarchy; | |
importer.swapUVChannels = referenceImporter.swapUVChannels; | |
importer.generateSecondaryUV = referenceImporter.generateSecondaryUV; | |
importer.importNormals = referenceImporter.importNormals; | |
importer.normalCalculationMode = referenceImporter.normalCalculationMode; | |
importer.normalSmoothingAngle = referenceImporter.normalSmoothingAngle; | |
importer.importTangents = referenceImporter.importTangents; | |
//rig tab | |
importer.animationType = referenceImporter.animationType; | |
importer.sourceAvatar = referenceImporter.sourceAvatar; | |
importer.optimizeGameObjects = referenceImporter.optimizeGameObjects; | |
//importer.SaveAndReimport(); //endless loop? Yes, endless loop | |
//materials tab | |
importer.importMaterials = referenceImporter.importMaterials; | |
importer.materialLocation = referenceImporter.materialLocation; | |
importer.materialName = referenceImporter.materialName; | |
importer.materialLocation = referenceImporter.materialLocation; | |
//animation tab | |
importer.importConstraints = referenceImporter.importConstraints; | |
importer.importAnimation = referenceImporter.importAnimation; | |
importer.animationCompression = referenceImporter.animationCompression; | |
importer.animationRotationError = referenceImporter.animationRotationError; | |
importer.animationPositionError = referenceImporter.animationPositionError; | |
importer.animationScaleError = referenceImporter.animationScaleError; | |
importer.importAnimatedCustomProperties = referenceImporter.importAnimatedCustomProperties; | |
var referenceClipAnimations = referenceImporter.clipAnimations; | |
Debug.Log(string.Format("referenceImporter.clipAnimations.Length {0}, is null: {1}", referenceClipAnimations != null ? referenceClipAnimations.Length : 0, referenceClipAnimations == null)); | |
if (referenceClipAnimations != null && referenceClipAnimations.Length > 0) | |
{ | |
var referenceClip = referenceClipAnimations[0]; | |
//https://answers.unity.com/questions/724415/change-animationclip-settings-during-import.html | |
//changing the clips can be done by editing the default animations and setting it back to the clipAnimations | |
var defaultClipAnimations = importer.defaultClipAnimations; | |
foreach (var clipAnimation in defaultClipAnimations) | |
{ | |
clipAnimation.hasAdditiveReferencePose = referenceClip.hasAdditiveReferencePose; | |
if (referenceClip.hasAdditiveReferencePose) | |
{ | |
clipAnimation.additiveReferencePoseFrame = referenceClip.additiveReferencePoseFrame; | |
} | |
clipAnimation.maskType = referenceClip.maskType; | |
clipAnimation.maskSource = referenceClip.maskSource; | |
clipAnimation.keepOriginalOrientation = referenceClip.keepOriginalOrientation; | |
clipAnimation.keepOriginalPositionXZ = referenceClip.keepOriginalPositionXZ; | |
clipAnimation.keepOriginalPositionY = referenceClip.keepOriginalPositionY; | |
clipAnimation.lockRootRotation = referenceClip.lockRootRotation; | |
clipAnimation.lockRootPositionXZ = referenceClip.lockRootPositionXZ; | |
clipAnimation.lockRootHeightY = referenceClip.lockRootHeightY; | |
clipAnimation.mirror = referenceClip.mirror; | |
clipAnimation.wrapMode = referenceClip.wrapMode; | |
} | |
importer.clipAnimations = defaultClipAnimations; | |
} | |
} | |
private string GetMainAvatarModelPathForFile(string assetPath) | |
{ | |
string directoryPath = Path.GetDirectoryName(assetPath); //Get the directory path, excluding the file | |
string[] filePaths = Directory.GetFiles(directoryPath, "*.fbx", SearchOption.AllDirectories); | |
foreach (string path in filePaths) | |
{ | |
string fileName = Path.GetFileName(path); | |
if (IsModelPathMainAvatar(fileName)) | |
{ | |
//main avatar found. | |
return path; | |
} | |
} | |
return null; | |
} | |
private bool IsModelPathMainAvatar(string fileName) | |
{ | |
return fileName.ToLower().Replace("_", "").Contains(mainAvatarContent); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment