Kevin Geschrieben 30. April 2012 Melden Share Geschrieben 30. April 2012 Hiho, ich hatte vor ein paar Tagen noch was nützliches entwickelt, das ich mit der Community teilen möchte. Was ist es? Wenn man sich animierte 3D Modelle lädt oder kauft, dann kommen diese häufig mit dutzenden von Animationen. D.h. man müsste beim importieren in den Importsettings erstmal jede Animation einzeln "heraussplitten", sofern das 3D Model nicht als Unity Package vorliegt. Das kann enorm lästig sein, besonders wenn ein 3D Model mal mehr als 15 Animationen enthält! Glücklicherweise kommen die meisten der 3D Modelle zumindest mit einer Liste der Animationen, die z.B. so aussehen kann: 000 - 005 t_pose 010 - 050 draw 050 - 060 Single_Shot 060 - 075 Triple_Shot 075 - 100 Multiple_Shot 100 - 115 Zoom_In 115 - 120 Z_Single_Shot 120 - 135 Z_Triple_Shot 135 - 160 Z_Multiple_Shot 160 - 175 Zoom_Out 175 - 275 Reload 275 - 375 Idle 375 - 405 Walk 410 - 435 Run 440 - 470 Jump 470 - 480 Hide 485 - 540 Zoom_in_2 540 - 640 Zoom_idle 640 - 680 Zoom_out Das Alles in Unity zu übertragen kostet unnötig Zeit, daher habe ich mir gedacht, dass ich ein Skript schreibe was dies automatisiert macht. Wie installiert man es? Der Code findet sich am Ende dieses Beitrages, dieser muss in ein neues C# Skript im Editor Ordner gepackt werden! Alle Skripts, die das GUI des Editors beinflussen oder den Editor auf andere Art und Weise beeinflussen müssen dort hinein. Sobald dies geschehen ist, sollte es in der Menüleiste erscheinen. Evtl. muss man den Editor nochmal neustarten. Wie funktioniert es? Das Skript ist eine Editor Extension, wird also in der Menüleiste von Unity erscheinen. Hier die Schritte zum erfolgreichen ausführen des Skripts: Ein 3D Model im Project View auswählen, dessen Animation Split Settings aus einer Text Datei gelesen werden sollen. Das Skript starten, standardmäßig ist es in der Menüleiste unter "My Extensions/Load Animation Splits from file" zu finden. Nun wird sich ein Dialog öffnen, der auffordert eine .txt Datei auszuwählen. In dieser Datei muss sich die Liste der Animationen finden. Der Parser liest diese dann Zeile für Zeile, wobei fast egal ist wie diese Zeilene aufgebaut sind. Die einzige Bedingung ist, dass die Reihenfolge entweder "Name-FrameStart-FrameEnd" oder "FrameStart-FrameEnd-Name" sein muss. Was zwischen zwei solcher Textblöcke (Name, FrameStart, FrameEnd) ist, ist egal. Der Parser ist so geschrieben, dass er möglichst dynamisch ist. Es kann nun dazu kommen, dass dieser Dialog angezeigt wird: Dies liegt an einem fehlenden Feature von Unity, wofür ich noch keinen geeigneten Workaround gefunden habe. Man muss den Dialog einfach oben rechts in der Ecke schließen und darf auf keinen Fall Apply drücken! Nun sollten die Animationen innterhalb des Model Importers eingestellt sein: Wie immer wäre es schön, wenn ihr Bugs melden würdet. Besonders wenn eine bestimmte .txt Datei mit den Animationen nicht geparst werden konnte. Das Ziel ist es nämlich, dynamisch jede beliebige Animation Split Datei parsen zu können! Der Code: using System; using System.Collections.Generic; using System.IO; using UnityEditor; using Object = UnityEngine.Object; public static class LoadSplitAnimationText { /// <summary>Removes all invalid characters at the beginning of the text (e.g. whitespace).</summary> static string RemoveStartCharacters(string text) { int count = 0; foreach(char c in text) { if (!char.IsLetter(c) && !char.IsNumber(c) && c != '_') count++; else break; } return text.Substring(count); } static ModelImporterClipAnimation ParseLine(string text) { //Two cases, either the text starts with the numbers or it starts with the //name. //Remove all the invalid stuff at the beginning... text = RemoveStartCharacters(text); string firstNumber = ""; string secondNumber = ""; string name = ""; //Does it start with a number? if(char.IsNumber(text[0])) { int index = 0; //Read the first number... while(char.IsNumber(text[index])) { firstNumber += text[index]; index++; } //Remove all the stuff between first and second number text = RemoveStartCharacters(text.Substring(index)); index = 0; //Read the second number... while (char.IsNumber(text[index])) { secondNumber += text[index]; index++; } //Remove all the stuff between second number and name text = RemoveStartCharacters(text.Substring(index)); index = 0; //Read the name while (index <= text.Length - 1 && (char.IsLetter(text[index]) || char.IsWhiteSpace(text[index]) || text[index] == '_' || char.IsNumber(text[index]))) { if (!char.IsWhiteSpace(text[index])) name += text[index]; index++; } } //Does it start with a letter? else { int index = 0; //Read the name while (char.IsLetter(text[index]) || char.IsWhiteSpace(text[index]) || char.IsNumber(text[index]) || text[index] == '_') { //If there was a whitespace and right afterwards a number, stop creating the name (the digit is the first digit of the //animation start number) if(index > 0 && char.IsWhiteSpace(text[index-1]) && char.IsNumber(text[index])) break; if (!char.IsWhiteSpace(text[index])) name += text[index]; index++; } //Remove all the stuff between name and first number text = RemoveStartCharacters(text.Substring(index)); index = 0; //Read first number... while (char.IsNumber(text[index])) { firstNumber += text[index]; index++; } //Remove all the stuff between first and second number text = RemoveStartCharacters(text.Substring(index)); index = 0; //Read the second number... while (index <= text.Length - 1 && char.IsNumber(text[index])) { secondNumber += text[index]; index++; } } int firstIntNumber, secondIntNumber; //Try converting the strings to floats... if(!Int32.TryParse(firstNumber, out firstIntNumber)) { EditorUtility.DisplayDialog("Error", string.Format("Error while parsing the animation frame start: '{0}'!", firstNumber), "Close"); return null; } if (!Int32.TryParse(secondNumber, out secondIntNumber)) { EditorUtility.DisplayDialog("Error", string.Format("Error while parsing the animation frame ende: '{0}'!", secondNumber), "Close"); return null; } //...and return the result return new ModelImporterClipAnimation { firstFrame = firstIntNumber, lastFrame = secondIntNumber, name = name }; } static bool IsLineValid(string line) { //Check for any valid character... foreach(char c in line) { if (char.IsNumber(c) || char.IsNumber(c)) return true; } return false; } [MenuItem("My Extensions/Load Animation Splits from file")] static void CreateWizard() { //Get the selected object in the project view. Object selectedObj = Selection.activeObject; //Create the importer... string assetPath = AssetDatabase.GetAssetPath(selectedObj); AssetImporter assetImporter = AssetImporter.GetAtPath(assetPath); if (assetImporter == null || !(assetImporter is ModelImporter)) { EditorUtility.DisplayDialog("Error", "The selected file is no model! Only animations of models can be split.", "Close"); return; } ModelImporter importer = assetImporter as ModelImporter; //Show open file dialog to user, to let him choose the txt file string file = EditorUtility.OpenFilePanel("Select the animation list text file!", "", "txt"); //Check if the file is valid if (string.IsNullOrEmpty(file) || !File.Exists(file)) { EditorUtility.DisplayDialog("Error", "No file selected, or the file does not exist!", "Close"); return; } //This List will contain all the animations. List<ModelImporterClipAnimation> anims = new List<ModelImporterClipAnimation>(); //Open the stream and begin reading using(FileStream stream = new FileStream(file, FileMode.Open)) { using(StreamReader reader = new StreamReader(stream)) { //Stores the content of the current line. string content = reader.ReadLine(); //If the first line is empty throw an error if(string.IsNullOrEmpty(content)) { EditorUtility.DisplayDialog("Error", "The selected text file is empty!", "Close"); return; } //Loop while the current line is valid. while(!string.IsNullOrEmpty(content)) { if(!IsLineValid(content)) { content = reader.ReadLine(); continue; } //Parse the line... ModelImporterClipAnimation desc = ParseLine(content); if (desc == null) return; //Something went wrong. //Add the animation description to the list anims.Add(desc); //Read next line. content = reader.ReadLine(); } } } //anims contains now all the animation information... importer.splitAnimations = true; //Assing the filled list importer.clipAnimations = anims.ToArray(); //And finally reimport the asset. AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); //Hack to disable the "Unapplied Import Settings" Bug, see http://answers.unity3d.com/questions/14246/editor-class-texture-importer-apply-import-setting.html //Note: Doesn't always work! Selection.objects = new Object[0]; } } P.S.: Wieso formatiert sich der denn nicht anständig? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.