How to create .anim file from .fbx file in Unity? - unity3d

I am new in using Unity. In my game, models and animations are exported from 3DMAX as .fbx files, animations are clipped in Unity, but there's no .anim files generated, I need separated .anim files because the following code will not work even I have clipped animation "run":
var clip = animation["run"];
Can someone help me? thanks in advance.

I finally found the answer, pressing CTRL+D on animation clip in .fbx file will create a separate .anim file, what a strange operation!

I wrote a script to do this easily
using System.IO;
using UnityEditor;
using UnityEngine;
public class AnimationExtractor: MonoBehaviour
{
[MenuItem("Assets/Extract Animation")]
private static void ExtractAnimation()
{
foreach (var obj in Selection.objects)
{
var fbx = AssetDatabase.GetAssetPath(obj);
var directory = Path.GetDirectoryName(fbx);
CreateAnim(fbx, directory);
}
}
static void CreateAnim(string fbx, string target)
{
var fileName = Path.GetFileNameWithoutExtension(fbx);
var filePath = $"{target}/{fileName}.anim";
AnimationClip src = AssetDatabase.LoadAssetAtPath<AnimationClip>(fbx);
AnimationClip temp = new AnimationClip();
EditorUtility.CopySerialized(src, temp);
AssetDatabase.CreateAsset(temp, filePath);
AssetDatabase.SaveAssets();
}
}

You have to set the animations up in the importing. Select the .fbx model in Unity and go to Animations tab. There you have to define the clips. The .anim files will be generated under the model.
If you do not see the clips inside the animations tab, change the "Animation Type" under Rig to Legacy.

Related

Create an animation from obj/gtlf files, import in Unity

I have 350 gtlf files. Originally files are in OBJ format (350 files + audio) and I have converted them into separate gtlf with obj2gtlf.
How can I create an animated gtlf file with all 350 keyframes? Or how can I create an animation in Unity using these 350 obj/gltf files?
I want to import/create a animation in Unity using these files and run a Hololens Application. By placing this animation I want to see a volumetric video playing inside my Hololens Application.
But I can not make a sequence using a gtlf-transform, it seems to take only one gtlf file (instead of all 350) and detach the texture into separate jpg-file. I can not create animation with Timeline in Unity.
Can anyone help me? I am new to Unity and can not find a solution
PS: Bone animation is not a solution. My files are represent a real man that is captured with a volumetric video method. He stays, speaks, smiles and moves his hand. I need to import a 3d animated model into Unity to use it my master thesis. So I did not animated that model, I have got a captured video as 350 obj files + meshes as jpg and audio. I can import a single 3d model as obj file but I can not find a way to import a animated volumetric video.
You seem to have a very specific use case where indeed you need to have these as separate 3D models and textures / materials.
As said the simplest but probably not most performant way would be to simply have all these 3D objects in your scene and only set one of them active at a time.
Something like e.g.
public class ModelFrames : MonoBehaviour
{
// You drag these all in once via the Inspector
public GameObject[] models;
private int currentIndex = -1;
private void Awake()
{
foreach(var model in models)
{
model.SetActive(false);
}
}
private void Update()
{
if(currentIndex >= 0)
{
models[currentIndex].SetActive(false);
}
currentIndex = (currentIndex + 1) % models.Length;
models[currentIndex].SetActive(true);
}
}
If you don't want to switch every frame you could also add some modifier and do
public class ModelFrames : MonoBehaviour
{
// You drag these all in once via the Inspector
public GameObject[] models;
public int targetFramesPerSecond = 60;
private void Awake()
{
foreach(var model in models)
{
model.SetActive(false);
}
}
private IEnumerator Start()
{
var currentIndex = 0;
models[currentIndex].SetActive(true);
while(true)
{
yield return new WaitForSeconds(1f / targetFramesPerSecond);
models[currentIndex].SetActive(false);
currentIndex = (currentIndex + 1) % models.Length;
models[currentIndex].SetActive(true);
}
}
}

