protected MeshTransform UnpackMeshTransform() { MeshTransform t = new MeshTransform(); t.Name = ReadULongPascalString(); var xformCount = ReadUInt32(); for (int x = 0; x < xformCount; x++) { MeshTransform.TransformData data = new MeshTransform.TransformData(); data.XFormType = (MeshTransform.TransformType)ReadByte(); if (data.XFormType == MeshTransform.TransformType.IndexTransform) { data.Index = ReadInt32(); } else { data.Data = new Vector4F(ReadVector3F()); if (data.XFormType == MeshTransform.TransformType.SpinTransform) { data.Data.A = ReadFloat(); } } t.Transforms.Add(data); } return(t); }
protected void WriteMeshTransform(MeshTransform t) { DynaBuffer.WriteULongPascalString(t.Name); DynaBuffer.WriteUInt32(t.Transforms.Count); foreach (var data in t.Transforms) { DynaBuffer.WriteByte((byte)data.XFormType); if (data.XFormType == MeshTransform.TransformType.IndexTransform) { DynaBuffer.WriteInt32(data.Index); } else { DynaBuffer.WriteFloat(data.Data.X); DynaBuffer.WriteFloat(data.Data.Y); DynaBuffer.WriteFloat(data.Data.Z); if (data.XFormType == MeshTransform.TransformType.SpinTransform) { DynaBuffer.WriteFloat(data.Data.A); } } } }
/// <summary> /// Goes through the list of all the children and the childrens children to find meshes (skinned or regular) to add to the mesh list. /// </summary> /// <param name="meshList"></param> /// <param name="parent"></param> /// <returns></returns> private List <MeshTransform> GetAndAddChildMeshesToList(List <MeshTransform> meshTransformList, Transform parent) { var childCount = parent.childCount; for (var i = 0; i < childCount; i++) { var t = parent.GetChild(i); var meshFilter = t.GetComponent <MeshFilter>(); if (meshFilter != null) { if (meshFilter.sharedMesh != null) { MeshTransform meshTransform = new MeshTransform(meshFilter.sharedMesh, t); meshTransformList.Add(meshTransform); } } else { var skinnedMeshRender = t.GetComponent <SkinnedMeshRenderer>(); if (skinnedMeshRender != null) { if (skinnedMeshRender.sharedMesh != null) { MeshTransform meshTransform = new MeshTransform(skinnedMeshRender.sharedMesh, t); meshTransformList.Add(meshTransform); } } } GetAndAddChildMeshesToList(meshTransformList, t); } return(meshTransformList); }
public SMD(H3D Scene, int MdlIndex, int AnimIndex = -1) { int Index = 0; if (Scene == null || Scene.Models.Count == 0) { return; } if (MdlIndex != -1 && AnimIndex == -1) { H3DModel Mdl = Scene.Models[MdlIndex]; foreach (H3DBone Bone in Mdl.Skeleton) { SMDNode Node = new SMDNode() { Index = Index, Name = Bone.Name, ParentIndex = Bone.ParentIndex }; SMDBone B = new SMDBone() { NodeIndex = Index++, Translation = Bone.Translation, Rotation = Bone.Rotation }; Nodes.Add(Node); Skeleton.Add(B); } foreach (H3DMesh Mesh in Mdl.Meshes) { if (Mesh.Type == H3DMeshType.Silhouette) { continue; } PICAVertex[] Vertices = Mesh.GetVertices(); string MaterialName = Mdl.Materials[Mesh.MaterialIndex].Texture0Name; if (MaterialName.Equals("projection_dummy") && Mdl.Materials[Mesh.MaterialIndex].Texture1Name != null) { MaterialName = Mdl.Materials[Mesh.MaterialIndex].Texture1Name; } Meshes.Add(new SMDMesh() { MaterialName = MaterialName + ".png", Vertices = MeshTransform.GetVerticesList(Mdl.Skeleton, Mesh) }); } } }
private static bool LoadMeshes(List <MeshTransform> meshes, string itemId, Matrix4x4 parentMatrix, bool viewTree, int depth = ItemFactory.ITEM_TREE_MAX_DEPTH) { if (depth <= 0) { return(true); } bool loaded = false; Item item = GetItemByIdEditor(itemId); if (item) { Matrix4x4 rootMatrix = item.transform.localToWorldMatrix.inverse; MeshFilter[] filters = item.GetComponentsInChildren <MeshFilter>(true); for (int i = 0; i < filters.Length; i++) { Mesh mesh = filters[i].sharedMesh; Renderer meshRenderer = filters[i].GetComponent <Renderer>(); MeshTransform cache = new MeshTransform(); cache.mesh = mesh; cache.matrix = parentMatrix * rootMatrix * filters[i].transform.localToWorldMatrix; cache.material = meshRenderer ? meshRenderer.sharedMaterial : null; meshes.Add(cache); } // If the item has no meshes it means it is a "scene" if (filters.Length == 0 || viewTree) { ItemReference[] childReferences = item.GetComponentsInChildren <ItemReference>(true); for (int i = 0; i < childReferences.Length; i++) { if (!childReferences[i].procedural) { LoadMeshes(meshes, childReferences[i].itemId, parentMatrix * rootMatrix * childReferences[i].transform.localToWorldMatrix, viewTree, depth - 1); } } } loaded = true; } return(loaded); }
/// <summary> /// Ensures required components are attached, like mesh colliders. /// Also ensures components that cause errors in functionality are disabled like rigidbodies, and other colliders. /// </summary> /// <param name="mt"></param> private void EnsureRequiredComponents(MeshTransform mt) { if (AddedComponents == null) { AddedComponents = new List <Component>(); } if (DisabledComponents == null) { DisabledComponents = new List <Component>(); } Collider[] colliders = mt.transform.GetComponents <Collider>(); foreach (Collider item in colliders) { MeshCollider testCast = item as MeshCollider; //if already has a mesh collider doesn't disable it. if (testCast == null) { Debug.LogWarning("Collider already on " + mt.transform.name + ". Disabling while creating colliders."); DisabledComponents.Add(item); //item.enabled = false; } } MeshCollider meshCollider = mt.transform.GetComponent <MeshCollider>(); if (meshCollider == null) { meshCollider = Undo.AddComponent <MeshCollider>(mt.transform.gameObject); if (meshCollider.sharedMesh == null) { meshCollider.sharedMesh = mt.mesh; } AddedComponents.Add(meshCollider); } Rigidbody rb = mt.transform.GetComponent <Rigidbody>(); if (rb != null) { if (!rb.isKinematic) //checks to see if rb is kinematic, non-kinematic rigidbodies do not allow for vertex selection. { Debug.LogWarning("Rigidbody attached to " + mt.transform.name + ". Setting to kinematic temporarily to enable functionality"); DisabledComponents.Add(rb); //only rigibodies with kinematic not set are added to disabled components. rb.isKinematic = true; } } }
public static void Convert(string sourseFile, string targetDirectory, Configuration configuration) { var importer = new AssimpContext(); //importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); var model = importer.ImportFile(sourseFile, PostProcessPreset.TargetRealTimeQuality | PostProcessPreset.ConvertToLeftHanded); var context = new ConverterContext(); var converters = configuration.VertexDeclarations.Select(converter => VertexConverterFactory.CreteConverter(converter.Type)).ToList(); var baseIndex = 0; var matrices = new MeshTransform[model.Meshes.Count]; for (var i = 0; i < matrices.Length; i++) { matrices[i] = new MeshTransform(); } ParseNode(context, converters, model.RootNode, model, ref baseIndex, matrices); context.Transforms = matrices; SaveVerticesAndIndicesToCCharpCode(context, Path.Combine(targetDirectory, Path.GetFileNameWithoutExtension(sourseFile) + "Resources.cs")); //SaveVerticesToBinaryFile(context, Path.Combine(targetDirectory, Path.GetFileNameWithoutExtension(sourseFile) + "_v.v")); //SaveIndicesToBinaryFile(context, Path.Combine(targetDirectory, Path.GetFileNameWithoutExtension(sourseFile) + "_i.i")); //SaveTransformsToBinaryFile(context, Path.Combine(targetDirectory, Path.GetFileNameWithoutExtension(sourseFile) + "_t.t")); }
/// <summary> /// Generates the mesh list from the base game object, searches for meshes/skinned meshes on children if include child meshes set to true. /// </summary> /// <param name="obj"></param> public List <MeshTransform> GetMeshList(GameObject baseGameObject, bool IncludeChildMeshes) { List <MeshTransform> meshTransformList = new List <MeshTransform>(); if (baseGameObject != null) { MeshFilter meshFilter = baseGameObject.GetComponent <MeshFilter>(); if (meshFilter != null) { if (meshFilter.sharedMesh != null) { MeshTransform meshTransform = new MeshTransform(meshFilter.sharedMesh, baseGameObject.transform); meshTransformList.Add(meshTransform); } } else { SkinnedMeshRenderer skinnedMeshRenderer = baseGameObject.GetComponent <SkinnedMeshRenderer>(); if (skinnedMeshRenderer != null) { if (skinnedMeshRenderer.sharedMesh != null) { MeshTransform meshTransform = new MeshTransform(skinnedMeshRenderer.sharedMesh, baseGameObject.transform); meshTransformList.Add(meshTransform); } } } if (IncludeChildMeshes) { meshTransformList = GetAndAddChildMeshesToList(meshTransformList, baseGameObject.transform); } } if (meshTransformList.Count == 0) { Debug.LogWarning("No meshes found! Make sure that the object you are selecting has a mesh filter, and a mesh renderer OR a skinned mesh renderer. " + "Or set include child meshes to true if selecting root empty/base object.", baseGameObject.transform); } return(meshTransformList); }
public DAE(H3D Scene, int MdlIndex, int AnimIndex = -1) { if (MdlIndex != -1) { library_visual_scenes = new List <DAEVisualScene>(); H3DModel Mdl = Scene.Models[MdlIndex]; DAEVisualScene VN = new DAEVisualScene(); VN.name = $"{Mdl.Name}_{MdlIndex.ToString("D2")}"; VN.id = $"{VN.name}_id"; //Materials if (Mdl.Materials.Count > 0) { library_materials = new List <DAEMaterial>(); library_effects = new List <DAEEffect>(); } foreach (H3DMaterial Mtl in Mdl.Materials) { string MtlName = $"{MdlIndex.ToString("D2")}_{Mtl.Name}"; DAEEffect Effect = new DAEEffect(); Effect.name = $"{Mtl.Name}_eff"; Effect.id = $"{Effect.name}_id"; DAEEffectParam ImgSurface = new DAEEffectParam(); DAEEffectParam ImgSampler = new DAEEffectParam(); ImgSurface.surface = new DAEEffectParamSurfaceElement(); ImgSampler.sampler2D = new DAEEffectParamSampler2DElement(); ImgSurface.sid = $"{Mtl.Name}_surf"; ImgSurface.surface.type = "2D"; ImgSurface.surface.init_from = Mtl.Texture0Name; ImgSurface.surface.format = "PNG"; ImgSampler.sid = $"{Mtl.Name}_samp"; ImgSampler.sampler2D.source = ImgSurface.sid; ImgSampler.sampler2D.wrap_s = Mtl.TextureMappers[0].WrapU.ToDAEWrap(); ImgSampler.sampler2D.wrap_t = Mtl.TextureMappers[0].WrapV.ToDAEWrap(); ImgSampler.sampler2D.minfilter = Mtl.TextureMappers[0].MinFilter.ToDAEFilter(); ImgSampler.sampler2D.magfilter = Mtl.TextureMappers[0].MagFilter.ToDAEFilter(); ImgSampler.sampler2D.mipfilter = DAEFilter.LINEAR; Effect.profile_COMMON.newparam.Add(ImgSurface); Effect.profile_COMMON.newparam.Add(ImgSampler); Effect.profile_COMMON.technique.sid = $"{Mtl.Name}_tech"; Effect.profile_COMMON.technique.phong.diffuse.texture.texture = ImgSampler.sid; library_effects.Add(Effect); DAEMaterial Material = new DAEMaterial(); Material.name = $"{Mtl.Name}_mat"; Material.id = $"{Material.name}_id"; Material.instance_effect.url = $"#{Effect.id}"; library_materials.Add(Material); } //Skeleton nodes string RootBoneId = string.Empty; if ((Mdl.Skeleton?.Count ?? 0) > 0) { Queue <Tuple <H3DBone, DAENode> > ChildBones = new Queue <Tuple <H3DBone, DAENode> >(); DAENode RootNode = new DAENode(); ChildBones.Enqueue(Tuple.Create(Mdl.Skeleton[0], RootNode)); RootBoneId = $"#{Mdl.Skeleton[0].Name}_bone_id"; while (ChildBones.Count > 0) { Tuple <H3DBone, DAENode> Bone_Node = ChildBones.Dequeue(); H3DBone Bone = Bone_Node.Item1; Bone_Node.Item2.id = $"{Bone.Name}_bone_id"; Bone_Node.Item2.name = Bone.Name; Bone_Node.Item2.sid = Bone.Name; Bone_Node.Item2.type = DAENodeType.JOINT; Bone_Node.Item2.SetBoneEuler(Bone.Translation, Bone.Rotation, Bone.Scale); foreach (H3DBone B in Mdl.Skeleton) { if (B.ParentIndex == -1) { continue; } H3DBone ParentBone = Mdl.Skeleton[B.ParentIndex]; if (ParentBone == Bone) { DAENode Node = new DAENode(); ChildBones.Enqueue(Tuple.Create(B, Node)); if (Bone_Node.Item2.Nodes == null) { Bone_Node.Item2.Nodes = new List <DAENode>(); } Bone_Node.Item2.Nodes.Add(Node); } } } VN.node.Add(RootNode); } //Mesh if (Mdl.Meshes.Count > 0) { library_geometries = new List <DAEGeometry>(); } for (int MeshIndex = 0; MeshIndex < Mdl.Meshes.Count; MeshIndex++) { if (Mdl.Meshes[MeshIndex].Type == H3DMeshType.Silhouette) { continue; } H3DMesh Mesh = Mdl.Meshes[MeshIndex]; PICAVertex[] Vertices = MeshTransform.GetWorldSpaceVertices(Mdl.Skeleton, Mesh); string MtlName = $"Mdl_{MdlIndex}_Mtl_{Mdl.Materials[Mesh.MaterialIndex].Name}"; string MtlTgt = library_materials[Mesh.MaterialIndex].id; for (int SMIndex = 0; SMIndex < Mesh.SubMeshes.Count; SMIndex++) { H3DSubMesh SM = Mesh.SubMeshes[SMIndex]; string ShortName = string.Empty; if (Mdl.MeshNodesTree != null && Mesh.NodeIndex < Mdl.MeshNodesTree.Count) { ShortName = Mdl.MeshNodesTree.Find(Mesh.NodeIndex); } string MeshName = $"{ShortName}_{MeshIndex}_{SMIndex}"; DAEGeometry Geometry = new DAEGeometry(); Geometry.name = MeshName; Geometry.id = $"{Geometry.name}_geo_id"; //Geometry string VertsId = $"{MeshName}_vtx_id"; Geometry.mesh.vertices.id = VertsId; Geometry.mesh.triangles.material = MtlName; Geometry.mesh.triangles.AddInput("VERTEX", $"#{VertsId}"); Geometry.mesh.triangles.Set_p(SM.Indices); foreach (PICAAttribute Attr in Mesh.Attributes) { if (Attr.Name >= PICAAttributeName.BoneIndex) { continue; } string[] Values = new string[Vertices.Length]; for (int Index = 0; Index < Vertices.Length; Index++) { PICAVertex v = Vertices[Index]; switch (Attr.Name) { case PICAAttributeName.Position: Values[Index] = DAEUtils.Vector3Str(v.Position); break; case PICAAttributeName.Normal: Values[Index] = DAEUtils.Vector3Str(v.Normal); break; case PICAAttributeName.Tangent: Values[Index] = DAEUtils.Vector3Str(v.Tangent); break; case PICAAttributeName.Color: Values[Index] = DAEUtils.Vector4Str(v.Color); break; case PICAAttributeName.TexCoord0: Values[Index] = DAEUtils.Vector2Str(v.TexCoord0); break; case PICAAttributeName.TexCoord1: Values[Index] = DAEUtils.Vector2Str(v.TexCoord1); break; case PICAAttributeName.TexCoord2: Values[Index] = DAEUtils.Vector2Str(v.TexCoord2); break; } } int Elements = 0; switch (Attr.Name) { case PICAAttributeName.Position: Elements = 3; break; case PICAAttributeName.Normal: Elements = 3; break; case PICAAttributeName.Tangent: Elements = 3; break; case PICAAttributeName.Color: Elements = 4; break; case PICAAttributeName.TexCoord0: Elements = 2; break; case PICAAttributeName.TexCoord1: Elements = 2; break; case PICAAttributeName.TexCoord2: Elements = 2; break; } DAESource Source = new DAESource(); Source.name = $"{MeshName}_{Attr.Name}"; Source.id = $"{Source.name}_id"; Source.float_array = new DAEArray() { id = $"{Source.name}_array_id", count = (uint)(Vertices.Length * Elements), data = string.Join(" ", Values) }; DAEAccessor Accessor = new DAEAccessor() { source = $"#{Source.float_array.id}", count = (uint)Vertices.Length, stride = (uint)Elements }; switch (Elements) { case 2: Accessor.AddParams("float", "S", "T"); break; case 3: Accessor.AddParams("float", "X", "Y", "Z"); break; case 4: Accessor.AddParams("float", "R", "G", "B", "A"); break; } Source.technique_common.accessor = Accessor; Geometry.mesh.source.Add(Source); if (Attr.Name < PICAAttributeName.Color) { string Semantic = string.Empty; switch (Attr.Name) { case PICAAttributeName.Position: Semantic = "POSITION"; break; case PICAAttributeName.Normal: Semantic = "NORMAL"; break; case PICAAttributeName.Tangent: Semantic = "TANGENT"; break; } Geometry.mesh.vertices.AddInput(Semantic, $"#{Source.id}"); } else if (Attr.Name == PICAAttributeName.Color) { Geometry.mesh.triangles.AddInput("COLOR", $"#{Source.id}", 0); } else { Geometry.mesh.triangles.AddInput("TEXCOORD", $"#{Source.id}", 0, (uint)Attr.Name - 4); } } //Attributes Loop library_geometries.Add(Geometry); //Controller bool HasController = SM.BoneIndicesCount > 0 && (Mdl.Skeleton?.Count ?? 0) > 0; DAEController Controller = new DAEController(); if (HasController) { if (library_controllers == null) { library_controllers = new List <DAEController>(); } Controller.name = $"{MeshName}_ctrl"; Controller.id = $"{Controller.name}_id"; Controller.skin.source = $"#{Geometry.id}"; Controller.skin.vertex_weights.count = (uint)Vertices.Length; string[] BoneNames = new string[Mdl.Skeleton.Count]; string[] BindPoses = new string[Mdl.Skeleton.Count]; for (int Index = 0; Index < Mdl.Skeleton.Count; Index++) { BoneNames[Index] = Mdl.Skeleton[Index].Name; BindPoses[Index] = DAEUtils.MatrixStr(Mdl.Skeleton[Index].InverseTransform); } //4 is the max number of bones per vertex int[] v = new int[Vertices.Length * 4 * 2]; int[] vcount = new int[Vertices.Length]; Dictionary <string, int> Weights = new Dictionary <string, int>(); int vi = 0, vci = 0; if (SM.Skinning == H3DSubMeshSkinning.Smooth) { foreach (PICAVertex Vertex in Vertices) { int Count = 0; for (int Index = 0; Index < 4; Index++) { int BIndex = Vertex.Indices[Index]; float Weight = Vertex.Weights[Index]; if (Weight == 0) { break; } if (BIndex < SM.BoneIndices.Length && BIndex > -1) { BIndex = SM.BoneIndices[BIndex]; } else { BIndex = 0; } string WStr = Weight.ToString(CultureInfo.InvariantCulture); v[vi++] = BIndex; if (Weights.ContainsKey(WStr)) { v[vi++] = Weights[WStr]; } else { v[vi++] = Weights.Count; Weights.Add(WStr, Weights.Count); } Count++; } vcount[vci++] = Count; } } else { foreach (PICAVertex Vertex in Vertices) { int BIndex = Vertex.Indices[0]; if (BIndex < SM.BoneIndices.Length && BIndex > -1) { BIndex = SM.BoneIndices[BIndex]; } else { BIndex = 0; } v[vi++] = BIndex; v[vi++] = 0; vcount[vci++] = 1; } Weights.Add("1", 0); } Array.Resize(ref v, vi); Controller.skin.src.Add(new DAESource($"{Controller.name}_names", 1, BoneNames, "JOINT", "Name")); Controller.skin.src.Add(new DAESource($"{Controller.name}_poses", 16, BindPoses, "TRANSFORM", "float4x4")); Controller.skin.src.Add(new DAESource($"{Controller.name}_weights", 1, Weights.Keys.ToArray(), "WEIGHT", "float")); Controller.skin.joints.AddInput("JOINT", $"#{Controller.skin.src[0].id}"); Controller.skin.joints.AddInput("INV_BIND_MATRIX", $"#{Controller.skin.src[1].id}"); Controller.skin.vertex_weights.AddInput("JOINT", $"#{Controller.skin.src[0].id}", 0); Controller.skin.vertex_weights.AddInput("WEIGHT", $"#{Controller.skin.src[2].id}", 1); Controller.skin.vertex_weights.vcount = string.Join(" ", vcount); Controller.skin.vertex_weights.v = string.Join(" ", v); library_controllers.Add(Controller); } //Mesh node DAENode Node = new DAENode(); Node.name = $"{MeshName}_node"; Node.id = $"{Node.name}_id"; Node.matrix = DAEMatrix.Identity; DAENodeInstance NodeInstance = new DAENodeInstance(); NodeInstance.url = $"#{(HasController ? Controller.id : Geometry.id)}"; NodeInstance.bind_material.technique_common.instance_material.symbol = MtlName; NodeInstance.bind_material.technique_common.instance_material.target = $"#{MtlTgt}"; if (HasController) { NodeInstance.skeleton = $"#{VN.node[0].id}"; Node.instance_controller = NodeInstance; } else { Node.instance_geometry = NodeInstance; } VN.node.Add(Node); } //SubMesh Loop } //Mesh Loop library_visual_scenes.Add(VN); if (library_visual_scenes.Count > 0) { scene.instance_visual_scene.url = $"#{library_visual_scenes[0].id}"; } library_images = new List <DAEImage>(); foreach (H3DTexture Tex in Scene.Textures) { //library_images.Add(new DAEImage() //{ // id = Tex.Name, // init_from = $"./{Tex.Name}.png" //}); } foreach (var mat in Scene.Models[MdlIndex].Materials) { if (mat.Texture0Name != null && !LibImgContainsThing(mat.Texture0Name)) { library_images.Add(new DAEImage() { id = mat.Texture0Name, init_from = $"./{mat.Texture0Name}.png" }); } if (mat.Texture1Name != null && !LibImgContainsThing(mat.Texture1Name)) { library_images.Add(new DAEImage() { id = mat.Texture0Name, init_from = $"./{mat.Texture0Name}.png" }); } if (mat.Texture2Name != null && !LibImgContainsThing(mat.Texture2Name)) { library_images.Add(new DAEImage() { id = mat.Texture0Name, init_from = $"./{mat.Texture0Name}.png" }); } } } //MdlIndex != -1 if (AnimIndex != -1) { library_animations = new List <DAEAnimation>(); string[] AnimElemNames = { "translate", "rotateX", "rotateY", "rotateZ", "scale" }; H3DAnimation SklAnim = Scene.SkeletalAnimations[AnimIndex]; H3DDict <H3DBone> Skeleton = Scene.Models[0].Skeleton; int FramesCount = (int)SklAnim.FramesCount + 1; foreach (H3DAnimationElement Elem in SklAnim.Elements) { if (Elem.PrimitiveType != H3DPrimitiveType.Transform && Elem.PrimitiveType != H3DPrimitiveType.QuatTransform) { continue; } H3DBone SklBone = Skeleton.FirstOrDefault(x => x.Name == Elem.Name); H3DBone Parent = null; if (SklBone != null && SklBone.ParentIndex != -1) { Parent = Skeleton[SklBone.ParentIndex]; } for (int i = 0; i < 5; i++) { string[] AnimTimes = new string[FramesCount]; string[] AnimPoses = new string[FramesCount]; string[] AnimLerps = new string[FramesCount]; bool IsRotation = i > 0 && i < 4; //1, 2, 3 bool Skip = Elem.PrimitiveType != H3DPrimitiveType.Transform && Elem.PrimitiveType != H3DPrimitiveType.QuatTransform; if (!Skip) { if (Elem.Content is H3DAnimTransform Transform) { switch (i) { case 0: Skip = !Transform.TranslationExists; break; case 1: Skip = !Transform.RotationX.Exists; break; case 2: Skip = !Transform.RotationY.Exists; break; case 3: Skip = !Transform.RotationZ.Exists; break; case 4: Skip = !Transform.ScaleExists; break; } } else if (Elem.Content is H3DAnimQuatTransform QuatTransform) { switch (i) { case 0: Skip = !QuatTransform.HasTranslation; break; case 1: Skip = !QuatTransform.HasRotation; break; case 2: Skip = !QuatTransform.HasRotation; break; case 3: Skip = !QuatTransform.HasRotation; break; case 4: Skip = !QuatTransform.HasScale; break; } } } if (Skip) { continue; } for (int Frame = 0; Frame < FramesCount; Frame++) { string StrTrans = string.Empty; H3DAnimationElement PElem = SklAnim.Elements.FirstOrDefault(x => x.Name == Parent?.Name); Vector3 InvScale = Vector3.One; if (Elem.Content is H3DAnimTransform Transform) { //Compensate parent bone scale (basically, don't inherit scales) if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0) { if (PElem != null) { H3DAnimTransform PTrans = (H3DAnimTransform)PElem.Content; InvScale /= new Vector3( PTrans.ScaleX.Exists ? PTrans.ScaleX.GetFrameValue(Frame) : Parent.Scale.X, PTrans.ScaleY.Exists ? PTrans.ScaleY.GetFrameValue(Frame) : Parent.Scale.Y, PTrans.ScaleZ.Exists ? PTrans.ScaleZ.GetFrameValue(Frame) : Parent.Scale.Z); } else { InvScale /= Parent.Scale; } } switch (i) { //Translation case 0: StrTrans = DAEUtils.VectorStr(new Vector3( Transform.TranslationX.Exists //X ? Transform.TranslationX.GetFrameValue(Frame) : SklBone.Translation.X, Transform.TranslationY.Exists //Y ? Transform.TranslationY.GetFrameValue(Frame) : SklBone.Translation.Y, Transform.TranslationZ.Exists //Z ? Transform.TranslationZ.GetFrameValue(Frame) : SklBone.Translation.Z)); break; //Scale case 4: StrTrans = DAEUtils.VectorStr(InvScale * new Vector3( Transform.ScaleX.Exists //X ? Transform.ScaleX.GetFrameValue(Frame) : SklBone.Scale.X, Transform.ScaleY.Exists //Y ? Transform.ScaleY.GetFrameValue(Frame) : SklBone.Scale.Y, Transform.ScaleZ.Exists //Z ? Transform.ScaleZ.GetFrameValue(Frame) : SklBone.Scale.Z)); break; //Rotation case 1: StrTrans = DAEUtils.RadToDegStr(Transform.RotationX.GetFrameValue(Frame)); break; case 2: StrTrans = DAEUtils.RadToDegStr(Transform.RotationY.GetFrameValue(Frame)); break; case 3: StrTrans = DAEUtils.RadToDegStr(Transform.RotationZ.GetFrameValue(Frame)); break; } } else if (Elem.Content is H3DAnimQuatTransform QuatTransform) { //Compensate parent bone scale (basically, don't inherit scales) if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0) { if (PElem != null) { InvScale /= ((H3DAnimQuatTransform)PElem.Content).GetScaleValue(Frame); } else { InvScale /= Parent.Scale; } } switch (i) { case 0: StrTrans = DAEUtils.VectorStr(QuatTransform.GetTranslationValue(Frame)); break; case 1: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().X); break; case 2: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Y); break; case 3: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Z); break; case 4: StrTrans = DAEUtils.VectorStr(InvScale * QuatTransform.GetScaleValue(Frame)); break; } } //This is the Time in seconds, so we divide by the target FPS AnimTimes[Frame] = (Frame / 30f).ToString(CultureInfo.InvariantCulture); AnimPoses[Frame] = StrTrans; AnimLerps[Frame] = "LINEAR"; } DAEAnimation Anim = new DAEAnimation(); Anim.name = $"{SklAnim.Name}_{Elem.Name}_{AnimElemNames[i]}"; Anim.id = $"{Anim.name}_id"; Anim.src.Add(new DAESource($"{Anim.name}_frame", 1, AnimTimes, "TIME", "float")); Anim.src.Add(new DAESource($"{Anim.name}_interp", 1, AnimLerps, "INTERPOLATION", "Name")); Anim.src.Add(IsRotation ? new DAESource($"{Anim.name}_pose", 1, AnimPoses, "ANGLE", "float") : new DAESource($"{Anim.name}_pose", 3, AnimPoses, "X", "float", "Y", "float", "Z", "float")); Anim.sampler.AddInput("INPUT", $"#{Anim.src[0].id}"); Anim.sampler.AddInput("INTERPOLATION", $"#{Anim.src[1].id}"); Anim.sampler.AddInput("OUTPUT", $"#{Anim.src[2].id}"); Anim.sampler.id = $"{Anim.name}_samp_id"; Anim.channel.source = $"#{Anim.sampler.id}"; Anim.channel.target = $"{Elem.Name}_bone_id/{AnimElemNames[i]}"; if (IsRotation) { Anim.channel.target += ".ANGLE"; } library_animations.Add(Anim); } //Axis 0-5 } //SklAnim.Elements } //AnimIndex != -1 }