Пример #1
0
        private void ProcessMeshOptions(Node3D model)
        {
            if (MeshOptions.Count == 0)
            {
                return;
            }

            var meshes = model.Descendants
                         .OfType <Mesh3D>()
                         .Where(d => !string.IsNullOrEmpty(d.Id));

            foreach (var mesh in meshes)
            {
                foreach (var meshOption in MeshOptions)
                {
                    if (mesh.Id != meshOption.Id)
                    {
                        continue;
                    }

                    if (meshOption.HitTestTarget)
                    {
                        mesh.HitTestTarget = true;
                        mesh.SkipRender    = true;
                    }
                    mesh.CullMode = meshOption.CullMode;
                    break;
                }
            }
        }
Пример #2
0
 private Node3DState(Node3D node3D)
 {
     this.node3D = node3D;
     position    = wantedPosition = node3D.Position;
     rotation    = wantedRotation = node3D.Rotation;
     scale       = wantedScale = node3D.Scale;
 }
Пример #3
0
 public void Apply(Node3D model)
 {
     ProcessMeshOptions(model);
     ProcessAnimations(model);
     ProcessMaterialEffects(model);
     ProcessComponents(model);
 }
Пример #4
0
 private IEnumerable <Node> GetAnimationNodes(Node3D model, Animation attachmentAnimation)
 {
     if (attachmentAnimation.Nodes.Count > 0)
     {
         var nodeList = new List <Node>();
         foreach (var attachmentNode in attachmentAnimation.Nodes.Distinct())
         {
             var node = model.TryFindNode(attachmentNode.Id);
             if (node == null)
             {
                 Console.WriteLine($"Attachment3D Warning: Undable to add \"{ attachmentNode.Id }\" to the list of animable nodes. Node not found");
                 continue;
             }
             nodeList.Add(node);
         }
         return(nodeList);
     }
     if (attachmentAnimation.IgnoredNodes.Count > 0)
     {
         var nodeList = new List <Node>();
         foreach (var nodeData in attachmentAnimation.IgnoredNodes.Distinct())
         {
             var node = model.TryFindNode(nodeData.Id);
             if (node == null)
             {
                 Console.WriteLine($"Attachment3D Warning: Undable to add \"{ nodeData.Id }\" to the list ignored for animation nodes. Node not found");
                 continue;
             }
             nodeList.Add(node);
         }
         return(model.Descendants.Where(i => !nodeList.Contains(i)));
     }
     return(model.Descendants);
 }
Пример #5
0
 public static NodeState TryGetState(Node3D node3D, Animation animation)
 {
     if (node3D is Mesh3D mesh3D && mesh3D.Submeshes.All(sm => sm.Bones.Count == 0))
     {
         var existsBones = false;
         for (var i = 0; i < mesh3D.Submeshes.Count; i++)
         {
             if (mesh3D.Submeshes[i].Bones.Count != 0)
             {
                 continue;
             }
             existsBones = true;
             break;
         }
         if (!existsBones)
         {
             return(null);
         }
     }
     node3D.Animators.TryFind("Position", out Animator <Vector3> positionAnimator, animation.Id);
     node3D.Animators.TryFind("Rotation", out Animator <Quaternion> rotationAnimator, animation.Id);
     node3D.Animators.TryFind("Scale", out Animator <Vector3> scaleAnimator, animation.Id);
     return
         (positionAnimator != null || rotationAnimator != null || scaleAnimator != null ?
          new Node3DState(node3D) :
          null);
 }
Пример #6
0
        private void MergeMeshes(Node3D model)
        {
            var meshes = model.Nodes.OfType <Mesh3D>();
            var map    = new Dictionary <int, List <Mesh3D> >();

            foreach (var mesh in meshes)
            {
                if (mesh.Animators.Any() ||
                    mesh.Components.Any(c => !(c is UpdatableNodeBehavior)) ||
                    (MeshOptions.FirstOrDefault(m => m.Id == mesh.Id)?.DisableMerging ?? mesh.Nodes.Count != 0) ||
                    !IsIdentityMatrix(mesh.LocalTransform) && IsAnyBoneAffectOnMesh(mesh)
                    )
                {
                    continue;
                }
                var hash = CalcHashForMesh(mesh);
                if (!map.ContainsKey(hash))
                {
                    map[hash] = new List <Mesh3D>();
                }
                map[hash].Add(mesh);
            }
            MergeMeshes(map, model);
            foreach (var node in model.Nodes)
            {
                MergeMeshes((Node3D)node);
            }
        }