Can you export sliced sprites (PNG images) in Unity?

So I have a Sprite 2d and UI in unity. (Png image) That contains many small images like buttons. So I slice them and I can use them individualy in unity. But the thing is that I want to export each of the png Images that I got while slicing them for another use. So can I do that? And have them as separate pngs?
And what I want is these Images:
To export them in my (lets say) desktop as individual pngs.
Thank you!
I had a need for this too, I ended up solving it with a simple editor script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ExportSubSprites : Editor {
[MenuItem("Assets/Export Sub-Sprites")]
public static void DoExportSubSprites() {
var folder = EditorUtility.OpenFolderPanel("Export subsprites into what folder?", "", "");
foreach (var obj in Selection.objects) {
var sprite = obj as Sprite;
if (sprite == null) continue;
var extracted = ExtractAndName(sprite);
SaveSubSprite(extracted, folder);
}
}
[MenuItem("Assets/Export Sub-Sprites", true)]
private static bool CanExportSubSprites()
{
return Selection.activeObject is Sprite;
}
// Since a sprite may exist anywhere on a tex2d, this will crop out the sprite's claimed region and return a new, cropped, tex2d.
private static Texture2D ExtractAndName(Sprite sprite) {
var output = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
var r = sprite.textureRect;
var pixels = sprite.texture.GetPixels((int)r.x, (int)r.y, (int)r.width, (int)r.height);
output.SetPixels(pixels);
output.Apply();
output.name = sprite.texture.name + " " + sprite.name;
return output;
}
private static void SaveSubSprite(Texture2D tex, string saveToDirectory) {
if (!System.IO.Directory.Exists(saveToDirectory)) System.IO.Directory.CreateDirectory(saveToDirectory);
System.IO.File.WriteAllBytes(System.IO.Path.Combine(saveToDirectory, tex.name + ".png"), tex.EncodeToPNG());
}
}
First, drop this into a script file named EditorSubSprites.cs and make sure that it resides in an Editor folder. If you have no editor folder you can simply create at /Assets/Editor/
To use, expand a texture asset's sprites, and select as many of the sprites as you wish to export. Right-click and select "Export SubSprites".
Use Photoshop, Crop it, a Lot of Cut and Paste is going to happen save as PNG.
Import it to unity inside the folder, i like your designs. Also Watch Brackeys Tutorial on Youtube, https://www.youtube.com/user/Brackeys , he save me from my school years.
(edit : i recommend Photoshop because its the only thing i know.)

Load binary data from the resources folder [duplicate]

