Skip to content

Commit

Permalink
fixed Animator usage to only work with emotes, embedded clips into an…
Browse files Browse the repository at this point in the history
…imator
  • Loading branch information
Kinerius committed Mar 15, 2024
1 parent 41585ec commit 2e78506
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using GLTFast;
using System.Diagnostics;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Profiling;
Expand All @@ -24,6 +25,12 @@ namespace DCL.ABConverter
{
public class AssetBundleConverter
{
public struct ConversionParams
{
public IReadOnlyList<ContentServerUtils.MappingPair> rawContents;
public string entityType;
}

private struct GltfImportSettings
{
public string url;
Expand Down Expand Up @@ -99,6 +106,8 @@ public enum Step

private bool isExitForced = false;
private IABLogger log => env.logger;
private Dictionary<AssetPath, byte[]> downloadedData = new();
private string entityType;

public AssetBundleConverter(Environment env, ClientSettings settings)
{
Expand All @@ -119,10 +128,12 @@ public AssetBundleConverter(Environment env, ClientSettings settings)
/// <summary>
/// Entry point of the AssetBundleConverter
/// </summary>
/// <param name="rawContents"></param>
/// <param name="conversionParams"></param>
/// <returns></returns>
public async Task ConvertAsync(IReadOnlyList<ContentServerUtils.MappingPair> rawContents)
public async Task ConvertAsync(ConversionParams conversionParams)
{
var rawContents = conversionParams.rawContents;
entityType = conversionParams.entityType;
startupAllocated = Profiler.GetTotalAllocatedMemoryLong() / 100000.0;
startupReserved = Profiler.GetTotalReservedMemoryLong() / 100000.0;

Expand Down Expand Up @@ -327,10 +338,10 @@ private async Task<bool> ProcessAllGltfs()

embedExtractTextureTime.Start();

string directory = Path.GetDirectoryName(relativePath);

if (textures.Count > 0)
{
string directory = Path.GetDirectoryName(relativePath);

textures = ExtractEmbedTexturesFromGltf(textures, directory);
}

Expand All @@ -340,6 +351,11 @@ private async Task<bool> ProcessAllGltfs()
ExtractEmbedMaterialsFromGltf(textures, gltf, gltfImport, gltfUrl);
embedExtractMaterialTime.Stop();

if (animationMethod == AnimationMethod.Mecanim)
{
CreateAnimatorController(gltfImport, directory);
}

log.Verbose($"Importing {relativePath}");

configureGltftime.Start();
Expand Down Expand Up @@ -419,8 +435,51 @@ private async Task<bool> ProcessAllGltfs()
return false;
}

private AnimationMethod GetAnimationMethod() =>
settings.buildTarget is BuildTarget.StandaloneWindows64 or BuildTarget.StandaloneOSX ? AnimationMethod.Mecanim : AnimationMethod.Legacy;
private void CreateAnimatorController(IGltfImport gltfImport, string directory)
{
var animatorRoot = $"{directory}/Animator/";

if (!env.directory.Exists(animatorRoot))
env.directory.CreateDirectory(animatorRoot);

var filePath = $"{animatorRoot}animatorController.controller";
var controller = AnimatorController.CreateAnimatorControllerAtPath(filePath);
var clips = gltfImport.GetClips();

var rootStateMachine = controller.layers[0].stateMachine;

foreach (AnimationClip animationClip in clips)
{
// copy the animation asset so we dont use the same references that will get disposed
var newCopy = Object.Instantiate(animationClip);
newCopy.name = animationClip.name;

// setup the loop
var animationSettings = AnimationUtility.GetAnimationClipSettings(newCopy);
animationSettings.loopTime = true;
AnimationUtility.SetAnimationClipSettings(newCopy, animationSettings);

// embed clip into the animatorController
AssetDatabase.AddObjectToAsset(newCopy, controller);
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(newCopy));

// configure the animator
string animationClipName = newCopy.name;
controller.AddParameter(animationClipName, AnimatorControllerParameterType.Trigger);
var state = controller.AddMotion(newCopy, 0);
var anyStateTransition = rootStateMachine.AddAnyStateTransition(state);
anyStateTransition.AddCondition(AnimatorConditionMode.If, 0, animationClipName);
}

AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}

private AnimationMethod GetAnimationMethod()
{
if (!entityType.ToLower().Contains("emote")) return AnimationMethod.Legacy;
return settings.buildTarget is BuildTarget.StandaloneWindows64 or BuildTarget.StandaloneOSX ? AnimationMethod.Mecanim : AnimationMethod.Legacy;
}

private void ExtractEmbedMaterialsFromGltf(List<Texture2D> textures, GltfImportSettings gltf, IGltfImport gltfImport, string gltfUrl)
{
Expand Down Expand Up @@ -813,7 +872,6 @@ private void PopulateLowercaseMappings(IReadOnlyList<ContentServerUtils.MappingP
/// <param name="rawContents">An array containing all the assets to be dumped.</param>
/// <returns>true if succeeded</returns>
///
private Dictionary<AssetPath, byte[]> downloadedData = new();

private async Task<bool> DownloadAssets(IReadOnlyList<ContentServerUtils.MappingPair> rawContents)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using GLTFast.Editor;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Animations;
using UnityEditor.AssetImporters;
using UnityEngine;
using Object = UnityEngine.Object;
Expand Down Expand Up @@ -79,7 +80,7 @@ public override void OnImportAsset(AssetImportContext ctx)
{
base.OnImportAsset(ctx);

SwapAnimatorPostProcess(ctx);
ReferenceAnimatorController(ctx);
}
catch (Exception e)
{
Expand All @@ -89,30 +90,30 @@ public override void OnImportAsset(AssetImportContext ctx)
}
}

// In explorer alpha we are using non legacy animations and since we cannot create an Animator graph, we just add the clips to an Animation component so we can fetch them easily
// we dont even need to check the current platform target since animators only are created by desktop targets
private void SwapAnimatorPostProcess(AssetImportContext ctx)
private void ReferenceAnimatorController(AssetImportContext ctx)
{
GameObject gameObject = ctx.mainObject as GameObject;

if (gameObject != null)
{
Animator animator = gameObject.GetComponent<Animator>();
var folderName = $"{Path.GetDirectoryName(ctx.assetPath)}/Animator/";
string filePath = folderName + "animatorController.controller";
AnimatorController animationController = AssetDatabase.LoadAssetAtPath<AnimatorController>(filePath);
animator.runtimeAnimatorController = animationController;
}
}

if (animator != null)
{
DestroyImmediate(animator);
var clips = m_Gltf.GetAnimationClips();
var animation = gameObject.AddComponent<Animation>();
// When creating Animators we embed the clips into the animator controller, so we prevent duplicating the clips here
protected override void CreateAnimationClips(AssetImportContext ctx)
{
GameObject gameObject = ctx.mainObject as GameObject;

foreach (AnimationClip animationClip in clips)
{
// we trick the Animation component believing that we are truly adding a legacy animation
animationClip.legacy = true;
animation.AddClip(animationClip, animationClip.name);
animationClip.legacy = false;
}
}
if (gameObject != null)
{
Animator animator = gameObject.GetComponent<Animator>();

if (animator == null)
base.CreateAnimationClips(ctx);
}
}

Expand Down Expand Up @@ -196,9 +197,11 @@ private List<Material> ReplaceMaterials(string folderName, Renderer[] renderers)
Material validDefaultMaterial = GetExtractedMaterial(folderName, m_Gltf.defaultMaterial.name);
materials.Add(validDefaultMaterial);
ReplaceReferences(renderers, validDefaultMaterial);

foreach (Renderer renderer in renderers)
{
var sharedMaterials = renderer.sharedMaterials;

for (var i = 0; i < sharedMaterials.Length; i++)
if (sharedMaterials[i] == null)
sharedMaterials[i] = validDefaultMaterial;
Expand Down
19 changes: 13 additions & 6 deletions asset-bundle-converter/Assets/AssetBundleConverter/SceneClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,15 @@ private static void ParseCommonSettings(string[] commandLineArgs, ClientSettings
var apiResponse = await Utils.GetEntityMappingsAsync(settings.targetHash, settings, env.webRequest);
if (apiResponse == null) return GetUnexpectedResult();
var mappings = apiResponse.SelectMany(m => m.content);
return await ConvertEntitiesToAssetBundles(mappings.ToArray(), settings);
string entityType = apiResponse[0].type;
return await ConvertEntitiesToAssetBundles(mappings.ToArray(), entityType, settings);
}

public static async Task<AssetBundleConverter.State> ConvertEmptyScenesByMapping(ClientSettings settings)
{
EnsureEnvironment(settings.BuildPipelineType);
return await ConvertEntitiesToAssetBundles(await Utils.GetEmptyScenesMappingAsync(settings.targetHash, settings, env.webRequest), settings);
ContentServerUtils.MappingPair[] emptyScenesMapping = await Utils.GetEmptyScenesMappingAsync(settings.targetHash, settings, env.webRequest);
return await ConvertEntitiesToAssetBundles(emptyScenesMapping, "scene", settings);
}

/// <summary>
Expand All @@ -302,7 +304,8 @@ private static void ParseCommonSettings(string[] commandLineArgs, ClientSettings
var apiResponse = await Utils.GetEntityMappings(settings.targetPointer.Value, settings, env.webRequest);
if (apiResponse == null) return GetUnexpectedResult();
var mappings = apiResponse.SelectMany(m => m.content);
return await ConvertEntitiesToAssetBundles(mappings.ToArray(), settings);
var entityType = apiResponse[0].type;
return await ConvertEntitiesToAssetBundles(mappings.ToArray(), entityType, settings);
}

private static AssetBundleConverter.State GetUnexpectedResult() =>
Expand All @@ -315,7 +318,7 @@ private static AssetBundleConverter.State GetUnexpectedResult() =>
settings.isWearable = true;

var mappings = await WearablesClient.GetCollectionMappingsAsync(settings.targetHash, ContentServerUtils.ApiTLD.ORG, env.webRequest);
return await ConvertEntitiesToAssetBundles(mappings, settings);
return await ConvertEntitiesToAssetBundles(mappings, "wearable", settings);
}

/// <summary>
Expand All @@ -324,7 +327,7 @@ private static AssetBundleConverter.State GetUnexpectedResult() =>
/// <param name="entitiesId">The cid list for the scenes to gather from the catalyst's content server</param>
/// <param name="settings">Any conversion settings object, if its null, a new one will be created</param>
/// <returns>A state context object useful for tracking the conversion progress</returns>
private static async Task<AssetBundleConverter.State> ConvertEntitiesToAssetBundles(IReadOnlyList<ContentServerUtils.MappingPair> mappingPairs, ClientSettings settings)
private static async Task<AssetBundleConverter.State> ConvertEntitiesToAssetBundles(IReadOnlyList<ContentServerUtils.MappingPair> mappingPairs, string entityType, ClientSettings settings)
{
if (mappingPairs == null || mappingPairs.Count == 0)
{
Expand All @@ -339,7 +342,11 @@ private static AssetBundleConverter.State GetUnexpectedResult() =>
EnsureEnvironment(settings.BuildPipelineType);

var core = new AssetBundleConverter(env, settings);
await core.ConvertAsync(mappingPairs);
await core.ConvertAsync(new AssetBundleConverter.ConversionParams
{
rawContents = mappingPairs,
entityType = entityType,
});
return core.CurrentState;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ private void ThrowIfExitCodeIsNotZero(int exitCode)
[Test]
public async Task LoadVisualSceneOnStart()
{
await converter.ConvertAsync(new List<ContentServerUtils.MappingPair>());
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

await editor.Received().LoadVisualTestSceneAsync();
}

[Test]
public async Task InitializeDirectories()
{
await converter.ConvertAsync(new List<ContentServerUtils.MappingPair>());
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

directory.Received(1).InitializeDirectory(Arg.Is(EXAMPLE_AB_PATH), Arg.Any<bool>());
}
Expand All @@ -112,7 +112,7 @@ public async Task TextureAssetIsProcessed()
var manifest = Substitute.For<IAssetBundleManifest>();
buildPipeline.BuildAssetBundles(Arg.Any<string>(), Arg.Any<BuildAssetBundleOptions>(), Arg.Any<BuildTarget>()).Returns(manifest);

await converter.ConvertAsync(new List<ContentServerUtils.MappingPair> { exampleAsset });
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

// Ensure that web request is done
webRequest.Received().Get(Arg.Is(exampleBaseURL));
Expand Down Expand Up @@ -159,7 +159,7 @@ public async Task GltfAssetIsProcessed()
gltf.TextureCount.Returns(0);
gltf.MaterialCount.Returns(0);

await converter.ConvertAsync(new List<ContentServerUtils.MappingPair> { exampleAsset });
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

// Ensure that web request is done
webRequest.Received().Get(Arg.Is(exampleBaseURL));
Expand Down Expand Up @@ -206,7 +206,7 @@ public async Task TextureIsExtractedFromGltf()
exampleTexture.name = textureName;
gltf.GetTexture(0).Returns(exampleTexture);

await converter.ConvertAsync(new List<ContentServerUtils.MappingPair> { exampleAsset });
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

var texturePath = $"{DOWNLOAD_FOLDER}{hash}{separator}Textures{separator}{textureName}.png";

Expand Down Expand Up @@ -250,7 +250,7 @@ public async Task MaterialIsExtractedFromGltf()
// Ensure that a when the material asset is created, the new instance of the material is a copy
assetDatabase.When(ad => ad.CreateAsset(Arg.Any<Material>(), Arg.Any<string>())).Do(c => Assert.AreNotEqual(c.Arg<Material>(), material));

await converter.ConvertAsync(new List<ContentServerUtils.MappingPair> { exampleAsset });
await converter.ConvertAsync(new DCL.ABConverter.AssetBundleConverter.ConversionParams());

// Ensure that a material asset is created and the texture is set for this material
assetDatabase.Received(1).CreateAsset(Arg.Is<Material>(m => m.GetTexture("_BaseMap")), Arg.Any<string>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using GLTFast.Logging;
using GLTFast.Materials;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

Expand Down Expand Up @@ -38,6 +39,9 @@ public Texture2D GetTexture(int index) =>
public Material GetMaterial(int index) =>
importer.GetMaterial(index);

public IReadOnlyList<AnimationClip> GetClips() =>
importer.GetAnimationClips();

public void Dispose()
{
importer.Dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using GLTFast;
using GLTFast.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

Expand All @@ -19,6 +20,8 @@ public interface IGltfImport

Material GetMaterial(int index);

IReadOnlyList<AnimationClip> GetClips();

void Dispose();

Material defaultMaterial { get; }
Expand Down

0 comments on commit 2e78506

Please sign in to comment.