Пример #7
0
        private void ProcessAnimations(Node3D model)
        {
            if (Animations.Count == 0)
            {
                return;
            }
            var srcAnimation = model.DefaultAnimation;

            foreach (var animationData in Animations)
            {
                var animation = srcAnimation;
                if (animationData.Name != DefaultAnimationName)
                {
                    animation = new Lime.Animation {
                        Id = animationData.Name
                    };
                    foreach (var node in GetAnimationNodes(model, animationData))
                    {
                        OverrideAnimation(node, srcAnimation, animation);
                    }
                    model.Animations.Add(animation);
                }

                var animationBlending = new AnimationBlending()
                {
                    Option = animationData.Blending
                };

                foreach (var markerData in animationData.Markers)
                {
                    animation.Markers.AddOrdered(markerData.Marker.Clone());
                    if (markerData.Blending != null)
                    {
                        animationBlending.MarkersOptions.Add(
                            markerData.Marker.Id,
                            new MarkerBlending {
                            Option = markerData.Blending
                        });
                    }
                }

                foreach (var markersBlendings in animationData.MarkersBlendings)
                {
                    if (!animationBlending.MarkersOptions.ContainsKey(markersBlendings.DestMarkerId))
                    {
                        animationBlending.MarkersOptions.Add(markersBlendings.DestMarkerId, new MarkerBlending());
                    }
                    animationBlending.MarkersOptions[markersBlendings.DestMarkerId].SourceMarkersOptions
                    .Add(markersBlendings.SourceMarkerId, markersBlendings.Blending);
                }

                if (animationBlending.Option != null || animationBlending.MarkersOptions.Count > 0)
                {
                    animation.AnimationEngine = BlendAnimationEngine.Instance;
                    model.Components.GetOrAdd <AnimationBlender>().Options.Add(animation.Id ?? "", animationBlending);
                }
            }
        }
Пример #8
0
        private void ProcessNodeRemovals(Node3D model)
        {
            var nodes = NodeRemovals.SelectMany(removal => model.Descendants.Where(node => string.Equals(removal.NodeId, node.Id))).ToList();

            foreach (var node in nodes)
            {
                node.Unlink();
            }
        }
Пример #9
0
        public void ApplyScaleFactor(Node3D model)
        {
            if (ScaleFactor == 1)
            {
                return;
            }
            var        sf    = Vector3.One * ScaleFactor;
            var        nodes = model.Descendants.OfType <Node3D>();
            Vector3    tranlation;
            Quaternion rotation;
            Vector3    scale;

            foreach (var node in nodes)
            {
                node.Position *= sf;
                if (node is Mesh3D)
                {
                    foreach (var submesh in (node as Mesh3D).Submeshes)
                    {
                        foreach (VertexBuffer <Mesh3D.Vertex> vb in submesh.Mesh.VertexBuffers)
                        {
                            for (var i = 0; i < vb.Data.Length; i++)
                            {
                                vb.Data[i].Pos *= sf;
                            }
                        }
                        ;
                        for (int i = 0; i < submesh.BoneBindPoses.Count; i++)
                        {
                            submesh.BoneBindPoses[i].Decompose(out scale, out rotation, out tranlation);
                            tranlation *= sf;
                            submesh.BoneBindPoses[i] =
                                Matrix44.CreateRotation(rotation) *
                                Matrix44.CreateScale(scale) *
                                Matrix44.CreateTranslation(tranlation);
                        }
                    }
                }
                else if (node is Camera3D)
                {
                    var cam = node as Camera3D;
                    cam.NearClipPlane *= ScaleFactor;
                    cam.FarClipPlane  *= ScaleFactor;
                }
                foreach (var animator in node.Animators)
                {
                    if (animator.TargetProperty == "Position")
                    {
                        foreach (Keyframe <Vector3> key in animator.Keys)
                        {
                            key.Value *= sf;
                        }
                    }
                }
            }
        }
Пример #10
0
 private IEnumerable <Node> GetAnimationNodes(Node3D model, Animation animationData)
 {
     if (animationData.Nodes.Count > 0)
     {
         return(animationData.Nodes.Distinct().Select(n => model.FindNode(n.Id)));
     }
     if (animationData.IgnoredNodes.Count > 0)
     {
         var ignoredNodes = new HashSet <Node>(animationData.IgnoredNodes.Select(n => model.FindNode(n.Id)));
         return(model.Descendants.Where(i => !ignoredNodes.Contains(i)));
     }
     return(model.Descendants);
 }
