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; } } }
private Node3DState(Node3D node3D) { this.node3D = node3D; position = wantedPosition = node3D.Position; rotation = wantedRotation = node3D.Rotation; scale = wantedScale = node3D.Scale; }
public void Apply(Node3D model) { ProcessMeshOptions(model); ProcessAnimations(model); ProcessMaterialEffects(model); ProcessComponents(model); }
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); }
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); }
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); } }
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); } } }
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(); } }
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; } } } } }
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); }
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; } } } } }
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; } } }
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; } } } }
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; } } } }
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."); } } } } }
public Matrix44 CalcTransformInSpaceOf(Node3D node) { return(GlobalTransform * node.GlobalTransform.CalcInverted()); }
public Matrix44 CalcPointTransformInSpaceOf(float amount, Node3D node) { return(CalcPointTransform(amount) * node.GlobalTransform.CalcInverted()); }
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); } } }
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(); } } }