Node CreateNodes(Model model, Object data, Node parent, Scene scene, List<AssimpSharp.Mesh> meshArray) { Debug.Assert(null != model); if (null == data) { return null; } var olsMeshSize = meshArray.Count; var node = new AssimpSharp.Node(); node.Name = data.ObjName; if (parent != null) { AppendChildToParentNode(parent, node); } foreach (var meshId in data.Meshes) { var mesh = CreateTopology(model, data, (int)meshId); if (mesh != null && mesh.NumFaces > 0) { meshArray.Add(mesh); } } if (data.SubObjects.Count > 0) { var numChilds = data.SubObjects.Count; } var meshSizeDiff = meshArray.Count - olsMeshSize; if (meshSizeDiff > 0) { int index = 0; for (int i = olsMeshSize; i < meshArray.Count; i++) { throw (new NotImplementedException()); } } return node; }
private void ConvertNodes(ulong id, aiNode parent, Matrix parentTransform) { var conns = Doc.GetConnectionsByDestinationSequenced(id, "Model"); var nodes = new List<aiNode>(conns.Count); var nodesChain = new List<aiNode>(); foreach (var con in conns) { // ignore object-property links if (con.PropertyName.Length > 0) { continue; } var obj = con.SourceObject; if (obj == null) { FBXImporter.LogWarn("failed to convert source object for Model link"); continue; } var model = obj as Model; if (model != null) { nodesChain.Clear(); var newAbsTransform = parentTransform; // even though there is only a single input node, the design of // assimp (or rather: the complicated transformation chain that // is employed by fbx) means that we may need multiple aiNode's // to represent a fbx node's transformation. GenerateTransformationNodeChain(model, out nodesChain); Debug.Assert(nodesChain.Count > 0); var originalName = FixNodeName(model.Name); // check if any of the nodes in the chain has the name the fbx node // is supposed to have. If there is none, add another node to // preserve the name - people might have scripts etc. that rely // on specific node names. aiNode nameCarrier = null; foreach (var prenode in nodesChain) { if (prenode.Name != originalName) { nameCarrier = prenode; break; } } if (nameCarrier != null) { nodesChain.Add(new aiNode(originalName)); nameCarrier = nodesChain[nodesChain.Count - 1]; } //setup metadata on newest node SetupNodeMetadata(model, nodesChain[nodesChain.Count - 1]); // link all nodes in a row var lastParent = parent; foreach (var prenode in nodesChain) { Debug.Assert(prenode != null); if (lastParent != parent) { lastParent.Children.Add(prenode); } prenode.Parent = lastParent; lastParent = prenode; newAbsTransform = prenode.Transformation; } ConvertModel(model, nodesChain[nodesChain.Count - 1], newAbsTransform); ConvertNodes(model.ID, nodesChain[nodesChain.Count - 1], newAbsTransform); if (Doc.Settings.ReadLights) { ConvertLights(model); } if (Doc.Settings.ReadCameras) { ConvertCameras(model); } nodes.Add(nodesChain[0]); nodesChain.Clear(); } } if (nodes.Count > 0) { parent.Children.AddRange(nodes); } }
/// <summary> /// Recursively creates scene nodes from the imported hierarchy. /// The meshes and materials of the nodes will be extracted on the way. /// </summary> /// <param name="scene">The scene to construct the return data in.</param> /// <param name="parent">The parent node where to create new child nodes</param> /// <param name="node">The temporary node to copy.</param> /// <returns>The created node</returns> protected AssimpSharp.Node CreateNodes(AssimpSharp.Scene scene, AssimpSharp.Node parent, AssimpSharp.XFile.Node node) { if (node == null) { return null; } // crate node var result = new AssimpSharp.Node(); result.Name = node.Name; result.Transformation = node.TrafoMatrix; result.Parent = parent; // convert meshes from the source node CreateMeshes(scene, result, node.Meshes); // handle childs if (node.Children.Count > 0) { result.Children.Clear(); foreach(var i in node.Children) { result.Children.Add(CreateNodes(scene, result, i)); } } return result; }
private void ConvertNodes(ulong id, aiNode node) { ConvertNodes(id, node, Matrix.Identity); }
private void ConvertModel(Model model, aiNode nd, Matrix nodeGlobalTransform) { var geos = model.Geometry; var meshes = new List<int>(geos.Count); foreach (var geo in geos) { var mesh = geo as MeshGeometry; if (mesh != null) { var indices = ConvertMesh(mesh, model, nodeGlobalTransform); meshes.AddRange(indices); } else { Debug.WriteLine("ignoring unrecognized geometry: " + geo.Name); } } if (meshes.Count > 0) { nd.Meshes.AddRange(meshes); } }
private void SetupNodeMetadata(Model model, aiNode nd) { var props = model.Props; var unparsedProperties = props.GetUnparsedProperties(); // create metadata on node int numStaticMetaData = 2; var data = nd.MetaData; data.NumProperties = unparsedProperties.Count + numStaticMetaData; data.Keys = new string[data.NumProperties]; data.Values = new AssimpSharp.MetadataEntry[data.NumProperties]; int index = 0; // find user defined properties (3ds Max) data.Set<string>(index++, "UserProperties", PropertyHelper.PropertyGet<string>(props, "UDP3DSMAX", "")); unparsedProperties.Remove("UDP3DSMAX"); data.Set(index++, "IsNull", model.IsNull ? true : false); foreach (var prop in unparsedProperties) { var interpreted = prop.Value.As<TypedProperty<bool>>(); if (interpreted != null) { data.Set(index++, prop.Key, interpreted.Value); } } }
/// <remarks> /// memory for output_nodes will be managed by the caller /// </remarks> private void GenerateTransformationNodeChain(Model model, out List<aiNode> outputNodes) { outputNodes = new List<aiNode>(); var props = model.Props; var rot = model.RotationOrder.Value; bool ok; var chain = new Matrix[Enum.GetValues(typeof(TransformationComp)).Length]; for(int i=0; i<chain.Length; i++) { chain[i] = Matrix.Identity; } float zeroEpsilon = 1e-6f; bool isComplex = false; Vector3 preRotation = PropertyHelper.PropertyGet<Vector3>(props, "PreRotation", out ok); if (ok && preRotation.LengthSquared() > zeroEpsilon) { isComplex = true; GetRotationMatrix(rot, preRotation, out chain[(int)TransformationComp.PreRotation]); } Vector3 postRotation = PropertyHelper.PropertyGet<Vector3>(props, "PostRotation", out ok); if (ok && postRotation.LengthSquared() > zeroEpsilon) { isComplex = true; GetRotationMatrix(rot, postRotation, out chain[(int)TransformationComp.PostRotation]); } Vector3 RotationPivot = PropertyHelper.PropertyGet<Vector3>(props, "RotationPivot", out ok); if (ok && RotationPivot.LengthSquared() > zeroEpsilon) { isComplex = true; Matrix.Translation(ref RotationPivot, out chain[(int)TransformationComp.RotationPivot]); chain[(int)TransformationComp.RotationPivotInverse] = Matrix.Translation(-RotationPivot); } Vector3 RotationOffset = PropertyHelper.PropertyGet<Vector3>(props, "RotationOffset", out ok); if (ok && RotationOffset.LengthSquared() > zeroEpsilon) { isComplex = true; Matrix.Translation(ref RotationOffset, out chain[(int)TransformationComp.RotationOffset]); } Vector3 ScalingOffset = PropertyHelper.PropertyGet<Vector3>(props, "ScalingOffset", out ok); if (ok && ScalingOffset.LengthSquared() > zeroEpsilon) { isComplex = true; Matrix.Translation(ref ScalingOffset, out chain[(int)TransformationComp.ScalingOffset]); } Vector3 ScalingPivot = PropertyHelper.PropertyGet<Vector3>(props, "ScalingPivot", out ok); if (ok && ScalingPivot.LengthSquared() > zeroEpsilon) { isComplex = true; chain[(int)TransformationComp.ScalingPivot] = Matrix.Translation(ScalingPivot); chain[(int)TransformationComp.ScalingPivotInverse] = Matrix.Translation(-ScalingPivot); } Vector3 Translation = PropertyHelper.PropertyGet<Vector3>(props, "Lcl Translation", out ok); if (ok && Translation.LengthSquared() > zeroEpsilon) { Matrix.Translation(ref Translation, out chain[(int)TransformationComp.Translation]); } Vector3 Scaling = PropertyHelper.PropertyGet<Vector3>(props, "Lcl Scaling", out ok); if (ok && Math.Abs(Scaling.LengthSquared() - 1.0f) > zeroEpsilon) { Matrix.Scaling(ref Scaling, out chain[(int)TransformationComp.Scaling]); } Vector3 Rotation = PropertyHelper.PropertyGet<Vector3>(props, "Lcl Rotation", out ok); if (ok && Rotation.LengthSquared() > zeroEpsilon) { GetRotationMatrix(rot, Rotation, out chain[(int)TransformationComp.Rotation]); } Vector3 GeometricScaling = PropertyHelper.PropertyGet<Vector3>(props, "GeometricScaling", out ok); if (ok && Math.Abs(GeometricScaling.LengthSquared() - 1.0f) > zeroEpsilon) { Matrix.Scaling(ref GeometricScaling, out chain[(int)TransformationComp.GeometricScaling]); } Vector3 GeometricRotation = PropertyHelper.PropertyGet<Vector3>(props, "GeometricRotation", out ok); if (ok && GeometricRotation.LengthSquared() > zeroEpsilon) { GetRotationMatrix(rot, GeometricRotation, out chain[(int)TransformationComp.GeometricRotation]); } Vector3 GeometricTranslation = PropertyHelper.PropertyGet<Vector3>(props, "GeometricTranslation", out ok); if (ok && GeometricTranslation.LengthSquared() > zeroEpsilon) { Matrix.Translation(ref GeometricTranslation, out chain[(int)TransformationComp.GeometricTranslation]); } // is_complex needs to be consistent with NeedsComplexTransformationChain() // or the interplay between this code and the animation converter would // not be guaranteed. Debug.Assert(NeedsComplexTransformationChain(model) == isComplex); string name = FixNodeName(model.Name); // now, if we have more than just Translation, Scaling and Rotation, // we need to generate a full node chain to accommodate for assimp's // lack to express pivots and offsets. if (isComplex && this.Doc.Settings.PreservePivots) { FBXImporter.LogInfo("generating full transformation chain for node: " + name); // query the anim_chain_bits dictionary to find out which chain elements // have associated node animation channels. These can not be dropped // even if they have identity transform in bind pose. uint animChainBitmask; if (!NodeAnimChainBits.TryGetValue(name, out animChainBitmask)) { animChainBitmask = 0; } uint bit = 0x1; for (int i = 0; i < Enum.GetValues(typeof(TransformationComp)).Length; ++i, bit <<= 1) { TransformationComp comp = (TransformationComp)i; if (chain[i].IsIdentity && (animChainBitmask & bit) == 0) { continue; } aiNode nd = new aiNode(); outputNodes.Add(nd); nd.Name = NameTransformationChainNode(name, comp); nd.Transformation = chain[i]; } Debug.Assert(outputNodes.Count > 0); return; } // else, we can just multiply the matrices together aiNode nd_ = new aiNode(); outputNodes.Add(nd_); nd_.Name = name; nd_.Transformation = Matrix.Identity; for (int i = 0; i < Enum.GetValues(typeof(TransformationComp)).Length; ++i) { nd_.Transformation = nd_.Transformation * chain[i]; } }
private void loadBtn_click(object sender, EventArgs e) { if (fileOpen.ShowDialog() == DialogResult.OK) { //Get the path of specified file FBXfilePath = fileOpen.FileName; } bool simpleFormat = false; // flipped if simpleFormat is detected. fbx = assimpSharpImporter.ReadFile(FBXfilePath); int materialCount = fbx.Materials.Count; int textureCount = 0; int mastervertCount = 0; int masterfaceCount = 0; int surfacevertCount = 0; int surfacefaceCount = 0; int masterObjectCount = 0; AssimpSharp.Node masterNode = fbx.RootNode.FindNode("Course Master Objects"); if (masterNode == null) { simpleFormat = true; } else { simpleFormat = false; } AssimpSharp.Node pathNode = fbx.RootNode.FindNode("Course Paths"); AssimpSharp.Mesh countObj = null; int sectionCount = 0; for (int searchSection = 1; ; searchSection++) { AssimpSharp.Node searchNode = fbx.RootNode.FindNode("Section " + searchSection.ToString()); if (searchNode != null) { sectionCount++; } else { break; } } // // Textures // textureArray = mk.loadTextures(fbx); materialCount = textureArray.Length; // // Course Objects // Surface Map // if (simpleFormat == false) { masterObjects = mk.loadMaster(fbx, textureArray); masterObjectCount = masterObjects.Length; surfaceObjects = mk.loadCollision(fbx, sectionCount, textureArray, simpleFormat); sectionList = mk.loadSection(fbx, sectionCount, masterObjects); } else { masterObjects = mk.createMaster(fbx, sectionCount, textureArray); masterObjectCount = masterObjects.Length; surfaceObjects = mk.loadCollision(fbx, sectionCount, textureArray, simpleFormat); sectionList = mk.automateSection(sectionCount, surfaceObjects, masterObjects, fbx); } // // Section Views // countBox.Text = sectionCount.ToString(); surfcountBox.Text = sectionCount.ToString(); for (int currentChild = 0; currentChild < masterObjects.Length; currentChild++) { masterBox.Items.Add(masterObjects[currentChild].objectName); } for (int currentIndex = 0; currentIndex < surfaceObjects.Length; currentIndex++) { surfaceobjectBox.Items.Add(surfaceObjects[currentIndex].objectName); } for (int currentSection = 0; currentSection < sectionCount; currentSection++) { surfsectionBox.Items.Add("Section " + (currentSection + 1).ToString()); sectionBox.Items.Add("Section " + (currentSection + 1).ToString()); } for (int surfacematerialIndex = 0; surfacematerialIndex < surfaceType.Length; surfacematerialIndex++) { surfmaterialBox.Items.Add(surfaceTypeID[surfacematerialIndex].ToString("X") + "- " + surfaceType[surfacematerialIndex]); } foreach (var viewstring in viewString) { viewBox.Items.Add(viewstring); } for (int materialIndex = 0; materialIndex < materialCount; materialIndex++) { if (textureArray[materialIndex].texturePath != null) { if (textureArray[materialIndex].textureClass == -1) { MessageBox.Show("Warning! Texture wrong dimensions -" + textureArray[materialIndex].textureName + "- Height: " + textureArray[materialIndex].textureHeight + " Width: " + textureArray[materialIndex].textureWidth); textureBox.Items.Add("UNUSABLE " + materialIndex.ToString() + " - " + textureArray[materialIndex].textureName); } else { textureBox.Items.Add("Material " + materialIndex.ToString() + " - " + textureArray[materialIndex].textureName); } textureCount++; } else { MessageBox.Show("Warning! Material " + fbx.Materials[materialIndex].Name + " does not have a diffuse texture and cannot be used."); textureArray[materialIndex].textureName = fbx.Materials[materialIndex].Name; textureBox.Items.Add("UNUSABLE " + materialIndex.ToString() + " - " + textureArray[materialIndex].textureName); } } viewBox.SelectedIndex = 0; mcountBox.Text = materialCount.ToString(); tcountBox.Text = textureCount.ToString(); textureBox.SelectedIndex = 0; lastMaterial = 0; objcountBox.Text = surfaceCount.ToString(); MessageBox.Show("Finished Loading .FBX"); loaded = true; sectionBox.SelectedIndex = 0; compilebtn.Enabled = true; mvertBox.Text = mastervertCount.ToString(); mfaceBox.Text = masterfaceCount.ToString(); mobjectbox.Text = masterObjectCount.ToString(); }