Пример #11
0
        private void ApplyScaleFactor(Node3D model)
        {
            if (ScaleFactor == 1)
            {
                return;
            }
            var sf    = Vector3.One * ScaleFactor;
            var nodes = model.Descendants.OfType <Node3D>();

            foreach (var node in nodes)
            {
                node.Position *= sf;
                if (node is Mesh3D)
                {
                    foreach (var submesh in (node as Mesh3D).Submeshes)
                    {
                        var vertices = submesh.Mesh.Vertices;
                        for (var i = 0; i < vertices.Length; i++)
                        {
                            vertices[i].Pos *= sf;
                        }
                        submesh.Mesh.DirtyFlags |= MeshDirtyFlags.Vertices;
                        for (var i = 0; i < submesh.BoneBindPoses.Count; i++)
                        {
                            submesh.BoneBindPoses[i].Decompose(out var scale, out Quaternion rotation, out var tranlation);
                            tranlation *= sf;
                            submesh.BoneBindPoses[i] =
                                Matrix44.CreateRotation(rotation) *
                                Matrix44.CreateScale(scale) *
                                Matrix44.CreateTranslation(tranlation);
                        }
                    }
                }
                else if (node is Camera3D cam)
                {
                    cam.NearClipPlane    *= ScaleFactor;
                    cam.FarClipPlane     *= ScaleFactor;
                    cam.OrthographicSize *= ScaleFactor;
                }
                foreach (var animator in node.Animators)
                {
                    if (animator.TargetPropertyPath == "Position")
                    {
                        foreach (Keyframe <Vector3> key in animator.Keys)
                        {
                            key.Value *= sf;
                        }
                    }
                }
            }
        }
Пример #12
0
        private void ProcessMeshOptions(Node3D model)
        {
            if (MeshOptions.Count == 0)
            {
                return;
            }

            var meshes = model.Descendants
                         .OfType <Mesh3D>()
                         .Where(d => !string.IsNullOrEmpty(d.Id));

            foreach (var mesh in meshes)
            {
                foreach (var meshOption in MeshOptions)
                {
                    if (mesh.Id != meshOption.Id)
                    {
                        continue;
                    }

                    if (meshOption.HitTestTarget)
                    {
                        mesh.HitTestTarget = true;
                        mesh.SkipRender    = true;
                    }
                    mesh.Opaque   = meshOption.Opaque;
                    mesh.CullMode = meshOption.CullMode;
                    if (meshOption.SkinningMode != SkinningMode.Default)
                    {
                        if (meshOption.SkinningMode == SkinningMode.DualQuaternion)
                        {
                            var scaleTransform           = Matrix44.CreateScale(mesh.Scale);
                            var scaleTransformForNormals = scaleTransform.CalcInverted().Transpose();
                            foreach (var submesh in mesh.Submeshes)
                            {
                                MeshUtils.TransformVertices(submesh.Mesh, (ref Mesh3D.Vertex v) => {
                                    v.Pos    *= scaleTransform;
                                    v.Normal *= scaleTransformForNormals;
                                });
                            }
                            mesh.Scale = Vector3.One;
                        }
                        mesh.SkinningMode = meshOption.SkinningMode;
                    }
                    break;
                }
            }
        }
Пример #13
0
        private void ProcessMaterials(Node3D model)
        {
            var submeshes = model.Descendants.OfType <Mesh3D>().SelectMany(m => m.Submeshes);

            foreach (var submesh in submeshes)
            {
                if (submesh.Material != null)
                {
                    var materialDescriptor = Materials.FirstOrDefault(d => d.SourceName == submesh.Material.Id);
                    if (materialDescriptor != null)
                    {
                        submesh.Material = materialDescriptor.Material;
                    }
                }
            }
        }
