Exemplo n.º 1
0
        // key - control point index
        public static Dictionary <int, BoneAssignment> GetBoneAssignments(FbxMesh mesh, Skeleton skeleton)
        {
            var boneAssignments = new Dictionary <int, BoneAssignment>();
            var weightLists     = new Dictionary <int, List <(int, double)> >();

            int skinCount = mesh.GetDeformerCount(FbxDeformer.EDeformerType.eSkin);

            if (skinCount == 0)
            {
                return(null);
            }
            if (1 < skinCount)
            {
                FbxImportLog.LogMessage(mesh.GetNode(), "Warning! Multiple skins for the mesh");                   //??? Может ли быть в одном Mesh несколько Skins? Скорее всего нет, хоть API позволяет.
            }
            FbxSkin pSkin = FbxSkin.Cast(mesh.GetDeformer(0, FbxDeformer.EDeformerType.eSkin));

            int clusterCount = pSkin.GetClusterCount();

            for (int iCluster = 0; iCluster < clusterCount; iCluster++)
            {
                FbxCluster pCluster = pSkin.GetCluster(iCluster);

                FbxNode pLink = pCluster.GetLink();
                if (pLink == null)
                {
                    continue;
                }

                int weightCount = pCluster.GetControlPointIndicesCount();
                if (weightCount == 0)
                {
                    continue;
                }

                int boneIndex = skeleton.GetBoneIndexByNode(pLink);

                var weightIndices = IntArray.frompointer(pCluster.GetControlPointIndices());
                var weightValues  = DoubleArray.frompointer(pCluster.GetControlPointWeights());
                for (int i = 0; i < weightCount; i++)
                {
                    int    vertexIndex = weightIndices.getitem(i);
                    double weight      = weightValues.getitem(i);

                    if (!weightLists.TryGetValue(vertexIndex, out var lst))
                    {
                        lst = new List <(int, double)>();
                        weightLists[vertexIndex] = lst;
                    }

                    lst.Add((boneIndex, weight));
                }
            }

            foreach (var pair in weightLists)
            {
                boneAssignments[pair.Key] = ConvertBoneWeightListToBoneAssignment(pair.Value);
            }
            return(boneAssignments);
        }
Exemplo n.º 2
0
        //Find the cluster that links to the skeleton bone node
        public static FbxCluster FindCluster(FbxNode boneNode, FbxSkin[] skins, out FbxSkin skin)
        {
            for (int i = 0; i < skins.Length; i++)
            {
                skin = skins[i];

                int nClusterCount = skin.GetClusterCount();
                for (int j = 0; j < nClusterCount; j++)
                {
                    FbxCluster fbxCluster = skin.GetCluster(j);
                    if (fbxCluster == null)
                    {
                        continue;
                    }

                    if (fbxCluster.GetLinkMode() == FbxCluster.ELinkMode.eAdditive && fbxCluster.GetAssociateModel() != null)
                    {
                        FbxImportLog.LogMessage(boneNode, "Warning! Associated model.");
                    }

                    if (fbxCluster.GetLink()?.GetUniqueID() == boneNode.GetUniqueID())
                    {
                        return(fbxCluster);
                    }
                }
            }

            skin = null;
            return(null);
        }
Exemplo n.º 3
0
        public void Cluster_SetLink_SetsLink()
        {
            // given:
            var cluster = new FbxCluster("");
            var node    = new FbxNode("");

            // require:
            Assert.AreEqual(0, cluster.GetSrcObjectCount());
            Assert.AreEqual(0, cluster.GetDstObjectCount());
            Assert.Null(cluster.GetLink());

            Assert.AreEqual(0, node.GetSrcObjectCount());
            Assert.AreEqual(0, node.GetDstObjectCount());

            // when:
            cluster.SetLink(node);

            // then:
            Assert.AreEqual(1, cluster.GetSrcObjectCount());
            Assert.AreSame(node, cluster.GetSrcObject(0));
            Assert.AreEqual(0, cluster.GetDstObjectCount());
            Assert.AreSame(node, cluster.GetLink());

            Assert.AreEqual(0, node.GetSrcObjectCount());
            Assert.AreEqual(1, node.GetDstObjectCount());
            Assert.AreSame(cluster, node.GetDstObject(0));
        }
