/// <summary> /// Creates a resource loader if none is provided. This resource loader replaces /// "package:/" with <paramref name="dataDirectory"/> and <paramref name="dataDirectory"/> /// must be relative to a resource folder, i.e., if you put the data in Something/Resources/foo /// the <paramref name="dataDirectory"/> should be "foo". /// /// When Collada is a resource any rotation of the loaded game objects are removed. /// </summary> /// <remarks> /// - If a Collada resource is missing, this loader checks if there's a .obj file with /// the same name. /// - If this method is used within the Editor, <paramref name="dataDirectory"/> should be relative /// to the project directory (i.e, start with "Assets"). /// </remarks> /// <param name="dataDirectory">Directory relative to a resource folder. Default: "" assuming /// the data to be structured as referenced in the URDF file inside /// a "Resources" folder.</param> /// <param name="resourceLoad">The actual call to Load. UnityEngine.Resources.Load by default (if null) and, e.g., /// AssetDataBase.LoadAssetAtPath can be used when in the editor.</param> /// <returns>Resource loader function.</returns> public static Func <string, ResourceType, Object> CreateDefaultResourceLoader(string dataDirectory = "", Func <string, ResourceType, Object> resourceLoad = null) { var isPlayerResource = resourceLoad == null; if (!string.IsNullOrEmpty(dataDirectory)) { dataDirectory.Replace('\\', '/'); if (!dataDirectory.EndsWith("/")) { dataDirectory += '/'; } } var loadedInstances = new List <GameObject>(); Func <string, ResourceType, Object> resourceLoader = (resourceFilename, type) => { if (type == ResourceType.FinalizedLoad) { loadedInstances.ForEach(instance => Object.DestroyImmediate(instance)); loadedInstances = null; return(null); } if (resourceFilename.StartsWith("package:/")) { resourceFilename = dataDirectory + resourceFilename.Substring("package://".Length); } else if (!string.IsNullOrEmpty(dataDirectory)) { resourceFilename = dataDirectory + resourceFilename; } var hasExtension = Path.HasExtension(resourceFilename); var isStlFile = hasExtension && Path.GetExtension(resourceFilename).ToLowerInvariant() == ".stl"; var isCollada = hasExtension && !isStlFile && Path.GetExtension(resourceFilename).ToLowerInvariant() == ".dae"; // STL file we instantiate it and delete them at FinalizeLoad. if (isStlFile) { var stlInstances = StlFileImporter.Instantiate(resourceFilename); loadedInstances.AddRange(stlInstances); return(stlInstances.FirstOrDefault()); } // Remove file extension when using Resources.Load. else if (isPlayerResource && hasExtension) { resourceFilename = resourceFilename.Substring(0, resourceFilename.LastIndexOf('.')); } // Search for .obj file instead of Collada if we're not loading from Resources. if (!isPlayerResource && !File.Exists(resourceFilename) && isCollada) { resourceFilename = resourceFilename.Substring(0, resourceFilename.Length - 3) + "obj"; } var resource = resourceLoad != null? resourceLoad(resourceFilename, type) : Resources.Load <Object>(resourceFilename); if (!isPlayerResource && isCollada && resource != null) { var colladaInfo = Utils.ParseColladaInfo(resourceFilename); var resourceGo = resource as GameObject; // Model implementation assumes Z-up, anything other than that // has to be transformed. if (resourceGo != null && !colladaInfo.IsDefault) { var colladaInstance = Object.Instantiate <GameObject>(resourceGo); if (colladaInfo.UpAxis == Utils.ColladaInfo.Axis.Y) { colladaInstance.transform.rotation = Quaternion.Euler(-90, 0, 0) * colladaInstance.transform.rotation; } else if (colladaInfo.UpAxis == Utils.ColladaInfo.Axis.X) { colladaInstance.transform.rotation = Quaternion.Euler(-90, 0, 90) * colladaInstance.transform.rotation; } loadedInstances.Add(colladaInstance); resource = colladaInstance; } } return(resource); }; return(resourceLoader); }
/// <summary> /// Creates a resource loader if none is provided. This resource loader replaces /// "package:/" with <paramref name="dataDirectory"/> and <paramref name="dataDirectory"/> /// must be relative to a resource folder, i.e., if you put the data in Something/Resources/foo /// the <paramref name="dataDirectory"/> should be "foo". /// /// When Collada is a resource any rotation of the loaded game objects are removed. /// </summary> /// <remarks> /// - If a Collada resource is missing, this loader checks if there's a .obj file with /// the same name. /// - If this method is used within the Editor, <paramref name="dataDirectory"/> should be relative /// to the project directory (i.e, start with "Assets"). /// </remarks> /// <param name="dataDirectory">Directory relative to a resource folder. Default: "" assuming /// the data to be structured as referenced in the URDF file inside /// a "Resources" folder.</param> /// <param name="resourceLoad">The actual call to Load. UnityEngine.Resources.Load by default (if null) and, e.g., /// AssetDataBase.LoadAssetAtPath can be used when in the editor.</param> /// <returns>Resource loader function.</returns> public static Func <string, ResourceType, Object> CreateDefaultResourceLoader(string dataDirectory = "", Func <string, ResourceType, Object> resourceLoad = null) { var isPlayerResource = resourceLoad == null; if (!string.IsNullOrEmpty(dataDirectory)) { dataDirectory.Replace('\\', '/'); if (!dataDirectory.EndsWith("/")) { dataDirectory += '/'; } } var loadedInstances = new List <GameObject>(); Func <string, ResourceType, Object> resourceLoader = (resourceFilename, type) => { if (type == ResourceType.FinalizedLoad) { loadedInstances.ForEach(instance => Object.DestroyImmediate(instance)); loadedInstances = null; return(null); } if (resourceFilename.StartsWith("package:/")) { resourceFilename = dataDirectory + resourceFilename.Substring("package://".Length); } else if (!string.IsNullOrEmpty(dataDirectory)) { resourceFilename = dataDirectory + resourceFilename; } var hasExtension = Path.HasExtension(resourceFilename); var patchRotation = hasExtension && Path.GetExtension(resourceFilename).ToLower() == ".dae"; var isStlFile = hasExtension && Path.GetExtension(resourceFilename).ToLower() == ".stl"; // STL file we instantiate it and delete them at FinalizeLoad. if (isStlFile) { var stlInstances = StlFileImporter.Instantiate(resourceFilename); loadedInstances.AddRange(stlInstances); return(stlInstances.FirstOrDefault()); } // Remove file extension when using Resources.Load. else if (isPlayerResource && Path.HasExtension(resourceFilename)) { resourceFilename = resourceFilename.Substring(0, resourceFilename.LastIndexOf('.')); } // Search for .obj file instead of Collada if we're not loading from Resources. if (!isPlayerResource && !File.Exists(resourceFilename) && resourceFilename.EndsWith(".dae")) { resourceFilename = resourceFilename.Substring(0, resourceFilename.Length - 3) + "obj"; } var resource = resourceLoad != null? resourceLoad(resourceFilename, type) : Resources.Load <Object>(resourceFilename); // Unity adds a -90 rotation about x for unknown reasons - reverting that. if (resource != null && patchRotation) { var resourceGo = resource as GameObject; var transforms = resourceGo.GetComponentsInChildren <Transform>(); foreach (var transform in transforms) { transform.rotation = Quaternion.identity; } } return(resource); }; return(resourceLoader); }