I have am developing a HoloLens project that needs to reference .txt files. I have the files stored in Unity's 'Resources' folder and have them working perfectly fine (when run via Unity):
string basePath = Application.dataPath;
string metadataPath = String.Format(#"\Resources\...\metadata.txt", list);
// If metadata exists, set title and introduction strings.
if (File.Exists(basePath + metadataPath))
{
using (StreamReader sr = new StreamReader(new FileStream(basePath + metadataPath, FileMode.Open)))
{
...
}
}
However, when building the program for HoloLens deployment, I am able to run the code but it doesn't work. None of the resources show up and when examining the HoloLens Visual Studio solution (created by selecting build in Unity), I don't even see a resources or assets folder. I am wondering if I am doing something wrong or if there was a special way to deal with such resources.
Also with image and sound files...
foreach (string str in im)
{
spriteList.Add(Resources.Load<Sprite>(str));
}
The string 'str' is valid; it works absolutely fine with Unity. However, again, it's not loading anything when running through the HoloLens.
You can't read the Resources directory with the StreamReader or the File class. You must use Resources.Load.
1.The path is relative to any Resources folder inside the Assets folder of your project.
2.Do not include the file extension names such as .txt, .png, .mp3 in the path parameter.
3.Use forward slashes instead of back slashes when you have another folder inside the Resources folder. backslashes won't work.
Text files:
TextAsset txtAsset = (TextAsset)Resources.Load("textfile", typeof(TextAsset));
string tileFile = txtAsset.text;
Supported TextAsset formats:
txt .html .htm .xml .bytes .json .csv .yaml .fnt
Sound files:
AudioClip audio = Resources.Load("soundFile", typeof(AudioClip)) as AudioClip;
Image files:
Texture2D texture = Resources.Load("textureFile", typeof(Texture2D)) as Texture2D;
Sprites - Single:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Single.
Sprite sprite = Resources.Load("spriteFile", typeof(Sprite)) as Sprite;
Sprites - Multiple:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Multiple.
Sprite[] sprite = Resources.LoadAll<Sprite>("spriteFile") as Sprite[];
Video files (Unity >= 5.6):
VideoClip video = Resources.Load("videoFile", typeof(VideoClip)) as VideoClip;
GameObject Prefab:
GameObject prefab = Resources.Load("shipPrefab", typeof(GameObject)) as GameObject;
3D Mesh (such as FBX files)
Mesh model = Resources.Load("yourModelFileName", typeof(Mesh)) as Mesh;
3D Mesh (from GameObject Prefab)
MeshFilter modelFromGameObject = Resources.Load("yourGameObject", typeof(MeshFilter)) as MeshFilter;
Mesh loadedMesh = modelFromGameObject.sharedMesh; //Or design.mesh
3D Model (as GameObject)
GameObject loadedObj = Resources.Load("yourGameObject") as GameObject;
//MeshFilter meshFilter = loadedObj.GetComponent<MeshFilter>();
//Mesh loadedMesh = meshFilter.sharedMesh;
GameObject object1 = Instantiate(loadedObj) as GameObject;
Accessing files in a sub-folder:
For example, if you have a shoot.mp3 file which is in a sub-folder called "Sound" that is placed in the Resources folder, you use the forward slash:
AudioClip audio = Resources.Load("Sound/shoot", typeof(AudioClip)) as AudioClip;
Asynchronous Loading:
IEnumerator loadFromResourcesFolder()
{
//Request data to be loaded
ResourceRequest loadAsync = Resources.LoadAsync("shipPrefab", typeof(GameObject));
//Wait till we are done loading
while (!loadAsync.isDone)
{
Debug.Log("Load Progress: " + loadAsync.progress);
yield return null;
}
//Get the loaded data
GameObject prefab = loadAsync.asset as GameObject;
}
To use: StartCoroutine(loadFromResourcesFolder());
If you want to load text file from resource please do not specify file extension
just simply follow the below given code
private void Start()
{
TextAsset t = Resources.Load<TextAsset>("textFileName");
List<string> lines = new List<string>(t.text.Split('\n'));
foreach (string line in lines)
{
Debug.Log(line);
}
}
debug.Log can print all the data that are available in text file
You can try to store your text files in streamingsasset folder. It works fine in my project

JSONReaderException when deploying on hololens [duplicate]

I have am developing a HoloLens project that needs to reference .txt files. I have the files stored in Unity's 'Resources' folder and have them working perfectly fine (when run via Unity):
string basePath = Application.dataPath;
string metadataPath = String.Format(#"\Resources\...\metadata.txt", list);
// If metadata exists, set title and introduction strings.
if (File.Exists(basePath + metadataPath))
{
using (StreamReader sr = new StreamReader(new FileStream(basePath + metadataPath, FileMode.Open)))
{
...
}
}
However, when building the program for HoloLens deployment, I am able to run the code but it doesn't work. None of the resources show up and when examining the HoloLens Visual Studio solution (created by selecting build in Unity), I don't even see a resources or assets folder. I am wondering if I am doing something wrong or if there was a special way to deal with such resources.
Also with image and sound files...
foreach (string str in im)
{
spriteList.Add(Resources.Load<Sprite>(str));
}
The string 'str' is valid; it works absolutely fine with Unity. However, again, it's not loading anything when running through the HoloLens.
You can't read the Resources directory with the StreamReader or the File class. You must use Resources.Load.
1.The path is relative to any Resources folder inside the Assets folder of your project.
2.Do not include the file extension names such as .txt, .png, .mp3 in the path parameter.
3.Use forward slashes instead of back slashes when you have another folder inside the Resources folder. backslashes won't work.
Text files:
TextAsset txtAsset = (TextAsset)Resources.Load("textfile", typeof(TextAsset));
string tileFile = txtAsset.text;
Supported TextAsset formats:
txt .html .htm .xml .bytes .json .csv .yaml .fnt
Sound files:
AudioClip audio = Resources.Load("soundFile", typeof(AudioClip)) as AudioClip;
Image files:
Texture2D texture = Resources.Load("textureFile", typeof(Texture2D)) as Texture2D;
Sprites - Single:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Single.
Sprite sprite = Resources.Load("spriteFile", typeof(Sprite)) as Sprite;
Sprites - Multiple:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Multiple.
Sprite[] sprite = Resources.LoadAll<Sprite>("spriteFile") as Sprite[];
Video files (Unity >= 5.6):
VideoClip video = Resources.Load("videoFile", typeof(VideoClip)) as VideoClip;
GameObject Prefab:
GameObject prefab = Resources.Load("shipPrefab", typeof(GameObject)) as GameObject;
3D Mesh (such as FBX files)
Mesh model = Resources.Load("yourModelFileName", typeof(Mesh)) as Mesh;
3D Mesh (from GameObject Prefab)
MeshFilter modelFromGameObject = Resources.Load("yourGameObject", typeof(MeshFilter)) as MeshFilter;
Mesh loadedMesh = modelFromGameObject.sharedMesh; //Or design.mesh
3D Model (as GameObject)
GameObject loadedObj = Resources.Load("yourGameObject") as GameObject;
//MeshFilter meshFilter = loadedObj.GetComponent<MeshFilter>();
//Mesh loadedMesh = meshFilter.sharedMesh;
GameObject object1 = Instantiate(loadedObj) as GameObject;
Accessing files in a sub-folder:
For example, if you have a shoot.mp3 file which is in a sub-folder called "Sound" that is placed in the Resources folder, you use the forward slash:
AudioClip audio = Resources.Load("Sound/shoot", typeof(AudioClip)) as AudioClip;
Asynchronous Loading:
IEnumerator loadFromResourcesFolder()
{
//Request data to be loaded
ResourceRequest loadAsync = Resources.LoadAsync("shipPrefab", typeof(GameObject));
//Wait till we are done loading
while (!loadAsync.isDone)
{
Debug.Log("Load Progress: " + loadAsync.progress);
yield return null;
}
//Get the loaded data
GameObject prefab = loadAsync.asset as GameObject;
}
To use: StartCoroutine(loadFromResourcesFolder());
If you want to load text file from resource please do not specify file extension
just simply follow the below given code
private void Start()
{
TextAsset t = Resources.Load<TextAsset>("textFileName");
List<string> lines = new List<string>(t.text.Split('\n'));
foreach (string line in lines)
{
Debug.Log(line);
}
}
debug.Log can print all the data that are available in text file
You can try to store your text files in streamingsasset folder. It works fine in my project

How can I add a scriptable tile at runtime to a Unity Tilemap?

I'm trying to add one of my scriptable tiles to my Unity Tilemap during runtime. I can paint the tile in the editor and everything looks fine but I would like to add it during runtime.
I tried instantiating the ScriptableObject asset itself, but it does not have the correct sprites it needs that the generated tile asset has in the editor. Also, I don't believe I should be instantiating the ScriptableObject asset for each tile since one asset is meant to be shared for all of the same tiles on the map.
The Tilemap API provides a way to add a tile, but no instructions or example of how to create the tile.
This is kinda off the top of my head, but I was messing around with something similar yesterday, instantiating a tile on click.
Vector3Int tilePos = map.WorldToCell(mousePos);
YourTileClass tileInstance = ScriptableObject.CreateInstance<YourTileClass>();
Texture2D tex = Resources.Load<Texture2D>("tileTexture") as Texture2D;
Sprite sprite = new Sprite();
sprite = Sprite.Create(tex, new Rect(0, 0, 400, 400), new Vector2(0.5f, 0.5f));
Tile tile = Resources.Load<Tile>("tileInstance") as Tile;
tileInstance .sprite = sprite;
yourTileMap.SetTile(tilePos , tile);
I am not 100% if that is the best way to do it, but it worked for me. Let me know if that does not work and I will double check the actual file.
Sorry, I can't comment, but not knowing what you've tried so far, have you tried assigning the ruletile in the inspector and then just assigning it with SetTile at runtime whenever you need to? From the sounds of it this should achieve what you're trying to do
public Tilemap tilemap;
public MyRuleTile myRuleTile;
tilemap.SetTile(coordinate, myRuleTile);
Assuming your ScriptableObject is inheriting from TileBase object you can do the following:
public Tilemap tilemap;
public TileBase tileToDraw; //Object to draw at runtime
//Get tilemap position from the worldposition
Vector3Int tilemapReferencePosition = tilemap.WorldToCell(reference.transform.position);//this can be the position of another gameObject e.g your Player or MousePosition
roadTileMap.SetTile(tilemapReferencePosition, tileToDraw);
I recently used something similar for a Fire Emblem style RPG where I wanted to draw all the potential directions a spell can be cast before casting it and I ended up with the following function
public void DrawPreAttack(GameObject reference, Spell spell) {
Vector3Int gridReferencePos = preAttackTileMap.WorldToCell(reference.transform.position);
foreach (Vector2 direction in spell.validDirections) {
for (int i = 0; i <= spell.maxDistance; i++) {
preAttackTileMap.SetTile(new Vector3Int(gridReferencePos.x + (i * (int)direction.x) , gridReferencePos.y + (i * (int)direction.y) , 0), preAttackTile);
}
}
}
I have provided two small scripts for you that show you exactly how to do this:
1) The ScriptableObject
After placing this script in the Assets/??? folder, you can create new ScriptableObjects (or rather "ScriptableTiles") by right-clicking in the folder -> ScriptableObjects/ScriptableTile. After you have created such an asset, you have to "fill" it with what you want to have in it. In this case: a Tile. Just drag any Tile from your folder into the "m_Tile" slot that the ScriptableTile provides for you.
using UnityEngine;
using UnityEngine.Tilemaps;
[CreateAssetMenu(fileName = "NewScriptableTile", menuName = "ScriptableObjects/ScriptableTile")]
public class ScriptableTile : ScriptableObject
{
public Tile m_Tile;// Fill this with a Tile
public bool m_IsCollider;// This does nothing, it's just a showcase for what else could be stored in here
}
2) A simple "Placer"
Attach the "Placer" MonoBehaviour to a GameObject and give it a reference to a TileMap and your ScriptableTile. On Start() it will place the Tile in the middle of the chosen TileMap.
using UnityEngine;
using UnityEngine.Tilemaps;
public class ScriptableTilePlacer : MonoBehaviour
{
public Tilemap m_ExampleTileMap;
public ScriptableTile m_ExampleTile;
private void Start()
{
m_ExampleTileMap.SetTile(Vector3Int.zero, m_ExampleTile.m_Tile);
}
}
I've played around with creating TileMaps at runtime myself - you can get even more out of ScriptableTiles by adding more variables. For example, if you have a separate Collider TileMap, you could use a bool to mark certain Tiles as "IsCollider" or "IsNotCollider". Another idea would be to not store Tiles inside the ScriptableTile, but Sprites. This allows you to completely bypass the TilePalette - which is pretty much useless when it comes to runtime creation. Just write a short public Tile GetTileFromSprite() method inside the ScriptableTile. With a few lines of code you can create Tiles from Sprites and return them.