Exemplo n.º 4
0
        public new static FbxCluster Create(FbxObject pContainer, string pName)
        {
            global::System.IntPtr cPtr = FbxWrapperNativePINVOKE.FbxCluster_Create__SWIG_1(FbxObject.getCPtr(pContainer), pName);
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            return(ret);
        }
Exemplo n.º 5
0
        public FbxCluster GetCluster(int pIndex)
        {
            global::System.IntPtr cPtr = fbx_wrapperPINVOKE.FbxSkin_GetCluster__SWIG_0(swigCPtr, pIndex);
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            return(ret);
        }
Exemplo n.º 6
0
        public FbxCluster RemoveCluster(FbxCluster pCluster)
        {
            global::System.IntPtr cPtr = fbx_wrapperPINVOKE.FbxSkin_RemoveCluster(swigCPtr, FbxCluster.getCPtr(pCluster));
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            return(ret);
        }
Exemplo n.º 7
0
        public void Skin_AddCluster_AddsCluster()
        {
            // given:
            var s = new FbxSkin("");
            var c = new FbxCluster("");

            // require:
            Assert.AreEqual(0, s.GetSrcObjectCount());
            Assert.AreEqual(0, s.GetDstObjectCount());
            Assert.AreEqual(0, s.GetClusterCount());

            Assert.AreEqual(0, c.GetSrcObjectCount());
            Assert.AreEqual(0, c.GetDstObjectCount());

            // when:
            s.AddCluster(c);

            // then:
            Assert.AreEqual(1, s.GetSrcObjectCount());
            Assert.AreSame(c, s.GetSrcObject(0));
            Assert.AreEqual(0, s.GetDstObjectCount());
            Assert.AreEqual(1, s.GetClusterCount());
            Assert.AreSame(c, s.GetCluster(0));

            Assert.AreEqual(0, c.GetSrcObjectCount());
            Assert.AreEqual(1, c.GetDstObjectCount());
            Assert.AreSame(s, c.GetDstObject(0));
        }
Exemplo n.º 8
0
        public new static FbxCluster Create(FbxManager pManager, string pName)
        {
            global::System.IntPtr cPtr = fbx_wrapperPINVOKE.FbxCluster_Create__SWIG_0(FbxManager.getCPtr(pManager), pName);
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            return(ret);
        }
Exemplo n.º 9
0
        public void FbxCluster_Create_HasNamespacePrefix()
        {
            // given:
            var obj = new FbxCluster("asdf");

            // then:
            Assert.AreEqual("SubDeformer::", obj.GetNameSpacePrefix());
        }
Exemplo n.º 10
0
 public bool Equals(FbxCluster other)
 {
     if (object.ReferenceEquals(other, null))
     {
         return(false);
     }
     return(this.swigCPtr.Handle.Equals(other.swigCPtr.Handle));
 }
