// 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); }
//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); }
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)); }
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); }
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); }
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); }
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)); }
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); }
public void FbxCluster_Create_HasNamespacePrefix() { // given: var obj = new FbxCluster("asdf"); // then: Assert.AreEqual("SubDeformer::", obj.GetNameSpacePrefix()); }
public bool Equals(FbxCluster other) { if (object.ReferenceEquals(other, null)) { return(false); } return(this.swigCPtr.Handle.Equals(other.swigCPtr.Handle)); }
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); }
public bool AddCluster(FbxCluster pCluster) { bool ret = NativeMethods.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster)); if (NativeMethods.SWIGPendingException.Pending) { throw NativeMethods.SWIGPendingException.Retrieve(); } return(ret); }
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); }
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); }
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>()); }
/// <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); }
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)); } } }
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 }
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); }
// 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; }
public bool AddCluster(FbxCluster pCluster) { bool ret = fbx_wrapperPINVOKE.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster)); return(ret); }
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); }
public ClusterPair(FbxCluster orig, FbxCluster import) { this.orig = orig; this.import = import; }
public bool AddCluster(FbxCluster pCluster) { bool ret = FbxWrapperNativePINVOKE.FbxSkin_AddCluster(swigCPtr, FbxCluster.getCPtr(pCluster)); return(ret); }
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()); }