Пример #14
0
        private void ProcessMaterialEffects(Node3D model)
        {
            var effectEngine = new MaterialEffectEngine();

            foreach (var effect in MaterialEffects)
            {
                try {
                    var effectPresenter = new MaterialEffectPresenter(effect.MaterialName, effect.Name, effect.Path);
                    model.CompoundPresenter.Add(effectPresenter);

                    if (effect.Blending != null)
                    {
                        effectPresenter.Animation.AnimationEngine = BlendAnimationEngine.Instance;
                        var blender           = effectPresenter.Scene.Components.GetOrAdd <AnimationBlender>();
                        var animationBlending = new AnimationBlending()
                        {
                            Option = effect.Blending
                        };
                        blender.Options.Add(effectPresenter.Animation.Id ?? "", animationBlending);
                    }

                    var animation = new Lime.Animation {
                        Id = effect.Name,
                        AnimationEngine = effectEngine
                    };

                    foreach (var marker in effectPresenter.Animation.Markers)
                    {
                        animation.Markers.Add(marker.Clone());
                    }

                    model.Animations.Add(animation);
                } catch (Lime.Exception e) {
                    if (Application.IsTangerine)
                    {
                        Console.WriteLine(e.Message);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
Пример #15
0
 private void ProcessComponents(Node3D model)
 {
     foreach (var nodeComponentData in NodeComponents)
     {
         var node = nodeComponentData.IsRoot ? model : model.TryFindNode(nodeComponentData.NodeId);
         if (node != null)
         {
             foreach (var component in nodeComponentData.Components)
             {
                 if (ValidateComponentType(node.GetType(), component.GetType()))
                 {
                     node.Components.Add(Cloner.Clone(component));
                 }
                 else
                 {
                     Console.WriteLine($"Warning: Unable to add {component.GetType().Name} to the {node.Id}." +
                                       " This component type isn't allowed for this node type.");
                 }
             }
         }
     }
 }
Пример #16
0
 public Matrix44 CalcTransformInSpaceOf(Node3D node)
 {
     return(GlobalTransform * node.GlobalTransform.CalcInverted());
 }
Пример #17
0
 public Matrix44 CalcPointTransformInSpaceOf(float amount, Node3D node)
 {
     return(CalcPointTransform(amount) * node.GlobalTransform.CalcInverted());
 }
Пример #18
0
        private void ProcessAnimations(Node3D model)
        {
            if (Animations.Count == 0)
            {
                return;
            }

            var newAnimators       = new List <NodeAndAnimator>();
            var newAnimations      = new List <Lime.Animation>();
            var animationsToReduce = new Dictionary <string, (int, int)>();

            foreach (var animation in Animations)
            {
                if (!model.Animations.TryFind(animation.SourceAnimationId, out var srcAnimation))
                {
                    if (string.IsNullOrEmpty(animation.SourceAnimationId))
                    {
                        // If no source animation id is present, it means that model attachment has obsolete format.
                        var ac = model.Components.Get <AnimationComponent>();
                        srcAnimation = ac != null && ac.Animations.Count > 0 ? ac.Animations[0] : null;
                        // Check if the animation has been deleted but attachment hasn't been modified after that.
                        if (srcAnimation == null)
                        {
#if TANGERINE
                            Console.WriteLine($"Attachment3D Warning: skip '{ animation.Id }' animation applying. Source Fbx file have no animation data.");
#endif // TANGERINE
                            continue;
                        }
                    }
                    else
                    {
#if TANGERINE
                        Console.WriteLine($"Attachment3D Warning: source animation '{ animation.SourceAnimationId }' not found");
#endif // TANGERINE
                        continue;
                    }
                }

                var animationId = animation.Id;
                // TODO: Replace 'Default' animation with its source animation id in all referring to Lime projects.
                if (animationId == "Default")
                {
                    animationId = srcAnimation.Id;
                }

                var newAnimation = srcAnimation;
                if (animationId != animation.SourceAnimationId)
                {
                    newAnimation = new Lime.Animation {
                        Id = animationId
                    };
                    newAnimations.Add(newAnimation);
                    model.Animations.Add(newAnimation);
                    foreach (var node in GetAnimationNodes(model, animation))
                    {
                        foreach (var animator in node.Animators)
                        {
                            if (animator.AnimationId == srcAnimation.Id)
                            {
                                var newAnimator = Cloner.Clone(animator);
                                animator.AnimationId = newAnimation.Id;
                                CopyKeys(animator, newAnimator, animation.StartFrame, animation.LastFrame);
                                if (newAnimator.Keys.Count > 0)
                                {
                                    newAnimators.Add(new NodeAndAnimator {
                                        Node     = node,
                                        Animator = newAnimator
                                    });
                                }
                            }
                        }
                    }
                }
                else
                {
                    animationsToReduce.Add(newAnimation.Id, (animation.StartFrame, animation.LastFrame));
                }

                var animationBlending = new AnimationBlending()
                {
                    Option = animation.Blending
                };

                foreach (var data in animation.Markers)
                {
                    newAnimation.Markers.AddOrdered(data.Marker.Clone());
                    if (data.Blending != null)
                    {
                        animationBlending.MarkersOptions.Add(
                            data.Marker.Id,
                            new MarkerBlending {
                            Option = data.Blending
                        });
                    }
                }

                foreach (var markersBlendings in animation.MarkersBlendings)
                {
                    if (!animationBlending.MarkersOptions.ContainsKey(markersBlendings.DestMarkerId))
                    {
                        animationBlending.MarkersOptions.Add(markersBlendings.DestMarkerId, new MarkerBlending());
                    }
                    animationBlending.MarkersOptions[markersBlendings.DestMarkerId].SourceMarkersOptions
                    .Add(markersBlendings.SourceMarkerId, markersBlendings.Blending);
                }

                if (animationBlending.Option != null || animationBlending.MarkersOptions.Count > 0)
                {
                    model.Components.GetOrAdd <AnimationBlender>().Options.Add(newAnimation.Id ?? "", animationBlending);
                }

                foreach (var i in newAnimators)
                {
                    i.Node.Animators.Add(i.Animator);
                }
                newAnimators.Clear();
            }

            foreach (var animation in model.Animations.Except(newAnimations).ToList())
            {
                var srcAnimators = new List <IAnimator>();
                animation.FindAnimators(srcAnimators);
                if (animationsToReduce.Keys.Contains(animation.Id))
                {
                    srcAnimators.ForEach(a => ReduceKeys(a, animationsToReduce[animation.Id].Item1, animationsToReduce[animation.Id].Item2));
                    foreach (var animator in srcAnimators.Where(a => a.Keys.Count == 0))
                    {
                        animator.Owner.Animators.Remove(animator);
                    }
                }
                else
                {
                    foreach (var animator in srcAnimators)
                    {
                        animator.Owner.Animators.Remove(animator);
                    }
                    model.Animations.Remove(animation);
                }
            }
        }
Пример #19
0
        private void MergeMeshes(Dictionary <int, List <Mesh3D> > map, Node3D model)
        {
            const int meshLimit  = ushort.MaxValue;
            const int bonesLimit = 50;

            if (map.Count == 0)
            {
                return;
            }
            foreach (var pair in map)
            {
                var materialsMap = new Dictionary <IMaterial, Dictionary <Mesh3D, List <Submesh3D> > >();
                foreach (var mesh in pair.Value)
                {
                    foreach (var submesh in mesh.Submeshes)
                    {
                        var material = submesh.Material;
                        if (!materialsMap.ContainsKey(material))
                        {
                            materialsMap[material] = new Dictionary <Mesh3D, List <Submesh3D> >();
                        }
                        if (!materialsMap[material].ContainsKey(mesh))
                        {
                            materialsMap[material][mesh] = new List <Submesh3D>();
                        }
                        materialsMap[material][mesh].Add(submesh);
                    }
                }

                foreach (var meshDescriptor in materialsMap.Values)
                {
                    var first   = meshDescriptor.First().Key;
                    var newMesh = new Mesh3D {
                        Opaque        = first.Opaque,
                        CullMode      = first.CullMode,
                        SkinningMode  = first.SkinningMode,
                        HitTestTarget = first.HitTestTarget
                    };
                    Submesh3D curSubmesh = null;
                    foreach (var meshAndSubmeshes in meshDescriptor)
                    {
                        var meshIdx = 0;
                        while (meshIdx < meshAndSubmeshes.Value.Count)
                        {
                            var submeshToMerge     = meshAndSubmeshes.Value[meshIdx];
                            var meshLocalTransform = meshAndSubmeshes.Key.LocalTransform;
                            MeshUtils.TransformVertices(submeshToMerge.Mesh, (ref Mesh3D.Vertex v) => {
                                v.Pos = meshLocalTransform.TransformVector(v.Pos);
                            });
                            if (curSubmesh == null)
                            {
                                curSubmesh = submeshToMerge;
                                meshAndSubmeshes.Value.RemoveAt(meshIdx);
                                meshIdx++;
                                continue;
                            }
                            if (curSubmesh.Mesh.Indices.Length + submeshToMerge.Mesh.Indices.Length < meshLimit &&
                                curSubmesh.BoneNames.Count + submeshToMerge.BoneNames.Count < bonesLimit
                                )
                            {
                                curSubmesh = Combine(curSubmesh, submeshToMerge);
                                meshAndSubmeshes.Value.RemoveAt(meshIdx);
                            }
                            else
                            {
                                newMesh.Submeshes.Add(curSubmesh);
                                curSubmesh = null;
                            }
                        }
                        newMesh.Id += (newMesh.Id == null ? "" : "|") + meshAndSubmeshes.Key.Id;
                    }
                    newMesh.Submeshes.Add(curSubmesh);
                    model.AddNode(newMesh);
                }
                foreach (var mesh in materialsMap.Values.SelectMany(kv => kv.Keys))
                {
                    mesh.UnlinkAndDispose();
                }
            }
        }