Exemplo n.º 11
0
        protected void LinkMeshToSkeleton(FbxScene scene, FbxNode meshNode, FbxNode skelRootNode)
        {
            FbxNode limb1 = skelRootNode.GetChild(0);
            FbxNode limb2 = limb1.GetChild(0);

            FbxCluster rootCluster = FbxCluster.Create(scene, "RootCluster");

            rootCluster.SetLink(skelRootNode);
            rootCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne);
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    rootCluster.AddControlPointIndex(4 * i + j, 1.0 - 0.25 * i);
                }
            }

            FbxCluster limb1Cluster = FbxCluster.Create(scene, "Limb1Cluster");

            limb1Cluster.SetLink(limb1);
            limb1Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne);
            for (int i = 1; i < 6; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    limb1Cluster.AddControlPointIndex(4 * i + j, (i == 1 || i == 5 ? 0.25 : 0.5));
                }
            }

            FbxCluster limb2Cluster = FbxCluster.Create(scene, "Limb2Cluster");

            limb2Cluster.SetLink(limb2);
            limb2Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne);
            for (int i = 3; i < 7; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    limb2Cluster.AddControlPointIndex(4 * i + j, 0.25 * (i - 2));
                }
            }

            FbxAMatrix globalTransform = meshNode.EvaluateGlobalTransform();

            rootCluster.SetTransformMatrix(globalTransform);
            limb1Cluster.SetTransformMatrix(globalTransform);
            limb2Cluster.SetTransformMatrix(globalTransform);

            rootCluster.SetTransformLinkMatrix(skelRootNode.EvaluateGlobalTransform());
            limb1Cluster.SetTransformLinkMatrix(limb1.EvaluateGlobalTransform());
            limb2Cluster.SetTransformLinkMatrix(limb2.EvaluateGlobalTransform());

            FbxSkin skin = FbxSkin.Create(scene, "Skin");

            skin.AddCluster(rootCluster);
            skin.AddCluster(limb1Cluster);
            skin.AddCluster(limb2Cluster);
            meshNode.GetMesh().AddDeformer(skin);
        }
