Migrating from TriLib 1 to TriLib 2
The usage of TriLib 2 is very similar to TriLib 1, but some fundamental changes have been made.
Loading a Model from a File
When loading a model from a file in TriLib 1, the following snippets are used:
// TriLib 1 Code // -------------------- using (var assetLoader = new AssetLoader()) { var assetLoaderOptions = AssetLoaderOptions.CreateInstance(); //Creates the AssetLoaderOptions instance. //AssetLoaderOptions let you specify options to load your model. //(Optional) You can skip this object creation and it's parameter or pass null. //You can modify assetLoaderOptions before passing it to LoadFromFile method. You can check the AssetLoaderOptions API reference at: //https://ricardoreis.net/trilib/manual/html/class_tri_lib_1_1_asset_loader_options.html var wrapperGameObject = gameObject; //Sets the game object where your model will be loaded into. //(Optional) You can skip this object creation and it's parameter or pass null. var myGameObject = assetLoader.LoadFromFile("PATH TO MY FILE.FBX", assetLoaderOptions, wrapperGameObject); //Loads the model synchronously and stores the reference in myGameObject. }
// TriLib 1 Code // -------------------- using (var assetLoaderAsync = new AssetLoaderAsync()) { var assetLoaderOptions = AssetLoaderOptions.CreateInstance(); //Creates the AssetLoaderOptions instance. //AssetLoaderOptions let you specify options to load your model. //(Optional) You can skip this object creation and it's parameter or pass null. //You can modify assetLoaderOptions before passing it to LoadFromFile method. You can check the AssetLoaderOptions API reference at: //https://ricardoreis.net/trilib/manual/html/class_tri_lib_1_1_asset_loader_options.html var wrapperGameObject = gameObject; //Sets the game object where your model will be loaded into. //(Optional) You can skip this object creation and it's parameter or pass null. var thread = assetLoaderAsync.LoadFromFile("PATH TO MY FILE.FBX", assetLoaderOptions, wrapperGameObject, delegate(GameObject myGameObject) { //Here you can get the reference to the loaded model using myGameObject. }); //Loads the model asynchronously and returns the reference to the created Task/Thread. }
The first difference on TriLib 2 is that we don't have to specify if we want to sync or async load our models since TriLib 2 will use async on platforms that support it and fallback to sync loading when there is no support.
- On TriLib 2, we don't have to instantiate an AssetLoader or AssetLoaderAsync class. All loading is done using the AssetLoader static class now.
- TriLib 2 no longer returns a GameObject or a Thread when loading a model. Instead, it will produce an AssetLoaderContext object containing the loaded GameObject as the RootGameObject field and much more information regarding the model loading.
- TriLib 2 also uses AssetLoaderOptions, but these have changed to adopt a cleaner and file-format agnostic approach. The way we create the AssetLoaderOptions remains the same.
Given these changes, a simple TriLib 2 model loading that matches the TriLib 1 samples above could be reproduced as:
// TriLib 2 Code // -------------------- var assetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions(); AssetLoader.LoadModelFromFile("PATH TO MY FILE.FBX", null, delegate(AssetLoaderContext assetLoaderContext) { var myGameObject = assetLoaderContext.RootGameObject; }, null, null, null, null, assetLoaderOptions);
Loading a Model from a Custom Source
TriLib 1 allows loading models from byte arrays using a callback to retrieve the custom data, a callback to check if such data exists, and a callback to return custom external textures data from any external resource the model uses:
// TriLib 1 Code // -------------------- var modelData = File.ReadAllBytes("PATH_TO_MY_FILE.OBJ"); using (var assetLoader = new AssetLoader()) { var assetLoaderOptions = AssetLoaderOptions.CreateInstance(); var myGameObject = assetLoader.LoadFromMemory(modelData, "MY_FILE.OBJ", assetLoaderOptions, null, "PATH_TO", delegate(string path, int fileId, ref int fileSize) { //External data reading callback var resourceData = File.ReadAllBytes(path); //Reads all external file data fileSize = resourceData.Length; //Retrieves the external file size return resourceData; //Returns the external file data }, delegate(string path, int fileId) { //External data checking callback return File.Exists(path); //Returns true when the external file exists }, delegate (string path, string basePath) { //External texture data reading callback var finalPath = Path.Combine(basePath, path); //Combines the model base path with the texture path if (File.Exists(finalPath)) { //Checks if there is a file on the combined path return File.ReadAllBytes(finalPath); //Returns the file data } return null; //Returns null when the given file could not be found }, delegate (float progress) { //Progress handling callback Debug.Log("Loaded:" + progress); //Writes the model loading progress to the console }); }
TriLib 2 uses different approaches to load models from custom data sources:
- First, it doesn't work with byte arrays, specifically anymore. TriLib 2 works with Stream data reading.
- Second, any external resource the model uses has to be loaded using a class inheriting the ExternalDataMapper class.
- Third, any external texture the model uses has to be loaded using a class inheriting the TextureMapper class.
The example below loads a model from a custom Stream and handles its external resources with custom ExternalDataMapper and TextureMapper classes.
// TriLib 2 Code // -------------------- var assetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions(); assetLoaderOptions.ExternalDataMapper = ScriptableObject.CreateInstance<ExternalDataMapperSample>(); assetLoaderOptions.TextureMapper = ScriptableObject.CreateInstance<TextureMapperSample>(); var modelPath = "PATH_TO_MY_MODEL.FBX"; AssetLoader.LoadModelFromStream(File.OpenRead(modelPath), modelPath, null, OnLoad, OnMaterialsLoad, OnProgress, OnError, null, assetLoaderOptions);
Here are the Mappers used on the code above. One creates Steams from external resource files and the other creates TextureLoadingContexts from files:
// TriLib 2 Code // -------------------- public class ExternalDataMapperSample : ExternalDataMapper { public override Stream Map(AssetLoaderContext assetLoaderContext, string originalFilename, out string finalPath) { finalPath = $"{assetLoaderContext.BasePath}/{FileUtils.GetFilename(originalFilename)}"; if (File.Exists(finalPath)) { Debug.Log($"Found external file at: {finalPath}"); return File.OpenRead(finalPath); } throw new Exception($"File {originalFilename} not found."); } }
// TriLib 2 Code // -------------------- public class TextureMapperSample : TextureMapper { public override TextureLoadingContext Map(AssetLoaderContext assetLoaderContext, ITexture texture) { var finalPath = $"{assetLoaderContext.BasePath}/{FileUtils.GetFilename(texture.Filename)}"; if (File.Exists(finalPath)) { var textureLoadingContext = new TextureLoadingContext { Context = assetLoaderContext, Stream = File.OpenRead(finalPath), Texture = texture }; Debug.Log($"Found texture at: {finalPath}"); return textureLoadingContext; } throw new Exception($"Texture {texture.Filename} not found."); } }