From 99afd9003294364c434e981697cf3c3e0c44d3f3 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 14 Feb 2024 16:46:29 +0100 Subject: [PATCH 01/20] updated KHR_animatio_pointer to get deserialized --- .../Extensions/KHR_animation_pointer.cs | 6 ++++ .../KHR_animation_pointerExtensionFactory.cs | 31 +++++++++++++++++++ ..._animation_pointerExtensionFactory.cs.meta | 3 ++ 3 files changed, 40 insertions(+) create mode 100644 Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs.meta diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointer.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointer.cs index eb24521a1..5a3f4a6be 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointer.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointer.cs @@ -22,6 +22,12 @@ public JProperty Serialize() if (path == null && clonedFrom != null) path = clonedFrom.path; return new JProperty(EXTENSION_NAME, new JObject(new JProperty("pointer", path))); } + + public void Deserialize(GLTFRoot root, JProperty extensionToken) + { + var extensionObject = (JObject) extensionToken.Value; + path = (string) extensionObject["pointer"]; + } public IExtension Clone(GLTFRoot root) { diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs new file mode 100644 index 000000000..625a1b04b --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json.Linq; +using UnityGLTF.Extensions; + +namespace GLTF.Schema +{ + public class KHR_animation_pointerExtensionFactory : ExtensionFactory + { + public const string EXTENSION_NAME = "KHR_animation_pointer"; + + + public KHR_animation_pointerExtensionFactory() + { + ExtensionName = EXTENSION_NAME; + } + + public override IExtension Deserialize(GLTFRoot root, JProperty extensionToken) + { + if (extensionToken != null) + { + var extensionObject = (JObject) extensionToken.Value; + string path = (string) extensionObject["pointer"]; + return new KHR_animation_pointer + { + path = path + }; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs.meta b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs.meta new file mode 100644 index 000000000..de883387d --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_animation_pointerExtensionFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7f3f2eb61a4b4dd088e62138724bac85 +timeCreated: 1707827260 \ No newline at end of file From fbad5197174397ecf301a318c01f931eec9534f9 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 14 Feb 2024 16:49:34 +0100 Subject: [PATCH 02/20] added support for KHR_animationpointer import: Nodes, Lights, SkinnendMeshes --- .../Schema/AnimationChannelTarget.cs | 3 +- .../GLTFSerialization/Schema/GLTFProperty.cs | 3 +- .../GLTFSerialization/Schema/IExtension.cs | 18 +++ .../Utilities/AnimationPointerPath.cs | 121 ++++++++++++++++ .../Utilities/AnimationPointerPath.cs.meta | 3 + .../Scripts/Plugins/AnimationPointerImport.cs | 17 +++ .../Plugins/AnimationPointerImport.cs.meta | 3 + .../SceneImporter/ImporterAnimation.cs | 137 ++++++++++++++++-- 8 files changed, 293 insertions(+), 12 deletions(-) create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta create mode 100644 Runtime/Scripts/Plugins/AnimationPointerImport.cs create mode 100644 Runtime/Scripts/Plugins/AnimationPointerImport.cs.meta diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AnimationChannelTarget.cs b/Runtime/Plugins/GLTFSerialization/Schema/AnimationChannelTarget.cs index a119b40a2..1c8a68137 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AnimationChannelTarget.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AnimationChannelTarget.cs @@ -89,6 +89,7 @@ public enum GLTFAnimationChannelPath translation, rotation, scale, - weights + weights, + pointer } } diff --git a/Runtime/Plugins/GLTFSerialization/Schema/GLTFProperty.cs b/Runtime/Plugins/GLTFSerialization/Schema/GLTFProperty.cs index 9a15ad4ce..2fe7b54ab 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/GLTFProperty.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/GLTFProperty.cs @@ -37,7 +37,8 @@ public static IReadOnlyList RegisteredExtensions { KHR_draco_mesh_compression_Factory.EXTENSION_NAME, new KHR_draco_mesh_compression_Factory() }, { KHR_texture_basisu_Factory.EXTENSION_NAME, new KHR_texture_basisu_Factory() }, { EXT_meshopt_compression_Factory.EXTENSION_NAME, new EXT_meshopt_compression_Factory() }, - { EXT_mesh_gpu_instancing_Factory.EXTENSION_NAME, new EXT_mesh_gpu_instancing_Factory() } + { EXT_mesh_gpu_instancing_Factory.EXTENSION_NAME, new EXT_mesh_gpu_instancing_Factory() }, + { KHR_animation_pointerExtensionFactory.EXTENSION_NAME, new KHR_animation_pointerExtensionFactory() } }; private static DefaultExtensionFactory _defaultExtensionFactory = new DefaultExtensionFactory(); diff --git a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs index 90425ac05..21d257557 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs @@ -1,7 +1,25 @@ +using GLTF.Utilities; using Newtonsoft.Json.Linq; +using System; namespace GLTF.Schema { + public class AnimationPointerData + { + public string[] unityProperties; + public Type animationType; + public int nodeId; + + public delegate float[] ValuesConvertion(NumericArray data, int frame); + + public ValuesConvertion conversion; + } + + public interface IAnimationPointerRootExtension + { + bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierarchy pointerPath, out AnimationPointerData pointerData); + } + /// /// General interface for extensions /// diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs new file mode 100644 index 000000000..5b323e340 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs @@ -0,0 +1,121 @@ +using System.Collections; + +namespace GLTF.Utilities +{ + public class AnimationPointerPathHierarchy + { + public enum ElementTypeOptions { Root, Extension, Index, Child, Property } + public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; + public int index { get; private set; } = -1; + public string elementName { get; private set; } = ""; + + public AnimationPointerPathHierarchy next { get; private set; }= null; + + public AnimationPointerPathHierarchy FindElement(ElementTypeOptions elementType) + { + if (this.elementType == elementType) + return this; + + if (next == null) + return null; + return next.FindElement(elementType); + } + + public static AnimationPointerPathHierarchy CreateHierarchyFromFullPath(string fullPath) + { + var path = new PathResolver(fullPath.Remove(0,1)); + + var result = new AnimationPointerPathHierarchy(); + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.Root; + + AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) + { + if (!path.MoveNext()) + return null; + + var result = new AnimationPointerPathHierarchy(); + if (path.GetCurrentAsInt(out int index)) + { + result.index = index; + result.elementType = ElementTypeOptions.Index; + result.elementName = index.ToString(); + result.next = TravelHierarchy(path); + return result; + } + + result.elementName = path.GetCurrentAsString(); + result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; + if (!path.IsLast()) + result.next = TravelHierarchy(path); + return result; + } + + if (result.elementName == "extensions") + { + if (path.MoveNext()) + { + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.Extension; + result.next = TravelHierarchy(path); + } + } + else + { + result.next = TravelHierarchy(path); + } + + return result; + } + } + public class PathResolver : IEnumerator + { + private string[] _splittedPath; + private int currentIndex; + + public PathResolver (string path) + { + _splittedPath = path.Split("/"); + currentIndex = 0; + } + + public bool IsLast() + { + return currentIndex == _splittedPath.Length - 1; + } + + public string GetCurrentAsString() + { + return _splittedPath[currentIndex]; + } + + public bool GetCurrentAsInt(out int result) + { + return int.TryParse(_splittedPath[currentIndex], out result); + } + + public bool MoveNext() + { + currentIndex++; + return currentIndex < _splittedPath.Length; + } + + public void Reset() + { + currentIndex = 0; + } + + public object Current + { + get + { + if (currentIndex < _splittedPath.Length) + { + return _splittedPath[currentIndex]; + } + + return null; + } + } + } +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta new file mode 100644 index 000000000..6712dc08f --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 26f0996784b744b3a0d324be1c95fe4f +timeCreated: 1707897204 \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/AnimationPointerImport.cs b/Runtime/Scripts/Plugins/AnimationPointerImport.cs new file mode 100644 index 000000000..e7199d12a --- /dev/null +++ b/Runtime/Scripts/Plugins/AnimationPointerImport.cs @@ -0,0 +1,17 @@ +namespace UnityGLTF.Plugins +{ + public class AnimationPointerImport: GLTFImportPlugin + { + public override string DisplayName => "KHR_animation_pointer"; + public override string Description => "Animate arbitrary material and object properties. Without this extension, only node transforms and blend shape weights can be animated."; + public override GLTFImportPluginContext CreateInstance(GLTFImportContext context) + { + return new AnimationPointerImportContext(); + } + } + + public class AnimationPointerImportContext: GLTFImportPluginContext + { + + } +} \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/AnimationPointerImport.cs.meta b/Runtime/Scripts/Plugins/AnimationPointerImport.cs.meta new file mode 100644 index 000000000..637b82fdd --- /dev/null +++ b/Runtime/Scripts/Plugins/AnimationPointerImport.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 473c2b5b3de547139304b32beee641e9 +timeCreated: 1707313653 \ No newline at end of file diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index cf5892c93..b468bada7 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -5,9 +5,12 @@ using System.Threading.Tasks; using GLTF; using GLTF.Schema; +using GLTF.Schema.KHR_lights_punctual; +using GLTF.Utilities; using UnityEngine; using UnityGLTF.Cache; using UnityGLTF.Extensions; +using UnityGLTF.Plugins; namespace UnityGLTF { @@ -264,10 +267,22 @@ protected async Task ConstructClip(Transform root, int animationI if (_options.AnimationMethod == AnimationMethod.Legacy) clip.legacy = true; + int nodeId = -1; + foreach (AnimationChannel channel in animation.Channels) { + bool usesPointer = false; + IExtension pointerExtension = null; AnimationSamplerCacheData samplerCache = animationCache.Samplers[channel.Sampler.Id]; - if (channel.Target.Node == null) + if (channel.Target.Extensions != null && channel.Target.Extensions.TryGetValue( + KHR_animation_pointer.EXTENSION_NAME, + out pointerExtension)) + { + if (Context.TryGetPlugin(out _)) + usesPointer = true; + } + + if (!usesPointer && channel.Target.Node == null) { // If a channel doesn't have a target node, then just skip it. // This is legal and is present in one of the asset generator models, but means that animation doesn't actually do anything. @@ -275,17 +290,113 @@ protected async Task ConstructClip(Transform root, int animationI // Model 08 continue; } - var node = await GetNode(channel.Target.Node.Id, cancellationToken); - string relativePath = RelativePathFrom(node.transform, root); - - NumericArray input = samplerCache.Input.AccessorContent, - output = samplerCache.Output.AccessorContent; + string relativePath = null; + AnimationPointerData pointerData = null; string[] propertyNames; - var known = Enum.TryParse(channel.Target.Path, out GLTFAnimationChannelPath path); - if (!known) continue; + GLTFAnimationChannelPath path = GLTFAnimationChannelPath.translation; + + if (usesPointer && pointerExtension != null) + { + KHR_animation_pointer pointer = pointerExtension as KHR_animation_pointer; + if (pointer == null || pointer.path == null) + continue; + + path = GLTFAnimationChannelPath.pointer; + relativePath = pointer.path; + var pointerHierarchy = AnimationPointerPathHierarchy.CreateHierarchyFromFullPath(relativePath); + + if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Extension) + { + if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) + continue; + + if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) + { + if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) + nodeId = pointerData.nodeId; + else + continue; + } + } + else + if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Root) + { + var rootType = pointerHierarchy.elementName; + var rootIndex = pointerHierarchy.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + if (rootIndex == null) + continue; + + switch (rootType) + { + case "nodes": + var pointerPropertyElement = pointerHierarchy.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + if (pointerPropertyElement == null) + continue; + + pointerData = new AnimationPointerData(); + pointerData.nodeId = rootIndex.index; + nodeId = rootIndex.index; + switch (pointerPropertyElement.elementName) + { + case "translation": + path = GLTFAnimationChannelPath.translation; + break; + case "rotation": + path = GLTFAnimationChannelPath.rotation; + break; + case "scale": + path = GLTFAnimationChannelPath.scale; + break; + case "weights": + path = GLTFAnimationChannelPath.weights; + break; + } + + break; + //case "materials": + //case "cameras": + //nodeId = _gltfRoot.Cameras[rootIndex]. pointerHierarchy.index; + //break; + default: + continue; + //throw new NotImplementedException(); + } + } + else + continue; + } + else + { + if (channel.Target == null || channel.Target.Node == null) + continue; + nodeId = channel.Target.Node.Id; + } + + var node = await GetNode(nodeId, cancellationToken); + var targetNode = _gltfRoot.Nodes[nodeId]; + relativePath = RelativePathFrom(node.transform, root); + NumericArray input = samplerCache.Input.AccessorContent; + NumericArray output = samplerCache.Output.AccessorContent; + + if (!usesPointer) + { + var known = Enum.TryParse(channel.Target.Path, out path); + if (!known) continue; + } + switch (path) { + case GLTFAnimationChannelPath.pointer: + if (pointerData == null) + continue; + if (pointerData.conversion == null) + continue; + propertyNames = pointerData.unityProperties; + SetAnimationCurve(clip, relativePath, propertyNames, input, output, + samplerCache.Interpolation, pointerData.animationType, + (data, frame) => pointerData.conversion(data, frame)); + break; case GLTFAnimationChannelPath.translation: propertyNames = new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }; #if UNITY_EDITOR @@ -308,13 +419,19 @@ protected async Task ConstructClip(Transform root, int animationI case GLTFAnimationChannelPath.rotation: propertyNames = new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }; - + bool hasLight = (targetNode.Extensions != null && + targetNode.Extensions.ContainsKey(KHR_lights_punctualExtensionFactory + .EXTENSION_NAME) && Context.TryGetPlugin(out _)); SetAnimationCurve(clip, relativePath, propertyNames, input, output, samplerCache.Interpolation, typeof(Transform), (data, frame) => { var rotation = data.AsFloat4s[frame]; var quaternion = rotation.ToUnityQuaternionConvert(); + if (hasLight) + { + quaternion *= Quaternion.Euler(0,180, 0); + } return new float[] { quaternion.x, quaternion.y, quaternion.z, quaternion.w }; }); @@ -333,7 +450,7 @@ protected async Task ConstructClip(Transform root, int animationI break; case GLTFAnimationChannelPath.weights: - var mesh = channel.Target.Node.Value.Mesh.Value; + var mesh = targetNode.Mesh.Value; var primitives = mesh.Primitives; if (primitives[0].Targets == null) break; var targetCount = primitives[0].Targets.Count; From 5fe551e9269bbdacb57967520c56d4eceb6bdb9e Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 14 Feb 2024 16:50:59 +0100 Subject: [PATCH 03/20] changed BuildAnimationSamplers to load accessor by accessor data type, not by animation sample type --- .../Plugins/GLTFSerialization/GLTFHelpers.cs | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs index c1a9bc6c1..ac8d585df 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using GLTF.Schema; @@ -408,20 +409,28 @@ public static void BuildAnimationSamplers(ref Dictionary bufferViewCache); - switch (samplerSet.Key) + switch (attributeAccessor.AccessorId.Value.Type) { - case "time": - attributeAccessor.AccessorId.Value.AsFloatArray(ref resultArray, bufferViewCache, 0, attributeAccessor.AccessorId.Value.Normalized); + case GLTFAccessorAttributeType.SCALAR: + attributeAccessor.AccessorId.Value.AsFloatArray(ref resultArray, bufferViewCache); break; - case "translation": - case "scale": - attributeAccessor.AccessorId.Value.AsFloat3Array(ref resultArray, bufferViewCache, 0, attributeAccessor.AccessorId.Value.Normalized); + case GLTFAccessorAttributeType.VEC2: + attributeAccessor.AccessorId.Value.AsFloat2Array(ref resultArray, bufferViewCache); break; - case "rotation": - attributeAccessor.AccessorId.Value.AsFloat4Array(ref resultArray, bufferViewCache, 0, attributeAccessor.AccessorId.Value.Normalized); + case GLTFAccessorAttributeType.VEC3: + attributeAccessor.AccessorId.Value.AsFloat3Array(ref resultArray, bufferViewCache); break; - case "weights": - attributeAccessor.AccessorId.Value.AsFloatArray(ref resultArray, bufferViewCache, 0, attributeAccessor.AccessorId.Value.Normalized); + case GLTFAccessorAttributeType.VEC4: + attributeAccessor.AccessorId.Value.AsFloat4Array(ref resultArray, bufferViewCache); + break; + case GLTFAccessorAttributeType.MAT2: + Debug.LogWarning("Unsupported MAT2 animation sampler type"); + break; + case GLTFAccessorAttributeType.MAT3: + Debug.LogWarning("Unsupported MAT3 animation sampler type"); + break; + case GLTFAccessorAttributeType.MAT4: + attributeAccessor.AccessorId.Value.AsMatrix4x4Array(ref resultArray, bufferViewCache); break; } From a089ac1827b3d517346a6cdb16a6058ac6bc02cc Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 14 Feb 2024 16:51:39 +0100 Subject: [PATCH 04/20] updated KHR_LightsPunctualExtension to support AnimationPointers --- .../Extensions/KHR_LightsPunctualExtension.cs | 85 ++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 64f4a20f7..10a7a6e50 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; -using GLTF.Math; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using GLTF.Extensions; +using GLTF.Utilities; +using UnityEngine; +using UnityGLTF.Extensions; +using Color = GLTF.Math.Color; namespace GLTF.Schema.KHR_lights_punctual { @@ -287,7 +290,7 @@ public IExtension Clone(GLTFRoot root) } } - public class KHR_LightsPunctualExtension : IExtension + public class KHR_LightsPunctualExtension : IExtension, IAnimationPointerRootExtension { public List Lights; @@ -314,6 +317,84 @@ public JProperty Serialize() ) ); } + + private static string[] GltfLightPropertyToUnityPropertyName(string gltfPropertyName) + { + switch (gltfPropertyName) + { + case "color": + return new string[] { "m_Color.r", "m_Color.g", "m_Color.b"}; + case "intensity": + return new string[] { "m_Intensity"}; + case "range": + return new string[] {"m_Range"}; + case "spot/innerConeAngle": + return new string[] {"m_InnerConeAngle"}; + case "spot/outerConeAngle": + return new string[] {"m_OuterConeAngle"}; + default: + return new string[] {gltfPropertyName}; + } + } + + private static AnimationPointerData.ValuesConvertion GetConversion(string gltfPropertyName) + { + switch (gltfPropertyName) + { + case "color": + return (NumericArray data, int frame) => + { + var col = data.AsFloats3[frame]; + return new float[] { col.x, col.y, col.z }; + }; + case "intensity": + return (data, frame) => new float[1] { data.AsFloats[frame] / Mathf.PI }; + case "range": + return (data, frame) => new float[1] { data.AsFloats[frame] }; + case "spot/innerConeAngle": + return (data, frame) => new float[] { data.AsFloats[frame] * 2 / (Mathf.Deg2Rad * 0.8f) }; + case "spot/outerConeAngle": + return (data, frame) => new float[] { data.AsFloats[frame] * 2 / Mathf.Deg2Rad }; + default: + return null; + } + } + + public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierarchy pointerPath, out AnimationPointerData pointerData) + { + pointerData = new AnimationPointerData(); + pointerData.nodeId = -1; + pointerData.animationType = typeof(UnityEngine.Light); + + var pointId = pointerPath.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + if (pointId == null) + return false; + + var property = pointerPath.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + if (property == null) + return false; + + for (int i = 0; i < root.Nodes.Count; i++) + { + var n = root.Nodes[i]; + if (n.Extensions != null && n.Extensions.TryGetValue(KHR_lights_punctualExtensionFactory.EXTENSION_NAME, out IExtension extension)) + { + if (extension is KHR_LightsPunctualNodeExtension lightExtension) + { + if (lightExtension.LightId.Id == pointId.index) + { + pointerData.nodeId = i;; + pointerData.unityProperties = GltfLightPropertyToUnityPropertyName(property.elementName); + pointerData.conversion = GetConversion(property.elementName); + + return true; + } + } + } + } + + return false; + } } public class PunctualLightId : GLTFId From 7924d0e92941132596f6938eb3047ad311647c7e Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Thu, 15 Feb 2024 18:10:25 +0100 Subject: [PATCH 05/20] added material support for animationpointer import (WIP) --- .../Extensions/KHR_LightsPunctualExtension.cs | 4 +- .../Utilities/AnimationPointerPath.cs | 20 +- .../Utilities/GltfRootExtensions.cs | 38 +++ .../Utilities/GltfRootExtensions.cs.meta | 3 + .../SceneExporter/ExporterAnimationPointer.cs | 292 +++++++++++++++++- .../SceneImporter/ImporterAnimation.cs | 131 +++++--- 6 files changed, 442 insertions(+), 46 deletions(-) create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs.meta diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 10a7a6e50..e7580ca69 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -366,11 +366,11 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar pointerData.nodeId = -1; pointerData.animationType = typeof(UnityEngine.Light); - var pointId = pointerPath.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + var pointId = pointerPath.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); if (pointId == null) return false; - var property = pointerPath.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var property = pointerPath.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); if (property == null) return false; diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs index 5b323e340..e0849694c 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs @@ -11,14 +11,19 @@ public enum ElementTypeOptions { Root, Extension, Index, Child, Property } public AnimationPointerPathHierarchy next { get; private set; }= null; - public AnimationPointerPathHierarchy FindElement(ElementTypeOptions elementType) + public string GetPath() + { + return elementName+ (next != null ? "/" + next.GetPath() : ""); + } + + public AnimationPointerPathHierarchy FindFirstElement(ElementTypeOptions elementType) { if (this.elementType == elementType) return this; if (next == null) return null; - return next.FindElement(elementType); + return next.FindFirstElement(elementType); } public static AnimationPointerPathHierarchy CreateHierarchyFromFullPath(string fullPath) @@ -35,6 +40,17 @@ AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) return null; var result = new AnimationPointerPathHierarchy(); + if (path.GetCurrentAsString() == "extensions") + { + if (path.MoveNext()) + { + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.Extension; + result.next = TravelHierarchy(path); + return result; + } + } + if (path.GetCurrentAsInt(out int index)) { result.index = index; diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs new file mode 100644 index 000000000..3247ea07f --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs @@ -0,0 +1,38 @@ +using System.Collections; +using System.Collections.Generic; +using GLTF.Schema; + +namespace GLTF.Utilities +{ + public static class GltfRootExtensions + { + public static int[] GetAllNodeIdsWithMaterialId(this GLTFRoot root, int id) + { + List ids = new List(); + + for (int iMeshes = 0; iMeshes < root.Meshes.Count; iMeshes++) + { + if (root.Meshes[iMeshes].Primitives == null) + continue; + + for (int iPrimitives = 0; iPrimitives < root.Meshes[iMeshes].Primitives.Count; iPrimitives++) + { + if (root.Meshes[iMeshes].Primitives[iPrimitives].Material != null && root.Meshes[iMeshes].Primitives[iPrimitives].Material.Id == id) + { + for (int iNodes = 0; iNodes < root.Nodes.Count; iNodes++) + { + if (root.Nodes[iNodes].Mesh != null &&root.Nodes[iNodes].Mesh.Id == iMeshes) + { + ids.Add(iNodes); + } + } + break; + } + } + } + + return ids.ToArray(); + } + + } +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs.meta b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs.meta new file mode 100644 index 000000000..266c7f2f4 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 14a6d519d0344f438f272a77e05a896c +timeCreated: 1707995699 \ No newline at end of file diff --git a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs index f55a895dc..18aaa9d6a 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs @@ -42,6 +42,296 @@ public void RegisterResolver(IJsonPointerResolver resolver) pointerResolvers.Add(resolver); } + public class MaterialPointerPropertyMap + { + public string[] propertyNames = new string[0]; + public int[] propertyIds = new int[0]; + + public string gltfPropertyName = null; + public string gltfSecondaryPropertyName = null; + public bool isTexture = false; + public bool isTextureTransform = false; + public bool keepColorAlpha = true; + public string extensionName = null; + public bool convertToLinearColor = false; + public bool flipValueRange = false; + + + public void BuildPropertyIds() + { + propertyIds = new int[propertyNames.Length]; + for (int i = 0; i < propertyNames.Length; i++) + propertyIds[i] = Shader.PropertyToID(propertyNames[i]); + } + } + + public class MaterialPointerPropertyRemapper + { + public List maps = new List(); + + public void AddDefaults() + { + var baseColor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, + convertToLinearColor = true, + gltfPropertyName = "pbrMetallicRoughness/baseColorFactor" + }; + maps.Add(baseColor); + + var smoothness = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Smoothness", "_Glossiness" }, + flipValueRange = true, + gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + maps.Add(smoothness); + + var roughness = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, + gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + + maps.Add(roughness); + + var metallic = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, + gltfPropertyName = "pbrMetallicRoughness/metallicFactor" + }; + maps.Add(metallic); + + var baseColorTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + maps.Add(baseColorTexture); + + var emissiveFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, + gltfPropertyName = "emissiveFactor", + gltfSecondaryPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", + extensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, + keepColorAlpha = false, + convertToLinearColor = true + }; + maps.Add(emissiveFactor); + + var emissiveTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(emissiveTexture); + + var alphaCutoff = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Cutoff", "_AlphaCutoff", "alphaCutoff" }, + gltfPropertyName = "alphaCutoff" + }; + maps.Add(alphaCutoff); + + var normalScale = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, + gltfPropertyName = "normalTexture/scale" + }; + maps.Add(normalScale); + + var normalTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(normalTexture); + + var occlusionStrength = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, + gltfPropertyName = "occlusionTexture/strength" + }; + + maps.Add(occlusionStrength); + + var occlusionTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(occlusionTexture); + + // KHR_materials_transmission + var transmissionFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}", + extensionName = KHR_materials_transmission_Factory.EXTENSION_NAME + }; + maps.Add(transmissionFactor); + + // KHR_materials_volume + var thicknessFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + maps.Add(thicknessFactor); + + var attenuationDistance = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + + maps.Add(attenuationDistance); + + var attenuationColor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_AttenuationColor", "attenuationColor" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME, + keepColorAlpha = false + }; + + maps.Add(attenuationColor); + + // KHR_materials_ior + var ior = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_IOR", "ior" }, + gltfPropertyName = $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}", + extensionName = KHR_materials_ior_Factory.EXTENSION_NAME + }; + maps.Add(ior); + + // KHR_materials_iridescence + var iridescenceFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}", + extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME + }; + + maps.Add(iridescenceFactor); + + // KHR_materials_specular + var specularFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_SpecularFactor", "specularFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}", + extensionName = KHR_materials_specular_Factory.EXTENSION_NAME + }; + maps.Add(specularFactor); + + var specularColorFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", + extensionName = KHR_materials_specular_Factory.EXTENSION_NAME, + keepColorAlpha = false + }; + + maps.Add(specularColorFactor); + } + + public bool GetFromUnityMaterial(Material mat, string unityPropertyName, out string gltfPropertyName, out string extensionName, + out bool isTextureTransform, out bool keepColorAlpha, out bool convertToLinearColor, out bool flipValueRange) + { + gltfPropertyName = ""; + extensionName = ""; + isTextureTransform = false; + keepColorAlpha = true; + convertToLinearColor = false; + flipValueRange = false; + + foreach (var m in maps) + { + if (m.propertyNames.Contains(unityPropertyName)) + { + if (m.isTexture) + { + if (m.propertyIds.Length != m.propertyNames.Length) + { + m.BuildPropertyIds(); + } + bool valid = false; + for (int i = 0; i < m.propertyIds.Length; i++) + valid &= (mat.HasProperty(m.propertyIds[i]) && mat.GetTexture(m.propertyIds[i])); + if (!valid) + return false; + } + + gltfPropertyName = m.gltfPropertyName; + extensionName = m.extensionName; + isTextureTransform = m.isTextureTransform; + keepColorAlpha = m.keepColorAlpha; + convertToLinearColor = m.convertToLinearColor; + flipValueRange = m.flipValueRange; + return true; + } + } + + return false; + } + + public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName) + { + propertyName = ""; + foreach (var m in maps) + { + if (m.gltfPropertyName == gltfPropertyName) + { + for (int i = 0; i < m.propertyNames.Length; i++) + { + if (mat.HasProperty(m.propertyNames[i])) + { + propertyName = m.propertyNames[i]; + return true; + } + } + + + } + } + + return false; + } + } + + + + /// /// AddAnimationData should be called within the event. /// @@ -94,7 +384,7 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni string secondPropertyName = null; string extensionName = null; var propertyType = values[0]?.GetType(); - + switch (animatedObject) { case Material material: diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index b468bada7..0a902b79e 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -267,7 +267,7 @@ protected async Task ConstructClip(Transform root, int animationI if (_options.AnimationMethod == AnimationMethod.Legacy) clip.legacy = true; - int nodeId = -1; + int[] nodeIds = new int[0]; foreach (AnimationChannel channel in animation.Channels) { @@ -314,7 +314,7 @@ protected async Task ConstructClip(Transform root, int animationI if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) { if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) - nodeId = pointerData.nodeId; + nodeIds = new int[] { pointerData.nodeId}; else continue; } @@ -323,20 +323,21 @@ protected async Task ConstructClip(Transform root, int animationI if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Root) { var rootType = pointerHierarchy.elementName; - var rootIndex = pointerHierarchy.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + var rootIndex = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); if (rootIndex == null) continue; switch (rootType) { case "nodes": - var pointerPropertyElement = pointerHierarchy.FindElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var pointerPropertyElement = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); if (pointerPropertyElement == null) continue; pointerData = new AnimationPointerData(); pointerData.nodeId = rootIndex.index; - nodeId = rootIndex.index; + nodeIds = new int[] {rootIndex.index}; + switch (pointerPropertyElement.elementName) { case "translation": @@ -354,7 +355,54 @@ protected async Task ConstructClip(Transform root, int animationI } break; - //case "materials": + case "materials": + nodeIds = _gltfRoot.GetAllNodeIdsWithMaterialId(rootIndex.index); + if (nodeIds.Length == 0) + continue; + var materialPath = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; + var propertyPath = materialPath.GetPath(); + if (materialPath == null) + continue; + + var m = new GLTFSceneExporter.MaterialPointerPropertyRemapper(); + m.AddDefaults(); + var mat = _assetCache.MaterialCache[rootIndex.index]; + + if (!m.GetUnityPropertyName(mat.UnityMaterial, propertyPath, out string unityPropertyName)) + continue; + + pointerData = new AnimationPointerData(); + pointerData.unityProperties = new string[] { "material."+unityPropertyName }; + + + + pointerData.animationType = typeof(MeshRenderer); // TODO: SkinnendMeshRenderer + //mat.UnityMaterial.GetType(); + + switch (samplerCache.Output.AccessorId.Value.Type) + { + case GLTFAccessorAttributeType.SCALAR: + pointerData.conversion = (data, frame) => new float[] { data.AsFloats[frame] }; + break; + case GLTFAccessorAttributeType.VEC2: + pointerData.conversion = (data, frame) => new float[] { data.AsFloats2[frame].x, data.AsFloats2[frame].y }; + break; + case GLTFAccessorAttributeType.VEC3: + pointerData.conversion = (data, frame) => new float[] { data.AsFloats3[frame].x, data.AsFloats3[frame].y, data.AsFloats3[frame].z }; + break; + case GLTFAccessorAttributeType.VEC4: + pointerData.conversion = (data, frame) => new float[] { data.AsFloats4[frame].x, data.AsFloats4[frame].y, data.AsFloats4[frame].z, data.AsFloats4[frame].w }; + break; + default: + continue; + } + + + + + break; + + //case "cameras": //nodeId = _gltfRoot.Cameras[rootIndex]. pointerHierarchy.index; //break; @@ -370,39 +418,41 @@ protected async Task ConstructClip(Transform root, int animationI { if (channel.Target == null || channel.Target.Node == null) continue; - nodeId = channel.Target.Node.Id; - } - - var node = await GetNode(nodeId, cancellationToken); - var targetNode = _gltfRoot.Nodes[nodeId]; - relativePath = RelativePathFrom(node.transform, root); - NumericArray input = samplerCache.Input.AccessorContent; - NumericArray output = samplerCache.Output.AccessorContent; - - if (!usesPointer) - { - var known = Enum.TryParse(channel.Target.Path, out path); - if (!known) continue; + nodeIds = new int[] {channel.Target.Node.Id}; } - - switch (path) + + foreach (var nodeId in nodeIds) { - case GLTFAnimationChannelPath.pointer: - if (pointerData == null) - continue; - if (pointerData.conversion == null) - continue; - propertyNames = pointerData.unityProperties; - SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, pointerData.animationType, - (data, frame) => pointerData.conversion(data, frame)); - break; - case GLTFAnimationChannelPath.translation: - propertyNames = new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }; + var node = await GetNode(nodeId, cancellationToken); + var targetNode = _gltfRoot.Nodes[nodeId]; + relativePath = RelativePathFrom(node.transform, root); + NumericArray input = samplerCache.Input.AccessorContent; + NumericArray output = samplerCache.Output.AccessorContent; + + if (!usesPointer) + { + var known = Enum.TryParse(channel.Target.Path, out path); + if (!known) continue; + } + + switch (path) + { + case GLTFAnimationChannelPath.pointer: + if (pointerData == null) + continue; + if (pointerData.conversion == null) + continue; + propertyNames = pointerData.unityProperties; + SetAnimationCurve(clip, relativePath, propertyNames, input, output, + samplerCache.Interpolation, pointerData.animationType, + (data, frame) => pointerData.conversion(data, frame)); + break; + case GLTFAnimationChannelPath.translation: + propertyNames = new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }; #if UNITY_EDITOR - // TODO technically this should be postprocessing in the ScriptedImporter instead, - // but performance is much better if we do it when constructing the clips - var factor = Context?.ImportScaleFactor ?? 1f; + // TODO technically this should be postprocessing in the ScriptedImporter instead, + // but performance is much better if we do it when constructing the clips + var factor = Context?.ImportScaleFactor ?? 1f; #endif SetAnimationCurve(clip, relativePath, propertyNames, input, output, samplerCache.Interpolation, typeof(Transform), @@ -410,7 +460,8 @@ protected async Task ConstructClip(Transform root, int animationI { var position = data.AsFloat3s[frame].ToUnityVector3Convert(); #if UNITY_EDITOR - return new float[] { position.x * factor, position.y * factor, position.z * factor}; + return new float[] + { position.x * factor, position.y * factor, position.z * factor }; #else return new float[] { position.x, position.y, position.z }; #endif @@ -466,17 +517,15 @@ protected async Task ConstructClip(Transform root, int animationI var blendShapeFrameWeight = _options.BlendShapeFrameWeight; SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, typeof(SkinnedMeshRenderer), + samplerCache.Interpolation, typeof(Transform), (data, frame) => { var allValues = data.AsFloats; for (var k = 0; k < targetCount; k++) frameFloats[k] = allValues[frame * targetCount + k] * blendShapeFrameWeight; - return frameFloats; + return new float[] { quaternion.x, quaternion.y, quaternion.z, quaternion.w }; }); - } - break; default: Debug.Log(LogType.Warning, $"Cannot read GLTF animation path (File: {_gltfFileName})"); From 418b8ba5b014d74463973818b2aba0b1e20a0ea9 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Fri, 16 Feb 2024 12:31:05 +0100 Subject: [PATCH 06/20] added support for TextureTransform in animation pointer + some refactoring of material animation pointer (WIP) --- .../Extensions/KHR_LightsPunctualExtension.cs | 4 +- .../Utilities/AnimationPointerPath.cs | 137 -------- .../Utilities/AnimationPointerUtilities.cs | 234 +++++++++++++ ...meta => AnimationPointerUtilities.cs.meta} | 0 .../Utilities/MaterialPropertyMapper.cs | 315 ++++++++++++++++++ .../Utilities/MaterialPropertyMapper.cs.meta | 3 + .../SceneExporter/ExporterAnimationPointer.cs | 291 +--------------- .../SceneImporter/ImporterAnimation.cs | 47 +-- 8 files changed, 566 insertions(+), 465 deletions(-) delete mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs rename Runtime/Plugins/GLTFSerialization/Utilities/{AnimationPointerPath.cs.meta => AnimationPointerUtilities.cs.meta} (100%) create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index e7580ca69..86800dc0a 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -366,11 +366,11 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar pointerData.nodeId = -1; pointerData.animationType = typeof(UnityEngine.Light); - var pointId = pointerPath.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + var pointId = pointerPath.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); if (pointId == null) return false; - var property = pointerPath.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var property = pointerPath.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); if (property == null) return false; diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs deleted file mode 100644 index e0849694c..000000000 --- a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System.Collections; - -namespace GLTF.Utilities -{ - public class AnimationPointerPathHierarchy - { - public enum ElementTypeOptions { Root, Extension, Index, Child, Property } - public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; - public int index { get; private set; } = -1; - public string elementName { get; private set; } = ""; - - public AnimationPointerPathHierarchy next { get; private set; }= null; - - public string GetPath() - { - return elementName+ (next != null ? "/" + next.GetPath() : ""); - } - - public AnimationPointerPathHierarchy FindFirstElement(ElementTypeOptions elementType) - { - if (this.elementType == elementType) - return this; - - if (next == null) - return null; - return next.FindFirstElement(elementType); - } - - public static AnimationPointerPathHierarchy CreateHierarchyFromFullPath(string fullPath) - { - var path = new PathResolver(fullPath.Remove(0,1)); - - var result = new AnimationPointerPathHierarchy(); - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.Root; - - AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) - { - if (!path.MoveNext()) - return null; - - var result = new AnimationPointerPathHierarchy(); - if (path.GetCurrentAsString() == "extensions") - { - if (path.MoveNext()) - { - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.Extension; - result.next = TravelHierarchy(path); - return result; - } - } - - if (path.GetCurrentAsInt(out int index)) - { - result.index = index; - result.elementType = ElementTypeOptions.Index; - result.elementName = index.ToString(); - result.next = TravelHierarchy(path); - return result; - } - - result.elementName = path.GetCurrentAsString(); - result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; - if (!path.IsLast()) - result.next = TravelHierarchy(path); - return result; - } - - if (result.elementName == "extensions") - { - if (path.MoveNext()) - { - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.Extension; - result.next = TravelHierarchy(path); - } - } - else - { - result.next = TravelHierarchy(path); - } - - return result; - } - } - public class PathResolver : IEnumerator - { - private string[] _splittedPath; - private int currentIndex; - - public PathResolver (string path) - { - _splittedPath = path.Split("/"); - currentIndex = 0; - } - - public bool IsLast() - { - return currentIndex == _splittedPath.Length - 1; - } - - public string GetCurrentAsString() - { - return _splittedPath[currentIndex]; - } - - public bool GetCurrentAsInt(out int result) - { - return int.TryParse(_splittedPath[currentIndex], out result); - } - - public bool MoveNext() - { - currentIndex++; - return currentIndex < _splittedPath.Length; - } - - public void Reset() - { - currentIndex = 0; - } - - public object Current - { - get - { - if (currentIndex < _splittedPath.Length) - { - return _splittedPath[currentIndex]; - } - - return null; - } - } - } -} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs new file mode 100644 index 000000000..8ec0f98f5 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs @@ -0,0 +1,234 @@ +using System.Collections; +using GLTF.Schema; +using UnityEngine; + +namespace GLTF.Utilities +{ + public class AnimationPointerPathHierarchy + { + public enum ElementTypeOptions { Root, RootExtension, Index, Child, Property } + public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; + public int index { get; private set; } = -1; + public string elementName { get; private set; } = ""; + + public AnimationPointerPathHierarchy next { get; private set; }= null; + + public string GetPath() + { + return elementName+ (next != null ? "/" + next.GetPath() : ""); + } + + public AnimationPointerPathHierarchy FindNext(ElementTypeOptions elementType) + { + if (this.elementType == elementType) + return this; + + if (next == null) + return null; + return next.FindNext(elementType); + } + + public static AnimationPointerPathHierarchy CreateHierarchyFromFullPath(string fullPath) + { + var path = new PathResolver(fullPath.Remove(0,1)); + + var result = new AnimationPointerPathHierarchy(); + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.Root; + + AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) + { + if (!path.MoveNext()) + return null; + + var result = new AnimationPointerPathHierarchy(); + // if (path.GetCurrentAsString() == "extensions") + // { + // if (path.MoveNext()) + // { + // result.elementName = path.GetCurrentAsString(); + // result.elementType = ElementTypeOptions.RootExtension; + // result.next = TravelHierarchy(path); + // return result; + // } + // } + + if (path.GetCurrentAsInt(out int index)) + { + result.index = index; + result.elementType = ElementTypeOptions.Index; + result.elementName = index.ToString(); + result.next = TravelHierarchy(path); + return result; + } + + result.elementName = path.GetCurrentAsString(); + result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; + if (!path.IsLast()) + result.next = TravelHierarchy(path); + return result; + } + + if (result.elementName == "extensions") + { + if (path.MoveNext()) + { + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.RootExtension; + result.next = TravelHierarchy(path); + } + } + else + { + result.next = TravelHierarchy(path); + } + + return result; + } + } + public class PathResolver : IEnumerator + { + private string[] _splittedPath; + private int currentIndex; + + public PathResolver (string path) + { + _splittedPath = path.Split("/"); + currentIndex = 0; + } + + public bool IsLast() + { + return currentIndex == _splittedPath.Length - 1; + } + + public string GetCurrentAsString() + { + return _splittedPath[currentIndex]; + } + + public bool GetCurrentAsInt(out int result) + { + return int.TryParse(_splittedPath[currentIndex], out result); + } + + public bool MoveNext() + { + currentIndex++; + return currentIndex < _splittedPath.Length; + } + + public void Reset() + { + currentIndex = 0; + } + + public object Current + { + get + { + if (currentIndex < _splittedPath.Length) + { + return _splittedPath[currentIndex]; + } + + return null; + } + } + } + + internal static class AnimationPointerHelpers + { + + private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; + + internal static bool Prepare(out AnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) + { + pointerData = new AnimationPointerData(); + + pointerData.animationType = typeof(MeshRenderer); // TODO: SkinnendMeshRenderer + var m = new MaterialPointerPropertyRemapper(); + m.AddDefaults(); + if (!m.GetUnityPropertyName(material, gltfProperty, out string unityPropertyName, + out MaterialPointerPropertyMap propertyMap, out bool isSecondaryGltfProperty)) + return false; + + switch (valueType) + { + case GLTFAccessorAttributeType.SCALAR: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 1, propertyMap); + break; + case GLTFAccessorAttributeType.VEC2: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 2, propertyMap); + break; + case GLTFAccessorAttributeType.VEC3: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 3, propertyMap); + break; + case GLTFAccessorAttributeType.VEC4: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 4, propertyMap); + break; + default: + return false; + } + + return true; + } + + internal static string[] GetAnimationChannelProperties(string propertyName, int componentCount, int componentOffset = 0) + { + var result = new string[ componentCount]; + if (componentCount == 1) + { + result[0] = $"material.{propertyName}"; + return result; + } + + for (int iComponent = 0; iComponent < componentCount; iComponent++) + result[iComponent] = $"material.{propertyName}.{MATERIAL_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; + return result; + } + + internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map) + { + float[] result = new float[componentCount]; + + if (map.convertToLinearColor && (componentCount == 3 || componentCount == 4)) + { + // TODO: ? + } + + switch (componentCount) + { + case 1: + result[0] = data.AsFloats[frame]; + break; + case 2: + var frameData2 = data.AsFloats2[frame]; + result[0] = frameData2.x; + result[1] = frameData2.y; + break; + case 3: + var frameData3 = data.AsFloats3[frame]; + result[0] = frameData3.x; + result[1] = frameData3.y; + result[2] = frameData3.z; + break; + case 4: + var frameData4 = data.AsFloats4[frame]; + result[0] = frameData4.x; + result[1] = frameData4.y; + result[2] = frameData4.z; + result[3] = frameData4.w; + break; + + } + + return result; + } + } + +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs.meta similarity index 100% rename from Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta rename to Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs.meta diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs b/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs new file mode 100644 index 000000000..9a95b8854 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs @@ -0,0 +1,315 @@ +using System.Collections.Generic; +using System.Linq; +using GLTF.Schema; +using UnityEngine; + +namespace GLTF.Utilities +{ + public class MaterialPointerPropertyMap + { + public string[] propertyNames = new string[0]; + + public int[] propertyIds = new int[0]; + + public string[] customPropertyComponents = null; + + public string gltfPropertyName = null; + public string gltfSecondaryPropertyName = null; + public bool isTexture = false; + public bool isTextureTransform = false; + public bool keepColorAlpha = true; + public string extensionName = null; + public bool convertToLinearColor = false; + public bool flipValueRange = false; + + public void BuildPropertyIds() + { + propertyIds = new int[propertyNames.Length]; + for (int i = 0; i < propertyNames.Length; i++) + propertyIds[i] = Shader.PropertyToID(propertyNames[i]); + } + } + + public class MaterialPointerPropertyRemapper + { + public List maps = new List(); + + public void AddDefaults() + { + var baseColor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, + convertToLinearColor = true, + gltfPropertyName = "pbrMetallicRoughness/baseColorFactor" + }; + maps.Add(baseColor); + + var smoothness = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Smoothness", "_Glossiness" }, + flipValueRange = true, + gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + maps.Add(smoothness); + + var roughness = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, + gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + + maps.Add(roughness); + + var metallic = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, + gltfPropertyName = "pbrMetallicRoughness/metallicFactor" + }; + maps.Add(metallic); + + var baseColorTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + maps.Add(baseColorTexture); + + var emissiveFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, + gltfPropertyName = "emissiveFactor", + gltfSecondaryPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", + extensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, + keepColorAlpha = false, + convertToLinearColor = true + }; + maps.Add(emissiveFactor); + + var emissiveTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(emissiveTexture); + + var alphaCutoff = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_AlphaCutoff", "alphaCutoff", "_Cutoff" }, + gltfPropertyName = "alphaCutoff" + }; + maps.Add(alphaCutoff); + + var normalScale = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, + gltfPropertyName = "normalTexture/scale" + }; + maps.Add(normalScale); + + var normalTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(normalTexture); + + var occlusionStrength = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, + gltfPropertyName = "occlusionTexture/strength" + }; + + maps.Add(occlusionStrength); + + var occlusionTexture = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(occlusionTexture); + + // KHR_materials_transmission + var transmissionFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}", + extensionName = KHR_materials_transmission_Factory.EXTENSION_NAME + }; + maps.Add(transmissionFactor); + + // KHR_materials_volume + var thicknessFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + maps.Add(thicknessFactor); + + var attenuationDistance = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + + maps.Add(attenuationDistance); + + var attenuationColor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_AttenuationColor", "attenuationColor" }, + gltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", + extensionName = KHR_materials_volume_Factory.EXTENSION_NAME, + keepColorAlpha = false + }; + + maps.Add(attenuationColor); + + // KHR_materials_ior + var ior = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_IOR", "ior" }, + gltfPropertyName = $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}", + extensionName = KHR_materials_ior_Factory.EXTENSION_NAME + }; + maps.Add(ior); + + // KHR_materials_iridescence + var iridescenceFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}", + extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME + }; + + maps.Add(iridescenceFactor); + + // KHR_materials_specular + var specularFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_SpecularFactor", "specularFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}", + extensionName = KHR_materials_specular_Factory.EXTENSION_NAME + }; + maps.Add(specularFactor); + + var specularColorFactor = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, + gltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", + extensionName = KHR_materials_specular_Factory.EXTENSION_NAME, + keepColorAlpha = false + }; + + maps.Add(specularColorFactor); + } + + public bool GetFromUnityMaterial(Material mat, string unityPropertyName, out string gltfPropertyName, out string extensionName, + out bool isTextureTransform, out bool keepColorAlpha, out bool convertToLinearColor, out bool flipValueRange) + { + gltfPropertyName = ""; + extensionName = ""; + isTextureTransform = false; + keepColorAlpha = true; + convertToLinearColor = false; + flipValueRange = false; + + foreach (var m in maps) + { + if (m.propertyNames.Contains(unityPropertyName)) + { + if (m.isTexture) + { + if (m.propertyIds.Length != m.propertyNames.Length) + { + m.BuildPropertyIds(); + } + bool valid = false; + for (int i = 0; i < m.propertyIds.Length; i++) + valid &= (mat.HasProperty(m.propertyIds[i]) && mat.GetTexture(m.propertyIds[i])); + if (!valid) + return false; + } + + gltfPropertyName = m.gltfPropertyName; + extensionName = m.extensionName; + isTextureTransform = m.isTextureTransform; + keepColorAlpha = m.keepColorAlpha; + convertToLinearColor = m.convertToLinearColor; + flipValueRange = m.flipValueRange; + return true; + } + } + + return false; + } + + public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName, out MaterialPointerPropertyMap map, out bool isSecondary) + { + foreach (var m in maps) + { + if (m.gltfPropertyName != gltfPropertyName && m.gltfSecondaryPropertyName != gltfPropertyName) + continue; + + for (int i = 0; i < m.propertyNames.Length; i++) + { + if (m.isTextureTransform) + { + foreach (var p in m.propertyNames) + { + var pWithOutST = p.Remove(p.Length - 3, 3); + if (mat.HasProperty(pWithOutST)) + { + map = m; + propertyName = p; + isSecondary = m.gltfSecondaryPropertyName == gltfPropertyName; + return true; + } + } + } + else + if (mat.HasProperty(m.propertyNames[i])) + { + map = m; + propertyName = m.propertyNames[i]; + isSecondary = m.gltfSecondaryPropertyName == gltfPropertyName; + return true; + } + } + } + + map = null; + propertyName = ""; + isSecondary = false; + return false; + } + + } + +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta b/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta new file mode 100644 index 000000000..dcb021e0d --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e35adb0d169a4046908867445f09f321 +timeCreated: 1708078060 \ No newline at end of file diff --git a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs index 18aaa9d6a..ef0976bc1 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs @@ -41,296 +41,6 @@ public void RegisterResolver(IJsonPointerResolver resolver) if (!pointerResolvers.Contains(resolver)) pointerResolvers.Add(resolver); } - - public class MaterialPointerPropertyMap - { - public string[] propertyNames = new string[0]; - public int[] propertyIds = new int[0]; - - public string gltfPropertyName = null; - public string gltfSecondaryPropertyName = null; - public bool isTexture = false; - public bool isTextureTransform = false; - public bool keepColorAlpha = true; - public string extensionName = null; - public bool convertToLinearColor = false; - public bool flipValueRange = false; - - - public void BuildPropertyIds() - { - propertyIds = new int[propertyNames.Length]; - for (int i = 0; i < propertyNames.Length; i++) - propertyIds[i] = Shader.PropertyToID(propertyNames[i]); - } - } - - public class MaterialPointerPropertyRemapper - { - public List maps = new List(); - - public void AddDefaults() - { - var baseColor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, - convertToLinearColor = true, - gltfPropertyName = "pbrMetallicRoughness/baseColorFactor" - }; - maps.Add(baseColor); - - var smoothness = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Smoothness", "_Glossiness" }, - flipValueRange = true, - gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" - }; - maps.Add(smoothness); - - var roughness = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, - gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" - }; - - maps.Add(roughness); - - var metallic = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, - gltfPropertyName = "pbrMetallicRoughness/metallicFactor" - }; - maps.Add(metallic); - - var baseColorTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - maps.Add(baseColorTexture); - - var emissiveFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, - gltfPropertyName = "emissiveFactor", - gltfSecondaryPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", - extensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, - keepColorAlpha = false, - convertToLinearColor = true - }; - maps.Add(emissiveFactor); - - var emissiveTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(emissiveTexture); - - var alphaCutoff = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Cutoff", "_AlphaCutoff", "alphaCutoff" }, - gltfPropertyName = "alphaCutoff" - }; - maps.Add(alphaCutoff); - - var normalScale = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, - gltfPropertyName = "normalTexture/scale" - }; - maps.Add(normalScale); - - var normalTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(normalTexture); - - var occlusionStrength = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, - gltfPropertyName = "occlusionTexture/strength" - }; - - maps.Add(occlusionStrength); - - var occlusionTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(occlusionTexture); - - // KHR_materials_transmission - var transmissionFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}", - extensionName = KHR_materials_transmission_Factory.EXTENSION_NAME - }; - maps.Add(transmissionFactor); - - // KHR_materials_volume - var thicknessFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME - }; - maps.Add(thicknessFactor); - - var attenuationDistance = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME - }; - - maps.Add(attenuationDistance); - - var attenuationColor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_AttenuationColor", "attenuationColor" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME, - keepColorAlpha = false - }; - - maps.Add(attenuationColor); - - // KHR_materials_ior - var ior = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_IOR", "ior" }, - gltfPropertyName = $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}", - extensionName = KHR_materials_ior_Factory.EXTENSION_NAME - }; - maps.Add(ior); - - // KHR_materials_iridescence - var iridescenceFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}", - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME - }; - - maps.Add(iridescenceFactor); - - // KHR_materials_specular - var specularFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_SpecularFactor", "specularFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}", - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME - }; - maps.Add(specularFactor); - - var specularColorFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME, - keepColorAlpha = false - }; - - maps.Add(specularColorFactor); - } - - public bool GetFromUnityMaterial(Material mat, string unityPropertyName, out string gltfPropertyName, out string extensionName, - out bool isTextureTransform, out bool keepColorAlpha, out bool convertToLinearColor, out bool flipValueRange) - { - gltfPropertyName = ""; - extensionName = ""; - isTextureTransform = false; - keepColorAlpha = true; - convertToLinearColor = false; - flipValueRange = false; - - foreach (var m in maps) - { - if (m.propertyNames.Contains(unityPropertyName)) - { - if (m.isTexture) - { - if (m.propertyIds.Length != m.propertyNames.Length) - { - m.BuildPropertyIds(); - } - bool valid = false; - for (int i = 0; i < m.propertyIds.Length; i++) - valid &= (mat.HasProperty(m.propertyIds[i]) && mat.GetTexture(m.propertyIds[i])); - if (!valid) - return false; - } - - gltfPropertyName = m.gltfPropertyName; - extensionName = m.extensionName; - isTextureTransform = m.isTextureTransform; - keepColorAlpha = m.keepColorAlpha; - convertToLinearColor = m.convertToLinearColor; - flipValueRange = m.flipValueRange; - return true; - } - } - - return false; - } - - public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName) - { - propertyName = ""; - foreach (var m in maps) - { - if (m.gltfPropertyName == gltfPropertyName) - { - for (int i = 0; i < m.propertyNames.Length; i++) - { - if (mat.HasProperty(m.propertyNames[i])) - { - propertyName = m.propertyNames[i]; - return true; - } - } - - - } - } - - return false; - } - } - - - /// /// AddAnimationData should be called within the event. @@ -392,6 +102,7 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni // mapping from known Unity property names to glTF property names switch (propertyName) { + case "_Color": case "_BaseColor": case "_BaseColorFactor": diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 0a902b79e..9832f6618 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -306,7 +306,7 @@ protected async Task ConstructClip(Transform root, int animationI relativePath = pointer.path; var pointerHierarchy = AnimationPointerPathHierarchy.CreateHierarchyFromFullPath(relativePath); - if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Extension) + if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.RootExtension) { if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) continue; @@ -323,14 +323,14 @@ protected async Task ConstructClip(Transform root, int animationI if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Root) { var rootType = pointerHierarchy.elementName; - var rootIndex = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + var rootIndex = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); if (rootIndex == null) continue; switch (rootType) { case "nodes": - var pointerPropertyElement = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var pointerPropertyElement = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); if (pointerPropertyElement == null) continue; @@ -359,47 +359,22 @@ protected async Task ConstructClip(Transform root, int animationI nodeIds = _gltfRoot.GetAllNodeIdsWithMaterialId(rootIndex.index); if (nodeIds.Length == 0) continue; - var materialPath = pointerHierarchy.FindFirstElement(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; - var propertyPath = materialPath.GetPath(); + var materialPath = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; if (materialPath == null) continue; - - var m = new GLTFSceneExporter.MaterialPointerPropertyRemapper(); - m.AddDefaults(); - var mat = _assetCache.MaterialCache[rootIndex.index]; - if (!m.GetUnityPropertyName(mat.UnityMaterial, propertyPath, out string unityPropertyName)) - continue; - pointerData = new AnimationPointerData(); - pointerData.unityProperties = new string[] { "material."+unityPropertyName }; - - - - pointerData.animationType = typeof(MeshRenderer); // TODO: SkinnendMeshRenderer - //mat.UnityMaterial.GetType(); - - switch (samplerCache.Output.AccessorId.Value.Type) + var gltfPropertyPath = materialPath.GetPath(); + if (gltfPropertyPath.Contains("scale") || gltfPropertyPath.Contains("offset")) { - case GLTFAccessorAttributeType.SCALAR: - pointerData.conversion = (data, frame) => new float[] { data.AsFloats[frame] }; - break; - case GLTFAccessorAttributeType.VEC2: - pointerData.conversion = (data, frame) => new float[] { data.AsFloats2[frame].x, data.AsFloats2[frame].y }; - break; - case GLTFAccessorAttributeType.VEC3: - pointerData.conversion = (data, frame) => new float[] { data.AsFloats3[frame].x, data.AsFloats3[frame].y, data.AsFloats3[frame].z }; - break; - case GLTFAccessorAttributeType.VEC4: - pointerData.conversion = (data, frame) => new float[] { data.AsFloats4[frame].x, data.AsFloats4[frame].y, data.AsFloats4[frame].z, data.AsFloats4[frame].w }; - break; - default: - continue; + Debug.Log(""); } - - + var mat = _assetCache.MaterialCache[rootIndex.index]; + if (!AnimationPointerHelpers.Prepare(out pointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) + continue; + break; From f33909f7e07685ea1f5c85ca817bb3bb737898b7 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Fri, 16 Feb 2024 17:05:11 +0100 Subject: [PATCH 07/20] added support for combined animation samples. eg. for emissive factor and strength. Fefactoring animation pointer structure --- .../Schema/AnimationPointerData.cs | 20 + .../Schema/AnimationPointerData.cs.meta | 3 + .../GLTFSerialization/Schema/IExtension.cs | 14 +- .../Utilities/AnimationPointerPath.cs | 129 ++++++ .../Utilities/AnimationPointerPath.cs.meta | 3 + .../Utilities/AnimationPointerUtilities.cs | 234 ----------- .../Utilities/MaterialPropertyMapper.cs | 315 --------------- .../KHR_animation_pointer_Resolver.cs | 18 - Runtime/Scripts/Plugins/AnimationPointer.meta | 3 + .../AnimationPointerUtilities.cs | 133 ++++++ .../AnimationPointerUtilities.cs.meta | 0 .../MaterialPropertiesRemapper.cs | 380 ++++++++++++++++++ .../MaterialPropertiesRemapper.cs.meta} | 0 .../Scripts/Plugins/AnimationPointerExport.cs | 1 + .../Scripts/Plugins/AnimationPointerImport.cs | 2 +- Runtime/Scripts/Plugins/Core/ImportContext.cs | 4 +- .../SceneExporter/ExporterAnimationPointer.cs | 241 ++--------- .../SceneImporter/ImporterAnimation.cs | 169 ++++---- .../SceneImporter/ImporterMaterials.cs | 1 + 19 files changed, 798 insertions(+), 872 deletions(-) create mode 100644 Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs.meta create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs create mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta delete mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs delete mode 100644 Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs create mode 100644 Runtime/Scripts/Plugins/AnimationPointer.meta create mode 100644 Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs rename Runtime/{Plugins/GLTFSerialization/Utilities => Scripts/Plugins/AnimationPointer}/AnimationPointerUtilities.cs.meta (100%) create mode 100644 Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs rename Runtime/{Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta => Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs.meta} (100%) diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs new file mode 100644 index 000000000..4efda5be0 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs @@ -0,0 +1,20 @@ +using System; + +namespace GLTF.Schema +{ + public class AnimationPointerData + { + public string[] unityProperties; + public Type animationType; + public int nodeId; + + public delegate float[] ValuesConvertion(NumericArray data, int frame); + public ValuesConvertion conversion; + } + + public class MaterialAnimationPointerData : AnimationPointerData + { + public string secondaryPath = ""; + public AttributeAccessor secondaryData; + } +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs.meta b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs.meta new file mode 100644 index 000000000..7a1bfe9c4 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b46ea1356e184122834984053bbe1693 +timeCreated: 1708099053 \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs index 21d257557..836cc1675 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs @@ -4,17 +4,9 @@ namespace GLTF.Schema { - public class AnimationPointerData - { - public string[] unityProperties; - public Type animationType; - public int nodeId; - - public delegate float[] ValuesConvertion(NumericArray data, int frame); - - public ValuesConvertion conversion; - } - + /// + /// Additional interface for Root Extensions to support custom animation pointers + /// public interface IAnimationPointerRootExtension { bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierarchy pointerPath, out AnimationPointerData pointerData); diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs new file mode 100644 index 000000000..3c9cd1506 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs @@ -0,0 +1,129 @@ +using System.Collections; + +namespace GLTF.Utilities +{ + public class AnimationPointerPathHierarchy + { + public enum ElementTypeOptions { Root, RootExtension, Index, Child, Property } + public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; + public int index { get; private set; } = -1; + public string elementName { get; private set; } = ""; + + public AnimationPointerPathHierarchy next { get; private set; }= null; + + public string ExtractPath() + { + return elementName+ (next != null ? "/" + next.ExtractPath() : ""); + } + + public AnimationPointerPathHierarchy FindNext(ElementTypeOptions elementType) + { + if (this.elementType == elementType) + return this; + + if (next == null) + return null; + return next.FindNext(elementType); + } + + public static AnimationPointerPathHierarchy CreateHierarchyFromPath(string fullPath) + { + var path = new PathResolver(fullPath.Remove(0,1)); + + var result = new AnimationPointerPathHierarchy(); + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.Root; + + AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) + { + if (!path.MoveNext()) + return null; + + var result = new AnimationPointerPathHierarchy(); + + if (path.GetCurrentAsInt(out int index)) + { + result.index = index; + result.elementType = ElementTypeOptions.Index; + result.elementName = index.ToString(); + result.next = TravelHierarchy(path); + return result; + } + + result.elementName = path.GetCurrentAsString(); + result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; + if (!path.IsLast()) + result.next = TravelHierarchy(path); + return result; + } + + if (result.elementName == "extensions") + { + if (path.MoveNext()) + { + result.elementName = path.GetCurrentAsString(); + result.elementType = ElementTypeOptions.RootExtension; + result.next = TravelHierarchy(path); + } + } + else + { + result.next = TravelHierarchy(path); + } + + return result; + } + } + + public class PathResolver : IEnumerator + { + private string[] _splittedPath; + private int currentIndex; + + public PathResolver (string path) + { + _splittedPath = path.Split("/"); + currentIndex = 0; + } + + public bool IsLast() + { + return currentIndex == _splittedPath.Length - 1; + } + + public string GetCurrentAsString() + { + return _splittedPath[currentIndex]; + } + + public bool GetCurrentAsInt(out int result) + { + return int.TryParse(_splittedPath[currentIndex], out result); + } + + public bool MoveNext() + { + currentIndex++; + return currentIndex < _splittedPath.Length; + } + + public void Reset() + { + currentIndex = 0; + } + + public object Current + { + get + { + if (currentIndex < _splittedPath.Length) + { + return _splittedPath[currentIndex]; + } + + return null; + } + } + } + +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta new file mode 100644 index 000000000..8e7976ce7 --- /dev/null +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dc6bc893b2f9428b94cb9972e35f3e24 +timeCreated: 1708087555 \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs deleted file mode 100644 index 8ec0f98f5..000000000 --- a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System.Collections; -using GLTF.Schema; -using UnityEngine; - -namespace GLTF.Utilities -{ - public class AnimationPointerPathHierarchy - { - public enum ElementTypeOptions { Root, RootExtension, Index, Child, Property } - public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; - public int index { get; private set; } = -1; - public string elementName { get; private set; } = ""; - - public AnimationPointerPathHierarchy next { get; private set; }= null; - - public string GetPath() - { - return elementName+ (next != null ? "/" + next.GetPath() : ""); - } - - public AnimationPointerPathHierarchy FindNext(ElementTypeOptions elementType) - { - if (this.elementType == elementType) - return this; - - if (next == null) - return null; - return next.FindNext(elementType); - } - - public static AnimationPointerPathHierarchy CreateHierarchyFromFullPath(string fullPath) - { - var path = new PathResolver(fullPath.Remove(0,1)); - - var result = new AnimationPointerPathHierarchy(); - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.Root; - - AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) - { - if (!path.MoveNext()) - return null; - - var result = new AnimationPointerPathHierarchy(); - // if (path.GetCurrentAsString() == "extensions") - // { - // if (path.MoveNext()) - // { - // result.elementName = path.GetCurrentAsString(); - // result.elementType = ElementTypeOptions.RootExtension; - // result.next = TravelHierarchy(path); - // return result; - // } - // } - - if (path.GetCurrentAsInt(out int index)) - { - result.index = index; - result.elementType = ElementTypeOptions.Index; - result.elementName = index.ToString(); - result.next = TravelHierarchy(path); - return result; - } - - result.elementName = path.GetCurrentAsString(); - result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; - if (!path.IsLast()) - result.next = TravelHierarchy(path); - return result; - } - - if (result.elementName == "extensions") - { - if (path.MoveNext()) - { - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.RootExtension; - result.next = TravelHierarchy(path); - } - } - else - { - result.next = TravelHierarchy(path); - } - - return result; - } - } - public class PathResolver : IEnumerator - { - private string[] _splittedPath; - private int currentIndex; - - public PathResolver (string path) - { - _splittedPath = path.Split("/"); - currentIndex = 0; - } - - public bool IsLast() - { - return currentIndex == _splittedPath.Length - 1; - } - - public string GetCurrentAsString() - { - return _splittedPath[currentIndex]; - } - - public bool GetCurrentAsInt(out int result) - { - return int.TryParse(_splittedPath[currentIndex], out result); - } - - public bool MoveNext() - { - currentIndex++; - return currentIndex < _splittedPath.Length; - } - - public void Reset() - { - currentIndex = 0; - } - - public object Current - { - get - { - if (currentIndex < _splittedPath.Length) - { - return _splittedPath[currentIndex]; - } - - return null; - } - } - } - - internal static class AnimationPointerHelpers - { - - private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; - - internal static bool Prepare(out AnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) - { - pointerData = new AnimationPointerData(); - - pointerData.animationType = typeof(MeshRenderer); // TODO: SkinnendMeshRenderer - var m = new MaterialPointerPropertyRemapper(); - m.AddDefaults(); - if (!m.GetUnityPropertyName(material, gltfProperty, out string unityPropertyName, - out MaterialPointerPropertyMap propertyMap, out bool isSecondaryGltfProperty)) - return false; - - switch (valueType) - { - case GLTFAccessorAttributeType.SCALAR: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 1, propertyMap); - break; - case GLTFAccessorAttributeType.VEC2: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 2, propertyMap); - break; - case GLTFAccessorAttributeType.VEC3: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 3, propertyMap); - break; - case GLTFAccessorAttributeType.VEC4: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 4, propertyMap); - break; - default: - return false; - } - - return true; - } - - internal static string[] GetAnimationChannelProperties(string propertyName, int componentCount, int componentOffset = 0) - { - var result = new string[ componentCount]; - if (componentCount == 1) - { - result[0] = $"material.{propertyName}"; - return result; - } - - for (int iComponent = 0; iComponent < componentCount; iComponent++) - result[iComponent] = $"material.{propertyName}.{MATERIAL_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; - return result; - } - - internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map) - { - float[] result = new float[componentCount]; - - if (map.convertToLinearColor && (componentCount == 3 || componentCount == 4)) - { - // TODO: ? - } - - switch (componentCount) - { - case 1: - result[0] = data.AsFloats[frame]; - break; - case 2: - var frameData2 = data.AsFloats2[frame]; - result[0] = frameData2.x; - result[1] = frameData2.y; - break; - case 3: - var frameData3 = data.AsFloats3[frame]; - result[0] = frameData3.x; - result[1] = frameData3.y; - result[2] = frameData3.z; - break; - case 4: - var frameData4 = data.AsFloats4[frame]; - result[0] = frameData4.x; - result[1] = frameData4.y; - result[2] = frameData4.z; - result[3] = frameData4.w; - break; - - } - - return result; - } - } - -} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs b/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs deleted file mode 100644 index 9a95b8854..000000000 --- a/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs +++ /dev/null @@ -1,315 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using GLTF.Schema; -using UnityEngine; - -namespace GLTF.Utilities -{ - public class MaterialPointerPropertyMap - { - public string[] propertyNames = new string[0]; - - public int[] propertyIds = new int[0]; - - public string[] customPropertyComponents = null; - - public string gltfPropertyName = null; - public string gltfSecondaryPropertyName = null; - public bool isTexture = false; - public bool isTextureTransform = false; - public bool keepColorAlpha = true; - public string extensionName = null; - public bool convertToLinearColor = false; - public bool flipValueRange = false; - - public void BuildPropertyIds() - { - propertyIds = new int[propertyNames.Length]; - for (int i = 0; i < propertyNames.Length; i++) - propertyIds[i] = Shader.PropertyToID(propertyNames[i]); - } - } - - public class MaterialPointerPropertyRemapper - { - public List maps = new List(); - - public void AddDefaults() - { - var baseColor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, - convertToLinearColor = true, - gltfPropertyName = "pbrMetallicRoughness/baseColorFactor" - }; - maps.Add(baseColor); - - var smoothness = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Smoothness", "_Glossiness" }, - flipValueRange = true, - gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" - }; - maps.Add(smoothness); - - var roughness = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, - gltfPropertyName = "pbrMetallicRoughness/roughnessFactor" - }; - - maps.Add(roughness); - - var metallic = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, - gltfPropertyName = "pbrMetallicRoughness/metallicFactor" - }; - maps.Add(metallic); - - var baseColorTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - maps.Add(baseColorTexture); - - var emissiveFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, - gltfPropertyName = "emissiveFactor", - gltfSecondaryPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", - extensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, - keepColorAlpha = false, - convertToLinearColor = true - }; - maps.Add(emissiveFactor); - - var emissiveTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(emissiveTexture); - - var alphaCutoff = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_AlphaCutoff", "alphaCutoff", "_Cutoff" }, - gltfPropertyName = "alphaCutoff" - }; - maps.Add(alphaCutoff); - - var normalScale = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, - gltfPropertyName = "normalTexture/scale" - }; - maps.Add(normalScale); - - var normalTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(normalTexture); - - var occlusionStrength = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, - gltfPropertyName = "occlusionTexture/strength" - }; - - maps.Add(occlusionStrength); - - var occlusionTexture = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, - isTexture = true, - isTextureTransform = true, - gltfPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", - gltfSecondaryPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME - }; - - maps.Add(occlusionTexture); - - // KHR_materials_transmission - var transmissionFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}", - extensionName = KHR_materials_transmission_Factory.EXTENSION_NAME - }; - maps.Add(transmissionFactor); - - // KHR_materials_volume - var thicknessFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME - }; - maps.Add(thicknessFactor); - - var attenuationDistance = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME - }; - - maps.Add(attenuationDistance); - - var attenuationColor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_AttenuationColor", "attenuationColor" }, - gltfPropertyName = - $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME, - keepColorAlpha = false - }; - - maps.Add(attenuationColor); - - // KHR_materials_ior - var ior = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_IOR", "ior" }, - gltfPropertyName = $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}", - extensionName = KHR_materials_ior_Factory.EXTENSION_NAME - }; - maps.Add(ior); - - // KHR_materials_iridescence - var iridescenceFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}", - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME - }; - - maps.Add(iridescenceFactor); - - // KHR_materials_specular - var specularFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_SpecularFactor", "specularFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}", - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME - }; - maps.Add(specularFactor); - - var specularColorFactor = new MaterialPointerPropertyMap - { - propertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, - gltfPropertyName = - $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME, - keepColorAlpha = false - }; - - maps.Add(specularColorFactor); - } - - public bool GetFromUnityMaterial(Material mat, string unityPropertyName, out string gltfPropertyName, out string extensionName, - out bool isTextureTransform, out bool keepColorAlpha, out bool convertToLinearColor, out bool flipValueRange) - { - gltfPropertyName = ""; - extensionName = ""; - isTextureTransform = false; - keepColorAlpha = true; - convertToLinearColor = false; - flipValueRange = false; - - foreach (var m in maps) - { - if (m.propertyNames.Contains(unityPropertyName)) - { - if (m.isTexture) - { - if (m.propertyIds.Length != m.propertyNames.Length) - { - m.BuildPropertyIds(); - } - bool valid = false; - for (int i = 0; i < m.propertyIds.Length; i++) - valid &= (mat.HasProperty(m.propertyIds[i]) && mat.GetTexture(m.propertyIds[i])); - if (!valid) - return false; - } - - gltfPropertyName = m.gltfPropertyName; - extensionName = m.extensionName; - isTextureTransform = m.isTextureTransform; - keepColorAlpha = m.keepColorAlpha; - convertToLinearColor = m.convertToLinearColor; - flipValueRange = m.flipValueRange; - return true; - } - } - - return false; - } - - public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName, out MaterialPointerPropertyMap map, out bool isSecondary) - { - foreach (var m in maps) - { - if (m.gltfPropertyName != gltfPropertyName && m.gltfSecondaryPropertyName != gltfPropertyName) - continue; - - for (int i = 0; i < m.propertyNames.Length; i++) - { - if (m.isTextureTransform) - { - foreach (var p in m.propertyNames) - { - var pWithOutST = p.Remove(p.Length - 3, 3); - if (mat.HasProperty(pWithOutST)) - { - map = m; - propertyName = p; - isSecondary = m.gltfSecondaryPropertyName == gltfPropertyName; - return true; - } - } - } - else - if (mat.HasProperty(m.propertyNames[i])) - { - map = m; - propertyName = m.propertyNames[i]; - isSecondary = m.gltfSecondaryPropertyName == gltfPropertyName; - return true; - } - } - } - - map = null; - propertyName = ""; - isSecondary = false; - return false; - } - - } - -} \ No newline at end of file diff --git a/Runtime/Scripts/Extensions/KHR_animation_pointer_Resolver.cs b/Runtime/Scripts/Extensions/KHR_animation_pointer_Resolver.cs index 0568c4c50..52ccfe2dd 100644 --- a/Runtime/Scripts/Extensions/KHR_animation_pointer_Resolver.cs +++ b/Runtime/Scripts/Extensions/KHR_animation_pointer_Resolver.cs @@ -14,24 +14,6 @@ public void Add(KHR_animation_pointer anim) registered.Add(anim); } - // private struct MaterialMapping - // { - // public string propertyName; - // public string exportName; - // } - // - // private readonly Dictionary> mappings = new Dictionary>(); - // - // // TODO: should we use a static switch instead? - // public void RegisterMapping(Material mat, string propertyName, string exportedPropertyName) - // { - // if (!mappings.ContainsKey(mat)) - // { - // mappings.Add(mat, new List()); - // } - // mappings[mat].Add(new MaterialMapping() { propertyName = propertyName, exportName = exportedPropertyName }); - // } - public void Resolve(GLTFSceneExporter exporter) { foreach (var reg in registered) diff --git a/Runtime/Scripts/Plugins/AnimationPointer.meta b/Runtime/Scripts/Plugins/AnimationPointer.meta new file mode 100644 index 000000000..63e639d42 --- /dev/null +++ b/Runtime/Scripts/Plugins/AnimationPointer.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bdaa28f0f907479faf8ffcc4e5233a12 +timeCreated: 1708087054 \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs new file mode 100644 index 000000000..16e76d246 --- /dev/null +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -0,0 +1,133 @@ +using GLTF.Schema; +using UnityEngine; + +namespace UnityGLTF.Plugins +{ + internal static class AnimationPointerHelpers + { + private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; + + internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, MaterialAnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) + { + if (!remapper.GetUnityPropertyName(material, gltfProperty, out string unityPropertyName, + out MaterialPointerPropertyMap propertyMap, out bool isSecondaryGltfProperty)) + return false; + + // e.g. Emission Factor and Emission Color are combined into a single property + if (isSecondaryGltfProperty && propertyMap.PrimaryAndSecondaryGetsCombined) + return false; + + if (propertyMap.PrimaryAndSecondaryGetsCombined) + { + if (propertyMap.CombinePrimaryAndSecondaryFunction == null) + return false; + pointerData.secondaryPath = propertyMap.GltfSecondaryPropertyName; + } + + var pointerDataCopy = pointerData; + switch (valueType) + { + case GLTFAccessorAttributeType.SCALAR: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 1, propertyMap, pointerDataCopy); + break; + case GLTFAccessorAttributeType.VEC2: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 2, propertyMap, pointerDataCopy); + break; + case GLTFAccessorAttributeType.VEC3: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 3, propertyMap, pointerDataCopy); + break; + case GLTFAccessorAttributeType.VEC4: + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 4, propertyMap, pointerDataCopy); + break; + default: + return false; + } + + return true; + } + + internal static string[] GetAnimationChannelProperties(string propertyName, int componentCount, int componentOffset = 0) + { + var result = new string[ componentCount]; + if (componentCount == 1) + { + result[0] = $"material.{propertyName}"; + return result; + } + + for (int iComponent = 0; iComponent < componentCount; iComponent++) + result[iComponent] = $"material.{propertyName}.{MATERIAL_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; + + return result; + } + + internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map, MaterialAnimationPointerData pointerData) + { + float[] result = new float[componentCount]; + + if (map.ExportConvertToLinearColor && (componentCount == 3 || componentCount == 4)) + { + // TODO: ? + } + + switch (componentCount) + { + case 1: + result[0] = data.AsFloats[frame]; + break; + case 2: + var frameData2 = data.AsFloats2[frame]; + result[0] = frameData2.x; + result[1] = frameData2.y; + break; + case 3: + var frameData3 = data.AsFloats3[frame]; + result[0] = frameData3.x; + result[1] = frameData3.y; + result[2] = frameData3.z; + break; + case 4: + var frameData4 = data.AsFloats4[frame]; + result[0] = frameData4.x; + result[1] = frameData4.y; + result[2] = frameData4.z; + result[3] = frameData4.w; + break; + } + + if (map.PrimaryAndSecondaryGetsCombined && map.CombinePrimaryAndSecondaryFunction != null) + { + float[] secondary = new float[0]; + NumericArray secondaryData = pointerData.secondaryData.AccessorContent; + switch (pointerData.secondaryData.AccessorId.Value.Type) + { + case GLTFAccessorAttributeType.SCALAR: + secondary = new float[] { secondaryData.AsFloats[frame] }; + break; + case GLTFAccessorAttributeType.VEC2: + var s2 = secondaryData.AsFloats2[frame]; + secondary = new float[] { s2.x, s2.y }; + break; + case GLTFAccessorAttributeType.VEC3: + var s3 = secondaryData.AsFloats3[frame]; + secondary = new float[] { s3.x, s3.y, s3.z }; + break; + case GLTFAccessorAttributeType.VEC4: + var s4 = secondaryData.AsFloats4[frame]; + secondary = new float[] { s4.x, s4.y, s4.z, s4.w }; + break; + default: + return result; + } + map.CombinePrimaryAndSecondaryFunction(result, secondary); + } + + return result; + } + } + +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs.meta b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs.meta similarity index 100% rename from Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerUtilities.cs.meta rename to Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs.meta diff --git a/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs new file mode 100644 index 000000000..9fe5e96f4 --- /dev/null +++ b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs @@ -0,0 +1,380 @@ +using System.Collections.Generic; +using System.Linq; +using GLTF.Schema; +using UnityEngine; +using UnityEngine.AI; + +namespace UnityGLTF.Plugins +{ + public class MaterialPointerPropertyMap + { + public string[] PropertyNames = new string[0]; + + internal int[] PropertyIds = new int[0]; + internal int[] PropertyTextureIds = new int[0]; + + public string GltfPropertyName = null; + public string GltfSecondaryPropertyName = null; + + public bool IsTexture = false; + public bool IsTextureTransform = false; + public bool PrimaryAndSecondaryGetsCombined = false; + + public bool ExportKeepColorAlpha = true; + public bool ExportConvertToLinearColor = false; + public bool ExportFlipValueRange = false; + public float ExportValueMultiplier = 1f; + public string ExtensionName = null; + + public delegate float[] CombinePrimaryAndSecondary(float[] primary, float[] secondary); + + public CombinePrimaryAndSecondary CombinePrimaryAndSecondaryFunction = null; + + internal void CreatePropertyIds() + { + PropertyIds = new int[PropertyNames.Length]; + for (int i = 0; i < PropertyNames.Length; i++) + PropertyIds[i] = Shader.PropertyToID(PropertyNames[i]); + + if (IsTextureTransform) + { + PropertyTextureIds = new int[PropertyNames.Length]; + for (int i = 0; i < PropertyNames.Length; i++) + { + var pWithoutST = PropertyNames[i].Remove(PropertyNames[i].Length - 3, 3); + + PropertyTextureIds[i] = Shader.PropertyToID(pWithoutST); + } + } + } + } + + public class MaterialPropertiesRemapper + { + private Dictionary maps = + new Dictionary(); + + public void AddMap(MaterialPointerPropertyMap map) + { + map.CreatePropertyIds(); + if (maps.ContainsKey(map.GltfPropertyName)) + return; + + maps.Add(map.GltfPropertyName, map); + } + + public bool GetMapFromUnityMaterial(Material mat, string unityPropertyName, out MaterialPointerPropertyMap map) + { + map = null; + foreach (var kvp in maps) + { + if (kvp.Value.PropertyNames.Contains(unityPropertyName)) + { + if (kvp.Value.IsTexture) + { + bool valid = false; + for (int i = 0; i < kvp.Value.PropertyIds.Length; i++) + valid &= (mat.HasProperty(kvp.Value.PropertyIds[i]) && mat.GetTexture(kvp.Value.PropertyIds[i])); + if (!valid) + return false; + } + + map = kvp.Value; + + return true; + } + } + + return false; + } + + public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName, + out MaterialPointerPropertyMap map, out bool isSecondary) + { + foreach (var kvp in maps) + { + var currentMap = kvp.Value; + if (currentMap.GltfPropertyName != gltfPropertyName && currentMap.GltfSecondaryPropertyName != gltfPropertyName) + continue; + + for (int i = 0; i < currentMap.PropertyNames.Length; i++) + { + if (currentMap.IsTextureTransform) + { + for (int j = 0; j < currentMap.PropertyNames.Length; j++) + { + if (mat.HasProperty(currentMap.PropertyTextureIds[j])) + { + map = currentMap; + propertyName = currentMap.PropertyNames[j]; + isSecondary = currentMap.GltfSecondaryPropertyName == gltfPropertyName; + return true; + } + } + } + else if (mat.HasProperty(currentMap.PropertyIds[i])) + { + map = currentMap; + propertyName = currentMap.PropertyNames[i]; + isSecondary = currentMap.GltfSecondaryPropertyName == gltfPropertyName; + return true; + } + } + } + + map = null; + propertyName = ""; + isSecondary = false; + return false; + } + } + + + public class DefaultMaterialPropertiesRemapper : MaterialPropertiesRemapper + { + public DefaultMaterialPropertiesRemapper() + { + var baseColor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, + ExportConvertToLinearColor = true, + GltfPropertyName = "pbrMetallicRoughness/baseColorFactor" + }; + AddMap(baseColor); + + var smoothness = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_Smoothness", "_Glossiness" }, + ExportFlipValueRange = true, + GltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + AddMap(smoothness); + + var roughness = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, + GltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + }; + AddMap(roughness); + + var metallic = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, + GltfPropertyName = "pbrMetallicRoughness/metallicFactor" + }; + AddMap(metallic); + + var baseColorTexture = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, + IsTexture = true, + IsTextureTransform = true, + GltfPropertyName = + $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + GltfSecondaryPropertyName = + $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + AddMap(baseColorTexture); + + var emissiveFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, + GltfPropertyName = "emissiveFactor", + GltfSecondaryPropertyName = + $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", + ExtensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, + PrimaryAndSecondaryGetsCombined = true, + ExportKeepColorAlpha = false, + ExportConvertToLinearColor = true, + CombinePrimaryAndSecondaryFunction = (primary, secondary) => + { + var result = new float[primary.Length]; + for (int i = 0; i < 3; i++) + result[i] = primary[i] * secondary[0]; + if (result.Length == 4) + result[3] = primary[3]; + return result; + } + }; + AddMap(emissiveFactor); + + var emissiveTexture = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, + IsTexture = true, + IsTextureTransform = true, + GltfPropertyName = + $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + GltfSecondaryPropertyName = + $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + AddMap(emissiveTexture); + + /*var roughnessTex = new MaterialPointerPropertyMap + { + propertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, + isTexture = true, + isTextureTransform = true, + gltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + gltfSecondaryPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + + maps.Add(roughnessTex); */ + + var alphaCutoff = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_AlphaCutoff", "alphaCutoff", "_Cutoff" }, + GltfPropertyName = "alphaCutoff" + }; + AddMap(alphaCutoff); + + var normalScale = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, + GltfPropertyName = "normalTexture/scale" + }; + AddMap(normalScale); + + var normalTexture = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, + IsTexture = true, + IsTextureTransform = true, + GltfPropertyName = + $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + GltfSecondaryPropertyName = + $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + AddMap(normalTexture); + + var occlusionStrength = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, + GltfPropertyName = "occlusionTexture/strength" + }; + AddMap(occlusionStrength); + + var occlusionTexture = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, + IsTexture = true, + IsTextureTransform = true, + GltfPropertyName = + $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", + GltfSecondaryPropertyName = + $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", + ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + }; + AddMap(occlusionTexture); + + // KHR_materials_transmission + var transmissionFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, + GltfPropertyName = + $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}", + ExtensionName = KHR_materials_transmission_Factory.EXTENSION_NAME + }; + AddMap(transmissionFactor); + + // KHR_materials_volume + var thicknessFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, + GltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}", + ExtensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + AddMap(thicknessFactor); + + var attenuationDistance = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, + GltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}", + ExtensionName = KHR_materials_volume_Factory.EXTENSION_NAME + }; + AddMap(attenuationDistance); + + var attenuationColor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_AttenuationColor", "attenuationColor" }, + GltfPropertyName = + $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", + ExtensionName = KHR_materials_volume_Factory.EXTENSION_NAME, + ExportKeepColorAlpha = false + }; + AddMap(attenuationColor); + + // KHR_materials_ior + var ior = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_IOR", "ior" }, + GltfPropertyName = + $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}", + ExtensionName = KHR_materials_ior_Factory.EXTENSION_NAME + }; + AddMap(ior); + + // KHR_materials_iridescence + var iridescenceFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, + GltfPropertyName = + $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}", + ExtensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME + }; + AddMap(iridescenceFactor); + + // KHR_materials_specular + var specularFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_SpecularFactor", "specularFactor" }, + GltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}", + ExtensionName = KHR_materials_specular_Factory.EXTENSION_NAME + }; + AddMap(specularFactor); + + var specularColorFactor = new MaterialPointerPropertyMap + { + PropertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, + GltfPropertyName = + $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", + ExtensionName = KHR_materials_specular_Factory.EXTENSION_NAME, + ExportKeepColorAlpha = false + }; + AddMap(specularColorFactor); + + + // TODO KHR_materials_clearcoat + // case "_ClearcoatFactor": + // case "clearcoatFactor": + // propertyName = $"extensions/{KHR_materials_clearcoat_Factory.EXTENSION_NAME}/{nameof(KHR_materials_clearcoat.clearcoatFactor)}"; + // extensionName = KHR_materials_clearcoat_Factory.EXTENSION_NAME; + // break; + // case "_ClearcoatRoughnessFactor": + // case "clearcoatRoughnessFactor": + // propertyName = $"extensions/{KHR_materials_clearcoat_Factory.EXTENSION_NAME}/{nameof(KHR_materials_clearcoat.clearcoatRoughnessFactor)}"; + // extensionName = KHR_materials_clearcoat_Factory.EXTENSION_NAME; + // break; + + // TODO KHR_materials_sheen + // case "_SheenColorFactor": + // case "sheenColorFactor": + // propertyName = $"extensions/{KHR_materials_sheen_Factory.EXTENSION_NAME}/{nameof(KHR_materials_sheen.sheenColorFactor)}"; + // extensionName = KHR_materials_sheen_Factory.EXTENSION_NAME; + // keepColorAlpha = false; + // break; + // case "_SheenRoughnessFactor": + // case "sheenRoughnessFactor": + // propertyName = $"extensions/{KHR_materials_sheen_Factory.EXTENSION_NAME}/{nameof(KHR_materials_sheen.sheenRoughnessFactor)}"; + // extensionName = KHR_materials_sheen_Factory.EXTENSION_NAME; + // break; + } + } +} \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs.meta similarity index 100% rename from Runtime/Plugins/GLTFSerialization/Utilities/MaterialPropertyMapper.cs.meta rename to Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs.meta diff --git a/Runtime/Scripts/Plugins/AnimationPointerExport.cs b/Runtime/Scripts/Plugins/AnimationPointerExport.cs index 8569a2ff2..2fd609db4 100644 --- a/Runtime/Scripts/Plugins/AnimationPointerExport.cs +++ b/Runtime/Scripts/Plugins/AnimationPointerExport.cs @@ -13,6 +13,7 @@ public override GLTFExportPluginContext CreateInstance(ExportContext context) public class AnimationPointerExportContext: GLTFExportPluginContext { + public MaterialPropertiesRemapper materialPropertiesRemapper = new DefaultMaterialPropertiesRemapper(); } } \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/AnimationPointerImport.cs b/Runtime/Scripts/Plugins/AnimationPointerImport.cs index e7199d12a..7588b7d0d 100644 --- a/Runtime/Scripts/Plugins/AnimationPointerImport.cs +++ b/Runtime/Scripts/Plugins/AnimationPointerImport.cs @@ -12,6 +12,6 @@ public override GLTFImportPluginContext CreateInstance(GLTFImportContext context public class AnimationPointerImportContext: GLTFImportPluginContext { - + public MaterialPropertiesRemapper materialPropertiesRemapper = new DefaultMaterialPropertiesRemapper(); } } \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/Core/ImportContext.cs b/Runtime/Scripts/Plugins/Core/ImportContext.cs index e1198b483..40a9bf119 100644 --- a/Runtime/Scripts/Plugins/Core/ImportContext.cs +++ b/Runtime/Scripts/Plugins/Core/ImportContext.cs @@ -51,8 +51,8 @@ internal GLTFImportContext(GLTFSettings settings) { Plugins = InitializePlugins(settings); } - - public bool TryGetPlugin(out GLTFImportPluginContext o) where T: GLTFImportPluginContext + + public bool TryGetPlugin(out T o) where T: GLTFImportPluginContext { foreach (var plugin in Plugins) { diff --git a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs index ef0976bc1..54bbccf9f 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs @@ -3,6 +3,7 @@ using System.Linq; using GLTF.Schema; using GLTF.Schema.KHR_lights_punctual; +using GLTF.Utilities; using UnityEngine; using UnityGLTF.Extensions; using UnityGLTF.JsonPointer; @@ -16,26 +17,6 @@ public partial class GLTFSceneExporter internal readonly List pointerResolvers = new List(); private readonly KHR_animation_pointer_Resolver animationPointerResolver = new KHR_animation_pointer_Resolver(); -#region Shader Property Names - // ReSharper disable InconsistentNaming - - private static readonly int _MainTex = Shader.PropertyToID("_MainTex"); - private static readonly int _BaseMap = Shader.PropertyToID("_BaseMap"); - private static readonly int _BaseColorTexture = Shader.PropertyToID("_BaseColorTexture"); - private static readonly int baseColorTexture = Shader.PropertyToID("baseColorTexture"); - private static readonly int _EmissionMap = Shader.PropertyToID("_EmissionMap"); - private static readonly int _EmissiveTexture = Shader.PropertyToID("_EmissiveTexture"); - private static readonly int emissiveTexture = Shader.PropertyToID("emissiveTexture"); - private static readonly int _BumpMap = Shader.PropertyToID("_BumpMap"); - private static readonly int _NormalTexture = Shader.PropertyToID("_NormalTexture"); - private static readonly int normalTexture = Shader.PropertyToID("normalTexture"); - private static readonly int _OcclusionMap = Shader.PropertyToID("_OcclusionMap"); - private static readonly int _OcclusionTexture = Shader.PropertyToID("_OcclusionTexture"); - private static readonly int occlusionTexture = Shader.PropertyToID("occlusionTexture"); - - // ReSharper restore InconsistentNaming -#endregion - public void RegisterResolver(IJsonPointerResolver resolver) { if (!pointerResolvers.Contains(resolver)) @@ -66,7 +47,7 @@ public void RegisterResolver(IJsonPointerResolver resolver) public void AddAnimationData(Object animatedObject, string propertyName, GLTFAnimation animation, float[] times, object[] values) { if (!animatedObject) return; - + // TODO should skip property switches that are not supported without KHR_animation_pointer // TODO should probably start with the transform check below and stop afterwards if KHR_animation_pointer is off @@ -94,206 +75,42 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni string secondPropertyName = null; string extensionName = null; var propertyType = values[0]?.GetType(); + + var animationPointerExportContext = _plugins.FirstOrDefault(x => x is AnimationPointerExportContext) as AnimationPointerExportContext; switch (animatedObject) { case Material material: // Debug.Log("material: " + material + ", propertyName: " + propertyName); // mapping from known Unity property names to glTF property names - switch (propertyName) + if (animationPointerExportContext == null || + animationPointerExportContext.materialPropertiesRemapper == null) { - - case "_Color": - case "_BaseColor": - case "_BaseColorFactor": - case "baseColorFactor": - propertyName = "pbrMetallicRoughness/baseColorFactor"; - convertToLinearColor = true; - break; - case "_Smoothness": - case "_Glossiness": - propertyName = "pbrMetallicRoughness/roughnessFactor"; - flipValueRange = true; - break; - case "_Roughness": - case "_RoughnessFactor": - case "roughnessFactor": - propertyName = "pbrMetallicRoughness/roughnessFactor"; - break; - case "_Metallic": - case "_MetallicFactor": - case "metallicFactor": - propertyName = "pbrMetallicRoughness/metallicFactor"; - break; - case "_MainTex_ST": - case "_BaseMap_ST": - case "_BaseColorTexture_ST": - case "baseColorTexture_ST": - if (!(material.HasProperty(_MainTex) && material.GetTexture(_MainTex)) && - !(material.HasProperty(_BaseMap) && material.GetTexture(_BaseMap)) && - !(material.HasProperty(_BaseColorTexture) && material.GetTexture(_BaseColorTexture)) && - !(material.HasProperty(baseColorTexture) && material.GetTexture(baseColorTexture))) return; - propertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}"; - secondPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}"; - isTextureTransform = true; - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME; - break; - case "_EmissionColor": - case "_EmissiveFactor": - case "emissiveFactor": - propertyName = "emissiveFactor"; - secondPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}"; - extensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME; - keepColorAlpha = false; - convertToLinearColor = true; - break; - case "_EmissionMap_ST": - case "_EmissiveTexture_ST": - case "emissiveTexture_ST": - if (!(material.HasProperty(_EmissionMap) && material.GetTexture(_EmissionMap)) && - !(material.HasProperty(_EmissiveTexture) && material.GetTexture(_EmissiveTexture)) && - !(material.HasProperty(emissiveTexture) && material.GetTexture(emissiveTexture))) return; - propertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}"; - secondPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}"; - isTextureTransform = true; - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME; - break; - case "_Cutoff": - case "_AlphaCutoff": - case "alphaCutoff": - propertyName = "alphaCutoff"; - break; - case "_BumpScale": - case "_NormalScale": - case "normalScale": - case "normalTextureScale": - propertyName = "normalTexture/scale"; - break; - case "_BumpMap_ST": - case "_NormalTexture_ST": - case "normalTexture_ST": - if (!(material.HasProperty(_BumpMap) && material.GetTexture(_BumpMap)) && - !(material.HasProperty(_NormalTexture) && material.GetTexture(_NormalTexture)) && - !(material.HasProperty(normalTexture) && material.GetTexture(normalTexture))) return; - propertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}"; - secondPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}"; - isTextureTransform = true; - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME; - break; - case "_OcclusionStrength": - case "occlusionStrength": - case "occlusionTextureStrength": - propertyName = "occlusionTexture/strength"; - break; - case "_OcclusionMap_ST": - case "_OcclusionTexture_ST": - case "occlusionTexture_ST": - if (!(material.HasProperty(_OcclusionMap) && material.GetTexture(_OcclusionMap)) && - !(material.HasProperty(_OcclusionTexture) && material.GetTexture(_OcclusionTexture)) && - !(material.HasProperty(occlusionTexture) && material.GetTexture(occlusionTexture))) return; - propertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}"; - secondPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}"; - isTextureTransform = true; - extensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME; - break; - - // TODO metallic/roughness _ST - - // KHR_materials_transmission - case "_TransmissionFactor": - case "transmissionFactor": - propertyName = $"extensions/{KHR_materials_transmission_Factory.EXTENSION_NAME}/{nameof(KHR_materials_transmission.transmissionFactor)}"; - extensionName = KHR_materials_transmission_Factory.EXTENSION_NAME; - break; - - // KHR_materials_volume - case "_ThicknessFactor": - case "thicknessFactor": - propertyName = $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.thicknessFactor)}"; - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME; - break; - case "_AttenuationDistance": - case "attenuationDistance": - propertyName = $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationDistance)}"; - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME; - break; - case "_AttenuationColor": - case "attenuationColor": - propertyName = $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}"; - extensionName = KHR_materials_volume_Factory.EXTENSION_NAME; - keepColorAlpha = false; - break; - - // KHR_materials_ior - case "_IOR": - case "ior": - propertyName = $"extensions/{KHR_materials_ior_Factory.EXTENSION_NAME}/{nameof(KHR_materials_ior.ior)}"; - extensionName = KHR_materials_ior_Factory.EXTENSION_NAME; - break; - - // KHR_materials_iridescence - case "_IridescenceFactor": - case "iridescenceFactor": - propertyName = $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceFactor)}"; - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME; - break; - case "_IridescenceIor": - case "iridescenceIor": - propertyName = $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceIor)}"; - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME; - break; - case "_IridescenceThicknessMinimum": - case "iridescenceThicknessMinimum": - propertyName = $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceThicknessMinimum)}"; - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME; - break; - case "_IridescenceThicknessMaximum": - case "iridescenceThicknessMaximum": - propertyName = $"extensions/{KHR_materials_iridescence_Factory.EXTENSION_NAME}/{nameof(KHR_materials_iridescence.iridescenceThicknessMaximum)}"; - extensionName = KHR_materials_iridescence_Factory.EXTENSION_NAME; - break; - - // KHR_materials_specular - case "_SpecularFactor": - case "specularFactor": - propertyName = $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularFactor)}"; - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME; - break; - case "_SpecularColorFactor": - case "specularColorFactor": - propertyName = $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}"; - extensionName = KHR_materials_specular_Factory.EXTENSION_NAME; - keepColorAlpha = false; - break; + if (animationPointerExportContext == null) + Debug.Log(LogType.Error, "No AnimationPointerExportContext found in GLTFSceneExporter. Skipping animation"); + else + Debug.Log(LogType.Error, "No MaterialPropertiesRemapper found in AnimationPointerExportContext. Skipping animation"); + return; + } + + if (!animationPointerExportContext.materialPropertiesRemapper.GetMapFromUnityMaterial(material, propertyName, out MaterialPointerPropertyMap map)) + { + Debug.Log(LogType.Warning, "Unknown property name on Material " + material + ": " + propertyName); - // TODO KHR_materials_clearcoat - // case "_ClearcoatFactor": - // case "clearcoatFactor": - // propertyName = $"extensions/{KHR_materials_clearcoat_Factory.EXTENSION_NAME}/{nameof(KHR_materials_clearcoat.clearcoatFactor)}"; - // extensionName = KHR_materials_clearcoat_Factory.EXTENSION_NAME; - // break; - // case "_ClearcoatRoughnessFactor": - // case "clearcoatRoughnessFactor": - // propertyName = $"extensions/{KHR_materials_clearcoat_Factory.EXTENSION_NAME}/{nameof(KHR_materials_clearcoat.clearcoatRoughnessFactor)}"; - // extensionName = KHR_materials_clearcoat_Factory.EXTENSION_NAME; - // break; - - // TODO KHR_materials_sheen - // case "_SheenColorFactor": - // case "sheenColorFactor": - // propertyName = $"extensions/{KHR_materials_sheen_Factory.EXTENSION_NAME}/{nameof(KHR_materials_sheen.sheenColorFactor)}"; - // extensionName = KHR_materials_sheen_Factory.EXTENSION_NAME; - // keepColorAlpha = false; - // break; - // case "_SheenRoughnessFactor": - // case "sheenRoughnessFactor": - // propertyName = $"extensions/{KHR_materials_sheen_Factory.EXTENSION_NAME}/{nameof(KHR_materials_sheen.sheenRoughnessFactor)}"; - // extensionName = KHR_materials_sheen_Factory.EXTENSION_NAME; - // break; - default: - Debug.Log(LogType.Warning, "Unknown property name on Material " + material + ": " + propertyName); - break; + return; } + + secondPropertyName = map.GltfSecondaryPropertyName; + propertyName = map.GltfPropertyName; + extensionName = map.ExtensionName; + + flipValueRange = map.ExportFlipValueRange; + valueMultiplier = map.ExportValueMultiplier == 1f ? null : map.ExportValueMultiplier; + isTextureTransform = map.IsTextureTransform; + keepColorAlpha = map.ExportKeepColorAlpha; + convertToLinearColor = map.ExportConvertToLinearColor; + + break; case Light light: extensionName = KHR_lights_punctualExtensionFactory.EXTENSION_NAME; diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 9832f6618..59e728594 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -269,6 +269,8 @@ protected async Task ConstructClip(Transform root, int animationI int[] nodeIds = new int[0]; + AnimationPointerImportContext pointerImportContext = null; + foreach (AnimationChannel channel in animation.Channels) { bool usesPointer = false; @@ -278,7 +280,7 @@ protected async Task ConstructClip(Transform root, int animationI KHR_animation_pointer.EXTENSION_NAME, out pointerExtension)) { - if (Context.TryGetPlugin(out _)) + if (Context.TryGetPlugin(out pointerImportContext)) usesPointer = true; } @@ -304,89 +306,93 @@ protected async Task ConstructClip(Transform root, int animationI path = GLTFAnimationChannelPath.pointer; relativePath = pointer.path; - var pointerHierarchy = AnimationPointerPathHierarchy.CreateHierarchyFromFullPath(relativePath); + var pointerHierarchy = AnimationPointerPathHierarchy.CreateHierarchyFromPath(relativePath); - if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.RootExtension) + switch (pointerHierarchy.elementType) { - if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) - continue; - - if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) - { - if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) - nodeIds = new int[] { pointerData.nodeId}; - else + case AnimationPointerPathHierarchy.ElementTypeOptions.RootExtension: + if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) continue; - } - } - else - if (pointerHierarchy.elementType == AnimationPointerPathHierarchy.ElementTypeOptions.Root) - { - var rootType = pointerHierarchy.elementName; - var rootIndex = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); - if (rootIndex == null) - continue; - - switch (rootType) - { - case "nodes": - var pointerPropertyElement = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); - if (pointerPropertyElement == null) - continue; - - pointerData = new AnimationPointerData(); - pointerData.nodeId = rootIndex.index; - nodeIds = new int[] {rootIndex.index}; - - switch (pointerPropertyElement.elementName) - { - case "translation": - path = GLTFAnimationChannelPath.translation; - break; - case "rotation": - path = GLTFAnimationChannelPath.rotation; - break; - case "scale": - path = GLTFAnimationChannelPath.scale; - break; - case "weights": - path = GLTFAnimationChannelPath.weights; - break; - } - - break; - case "materials": - nodeIds = _gltfRoot.GetAllNodeIdsWithMaterialId(rootIndex.index); - if (nodeIds.Length == 0) + + if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) + { + if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) + nodeIds = new int[] { pointerData.nodeId}; + else continue; - var materialPath = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; - if (materialPath == null) - continue; - + } + break; + case AnimationPointerPathHierarchy.ElementTypeOptions.Root: + var rootType = pointerHierarchy.elementName; + var rootIndex = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + if (rootIndex == null) + continue; + + switch (rootType) + { + case "nodes": + var pointerPropertyElement = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + if (pointerPropertyElement == null) + continue; - var gltfPropertyPath = materialPath.GetPath(); - if (gltfPropertyPath.Contains("scale") || gltfPropertyPath.Contains("offset")) - { - Debug.Log(""); - } - - var mat = _assetCache.MaterialCache[rootIndex.index]; + pointerData = new AnimationPointerData(); + pointerData.nodeId = rootIndex.index; + nodeIds = new int[] {rootIndex.index}; + + // Convert translate, scale, rotation from pointer path to to GLTFAnimationChannelPath, so we can use the same code as the other channels + if (!GLTFAnimationChannelPath.TryParse(pointerPropertyElement.elementName, out path)) + continue; + + break; + case "materials": + nodeIds = _gltfRoot.GetAllNodeIdsWithMaterialId(rootIndex.index); + if (nodeIds.Length == 0) + continue; + var materialPath = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; + if (materialPath == null) + continue; - if (!AnimationPointerHelpers.Prepare(out pointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) + var gltfPropertyPath = materialPath.ExtractPath(); + var mat = _assetCache.MaterialCache[rootIndex.index]; + + var matPointerData = new MaterialAnimationPointerData(); + pointerData = matPointerData; + + if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, matPointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) + continue; + if (!string.IsNullOrEmpty(matPointerData.secondaryPath)) + { + // When an property has potentially a second Sampler, we need to find it. e.g. like EmissionFactor and EmissionStrength + string secondaryPath = $"/{pointerHierarchy.elementName}/{rootIndex.index.ToString()}/{matPointerData.secondaryPath}"; + foreach (AnimationChannel secondAnimationChannel in animation.Channels) + { + if (secondAnimationChannel.Target.Extensions == null || !secondAnimationChannel.Target.Extensions.TryGetValue(KHR_animation_pointer.EXTENSION_NAME, out IExtension secondaryExt)) + continue; + if (secondaryExt is KHR_animation_pointer secondaryPointer) + { + AnimationSamplerCacheData secondarySamplerCache = animationCache.Samplers[secondAnimationChannel.Sampler.Id]; + if (secondaryPointer.path == secondaryPath) + { + + matPointerData.secondaryData = secondarySamplerCache.Output; + break; + } + } + } + } + break; + //case "cameras": + //nodeId = _gltfRoot.Cameras[rootIndex]. pointerHierarchy.index; + //break; + default: continue; - - break; - - - //case "cameras": - //nodeId = _gltfRoot.Cameras[rootIndex]. pointerHierarchy.index; - //break; - default: - continue; //throw new NotImplementedException(); - } + } break; + default: + continue; } - else + + if (pointerData == null) continue; } else @@ -396,6 +402,7 @@ protected async Task ConstructClip(Transform root, int animationI nodeIds = new int[] {channel.Target.Node.Id}; } + // In case an animated material are referenced from many nodes, whe need to create a curve for each node foreach (var nodeId in nodeIds) { var node = await GetNode(nodeId, cancellationToken); @@ -409,16 +416,20 @@ protected async Task ConstructClip(Transform root, int animationI var known = Enum.TryParse(channel.Target.Path, out path); if (!known) continue; } + else + { + pointerData.animationType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); + } + switch (path) { case GLTFAnimationChannelPath.pointer: - if (pointerData == null) - continue; + if (pointerData.conversion == null) continue; - propertyNames = pointerData.unityProperties; - SetAnimationCurve(clip, relativePath, propertyNames, input, output, + + SetAnimationCurve(clip, relativePath, pointerData.unityProperties, input, output, samplerCache.Interpolation, pointerData.animationType, (data, frame) => pointerData.conversion(data, frame)); break; diff --git a/Runtime/Scripts/SceneImporter/ImporterMaterials.cs b/Runtime/Scripts/SceneImporter/ImporterMaterials.cs index 413a0fd74..2caddc926 100644 --- a/Runtime/Scripts/SceneImporter/ImporterMaterials.cs +++ b/Runtime/Scripts/SceneImporter/ImporterMaterials.cs @@ -670,6 +670,7 @@ void SetTransformKeyword() } } + // ?? uniformMapper.EmissiveFactor = QualitySettings.activeColorSpace == ColorSpace.Linear ? def.EmissiveFactor.ToUnityColorLinear() : def.EmissiveFactor.ToUnityColorLinear(); var emissiveExt = GetEmissiveStrength(def); From 5d48669a5974db95312b2498518da39222246d6a Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 11:54:24 +0100 Subject: [PATCH 08/20] added camera import for nodes and animationpointer --- .../Schema/AnimationPointerData.cs | 3 - .../Utilities/GltfRootExtensions.cs | 13 +++ .../AnimationPointerUtilities.cs | 4 +- .../SceneImporter/ImporterAnimation.cs | 107 ++++++++++++++---- 4 files changed, 98 insertions(+), 29 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs index 4efda5be0..b8937e3a1 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs @@ -10,10 +10,7 @@ public class AnimationPointerData public delegate float[] ValuesConvertion(NumericArray data, int frame); public ValuesConvertion conversion; - } - public class MaterialAnimationPointerData : AnimationPointerData - { public string secondaryPath = ""; public AttributeAccessor secondaryData; } diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs index 3247ea07f..771a19f04 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/GltfRootExtensions.cs @@ -34,5 +34,18 @@ public static int[] GetAllNodeIdsWithMaterialId(this GLTFRoot root, int id) return ids.ToArray(); } + public static int[] GetAllNodeIdsWithCameraId(this GLTFRoot root, int id) + { + List ids = new List(); + + for (int i = 0; i < root.Nodes.Count; i++) + { + if (root.Nodes[i].Camera != null && root.Nodes[i].Camera.Id == id) + ids.Add(i); + } + + return ids.ToArray(); + } + } } \ No newline at end of file diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs index 16e76d246..ffc85c270 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -7,7 +7,7 @@ internal static class AnimationPointerHelpers { private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; - internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, MaterialAnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) + internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, AnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) { if (!remapper.GetUnityPropertyName(material, gltfProperty, out string unityPropertyName, out MaterialPointerPropertyMap propertyMap, out bool isSecondaryGltfProperty)) @@ -65,7 +65,7 @@ internal static string[] GetAnimationChannelProperties(string propertyName, int return result; } - internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map, MaterialAnimationPointerData pointerData) + internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map, AnimationPointerData pointerData) { float[] result = new float[componentCount]; diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 59e728594..b6ac2cd32 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -270,7 +270,29 @@ protected async Task ConstructClip(Transform root, int animationI int[] nodeIds = new int[0]; AnimationPointerImportContext pointerImportContext = null; - + + AttributeAccessor FindSecondaryChannel(string animationPointerPath) + { + foreach (AnimationChannel secondAnimationChannel in animation.Channels) + { + if (secondAnimationChannel.Target.Extensions == null || + !secondAnimationChannel.Target.Extensions.TryGetValue(KHR_animation_pointer.EXTENSION_NAME, + out IExtension secondaryExt)) + continue; + if (secondaryExt is KHR_animation_pointer secondaryPointer) + { + AnimationSamplerCacheData secondarySamplerCache = + animationCache.Samplers[secondAnimationChannel.Sampler.Id]; + if (secondaryPointer.path == animationPointerPath) + { + return secondarySamplerCache.Output; + } + } + } + + return null; + } + foreach (AnimationChannel channel in animation.Channels) { bool usesPointer = false; @@ -355,35 +377,71 @@ protected async Task ConstructClip(Transform root, int animationI var gltfPropertyPath = materialPath.ExtractPath(); var mat = _assetCache.MaterialCache[rootIndex.index]; - var matPointerData = new MaterialAnimationPointerData(); - pointerData = matPointerData; + pointerData = new AnimationPointerData(); - if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, matPointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) + if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, pointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) continue; - if (!string.IsNullOrEmpty(matPointerData.secondaryPath)) + if (!string.IsNullOrEmpty(pointerData.secondaryPath)) { // When an property has potentially a second Sampler, we need to find it. e.g. like EmissionFactor and EmissionStrength - string secondaryPath = $"/{pointerHierarchy.elementName}/{rootIndex.index.ToString()}/{matPointerData.secondaryPath}"; - foreach (AnimationChannel secondAnimationChannel in animation.Channels) - { - if (secondAnimationChannel.Target.Extensions == null || !secondAnimationChannel.Target.Extensions.TryGetValue(KHR_animation_pointer.EXTENSION_NAME, out IExtension secondaryExt)) - continue; - if (secondaryExt is KHR_animation_pointer secondaryPointer) + string secondaryPath = $"/{pointerHierarchy.elementName}/{rootIndex.index.ToString()}/{pointerData.secondaryPath}"; + pointerData.secondaryData = FindSecondaryChannel(secondaryPath); + } + break; + case "cameras": + int cameraId = rootIndex.index; + pointerData = new AnimationPointerData(); + pointerData.animationType = typeof(Camera); + + string gltfCameraPropertyPath = rootIndex.next.ExtractPath(); + switch (gltfCameraPropertyPath) + { + case "orthographic/ymag": + pointerData.secondaryPath = $"/{pointerHierarchy.elementName}/{rootIndex.index.ToString()}/orthographic/xmag"; + pointerData.unityProperties = new string[] { "orthographic size" }; + pointerData.secondaryData = FindSecondaryChannel(pointerData.secondaryPath); + pointerData.conversion = (data, frame) => + { + var xmag = pointerData.secondaryData.AccessorContent.AsFloats[frame]; + var ymag = data.AsFloats[frame]; + return new float[] {Mathf.Max(xmag, ymag)}; + }; + break; + case "orthographic/xmag": + continue; + case "orthographic/znear": + pointerData.unityProperties = new string[] { "near clip plane" }; + pointerData.conversion = (data, frame) => + new float[] {data.AsFloats[frame]}; + break; + case "orthographic/zfar": + pointerData.unityProperties = new string[] { "far clip plane" }; + pointerData.conversion = (data, frame) => + new float[] {data.AsFloats[frame]}; + break; + case "perspective/yfov": + pointerData.unityProperties = new string[] { "field of view" }; + pointerData.conversion = (data, frame) => { - AnimationSamplerCacheData secondarySamplerCache = animationCache.Samplers[secondAnimationChannel.Sampler.Id]; - if (secondaryPointer.path == secondaryPath) - { - - matPointerData.secondaryData = secondarySamplerCache.Output; - break; - } - } - } + var fov = data.AsFloats[frame] * Mathf.Rad2Deg; + return new float[] {fov}; + }; + break; + case "backgroundColor": + pointerData.unityProperties = new string[] { "background color.r", "background color.g", "background color.b", "background color.a" }; + pointerData.conversion = (data, frame) => + { + var color = data.AsFloats4[frame].ToUnityColorRaw(); + return new float[] {color.r, color.g, color.b, color.a}; + }; + break; + default: + Debug.Log(LogType.Warning, "Unknown property name on Camera " + cameraId.ToString() + ": " + gltfCameraPropertyPath); + break; } + + nodeIds = _gltfRoot.GetAllNodeIdsWithCameraId(cameraId); break; - //case "cameras": - //nodeId = _gltfRoot.Cameras[rootIndex]. pointerHierarchy.index; - //break; default: continue; //throw new NotImplementedException(); @@ -418,7 +476,8 @@ protected async Task ConstructClip(Transform root, int animationI } else { - pointerData.animationType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); + if (pointerData.animationType == null) + pointerData.animationType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); } From 94a762d8bb8280679282f6c1b043154bf3bc9981 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 17:16:54 +0100 Subject: [PATCH 09/20] added missing perspective clip plane import for camera animationpointer --- Runtime/Scripts/SceneImporter/ImporterAnimation.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index b6ac2cd32..59ba8f830 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -409,11 +409,13 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) break; case "orthographic/xmag": continue; + case "perspective/znear": case "orthographic/znear": pointerData.unityProperties = new string[] { "near clip plane" }; pointerData.conversion = (data, frame) => new float[] {data.AsFloats[frame]}; break; + case "perspective/zfar": case "orthographic/zfar": pointerData.unityProperties = new string[] { "far clip plane" }; pointerData.conversion = (data, frame) => From ee9d14367652f77f8a08746fe0c0845854f3c0ae Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 17:17:32 +0100 Subject: [PATCH 10/20] added Extension Class for GLTFAccessorAttributeType to get component count --- .../GLTFSerialization/Schema/Accessor.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs b/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs index 444d390ae..d39ee6bc4 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs @@ -1390,6 +1390,32 @@ public enum GLTFAccessorAttributeType MAT4 } + public static class GLTFAccessorAttributeTypeExtensions + { + public static int ComponentCount(this GLTFAccessorAttributeType attrType) + { + switch (attrType) + { + case GLTFAccessorAttributeType.SCALAR: + return 1; + case GLTFAccessorAttributeType.VEC2: + return 2; + case GLTFAccessorAttributeType.VEC3: + return 3; + case GLTFAccessorAttributeType.VEC4: + return 4; + case GLTFAccessorAttributeType.MAT2: + return 4; + case GLTFAccessorAttributeType.MAT3: + return 9; + case GLTFAccessorAttributeType.MAT4: + return 16; + } + + return 0; + } + } + /// [StructLayout(LayoutKind.Explicit)] public struct NumericArray From 828631912d0112739fc6ac102690e23839ea705e Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 17:38:49 +0100 Subject: [PATCH 11/20] added conversion to gamme color space for KHR_light_punctual animation pointers --- .../Extensions/KHR_LightsPunctualExtension.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 86800dc0a..f07997a72 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -344,8 +344,10 @@ private static AnimationPointerData.ValuesConvertion GetConversion(string gltfPr case "color": return (NumericArray data, int frame) => { - var col = data.AsFloats3[frame]; - return new float[] { col.x, col.y, col.z }; + var col = data.AsFloats3[frame]; + var color = new Color(col[0], col[1], col[2], 1f).ToUnityColorRaw(); + return new float[] { color.r, color.g, color.b }; + //return new float[] { col.x, col.y, col.z }; }; case "intensity": return (data, frame) => new float[1] { data.AsFloats[frame] / Mathf.PI }; From 5054a4f8aea7f69955a6d2f74186bf2429a000da Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 17:40:50 +0100 Subject: [PATCH 12/20] fixed innerspotangle on lights when importing and exporting them as an animationpointer --- .../Extensions/KHR_LightsPunctualExtension.cs | 4 ++-- Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index f07997a72..61aaaa6b5 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -354,9 +354,9 @@ private static AnimationPointerData.ValuesConvertion GetConversion(string gltfPr case "range": return (data, frame) => new float[1] { data.AsFloats[frame] }; case "spot/innerConeAngle": - return (data, frame) => new float[] { data.AsFloats[frame] * 2 / (Mathf.Deg2Rad * 0.8f) }; + return (data, frame) => new float[] { data.AsFloats[frame] * 2 / (Mathf.Deg2Rad * 0.8f)}; case "spot/outerConeAngle": - return (data, frame) => new float[] { data.AsFloats[frame] * 2 / Mathf.Deg2Rad }; + return (data, frame) => new float[] { data.AsFloats[frame] * 2 / Mathf.Deg2Rad}; default: return null; } diff --git a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs index 54bbccf9f..71c9cf7f2 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs @@ -130,7 +130,7 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni propertyName = $"spot/outerConeAngle"; break; case "m_InnerSpotAngle": - valueMultiplier = Mathf.Deg2Rad / 2; + valueMultiplier = Mathf.Deg2Rad / 2 * 0.8f; propertyName = $"spot/innerConeAngle"; break; case "m_Range": From ec83279fba8a2a70f47bd656db9c4e6bb69c7910 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 20 Feb 2024 17:43:01 +0100 Subject: [PATCH 13/20] refactoring of material mapper, more comments, support for animation property conversion to other property type --- .../Extensions/KHR_LightsPunctualExtension.cs | 18 +- .../AnimationPointerUtilities.cs | 132 ++++++--- .../MaterialPropertiesRemapper.cs | 275 ++++++++++++------ .../SceneExporter/ExporterAnimationPointer.cs | 3 +- .../SceneImporter/ImporterAnimation.cs | 3 +- 5 files changed, 289 insertions(+), 142 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 61aaaa6b5..4ef67a600 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -381,16 +381,16 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar var n = root.Nodes[i]; if (n.Extensions != null && n.Extensions.TryGetValue(KHR_lights_punctualExtensionFactory.EXTENSION_NAME, out IExtension extension)) { - if (extension is KHR_LightsPunctualNodeExtension lightExtension) + if (!(extension is KHR_LightsPunctualNodeExtension lightExtension)) + continue; + + if (lightExtension.LightId.Id == pointId.index) { - if (lightExtension.LightId.Id == pointId.index) - { - pointerData.nodeId = i;; - pointerData.unityProperties = GltfLightPropertyToUnityPropertyName(property.elementName); - pointerData.conversion = GetConversion(property.elementName); - - return true; - } + pointerData.nodeId = i;; + pointerData.unityProperties = GltfLightPropertyToUnityPropertyName(property.elementName); + pointerData.conversion = GetConversion(property.elementName); + + return true; } } } diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs index ffc85c270..fca845927 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -6,6 +6,7 @@ namespace UnityGLTF.Plugins internal static class AnimationPointerHelpers { private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; + private static readonly string[] MATERIAL_COLOR_PROPERTY_COMPONENTS = {"r", "g", "b", "a"}; internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, AnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) { @@ -14,34 +15,42 @@ internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemappe return false; // e.g. Emission Factor and Emission Color are combined into a single property - if (isSecondaryGltfProperty && propertyMap.PrimaryAndSecondaryGetsCombined) + if (isSecondaryGltfProperty && propertyMap.CombinePrimaryAndSecondaryOnImport) return false; - if (propertyMap.PrimaryAndSecondaryGetsCombined) + if (propertyMap.CombinePrimaryAndSecondaryOnImport) { - if (propertyMap.CombinePrimaryAndSecondaryFunction == null) + if (propertyMap.CombinePrimaryAndSecondaryDataFunction == null) return false; pointerData.secondaryPath = propertyMap.GltfSecondaryPropertyName; } var pointerDataCopy = pointerData; + + int primaryComponentCount = valueType.ComponentCount(); + + if (propertyMap.CombineComponentResult != MaterialPointerPropertyMap.CombineResultType.SameAsPrimary) + { + valueType = propertyMap.OverrideCombineResultType; + } + switch (valueType) { case GLTFAccessorAttributeType.SCALAR: pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 1, propertyMap, pointerDataCopy); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC2: pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 2, propertyMap, pointerDataCopy); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC3: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 3, propertyMap, pointerDataCopy); + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3, isColor: propertyMap.IsColor); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC4: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, 4, propertyMap, pointerDataCopy); + pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4, isColor: propertyMap.IsColor); + pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; default: return false; @@ -50,7 +59,7 @@ internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemappe return true; } - internal static string[] GetAnimationChannelProperties(string propertyName, int componentCount, int componentOffset = 0) + internal static string[] GetAnimationChannelProperties(string propertyName, int componentCount, int componentOffset = 0, bool isColor = false) { var result = new string[ componentCount]; if (componentCount == 1) @@ -58,21 +67,27 @@ internal static string[] GetAnimationChannelProperties(string propertyName, int result[0] = $"material.{propertyName}"; return result; } - + for (int iComponent = 0; iComponent < componentCount; iComponent++) - result[iComponent] = $"material.{propertyName}.{MATERIAL_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; + { + if (isColor) + result[iComponent] = $"material.{propertyName}.{MATERIAL_COLOR_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; + else + result[iComponent] = $"material.{propertyName}.{MATERIAL_PROPERTY_COMPONENTS[iComponent+componentOffset]}"; + } return result; } internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map, AnimationPointerData pointerData) { - float[] result = new float[componentCount]; - - if (map.ExportConvertToLinearColor && (componentCount == 3 || componentCount == 4)) + int resultComponentCount = componentCount; + if (map.CombineComponentResult == MaterialPointerPropertyMap.CombineResultType.Override) { - // TODO: ? + resultComponentCount = map.OverrideCombineResultType.ComponentCount(); } + float[] result = new float[resultComponentCount]; + switch (componentCount) { @@ -86,44 +101,71 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in break; case 3: var frameData3 = data.AsFloats3[frame]; - result[0] = frameData3.x; - result[1] = frameData3.y; - result[2] = frameData3.z; + if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) + { + Color gammaColor = new Color(frameData3.x, frameData3.y, frameData3.z).gamma; + result[0] = gammaColor.r; + result[1] = gammaColor.g; + result[2] = gammaColor.b; + } + else + { + result[0] = frameData3.x; + result[1] = frameData3.y; + result[2] = frameData3.z; + } break; case 4: var frameData4 = data.AsFloats4[frame]; - result[0] = frameData4.x; - result[1] = frameData4.y; - result[2] = frameData4.z; - result[3] = frameData4.w; + if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) + { + Color gammaColor = new Color(frameData4.x, frameData4.y, frameData4.z, frameData4.z).gamma; + result[0] = gammaColor.r; + result[1] = gammaColor.g; + result[2] = gammaColor.b; + result[3] = gammaColor.a; + } + else + { + result[0] = frameData4.x; + result[1] = frameData4.y; + result[2] = frameData4.z; + result[3] = frameData4.w; + } + break; } - - if (map.PrimaryAndSecondaryGetsCombined && map.CombinePrimaryAndSecondaryFunction != null) + + if (map.CombinePrimaryAndSecondaryOnImport && map.CombinePrimaryAndSecondaryDataFunction != null) { float[] secondary = new float[0]; - NumericArray secondaryData = pointerData.secondaryData.AccessorContent; - switch (pointerData.secondaryData.AccessorId.Value.Type) + + if (pointerData.secondaryData != null && pointerData.secondaryData.AccessorContent.AsFloats != null) { - case GLTFAccessorAttributeType.SCALAR: - secondary = new float[] { secondaryData.AsFloats[frame] }; - break; - case GLTFAccessorAttributeType.VEC2: - var s2 = secondaryData.AsFloats2[frame]; - secondary = new float[] { s2.x, s2.y }; - break; - case GLTFAccessorAttributeType.VEC3: - var s3 = secondaryData.AsFloats3[frame]; - secondary = new float[] { s3.x, s3.y, s3.z }; - break; - case GLTFAccessorAttributeType.VEC4: - var s4 = secondaryData.AsFloats4[frame]; - secondary = new float[] { s4.x, s4.y, s4.z, s4.w }; - break; - default: - return result; + NumericArray secondaryData = pointerData.secondaryData.AccessorContent; + switch (pointerData.secondaryData.AccessorId.Value.Type) + { + case GLTFAccessorAttributeType.SCALAR: + secondary = new float[] { secondaryData.AsFloats[frame] }; + break; + case GLTFAccessorAttributeType.VEC2: + var s2 = secondaryData.AsFloats2[frame]; + secondary = new float[] { s2.x, s2.y }; + break; + case GLTFAccessorAttributeType.VEC3: + var s3 = secondaryData.AsFloats3[frame]; + secondary = new float[] { s3.x, s3.y, s3.z }; + break; + case GLTFAccessorAttributeType.VEC4: + var s4 = secondaryData.AsFloats4[frame]; + secondary = new float[] { s4.x, s4.y, s4.z, s4.w }; + break; + default: + return result; + } } - map.CombinePrimaryAndSecondaryFunction(result, secondary); + + result = map.CombinePrimaryAndSecondaryDataFunction(result, secondary); } return result; diff --git a/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs index 9fe5e96f4..71dabadf3 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs @@ -1,97 +1,204 @@ -using System.Collections.Generic; -using System.Linq; +using System; +using System.Collections.Generic; using GLTF.Schema; using UnityEngine; -using UnityEngine.AI; namespace UnityGLTF.Plugins { public class MaterialPointerPropertyMap { - public string[] PropertyNames = new string[0]; - - internal int[] PropertyIds = new int[0]; - internal int[] PropertyTextureIds = new int[0]; + public enum PropertyTypeOption {LinearColor, SRGBColor, Texture, LinearTexture, TextureTransform, Generic} + public enum CombineResultType { SameAsPrimary, Override} + + public PropertyTypeOption PropertyType = PropertyTypeOption.Generic; + + public string[] PropertyNames + { + get => _propertyNames; + set + { + _propertyNames = value; + CreatePropertyIds(); + } + } public string GltfPropertyName = null; public string GltfSecondaryPropertyName = null; - public bool IsTexture = false; - public bool IsTextureTransform = false; - public bool PrimaryAndSecondaryGetsCombined = false; + public bool IsColor => PropertyType == PropertyTypeOption.LinearColor || + PropertyType == PropertyTypeOption.SRGBColor; + public bool IsTexture => PropertyType == PropertyTypeOption.Texture || + PropertyType == PropertyTypeOption.LinearTexture; + /// + /// When Data is splitted into primary and secondary, the data gets combined on import. + /// Don't forget to set CombinePrimaryAndSecondaryDataFunction if you set this to true. + /// + public bool CombinePrimaryAndSecondaryOnImport = false; + + /// + /// Possibility to override the result type of the combined data. + /// E.g. for combining two Vec2 properties into Vec4 (as for texture transform) + /// + public CombineResultType CombineComponentResult = CombineResultType.SameAsPrimary; + public GLTFAccessorAttributeType OverrideCombineResultType = GLTFAccessorAttributeType.VEC4; + + // Export settings public bool ExportKeepColorAlpha = true; public bool ExportConvertToLinearColor = false; public bool ExportFlipValueRange = false; public float ExportValueMultiplier = 1f; public string ExtensionName = null; - public delegate float[] CombinePrimaryAndSecondary(float[] primary, float[] secondary); + // The arrays contains the components of the primary and secondary properties. e.g. for a Vector3, the arrays will contain 3 elements + public delegate float[] CombinePrimaryAndSecondaryData(float[] primary, float[] secondary); + + /// + /// Function to combine primary and secondary data on import. + /// This used by the AnimationPointer system to combine data from two glTF properties into a single Unity property + /// The arrays contains the components of the primary and secondary properties. e.g. for a Vector3, the arrays will contain 3 elements + /// + public CombinePrimaryAndSecondaryData CombinePrimaryAndSecondaryDataFunction = null; + + private string[] _propertyNames = new string[0]; + internal int[] propertyIds = new int[0]; + internal int[] propertyTextureIds = new int[0]; - public CombinePrimaryAndSecondary CombinePrimaryAndSecondaryFunction = null; + public MaterialPointerPropertyMap(PropertyTypeOption propertyType) + { + PropertyType = propertyType; + switch (PropertyType) + { + case PropertyTypeOption.LinearColor: + break; + case PropertyTypeOption.SRGBColor: + ExportConvertToLinearColor = true; + break; + case PropertyTypeOption.Texture: + break; + case PropertyTypeOption.LinearTexture: + break; + case PropertyTypeOption.TextureTransform: + SetupAsTextureTransform(); + break; + case PropertyTypeOption.Generic: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } - internal void CreatePropertyIds() + private void CreatePropertyIds() { - PropertyIds = new int[PropertyNames.Length]; + propertyIds = new int[PropertyNames.Length]; for (int i = 0; i < PropertyNames.Length; i++) - PropertyIds[i] = Shader.PropertyToID(PropertyNames[i]); + propertyIds[i] = Shader.PropertyToID(PropertyNames[i]); - if (IsTextureTransform) + if (PropertyType == PropertyTypeOption.TextureTransform) { - PropertyTextureIds = new int[PropertyNames.Length]; + propertyTextureIds = new int[PropertyNames.Length]; for (int i = 0; i < PropertyNames.Length; i++) { var pWithoutST = PropertyNames[i].Remove(PropertyNames[i].Length - 3, 3); - PropertyTextureIds[i] = Shader.PropertyToID(pWithoutST); + propertyTextureIds[i] = Shader.PropertyToID(pWithoutST); } } } + + private static float[] CombineTextureTransform(float[] primary, float[] secondary) + { + var result = new float[4]; + result[0] = primary[0]; + result[1] = primary[1]; + result[2] = secondary[0]; + result[3] = 1f - secondary[1] - primary[1]; + return result; + } + + private void SetupAsTextureTransform() + { + PropertyType = PropertyTypeOption.TextureTransform; + CombinePrimaryAndSecondaryDataFunction = CombineTextureTransform; + CombinePrimaryAndSecondaryOnImport = true; + CombineComponentResult = MaterialPointerPropertyMap.CombineResultType.Override; + OverrideCombineResultType = GLTFAccessorAttributeType.VEC4; + } } public class MaterialPropertiesRemapper { - private Dictionary maps = + public enum ImportExportUsageOption {ImportOnly, ExportOnly, ImportAndExport} + + private Dictionary importMaps = new Dictionary(); + private Dictionary exportMaps = new Dictionary (); - public void AddMap(MaterialPointerPropertyMap map) + public void AddMap(MaterialPointerPropertyMap map, ImportExportUsageOption importExport = ImportExportUsageOption.ImportAndExport) { - map.CreatePropertyIds(); - if (maps.ContainsKey(map.GltfPropertyName)) - return; - - maps.Add(map.GltfPropertyName, map); + if (importExport == ImportExportUsageOption.ImportOnly || + importExport == ImportExportUsageOption.ImportAndExport) + { + if (importMaps.ContainsKey(map.GltfPropertyName)) + { + Debug.LogError("MaterialPropertiesRemapper: Import Map with the same glTF property name already exists: " + map.GltfPropertyName); + return; + } + importMaps.Add(map.GltfPropertyName, map); + } + if (importExport == ImportExportUsageOption.ExportOnly || + importExport == ImportExportUsageOption.ImportAndExport) + { + for (int i = 0; i < map.PropertyNames.Length; i++) + { + if (exportMaps.ContainsKey(map.PropertyNames[i])) + { + Debug.LogError("MaterialPropertiesRemapper: Export Map with the same unity property name already exists: " + map.PropertyNames[i]); + continue; + } + + exportMaps.Add(map.PropertyNames[i], map); + } + } } public bool GetMapFromUnityMaterial(Material mat, string unityPropertyName, out MaterialPointerPropertyMap map) { map = null; - foreach (var kvp in maps) + if (!exportMaps.TryGetValue(unityPropertyName, out map)) + return false; + + if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { - if (kvp.Value.PropertyNames.Contains(unityPropertyName)) + bool valid = false; + for (int i = 0; i < map.propertyTextureIds.Length; i++) + valid |= (mat.HasProperty(map.propertyTextureIds[i]) && mat.GetTexture(map.propertyTextureIds[i])); + if (!valid) { - if (kvp.Value.IsTexture) - { - bool valid = false; - for (int i = 0; i < kvp.Value.PropertyIds.Length; i++) - valid &= (mat.HasProperty(kvp.Value.PropertyIds[i]) && mat.GetTexture(kvp.Value.PropertyIds[i])); - if (!valid) - return false; - } - - map = kvp.Value; - - return true; + map = null; + return false; + } + } + else + { + bool valid = false; + for (int i = 0; i < map.propertyIds.Length; i++) + valid |= (mat.HasProperty(map.propertyIds[i])); + if (!valid) + { + map = null; + return false; } } - return false; + return true; + } public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out string propertyName, out MaterialPointerPropertyMap map, out bool isSecondary) { - foreach (var kvp in maps) + foreach (var kvp in importMaps) { var currentMap = kvp.Value; if (currentMap.GltfPropertyName != gltfPropertyName && currentMap.GltfSecondaryPropertyName != gltfPropertyName) @@ -99,11 +206,11 @@ public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out stri for (int i = 0; i < currentMap.PropertyNames.Length; i++) { - if (currentMap.IsTextureTransform) + if (currentMap.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { for (int j = 0; j < currentMap.PropertyNames.Length; j++) { - if (mat.HasProperty(currentMap.PropertyTextureIds[j])) + if (mat.HasProperty(currentMap.propertyTextureIds[j])) { map = currentMap; propertyName = currentMap.PropertyNames[j]; @@ -112,7 +219,7 @@ public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out stri } } } - else if (mat.HasProperty(currentMap.PropertyIds[i])) + else if (mat.HasProperty(currentMap.propertyIds[i])) { map = currentMap; propertyName = currentMap.PropertyNames[i]; @@ -129,81 +236,83 @@ public bool GetUnityPropertyName(Material mat, string gltfPropertyName, out stri } } - public class DefaultMaterialPropertiesRemapper : MaterialPropertiesRemapper { public DefaultMaterialPropertiesRemapper() { - var baseColor = new MaterialPointerPropertyMap + var baseColor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { PropertyNames = new[] { "_Color", "_BaseColor", "_BaseColorFactor", "baseColorFactor" }, - ExportConvertToLinearColor = true, - GltfPropertyName = "pbrMetallicRoughness/baseColorFactor" + GltfPropertyName = "pbrMetallicRoughness/baseColorFactor", }; AddMap(baseColor); - var smoothness = new MaterialPointerPropertyMap + var smoothness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_Smoothness", "_Glossiness" }, ExportFlipValueRange = true, - GltfPropertyName = "pbrMetallicRoughness/roughnessFactor" + GltfPropertyName = "pbrMetallicRoughness/roughnessFactor", }; - AddMap(smoothness); + AddMap(smoothness, ImportExportUsageOption.ExportOnly); - var roughness = new MaterialPointerPropertyMap + var roughness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, GltfPropertyName = "pbrMetallicRoughness/roughnessFactor" }; AddMap(roughness); - var metallic = new MaterialPointerPropertyMap + var metallic = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, GltfPropertyName = "pbrMetallicRoughness/metallicFactor" }; AddMap(metallic); - - var baseColorTexture = new MaterialPointerPropertyMap + + var baseColorTexture = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { PropertyNames = new[] { "_MainTex_ST", "_BaseMap_ST", "_BaseColorTexture_ST", "baseColorTexture_ST" }, - IsTexture = true, - IsTextureTransform = true, GltfPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", GltfSecondaryPropertyName = $"pbrMetallicRoughness/baseColorTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.OFFSET}", - ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME + ExtensionName = ExtTextureTransformExtensionFactory.EXTENSION_NAME, }; AddMap(baseColorTexture); - var emissiveFactor = new MaterialPointerPropertyMap + var emissiveFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { PropertyNames = new[] { "_EmissionColor", "_EmissiveFactor", "emissiveFactor" }, GltfPropertyName = "emissiveFactor", GltfSecondaryPropertyName = $"extensions/{KHR_materials_emissive_strength_Factory.EXTENSION_NAME}/{nameof(KHR_materials_emissive_strength.emissiveStrength)}", ExtensionName = KHR_materials_emissive_strength_Factory.EXTENSION_NAME, - PrimaryAndSecondaryGetsCombined = true, + CombinePrimaryAndSecondaryOnImport = true, ExportKeepColorAlpha = false, - ExportConvertToLinearColor = true, - CombinePrimaryAndSecondaryFunction = (primary, secondary) => + CombinePrimaryAndSecondaryDataFunction = (primary, secondary) => { + float strength = (secondary != null && secondary.Length > 0) ? secondary[0] : 1f; var result = new float[primary.Length]; for (int i = 0; i < 3; i++) - result[i] = primary[i] * secondary[0]; + result[i] = primary[i] * strength; if (result.Length == 4) result[3] = primary[3]; + + Color color = result.Length == 3 ? new Color(result[0], result[1], result[2]) : new Color(result[0], result[1], result[2], result[3]); + color = color.gamma; + result[0] = color.r; + result[1] = color.g; + result[2] = color.b; + if (result.Length == 4) + result[3] = color.a; return result; } }; AddMap(emissiveFactor); - var emissiveTexture = new MaterialPointerPropertyMap + var emissiveTexture = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { PropertyNames = new[] { "_EmissionMap_ST", "_EmissiveTexture_ST", "emissiveTexture_ST" }, - IsTexture = true, - IsTextureTransform = true, GltfPropertyName = $"emissiveTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", GltfSecondaryPropertyName = @@ -224,25 +333,23 @@ public DefaultMaterialPropertiesRemapper() maps.Add(roughnessTex); */ - var alphaCutoff = new MaterialPointerPropertyMap + var alphaCutoff = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_AlphaCutoff", "alphaCutoff", "_Cutoff" }, GltfPropertyName = "alphaCutoff" }; AddMap(alphaCutoff); - var normalScale = new MaterialPointerPropertyMap + var normalScale = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, GltfPropertyName = "normalTexture/scale" }; AddMap(normalScale); - var normalTexture = new MaterialPointerPropertyMap + var normalTexture = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { PropertyNames = new[] { "_BumpMap_ST", "_NormalTexture_ST", "normalTexture_ST" }, - IsTexture = true, - IsTextureTransform = true, GltfPropertyName = $"normalTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", GltfSecondaryPropertyName = @@ -251,18 +358,16 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(normalTexture); - var occlusionStrength = new MaterialPointerPropertyMap + var occlusionStrength = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, GltfPropertyName = "occlusionTexture/strength" }; AddMap(occlusionStrength); - var occlusionTexture = new MaterialPointerPropertyMap + var occlusionTexture = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform) { PropertyNames = new[] { "_OcclusionMap_ST", "_OcclusionTexture_ST", "occlusionTexture_ST" }, - IsTexture = true, - IsTextureTransform = true, GltfPropertyName = $"occlusionTexture/extensions/{ExtTextureTransformExtensionFactory.EXTENSION_NAME}/{ExtTextureTransformExtensionFactory.SCALE}", GltfSecondaryPropertyName = @@ -272,7 +377,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(occlusionTexture); // KHR_materials_transmission - var transmissionFactor = new MaterialPointerPropertyMap + var transmissionFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, GltfPropertyName = @@ -282,7 +387,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(transmissionFactor); // KHR_materials_volume - var thicknessFactor = new MaterialPointerPropertyMap + var thicknessFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, GltfPropertyName = @@ -291,7 +396,7 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(thicknessFactor); - var attenuationDistance = new MaterialPointerPropertyMap + var attenuationDistance = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, GltfPropertyName = @@ -300,18 +405,18 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(attenuationDistance); - var attenuationColor = new MaterialPointerPropertyMap + var attenuationColor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.LinearColor) { PropertyNames = new[] { "_AttenuationColor", "attenuationColor" }, GltfPropertyName = $"extensions/{KHR_materials_volume_Factory.EXTENSION_NAME}/{nameof(KHR_materials_volume.attenuationColor)}", ExtensionName = KHR_materials_volume_Factory.EXTENSION_NAME, - ExportKeepColorAlpha = false + ExportKeepColorAlpha = false, }; AddMap(attenuationColor); // KHR_materials_ior - var ior = new MaterialPointerPropertyMap + var ior = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_IOR", "ior" }, GltfPropertyName = @@ -321,7 +426,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(ior); // KHR_materials_iridescence - var iridescenceFactor = new MaterialPointerPropertyMap + var iridescenceFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, GltfPropertyName = @@ -331,7 +436,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(iridescenceFactor); // KHR_materials_specular - var specularFactor = new MaterialPointerPropertyMap + var specularFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) { PropertyNames = new[] { "_SpecularFactor", "specularFactor" }, GltfPropertyName = @@ -340,13 +445,13 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(specularFactor); - var specularColorFactor = new MaterialPointerPropertyMap + var specularColorFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.LinearColor) { PropertyNames = new[] { "_SpecularColorFactor", "specularColorFactor" }, GltfPropertyName = $"extensions/{KHR_materials_specular_Factory.EXTENSION_NAME}/{nameof(KHR_materials_specular.specularColorFactor)}", ExtensionName = KHR_materials_specular_Factory.EXTENSION_NAME, - ExportKeepColorAlpha = false + ExportKeepColorAlpha = false, }; AddMap(specularColorFactor); diff --git a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs index 71c9cf7f2..0b061b0b8 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs @@ -106,11 +106,10 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni flipValueRange = map.ExportFlipValueRange; valueMultiplier = map.ExportValueMultiplier == 1f ? null : map.ExportValueMultiplier; - isTextureTransform = map.IsTextureTransform; + isTextureTransform = map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.TextureTransform; keepColorAlpha = map.ExportKeepColorAlpha; convertToLinearColor = map.ExportConvertToLinearColor; - break; case Light light: extensionName = KHR_lights_punctualExtensionFactory.EXTENSION_NAME; diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 59ba8f830..d7febbb40 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -336,8 +336,10 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) continue; + // Check if the extension support animation pointers if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) { + // Let the extension handle the pointer data and create the nodeIds and unity properties if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) nodeIds = new int[] { pointerData.nodeId}; else @@ -481,7 +483,6 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) if (pointerData.animationType == null) pointerData.animationType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); } - switch (path) { From c2a05391a9d941bb8055cf6309421171f1d834cc Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 5 Mar 2024 09:59:53 +0100 Subject: [PATCH 14/20] fixed rebased issues --- .../Extensions/KHR_LightsPunctualExtension.cs | 2 +- .../AnimationPointerUtilities.cs | 12 +- .../SceneImporter/ImporterAnimation.cs | 142 +++++++++--------- 3 files changed, 80 insertions(+), 76 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 4ef67a600..7fc1654a1 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -344,7 +344,7 @@ private static AnimationPointerData.ValuesConvertion GetConversion(string gltfPr case "color": return (NumericArray data, int frame) => { - var col = data.AsFloats3[frame]; + var col = data.AsFloat3s[frame]; var color = new Color(col[0], col[1], col[2], 1f).ToUnityColorRaw(); return new float[] { color.r, color.g, color.b }; //return new float[] { col.x, col.y, col.z }; diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs index fca845927..28c965c65 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -95,12 +95,12 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in result[0] = data.AsFloats[frame]; break; case 2: - var frameData2 = data.AsFloats2[frame]; + var frameData2 = data.AsFloat2s[frame]; result[0] = frameData2.x; result[1] = frameData2.y; break; case 3: - var frameData3 = data.AsFloats3[frame]; + var frameData3 = data.AsFloat3s[frame]; if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { Color gammaColor = new Color(frameData3.x, frameData3.y, frameData3.z).gamma; @@ -116,7 +116,7 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in } break; case 4: - var frameData4 = data.AsFloats4[frame]; + var frameData4 = data.AsFloat4s[frame]; if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { Color gammaColor = new Color(frameData4.x, frameData4.y, frameData4.z, frameData4.z).gamma; @@ -149,15 +149,15 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in secondary = new float[] { secondaryData.AsFloats[frame] }; break; case GLTFAccessorAttributeType.VEC2: - var s2 = secondaryData.AsFloats2[frame]; + var s2 = secondaryData.AsFloat2s[frame]; secondary = new float[] { s2.x, s2.y }; break; case GLTFAccessorAttributeType.VEC3: - var s3 = secondaryData.AsFloats3[frame]; + var s3 = secondaryData.AsFloat3s[frame]; secondary = new float[] { s3.x, s3.y, s3.z }; break; case GLTFAccessorAttributeType.VEC4: - var s4 = secondaryData.AsFloats4[frame]; + var s4 = secondaryData.AsFloat4s[frame]; secondary = new float[] { s4.x, s4.y, s4.z, s4.w }; break; default: diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index d7febbb40..29a1b36ac 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -435,7 +435,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) pointerData.unityProperties = new string[] { "background color.r", "background color.g", "background color.b", "background color.a" }; pointerData.conversion = (data, frame) => { - var color = data.AsFloats4[frame].ToUnityColorRaw(); + var color = data.AsFloat4s[frame].ToUnityColorRaw(); return new float[] {color.r, color.g, color.b, color.a}; }; break; @@ -481,17 +481,17 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) else { if (pointerData.animationType == null) - pointerData.animationType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); + pointerData.animationType = targetNode.Skin != null + ? typeof(SkinnedMeshRenderer) + : typeof(MeshRenderer); } switch (path) { case GLTFAnimationChannelPath.pointer: - if (pointerData.conversion == null) continue; - - SetAnimationCurve(clip, relativePath, pointerData.unityProperties, input, output, + SetAnimationCurve(clip, relativePath, pointerData.unityProperties, input, output, samplerCache.Interpolation, pointerData.animationType, (data, frame) => pointerData.conversion(data, frame)); break; @@ -502,83 +502,87 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) // but performance is much better if we do it when constructing the clips var factor = Context?.ImportScaleFactor ?? 1f; #endif - SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, typeof(Transform), - (data, frame) => - { - var position = data.AsFloat3s[frame].ToUnityVector3Convert(); + SetAnimationCurve(clip, relativePath, propertyNames, input, output, + samplerCache.Interpolation, typeof(Transform), + (data, frame) => + { + var position = data.AsFloat3s[frame].ToUnityVector3Convert(); #if UNITY_EDITOR return new float[] { position.x * factor, position.y * factor, position.z * factor }; #else return new float[] { position.x, position.y, position.z }; #endif - }); - break; - - case GLTFAnimationChannelPath.rotation: - propertyNames = new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }; - bool hasLight = (targetNode.Extensions != null && - targetNode.Extensions.ContainsKey(KHR_lights_punctualExtensionFactory - .EXTENSION_NAME) && Context.TryGetPlugin(out _)); - SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, typeof(Transform), - (data, frame) => - { - var rotation = data.AsFloat4s[frame]; - var quaternion = rotation.ToUnityQuaternionConvert(); - if (hasLight) - { - quaternion *= Quaternion.Euler(0,180, 0); - } - return new float[] { quaternion.x, quaternion.y, quaternion.z, quaternion.w }; - }); - - break; - - case GLTFAnimationChannelPath.scale: - propertyNames = new string[] { "localScale.x", "localScale.y", "localScale.z" }; - - SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, typeof(Transform), - (data, frame) => - { - var scale = data.AsFloat3s[frame].ToUnityVector3Raw(); - return new float[] { scale.x, scale.y, scale.z }; - }); - break; - - case GLTFAnimationChannelPath.weights: - var mesh = targetNode.Mesh.Value; - var primitives = mesh.Primitives; - if (primitives[0].Targets == null) break; - var targetCount = primitives[0].Targets.Count; - for (int primitiveIndex = 0; primitiveIndex < primitives.Count; primitiveIndex++) - { - // see SceneImporter:156 - // blend shapes are always called "Morphtarget" - var targetNames = mesh.TargetNames; - propertyNames = new string[targetCount]; - for (var i = 0; i < targetCount; i++) - propertyNames[i] = _options.ImportBlendShapeNames ? ("blendShape." + ((targetNames != null && targetNames.Count > i) ? targetNames[i] : ("Morphtarget" + i))) : "blendShape."+i.ToString(); - var frameFloats = new float[targetCount]; - - var blendShapeFrameWeight = _options.BlendShapeFrameWeight; + }); + break; + + case GLTFAnimationChannelPath.rotation: + propertyNames = new string[] + { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }; + bool hasLight = (targetNode.Extensions != null + && targetNode.Extensions.ContainsKey(KHR_lights_punctualExtensionFactory.EXTENSION_NAME) + && Context.TryGetPlugin(out _)); SetAnimationCurve(clip, relativePath, propertyNames, input, output, samplerCache.Interpolation, typeof(Transform), (data, frame) => { - var allValues = data.AsFloats; - for (var k = 0; k < targetCount; k++) - frameFloats[k] = allValues[frame * targetCount + k] * blendShapeFrameWeight; - + var rotation = data.AsFloat4s[frame]; + var quaternion = rotation.ToUnityQuaternionConvert(); + if (hasLight) + quaternion *= Quaternion.Euler(0, 180, 0); return new float[] { quaternion.x, quaternion.y, quaternion.z, quaternion.w }; }); + break; + case GLTFAnimationChannelPath.scale: + propertyNames = new string[] { "localScale.x", "localScale.y", "localScale.z" }; - default: - Debug.Log(LogType.Warning, $"Cannot read GLTF animation path (File: {_gltfFileName})"); - break; - } // switch target type + SetAnimationCurve(clip, relativePath, propertyNames, input, output, + samplerCache.Interpolation, typeof(Transform), + (data, frame) => + { + var scale = data.AsFloat3s[frame].ToUnityVector3Raw(); + return new float[] { scale.x, scale.y, scale.z }; + }); + break; + + case GLTFAnimationChannelPath.weights: + var mesh = targetNode.Mesh.Value; + var primitives = mesh.Primitives; + if (primitives[0].Targets == null) break; + var targetCount = primitives[0].Targets.Count; + for (int primitiveIndex = 0; primitiveIndex < primitives.Count; primitiveIndex++) + { + // see SceneImporter:156 + // blend shapes are always called "Morphtarget" + var targetNames = mesh.TargetNames; + propertyNames = new string[targetCount]; + for (var i = 0; i < targetCount; i++) + propertyNames[i] = _options.ImportBlendShapeNames + ? ("blendShape." + ((targetNames != null && targetNames.Count > i) + ? targetNames[i] + : ("Morphtarget" + i))) + : "blendShape." + i.ToString(); + var frameFloats = new float[targetCount]; + + var blendShapeFrameWeight = _options.BlendShapeFrameWeight; + SetAnimationCurve(clip, relativePath, propertyNames, input, output, + samplerCache.Interpolation, typeof(Transform), + (data, frame) => + { + var allValues = data.AsFloats; + for (var k = 0; k < targetCount; k++) + frameFloats[k] = allValues[frame * targetCount + k] * blendShapeFrameWeight; + + return frameFloats; + }); + } + + break; + default: + Debug.Log(LogType.Warning, $"Cannot read GLTF animation path (File: {_gltfFileName})"); + break; + } // switch target type + } } // foreach channel // EnsureQuaternionContinuity results in unwanted tangents on the first and last keyframes > custom Solution in SetAnimationCurve From 3b08a81fb594e85570370fd3817f19b2b3027de4 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 3 Apr 2024 13:36:08 +0200 Subject: [PATCH 15/20] added await YieldOnTimeoutAndThrowOnLowMemory to Import animation --- Runtime/Scripts/SceneImporter/ImporterAnimation.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 29a1b36ac..e42377e09 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -583,6 +583,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) break; } // switch target type } + await YieldOnTimeoutAndThrowOnLowMemory(); } // foreach channel // EnsureQuaternionContinuity results in unwanted tangents on the first and last keyframes > custom Solution in SetAnimationCurve From 95b2e04bebfbd0b6c4977476369dcf2289858926 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 3 Apr 2024 13:37:13 +0200 Subject: [PATCH 16/20] changed BuildMaterialAnimationPointerData signature to out animationdata --- .../Plugins/AnimationPointer/AnimationPointerUtilities.cs | 4 +++- Runtime/Scripts/SceneImporter/ImporterAnimation.cs | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs index 28c965c65..eb04b87aa 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -8,8 +8,10 @@ internal static class AnimationPointerHelpers private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; private static readonly string[] MATERIAL_COLOR_PROPERTY_COMPONENTS = {"r", "g", "b", "a"}; - internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, AnimationPointerData pointerData, Material material, string gltfProperty, GLTFAccessorAttributeType valueType) + internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, Material material, + string gltfProperty, GLTFAccessorAttributeType valueType, out AnimationPointerData pointerData) { + pointerData = new AnimationPointerData(); if (!remapper.GetUnityPropertyName(material, gltfProperty, out string unityPropertyName, out MaterialPointerPropertyMap propertyMap, out bool isSecondaryGltfProperty)) return false; diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index e42377e09..00016e08c 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -378,11 +378,10 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) var gltfPropertyPath = materialPath.ExtractPath(); var mat = _assetCache.MaterialCache[rootIndex.index]; - - pointerData = new AnimationPointerData(); - if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, pointerData, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type)) + if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type, out pointerData)) continue; + if (!string.IsNullOrEmpty(pointerData.secondaryPath)) { // When an property has potentially a second Sampler, we need to find it. e.g. like EmissionFactor and EmissionStrength From 167f2dd3d82a194610de5c8f292e26dda0800285 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 3 Apr 2024 14:21:30 +0200 Subject: [PATCH 17/20] renamed MaterialPointerPropertyMap Type from Generic to Float --- .../MaterialPropertiesRemapper.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs index 71dabadf3..284594b45 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/MaterialPropertiesRemapper.cs @@ -7,10 +7,10 @@ namespace UnityGLTF.Plugins { public class MaterialPointerPropertyMap { - public enum PropertyTypeOption {LinearColor, SRGBColor, Texture, LinearTexture, TextureTransform, Generic} + public enum PropertyTypeOption {LinearColor, SRGBColor, Texture, LinearTexture, TextureTransform, Float} public enum CombineResultType { SameAsPrimary, Override} - public PropertyTypeOption PropertyType = PropertyTypeOption.Generic; + public PropertyTypeOption PropertyType = PropertyTypeOption.Float; public string[] PropertyNames { @@ -81,7 +81,7 @@ public MaterialPointerPropertyMap(PropertyTypeOption propertyType) case PropertyTypeOption.TextureTransform: SetupAsTextureTransform(); break; - case PropertyTypeOption.Generic: + case PropertyTypeOption.Float: break; default: throw new ArgumentOutOfRangeException(); @@ -247,7 +247,7 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(baseColor); - var smoothness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var smoothness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_Smoothness", "_Glossiness" }, ExportFlipValueRange = true, @@ -255,14 +255,14 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(smoothness, ImportExportUsageOption.ExportOnly); - var roughness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var roughness = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_Roughness", "_RoughnessFactor", "roughnessFactor" }, GltfPropertyName = "pbrMetallicRoughness/roughnessFactor" }; AddMap(roughness); - var metallic = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var metallic = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_Metallic", "_MetallicFactor", "metallicFactor" }, GltfPropertyName = "pbrMetallicRoughness/metallicFactor" @@ -333,14 +333,14 @@ public DefaultMaterialPropertiesRemapper() maps.Add(roughnessTex); */ - var alphaCutoff = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var alphaCutoff = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_AlphaCutoff", "alphaCutoff", "_Cutoff" }, GltfPropertyName = "alphaCutoff" }; AddMap(alphaCutoff); - var normalScale = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var normalScale = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_BumpScale", "_NormalScale", "normalScale", "normalTextureScale" }, GltfPropertyName = "normalTexture/scale" @@ -358,7 +358,7 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(normalTexture); - var occlusionStrength = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var occlusionStrength = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_OcclusionStrength", "occlusionStrength", "occlusionTextureStrength" }, GltfPropertyName = "occlusionTexture/strength" @@ -377,7 +377,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(occlusionTexture); // KHR_materials_transmission - var transmissionFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var transmissionFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_TransmissionFactor", "transmissionFactor" }, GltfPropertyName = @@ -387,7 +387,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(transmissionFactor); // KHR_materials_volume - var thicknessFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var thicknessFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_ThicknessFactor", "thicknessFactor" }, GltfPropertyName = @@ -396,7 +396,7 @@ public DefaultMaterialPropertiesRemapper() }; AddMap(thicknessFactor); - var attenuationDistance = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var attenuationDistance = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_AttenuationDistance", "attenuationDistance" }, GltfPropertyName = @@ -416,7 +416,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(attenuationColor); // KHR_materials_ior - var ior = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var ior = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_IOR", "ior" }, GltfPropertyName = @@ -426,7 +426,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(ior); // KHR_materials_iridescence - var iridescenceFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var iridescenceFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_IridescenceFactor", "iridescenceFactor" }, GltfPropertyName = @@ -436,7 +436,7 @@ public DefaultMaterialPropertiesRemapper() AddMap(iridescenceFactor); // KHR_materials_specular - var specularFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Generic) + var specularFactor = new MaterialPointerPropertyMap(MaterialPointerPropertyMap.PropertyTypeOption.Float) { PropertyNames = new[] { "_SpecularFactor", "specularFactor" }, GltfPropertyName = From 26f319f4e8c9203cc932c7731d02a518fe49c2d1 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 3 Apr 2024 14:24:56 +0200 Subject: [PATCH 18/20] PointerPath refactoring: renaming and removed PathResolver class --- .../Extensions/KHR_LightsPunctualExtension.cs | 7 +- .../Utilities/AnimationPointerPath.cs | 148 ++++++++---------- .../SceneImporter/ImporterAnimation.cs | 18 ++- 3 files changed, 79 insertions(+), 94 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index 7fc1654a1..ef7ab7e85 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -368,11 +368,14 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar pointerData.nodeId = -1; pointerData.animationType = typeof(UnityEngine.Light); - var pointId = pointerPath.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + if (root.Nodes == null) + return false; + + var pointId = pointerPath.FindNext(PointerPath.PathElement.Index); if (pointId == null) return false; - var property = pointerPath.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var property = pointerPath.FindNext(PointerPath.PathElement.Property); if (property == null) return false; diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs index 3c9cd1506..f8e9f0621 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/AnimationPointerPath.cs @@ -1,129 +1,109 @@ -using System.Collections; - -namespace GLTF.Utilities +namespace GLTF.Utilities { - public class AnimationPointerPathHierarchy + public class PointerPath { - public enum ElementTypeOptions { Root, RootExtension, Index, Child, Property } - public ElementTypeOptions elementType { get; private set; } = ElementTypeOptions.Root; + public enum PathElement { Root, RootExtension, Index, Extension, Child, Property } + public PathElement PathElementType { get; private set; } = PathElement.Root; public int index { get; private set; } = -1; public string elementName { get; private set; } = ""; - public AnimationPointerPathHierarchy next { get; private set; }= null; + public bool isValid { get; internal set; } = false; + + public PointerPath next { get; private set; } = null; public string ExtractPath() { return elementName+ (next != null ? "/" + next.ExtractPath() : ""); } - public AnimationPointerPathHierarchy FindNext(ElementTypeOptions elementType) + public PointerPath FindNext(PathElement pathElementType) { - if (this.elementType == elementType) + if (this.PathElementType == pathElementType) return this; if (next == null) return null; - return next.FindNext(elementType); + return next.FindNext(pathElementType); } - public static AnimationPointerPathHierarchy CreateHierarchyFromPath(string fullPath) + private PointerPath() + { + isValid = true; + } + + public PointerPath(string fullPath) { - var path = new PathResolver(fullPath.Remove(0,1)); + if (string.IsNullOrEmpty(fullPath)) + return; + - var result = new AnimationPointerPathHierarchy(); - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.Root; + var splittedPath = fullPath.Split("/"); + var pathIndex = 0; - AnimationPointerPathHierarchy TravelHierarchy(PathResolver path) + if (string.IsNullOrEmpty(splittedPath[0])) + pathIndex++; + + if (splittedPath.Length <= pathIndex) + return; + + isValid = true; + + elementName = splittedPath[pathIndex]; + PathElementType = PathElement.Root; + + string GetCurrentAsString() { - if (!path.MoveNext()) + return splittedPath[pathIndex]; + } + + bool GetCurrentAsInt(out int result) + { + return int.TryParse(splittedPath[pathIndex], out result); + } + + PointerPath TravelHierarchy() + { + pathIndex++; + if (pathIndex >= splittedPath.Length) return null; - var result = new AnimationPointerPathHierarchy(); + var result = new PointerPath(); - if (path.GetCurrentAsInt(out int index)) + if (GetCurrentAsInt(out int index)) { result.index = index; - result.elementType = ElementTypeOptions.Index; + result.PathElementType = PathElement.Index; result.elementName = index.ToString(); - result.next = TravelHierarchy(path); + result.next = TravelHierarchy(); return result; } - result.elementName = path.GetCurrentAsString(); - result.elementType = path.IsLast() ? ElementTypeOptions.Property : ElementTypeOptions.Child; - if (!path.IsLast()) - result.next = TravelHierarchy(path); + result.elementName = GetCurrentAsString(); + if (result.elementName == "extensions") + result.PathElementType = PathElement.Extension; + else + result.PathElementType = (pathIndex == splittedPath.Length-1) ? PathElement.Property : PathElement.Child; + if ((pathIndex < splittedPath.Length)) + result.next = TravelHierarchy(); return result; } - if (result.elementName == "extensions") + if (elementName == "extensions") { - if (path.MoveNext()) + pathIndex++; + if (pathIndex < splittedPath.Length) { - result.elementName = path.GetCurrentAsString(); - result.elementType = ElementTypeOptions.RootExtension; - result.next = TravelHierarchy(path); + elementName = GetCurrentAsString(); + PathElementType = PathElement.RootExtension; + next = TravelHierarchy(); } } else { - result.next = TravelHierarchy(path); + next = TravelHierarchy(); } - - return result; + } } - public class PathResolver : IEnumerator - { - private string[] _splittedPath; - private int currentIndex; - - public PathResolver (string path) - { - _splittedPath = path.Split("/"); - currentIndex = 0; - } - - public bool IsLast() - { - return currentIndex == _splittedPath.Length - 1; - } - - public string GetCurrentAsString() - { - return _splittedPath[currentIndex]; - } - - public bool GetCurrentAsInt(out int result) - { - return int.TryParse(_splittedPath[currentIndex], out result); - } - - public bool MoveNext() - { - currentIndex++; - return currentIndex < _splittedPath.Length; - } - - public void Reset() - { - currentIndex = 0; - } - - public object Current - { - get - { - if (currentIndex < _splittedPath.Length) - { - return _splittedPath[currentIndex]; - } - - return null; - } - } - } - } \ No newline at end of file diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 00016e08c..3bca2fba9 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -328,11 +328,13 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) path = GLTFAnimationChannelPath.pointer; relativePath = pointer.path; - var pointerHierarchy = AnimationPointerPathHierarchy.CreateHierarchyFromPath(relativePath); - - switch (pointerHierarchy.elementType) + var pointerHierarchy = new PointerPath(relativePath); + if (!pointerHierarchy.isValid) + continue; + + switch (pointerHierarchy.PathElementType) { - case AnimationPointerPathHierarchy.ElementTypeOptions.RootExtension: + case PointerPath.PathElement.RootExtension: if (!_gltfRoot.Extensions.TryGetValue(pointerHierarchy.elementName, out IExtension hierarchyExtension)) continue; @@ -346,16 +348,16 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) continue; } break; - case AnimationPointerPathHierarchy.ElementTypeOptions.Root: + case PointerPath.PathElement.Root: var rootType = pointerHierarchy.elementName; - var rootIndex = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index); + var rootIndex = pointerHierarchy.FindNext(PointerPath.PathElement.Index); if (rootIndex == null) continue; switch (rootType) { case "nodes": - var pointerPropertyElement = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Property); + var pointerPropertyElement = pointerHierarchy.FindNext(PointerPath.PathElement.Property); if (pointerPropertyElement == null) continue; @@ -372,7 +374,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) nodeIds = _gltfRoot.GetAllNodeIdsWithMaterialId(rootIndex.index); if (nodeIds.Length == 0) continue; - var materialPath = pointerHierarchy.FindNext(AnimationPointerPathHierarchy.ElementTypeOptions.Index).next; + var materialPath = pointerHierarchy.FindNext(PointerPath.PathElement.Index).next; if (materialPath == null) continue; From 34dafee2dbbcb0949117946d47e0f8cd63eb4a2e Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Wed, 3 Apr 2024 14:25:48 +0200 Subject: [PATCH 19/20] refactored AnimationPointerData and AnimPointer Extension interface --- .../Extensions/KHR_LightsPunctualExtension.cs | 38 +++++---- .../Schema/AnimationPointerData.cs | 14 ++-- .../GLTFSerialization/Schema/IExtension.cs | 4 +- .../AnimationPointerUtilities.cs | 36 ++++---- .../SceneImporter/ImporterAnimation.cs | 83 ++++++++++--------- 5 files changed, 96 insertions(+), 79 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs index ef7ab7e85..0a4be604f 100644 --- a/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Extensions/KHR_LightsPunctualExtension.cs @@ -290,7 +290,7 @@ public IExtension Clone(GLTFRoot root) } } - public class KHR_LightsPunctualExtension : IExtension, IAnimationPointerRootExtension + public class KHR_LightsPunctualExtension : IExtension, IImportAnimationPointerRootExtension { public List Lights; @@ -337,36 +337,36 @@ private static string[] GltfLightPropertyToUnityPropertyName(string gltfProperty } } - private static AnimationPointerData.ValuesConvertion GetConversion(string gltfPropertyName) + private static AnimationPointerData.ImportValuesConversion GetConversion(string gltfPropertyName) { switch (gltfPropertyName) { case "color": - return (NumericArray data, int frame) => + return (data, index) => { - var col = data.AsFloat3s[frame]; + var col = data.primaryData.AccessorContent.AsFloat3s[index]; var color = new Color(col[0], col[1], col[2], 1f).ToUnityColorRaw(); return new float[] { color.r, color.g, color.b }; //return new float[] { col.x, col.y, col.z }; }; case "intensity": - return (data, frame) => new float[1] { data.AsFloats[frame] / Mathf.PI }; + return (data, index) => new float[1] { data.primaryData.AccessorContent.AsFloats[index] / Mathf.PI }; case "range": - return (data, frame) => new float[1] { data.AsFloats[frame] }; + return (data, index) => new float[1] { data.primaryData.AccessorContent.AsFloats[index] }; case "spot/innerConeAngle": - return (data, frame) => new float[] { data.AsFloats[frame] * 2 / (Mathf.Deg2Rad * 0.8f)}; + return (data, index) => new float[] { data.primaryData.AccessorContent.AsFloats[index] * 2 / (Mathf.Deg2Rad * 0.8f)}; case "spot/outerConeAngle": - return (data, frame) => new float[] { data.AsFloats[frame] * 2 / Mathf.Deg2Rad}; + return (data, index) => new float[] { data.primaryData.AccessorContent.AsFloats[index] * 2 / Mathf.Deg2Rad}; default: return null; } } - public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierarchy pointerPath, out AnimationPointerData pointerData) + public bool TryGetImportAnimationPointerData(GLTFRoot root, PointerPath pointerPath, out AnimationPointerData pointerData) { pointerData = new AnimationPointerData(); - pointerData.nodeId = -1; - pointerData.animationType = typeof(UnityEngine.Light); + pointerData.targetNodeIds = new int[0]; + pointerData.targetType = typeof(UnityEngine.Light); if (root.Nodes == null) return false; @@ -379,6 +379,10 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar if (property == null) return false; + pointerData.unityPropertyNames = GltfLightPropertyToUnityPropertyName(property.elementName); + pointerData.importAccessorContentConversion = GetConversion(property.elementName); + + List targetNodes = new List(); for (int i = 0; i < root.Nodes.Count; i++) { var n = root.Nodes[i]; @@ -389,15 +393,17 @@ public bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierar if (lightExtension.LightId.Id == pointId.index) { - pointerData.nodeId = i;; - pointerData.unityProperties = GltfLightPropertyToUnityPropertyName(property.elementName); - pointerData.conversion = GetConversion(property.elementName); - - return true; + targetNodes.Add(i); } } } + if (targetNodes.Count > 0) + { + pointerData.targetNodeIds = targetNodes.ToArray(); + return true; + } + return false; } } diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs index b8937e3a1..d0b6af020 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AnimationPointerData.cs @@ -4,14 +4,18 @@ namespace GLTF.Schema { public class AnimationPointerData { - public string[] unityProperties; - public Type animationType; - public int nodeId; + public string[] unityPropertyNames; + public Type targetType; + public int[] targetNodeIds; - public delegate float[] ValuesConvertion(NumericArray data, int frame); - public ValuesConvertion conversion; + public delegate float[] ImportValuesConversion(AnimationPointerData data, int index); + public ImportValuesConversion importAccessorContentConversion; + public string primaryPath = ""; + public AttributeAccessor primaryData; + public string secondaryPath = ""; public AttributeAccessor secondaryData; } + } \ No newline at end of file diff --git a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs index 836cc1675..1733f8fda 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/IExtension.cs @@ -7,9 +7,9 @@ namespace GLTF.Schema /// /// Additional interface for Root Extensions to support custom animation pointers /// - public interface IAnimationPointerRootExtension + public interface IImportAnimationPointerRootExtension { - bool TryGetAnimationPointerData(GLTFRoot root, AnimationPointerPathHierarchy pointerPath, out AnimationPointerData pointerData); + bool TryGetImportAnimationPointerData(GLTFRoot root, PointerPath pointerPath, out AnimationPointerData pointerData); } /// diff --git a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs index eb04b87aa..049f90f28 100644 --- a/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs +++ b/Runtime/Scripts/Plugins/AnimationPointer/AnimationPointerUtilities.cs @@ -8,7 +8,7 @@ internal static class AnimationPointerHelpers private static readonly string[] MATERIAL_PROPERTY_COMPONENTS = {"x", "y", "z", "w"}; private static readonly string[] MATERIAL_COLOR_PROPERTY_COMPONENTS = {"r", "g", "b", "a"}; - internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, Material material, + internal static bool BuildImportMaterialAnimationPointerData(MaterialPropertiesRemapper remapper, Material material, string gltfProperty, GLTFAccessorAttributeType valueType, out AnimationPointerData pointerData) { pointerData = new AnimationPointerData(); @@ -39,20 +39,20 @@ internal static bool BuildMaterialAnimationPointerData(MaterialPropertiesRemappe switch (valueType) { case GLTFAccessorAttributeType.SCALAR: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); + pointerData.unityPropertyNames = GetAnimationChannelProperties(unityPropertyName, 1, isSecondaryGltfProperty ? 1 : 0 ); + pointerData.importAccessorContentConversion = (data, frame) => MaterialValueConversion(data.primaryData.AccessorContent, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC2: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); + pointerData.unityPropertyNames = GetAnimationChannelProperties(unityPropertyName, 2, isSecondaryGltfProperty ? 2 : 0); + pointerData.importAccessorContentConversion = (data, frame) => MaterialValueConversion(data.primaryData.AccessorContent, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC3: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 3, isColor: propertyMap.IsColor); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); + pointerData.unityPropertyNames = GetAnimationChannelProperties(unityPropertyName, 3, isColor: propertyMap.IsColor); + pointerData.importAccessorContentConversion = (data, frame) => MaterialValueConversion(data.primaryData.AccessorContent, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; case GLTFAccessorAttributeType.VEC4: - pointerData.unityProperties = AnimationPointerHelpers.GetAnimationChannelProperties(unityPropertyName, 4, isColor: propertyMap.IsColor); - pointerData.conversion = (data, frame) => AnimationPointerHelpers.MaterialValueConversion(data, frame, primaryComponentCount, propertyMap, pointerDataCopy); + pointerData.unityPropertyNames = GetAnimationChannelProperties(unityPropertyName, 4, isColor: propertyMap.IsColor); + pointerData.importAccessorContentConversion = (data, frame) => MaterialValueConversion(data.primaryData.AccessorContent, frame, primaryComponentCount, propertyMap, pointerDataCopy); break; default: return false; @@ -81,7 +81,7 @@ internal static string[] GetAnimationChannelProperties(string propertyName, int return result; } - internal static float[] MaterialValueConversion(NumericArray data, int frame, int componentCount, MaterialPointerPropertyMap map, AnimationPointerData pointerData) + internal static float[] MaterialValueConversion(NumericArray data, int index, int componentCount, MaterialPointerPropertyMap map, AnimationPointerData pointerData) { int resultComponentCount = componentCount; if (map.CombineComponentResult == MaterialPointerPropertyMap.CombineResultType.Override) @@ -94,15 +94,15 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in switch (componentCount) { case 1: - result[0] = data.AsFloats[frame]; + result[0] = data.AsFloats[index]; break; case 2: - var frameData2 = data.AsFloat2s[frame]; + var frameData2 = data.AsFloat2s[index]; result[0] = frameData2.x; result[1] = frameData2.y; break; case 3: - var frameData3 = data.AsFloat3s[frame]; + var frameData3 = data.AsFloat3s[index]; if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { Color gammaColor = new Color(frameData3.x, frameData3.y, frameData3.z).gamma; @@ -118,7 +118,7 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in } break; case 4: - var frameData4 = data.AsFloat4s[frame]; + var frameData4 = data.AsFloat4s[index]; if (map.PropertyType == MaterialPointerPropertyMap.PropertyTypeOption.SRGBColor) { Color gammaColor = new Color(frameData4.x, frameData4.y, frameData4.z, frameData4.z).gamma; @@ -148,18 +148,18 @@ internal static float[] MaterialValueConversion(NumericArray data, int frame, in switch (pointerData.secondaryData.AccessorId.Value.Type) { case GLTFAccessorAttributeType.SCALAR: - secondary = new float[] { secondaryData.AsFloats[frame] }; + secondary = new float[] { secondaryData.AsFloats[index] }; break; case GLTFAccessorAttributeType.VEC2: - var s2 = secondaryData.AsFloat2s[frame]; + var s2 = secondaryData.AsFloat2s[index]; secondary = new float[] { s2.x, s2.y }; break; case GLTFAccessorAttributeType.VEC3: - var s3 = secondaryData.AsFloat3s[frame]; + var s3 = secondaryData.AsFloat3s[index]; secondary = new float[] { s3.x, s3.y, s3.z }; break; case GLTFAccessorAttributeType.VEC4: - var s4 = secondaryData.AsFloat4s[frame]; + var s4 = secondaryData.AsFloat4s[index]; secondary = new float[] { s4.x, s4.y, s4.z, s4.w }; break; default: diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 3bca2fba9..960c9df6c 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -339,14 +339,15 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) continue; // Check if the extension support animation pointers - if (hierarchyExtension is IAnimationPointerRootExtension rootExtension) + if (hierarchyExtension is IImportAnimationPointerRootExtension rootExtension) { // Let the extension handle the pointer data and create the nodeIds and unity properties - if (rootExtension.TryGetAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) - nodeIds = new int[] { pointerData.nodeId}; + if (rootExtension.TryGetImportAnimationPointerData(_gltfRoot, pointerHierarchy, out pointerData)) + nodeIds = pointerData.targetNodeIds; else continue; } + pointerData.primaryData = samplerCache.Output; break; case PointerPath.PathElement.Root: var rootType = pointerHierarchy.elementName; @@ -362,10 +363,10 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) continue; pointerData = new AnimationPointerData(); - pointerData.nodeId = rootIndex.index; - nodeIds = new int[] {rootIndex.index}; + pointerData.targetNodeIds = new int[] {rootIndex.index}; + nodeIds = pointerData.targetNodeIds; - // Convert translate, scale, rotation from pointer path to to GLTFAnimationChannelPath, so we can use the same code as the other channels + // Convert translate, scale, rotation from pointer path to to GLTFAnimationChannelPath, so we can use the same code path as the non-animation-pointer channels if (!GLTFAnimationChannelPath.TryParse(pointerPropertyElement.elementName, out path)) continue; @@ -380,10 +381,14 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) var gltfPropertyPath = materialPath.ExtractPath(); var mat = _assetCache.MaterialCache[rootIndex.index]; + if (!mat.UnityMaterial) + continue; - if (!AnimationPointerHelpers.BuildMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type, out pointerData)) + if (!AnimationPointerHelpers.BuildImportMaterialAnimationPointerData(pointerImportContext.materialPropertiesRemapper, mat.UnityMaterial, gltfPropertyPath, samplerCache.Output.AccessorId.Value.Type, out pointerData)) continue; + pointerData.primaryData = samplerCache.Output; + pointerData.primaryPath = pointer.path; if (!string.IsNullOrEmpty(pointerData.secondaryPath)) { // When an property has potentially a second Sampler, we need to find it. e.g. like EmissionFactor and EmissionStrength @@ -394,19 +399,20 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) case "cameras": int cameraId = rootIndex.index; pointerData = new AnimationPointerData(); - pointerData.animationType = typeof(Camera); - + pointerData.targetType = typeof(Camera); + pointerData.primaryData = samplerCache.Output; + string gltfCameraPropertyPath = rootIndex.next.ExtractPath(); switch (gltfCameraPropertyPath) { case "orthographic/ymag": pointerData.secondaryPath = $"/{pointerHierarchy.elementName}/{rootIndex.index.ToString()}/orthographic/xmag"; - pointerData.unityProperties = new string[] { "orthographic size" }; + pointerData.unityPropertyNames = new string[] { "orthographic size" }; pointerData.secondaryData = FindSecondaryChannel(pointerData.secondaryPath); - pointerData.conversion = (data, frame) => + pointerData.importAccessorContentConversion = (data, frame) => { - var xmag = pointerData.secondaryData.AccessorContent.AsFloats[frame]; - var ymag = data.AsFloats[frame]; + var xmag = data.secondaryData.AccessorContent.AsFloats[frame]; + var ymag = data.primaryData.AccessorContent.AsFloats[frame]; return new float[] {Mathf.Max(xmag, ymag)}; }; break; @@ -414,29 +420,29 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) continue; case "perspective/znear": case "orthographic/znear": - pointerData.unityProperties = new string[] { "near clip plane" }; - pointerData.conversion = (data, frame) => - new float[] {data.AsFloats[frame]}; + pointerData.unityPropertyNames = new string[] { "near clip plane" }; + pointerData.importAccessorContentConversion = (data, frame) => + new float[] {data.primaryData.AccessorContent.AsFloats[frame]}; break; case "perspective/zfar": case "orthographic/zfar": - pointerData.unityProperties = new string[] { "far clip plane" }; - pointerData.conversion = (data, frame) => - new float[] {data.AsFloats[frame]}; + pointerData.unityPropertyNames = new string[] { "far clip plane" }; + pointerData.importAccessorContentConversion = (data, frame) => + new float[] {data.primaryData.AccessorContent.AsFloats[frame]}; break; case "perspective/yfov": - pointerData.unityProperties = new string[] { "field of view" }; - pointerData.conversion = (data, frame) => + pointerData.unityPropertyNames = new string[] { "field of view" }; + pointerData.importAccessorContentConversion = (data, frame) => { - var fov = data.AsFloats[frame] * Mathf.Rad2Deg; + var fov = data.primaryData.AccessorContent.AsFloats[frame] * Mathf.Rad2Deg; return new float[] {fov}; }; break; case "backgroundColor": - pointerData.unityProperties = new string[] { "background color.r", "background color.g", "background color.b", "background color.a" }; - pointerData.conversion = (data, frame) => + pointerData.unityPropertyNames = new string[] { "background color.r", "background color.g", "background color.b", "background color.a" }; + pointerData.importAccessorContentConversion = (data, frame) => { - var color = data.AsFloat4s[frame].ToUnityColorRaw(); + var color = data.primaryData.AccessorContent.AsFloat4s[frame].ToUnityColorRaw(); return new float[] {color.r, color.g, color.b, color.a}; }; break; @@ -450,7 +456,8 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) default: continue; //throw new NotImplementedException(); - } break; + } + break; default: continue; } @@ -465,7 +472,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) nodeIds = new int[] {channel.Target.Node.Id}; } - // In case an animated material are referenced from many nodes, whe need to create a curve for each node + // In case an animated material are referenced from many nodes, whe need to create a curve for each node. (e.g. Materials) foreach (var nodeId in nodeIds) { var node = await GetNode(nodeId, cancellationToken); @@ -481,8 +488,8 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) } else { - if (pointerData.animationType == null) - pointerData.animationType = targetNode.Skin != null + if (pointerData.targetType == null) + pointerData.targetType = targetNode.Skin != null ? typeof(SkinnedMeshRenderer) : typeof(MeshRenderer); } @@ -490,11 +497,11 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) switch (path) { case GLTFAnimationChannelPath.pointer: - if (pointerData.conversion == null) + if (pointerData.importAccessorContentConversion == null) continue; - SetAnimationCurve(clip, relativePath, pointerData.unityProperties, input, output, - samplerCache.Interpolation, pointerData.animationType, - (data, frame) => pointerData.conversion(data, frame)); + SetAnimationCurve(clip, relativePath, pointerData.unityPropertyNames, input, output, + samplerCache.Interpolation, pointerData.targetType, + (data, frame) => pointerData.importAccessorContentConversion(pointerData, frame)); break; case GLTFAnimationChannelPath.translation: propertyNames = new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }; @@ -520,7 +527,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) case GLTFAnimationChannelPath.rotation: propertyNames = new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }; - bool hasLight = (targetNode.Extensions != null + bool flipRotation = (targetNode.Extensions != null && targetNode.Extensions.ContainsKey(KHR_lights_punctualExtensionFactory.EXTENSION_NAME) && Context.TryGetPlugin(out _)); SetAnimationCurve(clip, relativePath, propertyNames, input, output, @@ -529,7 +536,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) { var rotation = data.AsFloat4s[frame]; var quaternion = rotation.ToUnityQuaternionConvert(); - if (hasLight) + if (flipRotation) quaternion *= Quaternion.Euler(0, 180, 0); return new float[] { quaternion.x, quaternion.y, quaternion.z, quaternion.w }; }); @@ -567,7 +574,7 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) var blendShapeFrameWeight = _options.BlendShapeFrameWeight; SetAnimationCurve(clip, relativePath, propertyNames, input, output, - samplerCache.Interpolation, typeof(Transform), + samplerCache.Interpolation, typeof(SkinnedMeshRenderer), (data, frame) => { var allValues = data.AsFloats; @@ -577,13 +584,13 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath) return frameFloats; }); } - break; default: Debug.Log(LogType.Warning, $"Cannot read GLTF animation path (File: {_gltfFileName})"); break; } // switch target type - } + } // foreach nodeIds + await YieldOnTimeoutAndThrowOnLowMemory(); } // foreach channel From 72fa8a77be1fe39d57e3dcfbe9d67045e9d3cff2 Mon Sep 17 00:00:00 2001 From: pfcDorn Date: Tue, 16 Apr 2024 11:39:25 +0200 Subject: [PATCH 20/20] fixed removing empty root objects when they are animated --- Editor/Scripts/GLTFImporter.cs | 126 ++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/Editor/Scripts/GLTFImporter.cs b/Editor/Scripts/GLTFImporter.cs index f8dc9c45a..173762e82 100644 --- a/Editor/Scripts/GLTFImporter.cs +++ b/Editor/Scripts/GLTFImporter.cs @@ -317,65 +317,95 @@ string GetUniqueName(string desiredName) // Remove empty roots if (gltfScene && _removeEmptyRootObjects) { + // To avoid removing a Root object which is animated, we collect from all animation clips the paths that are animated. + var pathBindings = new List(); + foreach (var aniClip in animations) + { + var bindings = AnimationUtility.GetCurveBindings(aniClip); + var distinctPaths = bindings.Select( x => x.path).Distinct(); + pathBindings.AddRange(distinctPaths); + } + pathBindings = pathBindings.Distinct().ToList(); + var t = gltfScene.transform; var existingAnimator = t.GetComponent(); var hadAnimator = (bool)existingAnimator; var existingAvatar = existingAnimator ? existingAnimator.avatar : default; + var rootIsAnimated = false; if (existingAnimator) - DestroyImmediate(existingAnimator); + { + var firstChildName = t.childCount > 0 ? t.GetChild(0).gameObject.name : ""; + // check if the object is animated, when true, cancel here + rootIsAnimated = firstChildName != "" && pathBindings.Contains(firstChildName); + + if (!rootIsAnimated) + DestroyImmediate(existingAnimator); + } var animationPathPrefix = ""; var originalImportName = gltfScene.name; - while ( - gltfScene.transform.childCount == 1 && - gltfScene.GetComponents().Length == 1) // Transform component + if (!rootIsAnimated) { - var parent = gltfScene; - gltfScene = gltfScene.transform.GetChild(0).gameObject; - var importName = gltfScene.name; - t = gltfScene.transform; - t.parent = null; // To keep transform information in the new parent - DestroyImmediate(parent); // Get rid of the parent - if (animationPathPrefix != "") - animationPathPrefix += "/"; - animationPathPrefix += importName; - } - animationPathPrefix += "/"; + while ( + gltfScene.transform.childCount == 1 && + gltfScene.GetComponents().Length == 1) // Transform component + { + // check if the object is animated, when true, cancel here + if (pathBindings.Contains(animationPathPrefix != "" + ? $"{animationPathPrefix}/{gltfScene.transform.GetChild(0).gameObject.name}" + : gltfScene.transform.GetChild(0).gameObject.name)) + break; + + var parent = gltfScene; + gltfScene = gltfScene.transform.GetChild(0).gameObject; + var importName = gltfScene.name; - // Re-add animator if it was removed - if (hadAnimator) - { - var newAnimator = gltfScene.AddComponent(); - newAnimator.avatar = existingAvatar; - } - // Re-target animation clips - when we strip the root, all animations also change and have a different path now. - if (animations != null) - { - foreach (var clip in animations) - { - if (clip == null) continue; - - // change all animation clip targets - var bindings = AnimationUtility.GetCurveBindings(clip); - var curves = new AnimationCurve[bindings.Length]; - var newBindings = new EditorCurveBinding[bindings.Length]; - for (var index = 0; index < bindings.Length; index++) - { - var binding = bindings[index]; - curves[index] = AnimationUtility.GetEditorCurve(clip, binding); - - var newBinding = bindings[index]; - if (binding.path.StartsWith(animationPathPrefix, StringComparison.Ordinal)) - newBinding.path = binding.path.Substring(animationPathPrefix.Length); - newBindings[index] = newBinding; - } - - var emptyCurves = new AnimationCurve[curves.Length]; - AnimationUtility.SetEditorCurves(clip, bindings, emptyCurves); - AnimationUtility.SetEditorCurves(clip, newBindings, curves); - } - } + t = gltfScene.transform; + t.parent = null; // To keep transform information in the new parent + DestroyImmediate(parent); // Get rid of the parent + if (animationPathPrefix != "") + animationPathPrefix += "/"; + animationPathPrefix += importName; + } + + animationPathPrefix += "/"; + + // Re-add animator if it was removed + if (hadAnimator) + { + var newAnimator = gltfScene.AddComponent(); + newAnimator.avatar = existingAvatar; + } + + // Re-target animation clips - when we strip the root, all animations also change and have a different path now. + if (animations != null) + { + foreach (var clip in animations) + { + if (clip == null) continue; + + // change all animation clip targets + var bindings = AnimationUtility.GetCurveBindings(clip); + var curves = new AnimationCurve[bindings.Length]; + var newBindings = new EditorCurveBinding[bindings.Length]; + for (var index = 0; index < bindings.Length; index++) + { + var binding = bindings[index]; + curves[index] = AnimationUtility.GetEditorCurve(clip, binding); + + var newBinding = bindings[index]; + if (binding.path.StartsWith(animationPathPrefix, StringComparison.Ordinal)) + newBinding.path = binding.path.Substring(animationPathPrefix.Length); + newBindings[index] = newBinding; + } + + var emptyCurves = new AnimationCurve[curves.Length]; + AnimationUtility.SetEditorCurves(clip, bindings, emptyCurves); + AnimationUtility.SetEditorCurves(clip, newBindings, curves); + } + } + } // (!rootIsAnimated) gltfScene.name = originalImportName; }