Exemplo n.º 12
0
        public bool AddCluster(FbxCluster pCluster)
        {
            bool ret = NativeMethods.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster));

            if (NativeMethods.SWIGPendingException.Pending)
            {
                throw NativeMethods.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
Exemplo n.º 13
0
        public new static FbxCluster Create(FbxObject pContainer, string pName)
        {
            global::System.IntPtr cPtr = NativeMethods.FbxCluster_Create__SWIG_1(FbxObject.getCPtr(pContainer), pName);
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            if (NativeMethods.SWIGPendingException.Pending)
            {
                throw NativeMethods.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
Exemplo n.º 14
0
        public FbxCluster GetCluster(int pIndex)
        {
            global::System.IntPtr cPtr = NativeMethods.FbxSkin_GetCluster(swigCPtr, pIndex);
            FbxCluster            ret  = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);

            if (NativeMethods.SWIGPendingException.Pending)
            {
                throw NativeMethods.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
Exemplo n.º 15
0
        public void TestAddCluster()
        {
            var fbxSkin    = CreateObject("skin");
            var fbxCluster = FbxCluster.Create(Manager, "cluster");

            bool result = fbxSkin.AddCluster(fbxCluster);

            Assert.IsTrue(result);
            Assert.AreEqual(fbxSkin.GetCluster(0), fbxCluster);

            // test adding null cluster
            Assert.That(() => { fbxSkin.AddCluster(null); }, Throws.Exception.TypeOf <System.ArgumentNullException>());

            // add invalid cluster
            var fbxCluster2 = FbxCluster.Create(Manager, "cluster2");

            fbxCluster2.Dispose();
            Assert.That(() => { fbxSkin.AddCluster(fbxCluster2); }, Throws.Exception.TypeOf <System.ArgumentNullException>());
        }
Exemplo n.º 16
0
            /// <summary>
            /// Export binding of mesh to skeleton
            /// </summary>
            protected void ExportSkin(MeshInfo meshInfo, FbxScene fbxScene, FbxMesh fbxMesh,
                                      FbxNode fbxRootNode,
                                      Dictionary <Transform, FbxNode> boneNodes)
            {
                SkinnedMeshRenderer unitySkinnedMeshRenderer
                    = meshInfo.renderer as SkinnedMeshRenderer;

                FbxSkin fbxSkin = FbxSkin.Create(fbxScene, (meshInfo.unityObject.name + "_Skin"));

                FbxAMatrix fbxMeshMatrix = fbxRootNode.EvaluateGlobalTransform();

                // keep track of the bone index -> fbx cluster mapping, so that we can add the bone weights afterwards
                Dictionary <int, FbxCluster> boneCluster = new Dictionary <int, FbxCluster> ();

                for (int i = 0; i < unitySkinnedMeshRenderer.bones.Length; i++)
                {
                    FbxNode fbxBoneNode = boneNodes [unitySkinnedMeshRenderer.bones[i]];

                    // Create the deforming cluster
                    FbxCluster fbxCluster = FbxCluster.Create(fbxScene, "BoneWeightCluster");

                    fbxCluster.SetLink(fbxBoneNode);
                    fbxCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne);

                    boneCluster.Add(i, fbxCluster);

                    // set the Transform and TransformLink matrix
                    fbxCluster.SetTransformMatrix(fbxMeshMatrix);

                    FbxAMatrix fbxLinkMatrix = fbxBoneNode.EvaluateGlobalTransform();
                    fbxCluster.SetTransformLinkMatrix(fbxLinkMatrix);

                    // add the cluster to the skin
                    fbxSkin.AddCluster(fbxCluster);
                }

                // set the vertex weights for each bone
                SetVertexWeights(meshInfo, boneCluster);

                // Add the skin to the mesh after the clusters have been added
                fbxMesh.AddDeformer(fbxSkin);
            }
Exemplo n.º 17
0
        protected void CheckMeshLinkedToSkeleton(FbxMesh origMesh, FbxMesh importMesh)
        {
            FbxSkin origSkin = origMesh.GetDeformer(0, new FbxStatus()) as FbxSkin;

            Assert.IsNotNull(origSkin);

            FbxSkin importSkin = origMesh.GetDeformer(0, new FbxStatus()) as FbxSkin;

            Assert.IsNotNull(importSkin);

            ClusterPair[] clusters = new ClusterPair[3];

            for (int i = 0; i < 3; i++)
            {
                FbxCluster origCluster = origSkin.GetCluster(i);
                Assert.IsNotNull(origCluster);

                FbxCluster importCluster = importSkin.GetCluster(i);
                Assert.IsNotNull(importCluster);

                clusters [i] = new ClusterPair(origCluster, importCluster);
            }

            foreach (var c in clusters)
            {
                FbxAMatrix origTransformMatrix   = null;
                FbxAMatrix importTransformMatrix = null;
                Assert.AreEqual(c.orig.GetTransformMatrix(origTransformMatrix), c.import.GetTransformMatrix(importTransformMatrix));
                Assert.AreEqual(c.orig.GetTransformLinkMatrix(origTransformMatrix), c.import.GetTransformLinkMatrix(importTransformMatrix));

                Assert.AreEqual(c.orig.GetLink(), c.import.GetLink());
                Assert.AreEqual(c.orig.GetLinkMode(), c.import.GetLinkMode());
                Assert.AreEqual(c.orig.GetControlPointIndicesCount(), c.import.GetControlPointIndicesCount());

                for (int i = 0; i < c.orig.GetControlPointIndicesCount(); i++)
                {
                    Assert.AreEqual(c.orig.GetControlPointIndexAt(i), c.import.GetControlPointIndexAt(i));
                    Assert.AreEqual(c.orig.GetControlPointWeightAt(i), c.import.GetControlPointWeightAt(i));
                }
            }
        }
Exemplo n.º 18
0
        public SkeletonBone(FbxNode boneNode, SkeletonBone parentBone, FbxSkin[] skins, SceneLoader scene)
        {
            //this.scene = scene;
            this.scene = scene;
            Node       = boneNode;
            ParentBone = parentBone;
            //animationTrackKeyFrames = new List<HashSet<double>>();
            cluster = Skeleton.FindCluster(Node, skins, out skin);               //Поиск по всем skins во всех mesh. Можно было бы сделать эффективнее.

            globalMeshTransform = new FbxAMatrix();
            globalMeshTransform.SetIdentity();
            geometryOffset = new FbxAMatrix();
            geometryOffset.SetIdentity();
            if (cluster != null)
            {
                FbxNode meshNode = skin.GetGeometry()?.GetNode();
                if (meshNode != null)
                {
                    globalMeshTransform = meshNode.EvaluateGlobalTransform(FbxExtensions.ToFbxTime(-1));                         // FbxMath.GetGlobalPosition( meshNode, FbxExtensions.ToFbxTime( -1 ), null );
                    geometryOffset      = FbxMath.GetGeometryOffset(meshNode);
                }
            }
            InitialTransform = GetInitialTransform().ToMatrix4();             //Во внешнем коде надо использовать это значение, т.к. результат GetInitialTransform() может зависеть от установленного AnimationTrack
        }
Exemplo n.º 19
0
        protected override FbxSkin GenerateFbx()
        {
            MeshExportData meshData = Souls.meshData.SoulsData;

            ICollection <BoneIndexToWeightPair> rawBoneDeformerData = new List <BoneIndexToWeightPair>();

            for (int vertexIndex = 0; vertexIndex < meshData.mesh.Vertices.Count; ++vertexIndex)
            {
                FLVER.Vertex vertex = meshData.mesh.Vertices[vertexIndex];

                const int maxVertexDeformations = 4;
                for (int vertexDeformationIndex = 0; vertexDeformationIndex < maxVertexDeformations; ++vertexDeformationIndex)
                {
                    BoneIndexToWeightPair weightData = new BoneIndexToWeightPair()
                    {
                        flverBoneIndex = vertex.BoneIndices[vertexDeformationIndex],
                        boneWeight     = vertex.BoneWeights[vertexDeformationIndex],
                        vertexIndex    = vertexIndex
                    };

                    if (weightData.flverBoneIndex > 0 && weightData.boneWeight > 0)
                    {
                        rawBoneDeformerData.Add(weightData);
                    }
                }
            }

            foreach (var ddd in rawBoneDeformerData.GroupBy(boneDeformerData => boneDeformerData.vertexIndex).Select(boneDeformedGroup => (vertexIndex: boneDeformedGroup.Key, affectingBonesCount: boneDeformedGroup.Count())).Where((ddd) => ddd.affectingBonesCount > 4))
            {
                System.Console.WriteLine($"Vertex {ddd.vertexIndex} : {ddd.affectingBonesCount}");
            }

            foreach (var ddd in rawBoneDeformerData.GroupBy(boneDeformedData => boneDeformedData.flverBoneIndex).Select(boneDeformerGroup => (boneIndex: boneDeformerGroup.Key, affectingVerticesCount: boneDeformerGroup.Count(), uniqueAffectingVerticesCount: boneDeformerGroup.Select(boneDeformerData => boneDeformerData.vertexIndex).Distinct().Count())))
            {
                if (ddd.affectingVerticesCount != ddd.uniqueAffectingVerticesCount)
                {
                    System.Console.WriteLine($"Bone {ddd.boneIndex} : vertices {ddd.affectingVerticesCount} : unique {ddd.uniqueAffectingVerticesCount}");
                }
            }

            FbxSkin skin = FbxSkin.Create(Owner, meshData.meshRoot.Name + "_Skin");

            System.Console.WriteLine($"Generating {meshData.meshRoot.Name}");

            foreach (var deformerData in rawBoneDeformerData.ToLookup(boneDeformerData => boneDeformerData.flverBoneIndex))
            {
                FLVER2 flver = Souls.flver;

                FLVER.Bone flverBone = flver.Bones[deformerData.Key];

                DsBoneData boneData = Souls.skeleton.boneDatas.Single(boneData => boneData.flverBone == flverBone);

                //System.Console.WriteLine($"Exporting {deformerData.Key} : {flverBone.Name} with {deformerData.Count(weight=>weight.boneWeight > 0)} vertices");

                FbxCluster boneCluster = FbxCluster.Create(skin, meshData.meshRoot.Name + "_" + boneData.exportData.SoulsData.Name + "_Cluster");

                boneCluster.SetLink(boneData.exportData.FbxNode);
                boneCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne);
                boneCluster.SetControlPointIWCount(deformerData.Count());
                boneCluster.SetTransformMatrix(Souls.meshData.FbxNode.EvaluateGlobalTransform());
                boneCluster.SetTransformLinkMatrix(boneData.exportData.FbxNode.EvaluateGlobalTransform());
                foreach (BoneIndexToWeightPair boneWeightPair in deformerData)
                {
                    boneCluster.AddControlPointIndex(boneWeightPair.vertexIndex, boneWeightPair.boneWeight);

                    //Console.WriteLine("Bone {0} has vertex {1} with weight {2}", flverBone.Name, boneWeightPair.vertexIndex, boneWeightPair.boneWeight);
                }

                skin.AddCluster(boneCluster);
            }

            //foreach (var dd in rawBoneDeformerData.GroupBy(biwp => biwp.vertexIndex).Where(group => group.Count() > 2))
            //{
            //System.Console.WriteLine($"Vertex {dd.Key} : {dd.Count()}");
            //}

            //var set = new HashSet<int>();
            //for (int vertexIndex = 0; vertexIndex < meshData.mesh.Vertices.Count; ++vertexIndex)
            //{
            //    if (!rawBoneDeformerData.Any(x=>x.vertexIndex == vertexIndex))
            //    {
            //        set.Add(vertexIndex);
            //    }
            //}

            //System.Console.WriteLine($"Total {set.Count} unweighted nodes");

            return(skin);
        }
Exemplo n.º 20
0
  // override void Dispose() {base.Dispose();}

  public new static FbxCluster Create(FbxManager pManager, string pName) {
    global::System.IntPtr cPtr = NativeMethods.FbxCluster_Create__SWIG_0(FbxManager.getCPtr(pManager), pName);
    FbxCluster ret = (cPtr == global::System.IntPtr.Zero) ? null : new FbxCluster(cPtr, false);
    if (NativeMethods.SWIGPendingException.Pending) throw NativeMethods.SWIGPendingException.Retrieve();
    return ret;
  }
Exemplo n.º 21
0
        public bool AddCluster(FbxCluster pCluster)
        {
            bool ret = fbx_wrapperPINVOKE.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster));

            return(ret);
        }
Exemplo n.º 22
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FbxCluster obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
Exemplo n.º 23
0
 public ClusterPair(FbxCluster orig, FbxCluster import)
 {
     this.orig   = orig;
     this.import = import;
 }
Exemplo n.º 24
0
        public bool AddCluster(FbxCluster pCluster)
        {
            bool ret = FbxWrapperNativePINVOKE.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster));

            return(ret);
        }
Exemplo n.º 25
0
        public void Scene_AddObjectWithSrcObjects_AddsAllSrcObjects()
        {
            // given:
            var scene = new FbxScene("s");
            var node  = new FbxNode("n");
            var m1    = new FbxMesh("m1");
            var m2    = new FbxMesh("m2");
            var v     = new FbxVideo("v");
            var c     = new FbxCluster("c");
            var n2    = new FbxNode("n2");
            var c2    = new FbxCluster("c2");

            node.ConnectSrcObject(m1);
            node.ConnectSrcObject(m2);
            node.ConnectSrcObject(v);
            node.ConnectSrcObject(c);
            c.ConnectSrcObject(n2);;
            n2.ConnectSrcObject(c2);

            // require:
            Assert.AreEqual(3, scene.GetSrcObjectCount());

            Assert.AreEqual(4, node.GetSrcObjectCount());
            Assert.AreSame(m1, node.GetSrcObject(0));
            Assert.AreSame(m2, node.GetSrcObject(1));
            Assert.AreSame(v, node.GetSrcObject(2));
            Assert.AreSame(c, node.GetSrcObject(3));
            Assert.AreEqual(0, node.GetDstObjectCount());
            Assert.Null(node.GetScene());

            Assert.AreEqual(0, m1.GetSrcObjectCount());
            Assert.AreEqual(1, m1.GetDstObjectCount());
            Assert.AreSame(node, m1.GetDstObject(0));
            Assert.Null(m1.GetScene());

            Assert.AreEqual(0, m2.GetSrcObjectCount());
            Assert.AreEqual(1, m2.GetDstObjectCount());
            Assert.AreSame(node, m2.GetDstObject(0));
            Assert.Null(m2.GetScene());

            Assert.AreEqual(0, v.GetSrcObjectCount());
            Assert.AreEqual(1, v.GetDstObjectCount());
            Assert.AreSame(node, v.GetDstObject(0));
            Assert.Null(v.GetScene());

            Assert.AreEqual(1, c.GetSrcObjectCount());
            Assert.AreSame(n2, c.GetSrcObject());;
            Assert.AreEqual(1, c.GetDstObjectCount());
            Assert.AreSame(node, c.GetDstObject(0));
            Assert.Null(c.GetScene());

            Assert.AreEqual(1, n2.GetSrcObjectCount());
            Assert.AreSame(c2, n2.GetSrcObject());;
            Assert.AreEqual(1, n2.GetDstObjectCount());
            Assert.AreSame(c, n2.GetDstObject(0));
            Assert.Null(n2.GetScene());

            Assert.AreEqual(0, c2.GetSrcObjectCount());
            Assert.AreEqual(1, c2.GetDstObjectCount());
            Assert.AreSame(n2, c2.GetDstObject(0));
            Assert.Null(c2.GetScene());

            // when:
            scene.ConnectSrcObject(node);

            // then:
            Assert.AreEqual(10, scene.GetSrcObjectCount());
            Assert.AreSame(node, scene.GetSrcObject(3));
            Assert.AreSame(m1, scene.GetSrcObject(4));
            Assert.AreSame(m2, scene.GetSrcObject(5));
            Assert.AreSame(v, scene.GetSrcObject(6));
            Assert.AreSame(c, scene.GetSrcObject(7));
            Assert.AreSame(n2, scene.GetSrcObject(8));
            Assert.AreSame(c2, scene.GetSrcObject(9));

            Assert.AreEqual(4, node.GetSrcObjectCount());
            Assert.AreSame(m1, node.GetSrcObject(0));
            Assert.AreSame(m2, node.GetSrcObject(1));
            Assert.AreSame(v, node.GetSrcObject(2));
            Assert.AreSame(c, node.GetSrcObject(3));
            Assert.AreEqual(1, node.GetDstObjectCount());
            Assert.AreSame(scene, node.GetDstObject(0));
            Assert.AreSame(scene, node.GetScene());

            Assert.AreEqual(0, m1.GetSrcObjectCount());
            Assert.AreEqual(2, m1.GetDstObjectCount());
            Assert.AreSame(node, m1.GetDstObject(0));
            Assert.AreSame(scene, m1.GetDstObject(1));
            Assert.AreSame(scene, m1.GetScene());

            Assert.AreEqual(0, m2.GetSrcObjectCount());
            Assert.AreEqual(2, m2.GetDstObjectCount());
            Assert.AreSame(node, m2.GetDstObject(0));
            Assert.AreSame(scene, m2.GetDstObject(1));
            Assert.AreSame(scene, m2.GetScene());

            Assert.AreEqual(0, v.GetSrcObjectCount());
            Assert.AreEqual(2, v.GetDstObjectCount());
            Assert.AreSame(node, v.GetDstObject(0));
            Assert.AreSame(scene, v.GetDstObject(1));
            Assert.AreSame(scene, v.GetScene());

            Assert.AreEqual(1, c.GetSrcObjectCount());
            Assert.AreSame(n2, c.GetSrcObject(0));
            Assert.AreEqual(2, c.GetDstObjectCount());
            Assert.AreSame(node, c.GetDstObject(0));
            Assert.AreSame(scene, c.GetDstObject(1));
            Assert.AreSame(scene, c.GetScene());

            Assert.AreEqual(1, n2.GetSrcObjectCount());
            Assert.AreSame(c2, n2.GetSrcObject());;
            Assert.AreEqual(2, n2.GetDstObjectCount());
            Assert.AreSame(c, n2.GetDstObject(0));
            Assert.AreSame(scene, n2.GetDstObject(1));
            Assert.AreSame(scene, n2.GetScene());

            Assert.AreEqual(0, c2.GetSrcObjectCount());
            Assert.AreEqual(2, c2.GetDstObjectCount());
            Assert.AreSame(n2, c2.GetDstObject(0));
            Assert.AreSame(scene, c2.GetDstObject(1));
            Assert.AreSame(scene, c2.GetScene());
        }