public void ImportModel() { OpenFileDialog dlg = new OpenFileDialog() { DefaultExt = "sa1mdl", Filter = "Model Files|*.sa1mdl;*.obj;*.objf", RestoreDirectory = true }; if (dlg.ShowDialog() == DialogResult.OK) { switch (Path.GetExtension(dlg.FileName).ToLowerInvariant()) { case ".obj": case ".fbx": case ".dae": case ".objf": Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene scene = context.ImportFile(dlg.FileName, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); NJS_OBJECT newmodel = SAEditorCommon.Import.AssimpStuff.AssimpImport(scene, scene.RootNode, ModelFormat.BasicDX, LevelData.TextureBitmaps[LevelData.leveltexs].Select(a => a.Name).ToArray(), true); Model.Attach = newmodel.Attach; Model.ProcessVertexData(); Mesh = Model.Attach.CreateD3DMesh(); break; case ".sa1mdl": ModelFile mf = new ModelFile(dlg.FileName); Model.Attach = mf.Model.Attach; Model.ProcessVertexData(); Mesh = Model.Attach.CreateD3DMesh(); break; } } }
private bool loadFile(string path) { Assimp.AssimpContext importer = new Assimp.AssimpContext(); importer.SetConfig(new NormalSmoothingAngleConfig(66f)); //TODO check which other post processes we need m_scene = importer.ImportFile(path, Assimp.PostProcessSteps.CalculateTangentSpace | Assimp.PostProcessSteps.GenerateNormals | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.OptimizeMeshes); //failed loading :( if (!m_scene.HasMeshes) { textBoxInfo.Text = "No Valid Meshes found."; return(false); } //display some info string msg = "Mesh Count: " + m_scene.MeshCount.ToString() + Environment.NewLine + "Material count: " + m_scene.MaterialCount.ToString() + " (Maximum material count is 32)"; textBoxInfo.Text = msg; buttonSave.Enabled = (m_scene.MeshCount > 0 && m_scene.MaterialCount <= maxMaterials); return(true); }
public void ShowSelectFileDialog() { using (var ofd = new OpenFileDialog()) { ofd.Filter = "Mesh files (*.dae, *.obj, *.stl)|*.dae;*.obj;*.stl|Wavefront (*.obj)|*.obj|Collada (*.dae)|*.dae|STL (*.stl)|*.stl|All files (*.*)|*.*"; if (!string.IsNullOrEmpty(browseTextBox1.Value)) { ofd.FileName = browseTextBox1.Value; } if (ofd.ShowDialog() == DialogResult.OK) { try { browseTextBox1.Value = ofd.FileName; SceneToImport = AssimpContext.ImportFile(ofd.FileName, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.GenerateNormals | Assimp.PostProcessSteps.FlipUVs); FillModelsGridView(); } catch (Exception ex) { MessageBox.Show("Could not import file!"); } } } }
private LoadedModel LoadModelOfd() { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if (ofd.CheckFileExists) { string dirName = Path.GetDirectoryName(ofd.FileName); try { using (Assimp.AssimpContext importer = new Assimp.AssimpContext()) { importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); Assimp.Scene model = importer.ImportFile(ofd.FileName, Assimp.PostProcessPreset.TargetRealTimeMaximumQuality); LoadedModel loadedModel = new LoadedModel(model, dirName); loadedModel.Name = Path.GetFileName(ofd.FileName); return(loadedModel); } } catch { System.Windows.MessageBox.Show("Unsupported file type.", "Error"); } } } return(null); }
public void ImportModel(string filePath, bool legacyImport = false) { NJS_OBJECT newmodel; // Old OBJ import (with vcolor face) for NodeTable and legacy import if (legacyImport) { newmodel = new NJS_OBJECT { Attach = SAModel.Direct3D.Extensions.obj2nj(filePath, LevelData.TextureBitmaps != null ? LevelData.TextureBitmaps[LevelData.leveltexs].Select(a => a.Name).ToArray() : null), }; COL.Model.Attach = newmodel.Attach; COL.Model.ProcessVertexData(); Visible = true; Solid = true; mesh = COL.Model.Attach.CreateD3DMesh(); return; } Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene scene = context.ImportFile(filePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); newmodel = SAEditorCommon.Import.AssimpStuff.AssimpImport(scene, scene.RootNode, ModelFormat.BasicDX, LevelData.TextureBitmaps[LevelData.leveltexs].Select(a => a.Name).ToArray(), true); COL.Model.Attach = newmodel.Attach; COL.Model.ProcessVertexData(); Visible = true; Solid = true; mesh = COL.Model.Attach.CreateD3DMesh(); }
static Assimp.Scene LoadAssimpScene(string fileName) { Assimp.AssimpContext cont = new Assimp.AssimpContext(); // AssImp adds dummy nodes for pivots from FBX, so we'll force them off cont.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); cont.ZAxisRotation = -90.0f; return(cont.ImportFile(fileName, Assimp.PostProcessSteps.Triangulate)); }
public void Load() { BoneAnimations = new List <BoneAnimation>(); var importer = new Assimp.AssimpContext(); var aScene = importer.ImportFile(FilePath, Assimp.PostProcessPreset.TargetRealTimeMaximumQuality); RootBoneAnimation = LoadBoneAnimation(aScene, aScene.RootNode, null); }
public DeviceModelCollection LoadModel(string filePath) { var context = new Assimp.AssimpContext(); var pp = Assimp.PostProcessSteps.FindInvalidData | Assimp.PostProcessSteps.OptimizeGraph; var scene = context.ImportFile(filePath, pp); return(ReadModel(scene)); }
public void SetUp() { var assimpNetimporter = new Assimp.AssimpContext(); Assimp.LogStream.IsVerboseLoggingEnabled = true; var logger = new Assimp.ConsoleLogStream(); logger.Attach(); assimpNetScene = assimpNetimporter.ImportFile(filename); logger.Detach(); var assimpSharpImporter = new AssimpSharp.FBX.FBXImporter(); assimpSharpScene = new AssimpSharp.Scene(); assimpSharpScene = assimpSharpImporter.ReadFile(filename); }
public static MeshGroup FromFbx(string filePath) { const float Scale = 1.0f; var assimp = new Assimp.AssimpContext(); var scene = assimp.ImportFile(filePath, Assimp.PostProcessSteps.PreTransformVertices); var baseFilePath = Path.GetDirectoryName(filePath); TexList = new List <string>(); TextureData = new List <Tm2>(); foreach (Assimp.Material mat in scene.Materials) { TexList.Add(Path.GetFileName(mat.TextureDiffuse.FilePath)); Stream str = File.OpenRead(TexList[TexList.Count - 1]); PngImage png = new PngImage(str); Tm2 tmImage = Tm2.Create(png); TextureData.Add(tmImage); } int childCount = scene.RootNode.ChildCount; return(new MeshGroup() { MeshDescriptors = scene.Meshes .Select(x => { var vertices = new PositionColoredTextured[x.Vertices.Count]; for (var i = 0; i < vertices.Length; i++) { vertices[i].X = x.Vertices[i].X * Scale; vertices[i].Y = x.Vertices[i].Y * Scale; vertices[i].Z = x.Vertices[i].Z * Scale; vertices[i].Tu = x.TextureCoordinateChannels[0][i].X; vertices[i].Tv = 1.0f - x.TextureCoordinateChannels[0][i].Y; vertices[i].R = 1.0f; vertices[i].G = 1.0f; vertices[i].B = 1.0f; vertices[i].A = 1.0f; } return new MeshDescriptor { Vertices = vertices, Indices = x.GetIndices(), IsOpaque = true, TextureIndex = x.MaterialIndex }; }).ToList() }); }
public static void AssimpPRMConvert(string initialFilePath, string finalFilePath) { Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); PRMModel prm = new PRMModel(); int totalVerts = 0; //Iterate through and combine meshes. PRMs can only have a single mesh IterateAiNodesPRM(prm, ref totalVerts, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform))); AquaUtil.WritePRMToFile(prm, finalFilePath, 4); }
public static Assimp.Scene ImportScene(string path, bool allowWeights) { using (var aiContext = new Assimp.AssimpContext()) { aiContext.SetConfig(new Assimp.Configs.VertexBoneWeightLimitConfig(allowWeights ? 3 : 1)); aiContext.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); return(aiContext.ImportFile(path, Assimp.PostProcessSteps.FindDegenerates | Assimp.PostProcessSteps.FindInvalidData | Assimp.PostProcessSteps.FlipUVs | Assimp.PostProcessSteps.ImproveCacheLocality | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.LimitBoneWeights | Assimp.PostProcessSteps.SplitByBoneCount | Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.ValidateDataStructure | Assimp.PostProcessSteps.GenerateUVCoords)); } }
public override Assimp.Scene Import(string filename, ContentImporterContext context) { if (dllLoadExc != null) { context.RaiseBuildMessage("FBXIMPORT", dllLoadExc.Message, BuildMessageEventArgs.BuildMessageType.Error); } try { Assimp.AssimpContext c = new Assimp.AssimpContext(); return(c.ImportFile(filename, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.OptimizeMeshes | Assimp.PostProcessSteps.OptimizeGraph)); } catch (Exception ex) { context.RaiseBuildMessage(filename, ex.Message, BuildMessageEventArgs.BuildMessageType.Error); } return(null); }
internal static Engine_MeshInfo LoadFilePro(string _fileName) { var a = new Assimp.AssimpContext(); var s = a.ImportFile(_fileName); Engine_MeshInfo obj = new Engine_MeshInfo(); obj.vertices = new List <Engine_Vertex>(); obj.indices = new List <ushort>(); foreach (var mesh in s.Meshes) { for (int i = 0; i < mesh.VertexCount; i++) { obj.vertices.Add(new Engine_Vertex( mesh.Vertices[i].X, mesh.Vertices[i].Y, mesh.Vertices[i].Z, mesh.TextureCoordinateChannels[0][i].X, mesh.TextureCoordinateChannels[0][i].Y, mesh.Normals[i].X, mesh.Normals[i].Y, mesh.Normals[i].Z)); } foreach (var item in mesh.Faces) { var rangeIndices = new ushort[] { (ushort)(item.Indices[0]), (ushort)(item.Indices[1]), (ushort)(item.Indices[2]) }; obj.indices.AddRange(rangeIndices); if (item.IndexCount == 4) { rangeIndices = new ushort[] { (ushort)(item.Indices[0]), (ushort)(item.Indices[2]), (ushort)(item.Indices[3]) }; obj.indices.AddRange(rangeIndices); } } } return(obj); }
public static MeshGroup FromFbx(GraphicsDevice graphics, string filePath) { const float Scale = 96.0f; var assimp = new Assimp.AssimpContext(); var scene = assimp.ImportFile(filePath, Assimp.PostProcessSteps.PreTransformVertices); var baseFilePath = Path.GetDirectoryName(filePath); return(new MeshGroup() { MeshDescriptors = scene.Meshes .Select(x => { var vertices = new PositionColoredTextured[x.Vertices.Count]; for (var i = 0; i < vertices.Length; i++) { vertices[i].X = x.Vertices[i].X * Scale; vertices[i].Y = x.Vertices[i].Y * Scale; vertices[i].Z = x.Vertices[i].Z * Scale; vertices[i].Tu = x.TextureCoordinateChannels[0][i].X; vertices[i].Tv = 1.0f - x.TextureCoordinateChannels[0][i].Y; vertices[i].R = 0xFF; vertices[i].G = 0xFF; vertices[i].B = 0xFF; vertices[i].A = 0xFF; } return new MeshDescriptor { Vertices = vertices, Indices = x.Faces.SelectMany(f => f.Indices).ToArray(), IsOpaque = true, TextureIndex = x.MaterialIndex }; }).ToList(), Textures = scene.Materials.Select(x => { var path = Path.Join(baseFilePath, $"{x.Name}.png"); return new PngKingdomTexture(path, graphics); }).ToArray(), }); }
private async Task <Assimp.Scene> ImportAssimpFile(string fileName) { Assimp.Scene aScene = null; await Task <Assimp.Scene> .Run(() => { try { Assimp.AssimpContext ctx = new Assimp.AssimpContext(); aScene = ctx.ImportFile(fileName, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.GenerateNormals | Assimp.PostProcessSteps.GenerateUVCoords); } catch (Assimp.AssimpException e) { Debug.LogError(e.Message); aScene = null; } }); return(aScene); }
public void Import(string fileName, Transform root, bool synchronous = false) { blocking = synchronous; if (synchronous) { Assimp.AssimpContext ctx = new Assimp.AssimpContext(); var aScene = ctx.ImportFile(fileName, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.GenerateNormals | Assimp.PostProcessSteps.GenerateUVCoords); CreateUnityDataFromAssimp(fileName, aScene, root).MoveNext(); Clear(); progress = 1.0f; } else { unityDataInCoroutineCreated = false; ImportTaskData d = new ImportTaskData(); d.fileName = fileName; d.root = root; taskData.Add(d); } }
public static RwAnimationNode FromAssimpScene(RwNode parent, RwFrameListNode frameList, string path) { var aiContext = new Assimp.AssimpContext(); var aiScene = aiContext.ImportFile(path); var aiAnimation = aiScene.Animations.FirstOrDefault(); RwAnimationNode animationNode; if (aiAnimation != null) { animationNode = new RwAnimationNode(parent, RwKeyFrameType.Uncompressed, ( float )(aiAnimation.DurationInTicks / aiAnimation.TicksPerSecond)); var nodeNameToHAnimId = aiAnimation.NodeAnimationChannels.ToDictionary(x => x.NodeName, x => frameList.GetNameIdByName(x.NodeName)); var nodeKeyframeTimes = aiAnimation.NodeAnimationChannels.SelectMany(x => x.PositionKeys) .Select(x => x.Time) .Concat(aiAnimation.NodeAnimationChannels.SelectMany(x => x.RotationKeys.Select(y => y.Time))) .Distinct() .OrderBy(x => x) .ToList(); var previousKeyFrames = new Dictionary <int, RwKeyFrame>(); var nodeKeyFrames = new Dictionary <int, List <RwKeyFrame> >(); // Add initial pose foreach (var hierarchyNode in frameList.AnimationRootNode.HAnimFrameExtensionNode.Hierarchy.Nodes) { var frame = frameList[frameList.GetFrameIndexByNameId(hierarchyNode.NodeId)]; var firstRotation = Quaternion.CreateFromRotationMatrix(frame.Transform); var firstTranslation = frame.Transform.Translation; var channel = aiAnimation.NodeAnimationChannels.FirstOrDefault(x => nodeNameToHAnimId[x.NodeName] == hierarchyNode.NodeId); if (channel != null) { if (channel.HasRotationKeys) { firstRotation = ToQuaternion(channel.RotationKeys.First().Value); } if (channel.HasPositionKeys) { firstTranslation = ToVector3(channel.PositionKeys.First().Value); } } var keyFrame = new RwKeyFrame(0, firstRotation, firstTranslation, null); animationNode.KeyFrames.Add(keyFrame); previousKeyFrames[hierarchyNode.NodeId] = keyFrame; nodeKeyFrames[hierarchyNode.NodeId] = new List <RwKeyFrame>(); } foreach (var keyFrameTime in nodeKeyframeTimes) { if (keyFrameTime == 0.0f) { continue; } foreach (var channel in aiAnimation.NodeAnimationChannels) { if (!channel.HasPositionKeys && !channel.HasRotationKeys) { continue; } if (!channel.RotationKeys.Any(x => x.Time == keyFrameTime) || !channel.PositionKeys.Any(x => x.Time == keyFrameTime)) { continue; } var hierarchAnimNodeId = nodeNameToHAnimId[channel.NodeName]; var previousKeyFrame = previousKeyFrames[hierarchAnimNodeId]; var rotation = previousKeyFrame.Rotation; var translation = previousKeyFrame.Translation; var rotationKeys = channel.RotationKeys.Where(x => x.Time == keyFrameTime); if (rotationKeys.Any()) { var aiRotation = rotationKeys.First().Value; rotation = new Quaternion(aiRotation.X, aiRotation.Y, aiRotation.Z, aiRotation.W); } var translationKeys = channel.PositionKeys.Where(x => x.Time == keyFrameTime); if (translationKeys.Any()) { var aiTranslation = translationKeys.First().Value; translation = new Vector3(aiTranslation.X, aiTranslation.Y, aiTranslation.Z); } var keyFrame = new RwKeyFrame(( float )(keyFrameTime / aiAnimation.TicksPerSecond), rotation, translation, previousKeyFrame); nodeKeyFrames[hierarchAnimNodeId].Add(keyFrame); previousKeyFrames[hierarchAnimNodeId] = keyFrame; } } while (!nodeKeyFrames.All(x => x.Value.Count == 0)) { foreach (var kvp in nodeKeyFrames) { if (animationNode.KeyFrames.Count == 0) { continue; } var keyFrame = kvp.Value.First(); animationNode.KeyFrames.Add(keyFrame); kvp.Value.Remove(keyFrame); if (animationNode.KeyFrames.Count == 0) { var previousKeyFrame = previousKeyFrames[kvp.Key]; if (previousKeyFrame.Time != animationNode.Duration) { var lastRotation = previousKeyFrame.Rotation; var lastTranslation = previousKeyFrame.Translation; var channel = aiAnimation.NodeAnimationChannels.SingleOrDefault(x => nodeNameToHAnimId[x.NodeName] == kvp.Key); if (channel != null) { if (channel.HasRotationKeys) { lastRotation = ToQuaternion(channel.RotationKeys.Last().Value); } if (channel.HasPositionKeys) { lastTranslation = ToVector3(channel.PositionKeys.Last().Value); } } animationNode.KeyFrames.Add(new RwKeyFrame(animationNode.Duration, lastRotation, lastTranslation, previousKeyFrame)); } } } } } else { animationNode = new RwAnimationNode(null, RwKeyFrameType.Uncompressed, 0f); } return(animationNode); }
void LoadAssimpNetScene(string file) { var importer = new Assimp.AssimpContext(); var assimpNetScene = importer.ImportFile(file); }
private static void ImportDAEFile(ResourceWrapper res, string path) { var ctx = new Assimp.AssimpContext(); res.WrappedObject = new RWScene(ctx.ImportFile(path)); }
public static void AssimpAQMConvert(string initialFilePath, bool playerExport, bool useScaleFrames, float scaleFactor) { float baseScale = 1f / 100f * scaleFactor; //We assume that this will be 100x the true scale because 1 unit to 1 meter isn't the norm Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); string inputFilename = Path.GetFileNameWithoutExtension(initialFilePath); List <string> aqmNames = new List <string>(); //Leave off extensions in case we want this to be .trm later List <AquaMotion> aqmList = new List <AquaMotion>(); Dictionary <int, Assimp.Node> aiNodes = GetAnimatedNodes(aiScene); var nodeKeys = aiNodes.Keys.ToList(); nodeKeys.Sort(); int animatedNodeCount = nodeKeys.Last() + 1; AquaUtil aqua = new AquaUtil(); for (int i = 0; i < aiScene.Animations.Count; i++) { if (aiScene.Animations[i] == null) { continue; } AquaMotion aqm = new AquaMotion(); var anim = aiScene.Animations[i]; int animEndFrame = 0; //We'll fill this later. Assumes frame 0 to be the start if (anim.Name != null && anim.Name != "") { //Make sure we're not overwriting anims that somehow have duplicate names if (aqmNames.Contains(anim.Name)) { aqmNames.Add($"Anim_{i}_" + anim.Name + ".aqm"); } else { aqmNames.Add(anim.Name + ".aqm"); } } else { aqmNames.Add($"Anim_{i}_" + inputFilename + ".aqm"); } aqm.moHeader = new AquaMotion.MOHeader(); //Get anim fps if (anim.TicksPerSecond == 0) { //Default to 30 aqm.moHeader.frameSpeed = 30; } else { aqm.moHeader.frameSpeed = (float)anim.TicksPerSecond; } aqm.moHeader.unkInt0 = 2; //Always, always 2 for NIFL aqm.moHeader.variant = 0x2; //These are flags for the animation to tell the game what type it is. Since this is a skeletal animation, we always put 2 here. //If it's a player one specifically, the game generally adds 0x10 to this. aqm.moHeader.nodeCount = animatedNodeCount; if (playerExport) { aqm.moHeader.variant += 0x10; aqm.moHeader.nodeCount++; //Add an extra for the nodeTreeFlag 'node' } aqm.moHeader.testString.SetString("test"); //Set this ahead of time in case these are out of order aqm.motionKeys = new List <AquaMotion.KeyData>(new AquaMotion.KeyData[aqm.moHeader.nodeCount]); //Nodes foreach (var animNode in anim.NodeAnimationChannels) { if (animNode == null) { continue; } int id = GetNodeNumber(animNode.NodeName); var node = aqm.motionKeys[id] = new AquaMotion.KeyData(); node.mseg.nodeName.SetString(animNode.NodeName); node.mseg.nodeId = id; node.mseg.nodeType = 2; node.mseg.nodeDataCount = useScaleFrames ? 3 : 2; if (animNode.HasPositionKeys) { AquaMotion.MKEY posKeys = new AquaMotion.MKEY(); posKeys.keyType = 1; posKeys.dataType = 1; var first = true; foreach (var pos in animNode.PositionKeys) { posKeys.vector4Keys.Add(new Vector4(pos.Value.X * baseScale, pos.Value.Y * baseScale, pos.Value.Z * baseScale, 0)); //Account for first frame difference if (first) { posKeys.frameTimings.Add(1); first = false; } else { posKeys.frameTimings.Add((ushort)(pos.Time * 0x10)); } posKeys.keyCount++; } posKeys.frameTimings[posKeys.keyCount - 1] += 2; //Account for final frame bitflags animEndFrame = Math.Max(animEndFrame, posKeys.keyCount); node.keyData.Add(posKeys); } if (animNode.HasRotationKeys) { AquaMotion.MKEY rotKeys = new AquaMotion.MKEY(); rotKeys.keyType = 2; rotKeys.dataType = 3; var first = true; foreach (var rot in animNode.RotationKeys) { rotKeys.vector4Keys.Add(new Vector4(rot.Value.X, rot.Value.Y, rot.Value.Z, rot.Value.W)); //Account for first frame difference if (first) { rotKeys.frameTimings.Add(1); first = false; } else { rotKeys.frameTimings.Add((ushort)(rot.Time * 0x10)); } rotKeys.keyCount++; } rotKeys.frameTimings[rotKeys.keyCount - 1] += 2; //Account for final frame bitflags animEndFrame = Math.Max(animEndFrame, rotKeys.keyCount); node.keyData.Add(rotKeys); } if (animNode.HasScalingKeys) { AquaMotion.MKEY sclKeys = new AquaMotion.MKEY(); sclKeys.keyType = 2; sclKeys.dataType = 3; var first = true; foreach (var scl in animNode.ScalingKeys) { sclKeys.vector4Keys.Add(new Vector4(scl.Value.X, scl.Value.Y, scl.Value.Z, 0)); //Account for first frame difference if (first) { sclKeys.frameTimings.Add(1); first = false; } else { sclKeys.frameTimings.Add((ushort)(scl.Time * 0x10)); } sclKeys.keyCount++; } sclKeys.frameTimings[sclKeys.keyCount - 1] += 2; //Account for final frame bitflags animEndFrame = Math.Max(animEndFrame, sclKeys.keyCount); node.keyData.Add(sclKeys); } } //NodeTreeFlag if (playerExport) { var node = aqm.motionKeys[aqm.motionKeys.Count - 1] = new AquaMotion.KeyData(); node.mseg.nodeName.SetString("__NodeTreeFlag__"); node.mseg.nodeId = aqm.motionKeys.Count - 1; node.mseg.nodeType = 0x10; node.mseg.nodeDataCount = useScaleFrames ? 3 : 2; //Position AquaMotion.MKEY posKeys = new AquaMotion.MKEY(); posKeys.keyType = 0x10; posKeys.dataType = 5; posKeys.keyCount = animEndFrame + 1; for (int frame = 0; frame < posKeys.keyCount; frame++) { if (frame == 0) { posKeys.frameTimings.Add(0x9); } else if (frame == posKeys.keyCount - 1) { posKeys.frameTimings.Add((ushort)((frame * 0x10) + 0xA)); } else { posKeys.frameTimings.Add((ushort)((frame * 0x10) + 0x8)); } posKeys.intKeys.Add(0x31); } node.keyData.Add(posKeys); //Rotation AquaMotion.MKEY rotKeys = new AquaMotion.MKEY(); rotKeys.keyType = 0x11; rotKeys.dataType = 5; rotKeys.keyCount = animEndFrame + 1; for (int frame = 0; frame < rotKeys.keyCount; frame++) { if (frame == 0) { rotKeys.frameTimings.Add(0x9); } else if (frame == rotKeys.keyCount - 1) { rotKeys.frameTimings.Add((ushort)((frame * 0x10) + 0xA)); } else { rotKeys.frameTimings.Add((ushort)((frame * 0x10) + 0x8)); } rotKeys.intKeys.Add(0x31); } node.keyData.Add(rotKeys); //Scale if (useScaleFrames) { AquaMotion.MKEY sclKeys = new AquaMotion.MKEY(); sclKeys.keyType = 0x12; sclKeys.dataType = 5; sclKeys.keyCount = animEndFrame + 1; for (int frame = 0; frame < sclKeys.keyCount; frame++) { if (frame == 0) { sclKeys.frameTimings.Add(0x9); } else if (frame == sclKeys.keyCount - 1) { sclKeys.frameTimings.Add((ushort)((frame * 0x10) + 0xA)); } else { sclKeys.frameTimings.Add((ushort)((frame * 0x10) + 0x8)); } sclKeys.intKeys.Add(0x31); } node.keyData.Add(sclKeys); } } //Sanity check foreach (var aiPair in aiNodes) { var node = aqm.motionKeys[aiPair.Key]; var aiNode = aiPair.Value; if (node == null) { node = aqm.motionKeys[aiPair.Key] = new AquaMotion.KeyData(); node.mseg.nodeName.SetString(aiNode.Name); node.mseg.nodeId = aiPair.Key; node.mseg.nodeType = 2; node.mseg.nodeDataCount = useScaleFrames ? 3 : 2; //Position AddOnePosFrame(node, aiNode, baseScale); //Rotation AddOneRotFrame(node, aiNode); //Scale AddOneScaleFrame(useScaleFrames, node); } else { if (node.keyData[0].vector4Keys.Count < 1) { AddOnePosFrame(node, aiNode, baseScale); } if (node.keyData[1].vector4Keys.Count < 1) { AddOneRotFrame(node, aiNode); } if (useScaleFrames && node.keyData[2].vector4Keys.Count < 1) { AddOneScaleFrame(useScaleFrames, node, aiNode); } } } aqmList.Add(aqm); } for (int i = 0; i < aqmList.Count; i++) { var aqm = aqmList[i]; AquaUtil.AnimSet set = new AquaUtil.AnimSet(); set.anims.Add(aqm); aqua.aquaMotions.Add(set); aqua.WriteNIFLMotion(initialFilePath + "_" + aqmNames[i]); aqua.aquaMotions.Clear(); } }
/// <summary> /// Converts a given .GR2 file to a .dae file for rendering and further conversion. /// </summary> /// <param name="filename">The file name.</param> /// <returns>The .dae converted model file.</returns> private static HelixToolkitScene LoadFile(string filename) { var dae = $"{filename}.dae"; if (!File.Exists(dae)) { GeneralHelper.WriteToConsole($"Converting model to .dae for rendering...\n"); var divine = $" -g \"bg3\" --action \"convert-model\" --output-format \"dae\" --source \"\\\\?\\{filename}.GR2\" --destination \"\\\\?\\{dae}\" -l \"all\""; var process = new Process(); var startInfo = new ProcessStartInfo { FileName = Properties.Settings.Default.divineExe, Arguments = divine, WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true }; process.StartInfo = startInfo; process.Start(); process.WaitForExit(); GeneralHelper.WriteToConsole(process.StandardOutput.ReadToEnd()); GeneralHelper.WriteToConsole(process.StandardError.ReadToEnd()); } try { var importer = new Importer(); // Update material here? var file = importer.Load(dae); if (file == null && File.Exists(dae)) { GeneralHelper.WriteToConsole("Fixing vertices...\n"); try { var xml = XDocument.Load(dae); var geometryList = xml.Descendants().Where(x => x.Name.LocalName == "geometry").ToList(); foreach (var lod in geometryList) { var vertexId = lod.Descendants().Where(x => x.Name.LocalName == "vertices").Select(x => x.Attribute("id").Value).First(); var vertex = lod.Descendants().Single(x => x.Name.LocalName == "input" && x.Attribute("semantic").Value == "VERTEX"); vertex.Attribute("source").Value = $"#{vertexId}"; } xml.Save(dae); GeneralHelper.WriteToConsole("Model conversion complete!\n"); file = importer.Load(dae); } catch (Exception ex) { // in use by another process GeneralHelper.WriteToConsole($"Error : {ex.Message}\n"); } } if (!File.Exists($"{filename}.fbx")) { var converter = new Assimp.AssimpContext(); var exportFormats = converter.GetSupportedExportFormats().Select(e => e.FormatId); var importFormats = converter.GetSupportedImportFormats(); var imported = converter.ImportFile(dae); converter.ExportFile(imported, $"{filename}.fbx", "fbx"); } importer.Dispose(); return(file); } catch (Exception ex) { GeneralHelper.WriteToConsole($"Error loading .dae: {ex.Message}. Inner exception: {ex.InnerException?.Message}\n"); } return(null); }
protected unsafe override bool OnLoad(Model model, File stream) { var filePath = FileUtil.StandardlizeFile(stream.Name); filePath = FileUtil.GetPath(stream.Name); FileSystem.AddResourceDir(filePath); FileSystem.AddResourceDir(filePath + "textures"); var ctx = new Assimp.AssimpContext(); string ext = FileUtil.GetExtension(loadingFile); if (!ctx.IsImportFormatSupported(ext)) { ctx.Dispose(); return(false); } //Assimp.Scene scene = ctx.ImportFileFromStream(stream, assimpFlags, ext); Assimp.Scene scene = ctx.ImportFile(stream.Name, assimpFlags); BoundingBox boundingBox = new BoundingBox(); string path = FileUtil.GetPath(loadingFile); model.VertexBuffers = new List <Buffer>(); model.IndexBuffers = new List <Buffer>(); vertexBuffer.Clear(); indexBuffer.Clear(); vertexOffset = 0; indexOffset = 0; VertexLayout vertexLayout = new VertexLayout(vertexComponents); List <Geometry> geoList = new List <Geometry>(); // Iterate through all meshes in the file and extract the vertex components for (int m = 0; m < scene.MeshCount; m++) { Assimp.Mesh mesh = scene.Meshes[m]; if (mesh.MaterialIndex >= 0 && mesh.MaterialIndex < scene.MaterialCount) { Material mat = ConvertMaterial(path, scene.Materials[mesh.MaterialIndex], mesh.HasTangentBasis); if (mat == null) { continue; } model.Materials.Add(mat); } else { Log.Error("No material : " + mesh.Name); } var geometry = ConvertGeometry(mesh, scale, vertexLayout, vertexComponents, combineVB, combineIB, out var meshBoundingBox); geoList.Add(geometry); if (geometry.VertexBuffer != null) { model.VertexBuffers.Add(geometry.VertexBuffer); } if (geometry.IndexBuffer != null) { model.IndexBuffers.Add(geometry.IndexBuffer); } model.Geometries.Add(new [] { geometry }); model.GeometryCenters.Add(meshBoundingBox.Center); boundingBox.Merge(meshBoundingBox); } if (combineVB) { var vb = Buffer.Create(VkBufferUsageFlags.VertexBuffer, false, sizeof(float), vertexBuffer.Count, vertexBuffer.Data); model.VertexBuffers.Add(vb); foreach (var geo in geoList) { geo.VertexBuffer = vb; } } if (combineIB) { var ib = Buffer.Create(VkBufferUsageFlags.IndexBuffer, false, sizeof(uint), indexBuffer.Count, indexBuffer.Data); model.IndexBuffers.Add(ib); foreach (var geo in geoList) { geo.IndexBuffer = ib; } } model.BoundingBox = boundingBox; ctx.Dispose(); FileSystem.RemoveResourceDir(filePath); FileSystem.RemoveResourceDir(filePath + "textures"); return(true); }
private void FrmGenNormal_Load(object sender, EventArgs e) { context3D = new Context3D(); System.Drawing.Bitmap bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); RenderTargetAdapter renderBufferAdapter = new RenderTargetAdapter(bitmap, pictureBox1); context3D.configureBackBuffer(pictureBox1.Width, pictureBox1.Height, renderBufferAdapter); pictureBox1.BackgroundImage = bitmap; System.Drawing.Bitmap debuglayer = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); RenderTargetAdapter debuggerAdapter = new RenderTargetAdapter(debuglayer, pictureBox1); pictureBox1.Image = debuglayer; context3D.debugLayerAdapter = debuggerAdapter; Assimp.AssimpContext importer = new Assimp.AssimpContext(); Assimp.Scene scene = importer.ImportFile("../../../models/Quad.fbx", Assimp.PostProcessSteps.MakeLeftHanded | Assimp.PostProcessSteps.CalculateTangentSpace ); lst_indexList = new List <IndexBuffer3D>(); lst_vertexes = new List <VertexBuffer3D>(); texsize = new float2(1.0f / 2, 1.0f / 2); var texture = MiniRender.textures.Texture.white; texture.AutoGenMipMap(); context3D.setTextureAt(0, texture); context3D.setSamplerStateAt(0, Context3DWrapMode.REPEAT, Context3DTextureFilter.LINEAR, Context3DMipFilter.MIPNONE); for (int k = 0; k < scene.MeshCount; k++) { var mesh = scene.Meshes[k]; var vs = mesh.Vertices; var indices = mesh.GetUnsignedIndices(); var normals = mesh.Normals; var tangents = mesh.Tangents; var coords = mesh.TextureCoordinateChannels[0]; var indexList = context3D.createIndexBuffer(indices.Length); indexList.uploadFromVector(indices); lst_indexList.Add(indexList); List <Vertex> vertices = new List <Vertex>(); for (int i = 0; i < vs.Count; i++) { vertices.Add( new Vertex() { vertex = new float3(vs[i].X, vs[i].Y, vs[i].Z) } ); } if (mesh.HasNormals) { for (int i = 0; i < vs.Count; i++) { vertices[i].normal = (new float3(normals[i].X, normals[i].Y, normals[i].Z)); } } if (mesh.HasTangentBasis) { for (int i = 0; i < vs.Count; i++) { vertices[i].tangent = new float3(tangents[i].X, tangents[i].Y, tangents[i].Z); } } if (mesh.HasTextureCoords(0)) { for (int i = 0; i < vs.Count; i++) { vertices[i].uv = new float3(coords[i].X, coords[i].Y, coords[i].Z); } } if (mesh.HasVertexColors(0)) { var color = mesh.VertexColorChannels[0]; for (int i = 0; i < vs.Count; i++) { vertices[i].color = new float4(color[i].R, color[i].G, color[i].B, color[i].A); } } var vertexes = context3D.createVertexBuffer(vertices.Count); vertexes.uploadFromVector(vertices.ToArray()); lst_vertexes.Add(vertexes); } var program3d = context3D.createProgram(); program3d.upload(new VShader(), new FShader() ); context3D.setProgram(program3d); //refreshCtl(); //render(); }
private void Form1_Load(object sender, EventArgs e) { context3D = new Context3D(); System.Drawing.Bitmap bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); RenderTargetAdapter renderBufferAdapter = new RenderTargetAdapter(bitmap, pictureBox1); context3D.configureBackBuffer(pictureBox1.Width, pictureBox1.Height, renderBufferAdapter); pictureBox1.BackgroundImage = bitmap; System.Drawing.Bitmap debuglayer = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); RenderTargetAdapter debuggerAdapter = new RenderTargetAdapter(debuglayer, pictureBox1); pictureBox1.Image = debuglayer; context3D.debugLayerAdapter = debuggerAdapter; Assimp.AssimpContext importer = new Assimp.AssimpContext(); scene = importer.ImportFile("../../../models/cube.fbx", Assimp.PostProcessSteps.MakeLeftHanded | Assimp.PostProcessSteps.Triangulate //| Assimp.PostProcessSteps.GenerateSmoothNormals | Assimp.PostProcessSteps.CalculateTangentSpace //| Assimp.PostProcessSteps.PreTransformVertices ); lst_indexList = new List <IndexBuffer3D>(); lst_vertexes = new List <VertexBuffer3D>(); //var texture = context3D.createTexture(474, 474); //texture.uploadFromByteArray(SceneUtils.LoadBitmapData("../../../models/texs/th.jpg"), 0); var texture = MiniRender.textures.Texture.white; //SceneUtils.MakeAndUploadTexture(context3D, "../../../models/texs/duckCM.bmp"); texture.AutoGenMipMap(); context3D.setTextureAt(0, texture); context3D.setSamplerStateAt(0, Context3DWrapMode.REPEAT, Context3DTextureFilter.LINEAR, Context3DMipFilter.MIPLINEAR); //设置matcap var matcap = SceneUtils.MakeAndUploadTexture(context3D, "../../../models/texs/MaCrea_3.png"); matcap.AutoGenMipMap(); context3D.setTextureAt(1, matcap); context3D.setSamplerStateAt(1, Context3DWrapMode.CLAMP, Context3DTextureFilter.LINEAR, Context3DMipFilter.MIPLINEAR); //设置法线 var normalmap = MiniRender.textures.Texture.planeNormal; //SceneUtils.MakeAndUploadTexture(context3D, "../../../models/texs/Robot_Normal.png"); normalmap.AutoGenMipMap(); context3D.setTextureAt(2, normalmap); context3D.setSamplerStateAt(2, Context3DWrapMode.REPEAT, Context3DTextureFilter.LINEAR, Context3DMipFilter.MIPNEAREST); //设置粗糙度与金属性贴图 var metallic = SceneUtils.MakeAndUploadTexture(context3D, "../../../models/texs/jian_2_m.png"); metallic.AutoGenMipMap(); context3D.setTextureAt(3, metallic); context3D.setSamplerStateAt(3, Context3DWrapMode.REPEAT, Context3DTextureFilter.LINEAR, Context3DMipFilter.MIPNEAREST); for (int k = 0; k < scene.MeshCount; k++) { var mesh = scene.Meshes[k]; var vs = mesh.Vertices; var indices = mesh.GetUnsignedIndices(); var normals = mesh.Normals; var tangents = mesh.Tangents; var coords = mesh.TextureCoordinateChannels[0]; var indexList = context3D.createIndexBuffer(indices.Length); indexList.uploadFromVector(indices); lst_indexList.Add(indexList); List <Vertex> vertices = new List <Vertex>(); for (int i = 0; i < vs.Count; i++) { vertices.Add( new Vertex() { vertex = new float3(vs[i].X, vs[i].Y, vs[i].Z) * 3 } ); } if (mesh.HasNormals) { for (int i = 0; i < vs.Count; i++) { vertices[i].normal = (new float3(normals[i].X, normals[i].Y, normals[i].Z)); } } if (mesh.HasTangentBasis) { for (int i = 0; i < vs.Count; i++) { vertices[i].tangent = new float3(tangents[i].X, tangents[i].Y, tangents[i].Z); } } if (mesh.HasTextureCoords(0)) { for (int i = 0; i < vs.Count; i++) { vertices[i].uv = new float3(coords[i].X, coords[i].Y, coords[i].Z); } } if (mesh.HasVertexColors(0)) { var color = mesh.VertexColorChannels[0]; for (int i = 0; i < vs.Count; i++) { vertices[i].color = new float4(color[i].R, color[i].G, color[i].B, color[i].A); } } var vertexes = context3D.createVertexBuffer(vertices.Count); vertexes.uploadFromVector(vertices.ToArray()); lst_vertexes.Add(vertexes); } var program3d = context3D.createProgram(); fShader = new programs.test3.FShader_Metallic(); program3d.upload(new programs.test4.VShader_Bump(), new programs.test4.FShader_Bump() //fShader ); context3D.setProgram(program3d); }
public static MeshGroup FromFbx(string filePath) { const float Scale = 1.0f; var assimp = new Assimp.AssimpContext(); var scene = assimp.ImportFile(filePath, Assimp.PostProcessSteps.PreTransformVertices); var BoneScene = assimp.ImportFile(filePath); var baseFilePath = Path.GetDirectoryName(filePath); TexList = new List <string>(); TextureData = new List <Tm2>(); BoneData = new List <Assimp.Bone>(); NodeData = new List <Assimp.Node>(); foreach (Assimp.Material mat in scene.Materials) { Stream str = null; var name = Path.GetFileName(mat.TextureDiffuse.FilePath); if (name != "" || name != null) { str = File.OpenRead(name); } if (str != null) { TexList.Add(Path.GetFileName(mat.TextureDiffuse.FilePath)); PngImage png = new PngImage(str); Tm2 tmImage = Tm2.Create(png); TextureData.Add(tmImage); } } Assimp.Bone rBone = new Assimp.Bone(); foreach (var m in BoneScene.Meshes) { foreach (var bn in m.Bones) { if (!BoneData.Contains(bn)) { BoneData.Add(bn); } } } NodeData.AddRange(BoneScene.RootNode.Children.ToList()); return(new MeshGroup() { MeshDescriptors = scene.Meshes .Select(x => { var vertices = new PositionColoredTextured[x.Vertices.Count]; for (var i = 0; i < vertices.Length; i++) { vertices[i].X = x.Vertices[i].X * Scale; vertices[i].Y = x.Vertices[i].Y * Scale; vertices[i].Z = x.Vertices[i].Z * Scale; vertices[i].Tu = x.TextureCoordinateChannels[0][i].X; vertices[i].Tv = 1.0f - x.TextureCoordinateChannels[0][i].Y; vertices[i].R = x.VertexColorChannels[0][i].R; vertices[i].G = x.VertexColorChannels[0][i].G; vertices[i].B = x.VertexColorChannels[0][i].B; vertices[i].A = x.VertexColorChannels[0][i].A; } return new MeshDescriptor { Vertices = vertices, Indices = x.GetIndices(), IsOpaque = true, TextureIndex = x.MaterialIndex }; }).ToList() }); }
static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("No arguments!"); } var objectFile = args[0]; Console.WriteLine("Loading mesh..."); Geometry.Geometry geo; if (Path.GetExtension(objectFile) == ".hfe") { // Loading an hfe file geo = Geometry.Geometry.LoadFromBinary(objectFile); } else if (Path.GetExtension(objectFile) == ".json") { // Loading geometry from json geo = Geometry.Geometry.LoadFromJson(objectFile); } else { // Loading an external file format var importer = new Assimp.AssimpContext(); importer.SetConfig(new Assimp.Configs.NormalSmoothingAngleConfig(66.0f)); var scene = importer.ImportFile(objectFile, Assimp.PostProcessPreset.TargetRealTimeMaximumQuality); if (!scene.HasMeshes) { Console.WriteLine("Scene has no meshes!"); return; } Console.WriteLine("Processing mesh..."); geo = Geometry.Geometry.FromAssimp(scene.Meshes[0], true, true); scene.Clear(); importer.Dispose(); } bool bUseSymmetricLaplacian = false; var indx = Array.FindIndex(args, t => t == "-sym"); if (indx != -1) { Console.WriteLine("Using symmetric laplacian..."); bUseSymmetricLaplacian = true; } indx = Array.FindIndex(args, t => t == "-lapout"); if (indx != -1) { Console.WriteLine("Creating differential structure..."); var diff = new DifferentialStructure(geo); Console.WriteLine("Writing mesh laplacian to file..."); var outputFile = args[indx + 1]; if (bUseSymmetricLaplacian) { DifferentialStructure.WriteSparseMatrix(diff.InteriorSymmetrizedLaplacian, outputFile); } else { DifferentialStructure.WriteSparseMatrix(diff.InteriorLaplacian, outputFile); } } indx = Array.FindIndex(args, t => t == "-modesin"); Mat modes = null; Vec spec = null; GeometryVisualMode visMode = GeometryVisualMode.ViewMesh; if (indx != -1) { Console.WriteLine("Reading mode data..."); var inputFile = args[indx + 1]; DifferentialStructure.ReadModeData(inputFile, out modes, out spec); var diff = new DifferentialStructure(geo); if (bUseSymmetricLaplacian) { modes = diff.HalfInverseMassMatrix * modes; } if (geo.HasBoundary) { modes = diff.InteriorToClosureMap * modes; } visMode = GeometryVisualMode.ViewModes; } indx = Array.FindIndex(args, t => t == "-funcin"); if (indx != -1) { Console.WriteLine("Reading function data..."); var inputFile = args[indx + 1]; DifferentialStructure.ReadFunctionData(inputFile, out modes); var diff = new DifferentialStructure(geo); if (geo.HasBoundary) { modes = diff.InteriorToClosureMap * modes; } visMode = GeometryVisualMode.ViewModes; spec = Vec.Build.Dense(modes.RowCount, 0d); } indx = Array.FindIndex(args, t => t == "-viewmass"); if (indx != -1) { visMode = GeometryVisualMode.ViewDegreeVector; } indx = Array.FindIndex(args, t => t == "-viewlapdiag"); if (indx != -1) { visMode = GeometryVisualMode.ViewLapDiagonal; } indx = Array.FindIndex(args, t => t == "-meshout"); if (indx != -1) { Console.WriteLine("Saving processed mesh..."); var path = args[indx + 1]; if (Path.GetExtension(path) == ".hfe") { geo.SaveToBinary(path); } else if (Path.GetExtension(path) == ".json") { geo.SaveToJson(path); } else { Console.WriteLine("Unrecognized meshout file extension!"); } } indx = Array.FindIndex(args, t => t == "-noview"); if (indx != -1) { return; } using (var window = new GeometryDisplayWindow(geo)) { window.VisualMode = visMode; window.ObjectModes = modes; window.ObjectEigenvalues = spec; window.Run(); } }
//Takes in an Assimp model and generates a full PSO2 model and skeleton from it. public static AquaObject AssimpAquaConvertFull(string initialFilePath, float scaleFactor, bool preAssignNodeIds, bool isNGS) { AquaUtil aquaUtil = new AquaUtil(); float baseScale = 1f / 100f * scaleFactor; //We assume that this will be 100x the true scale because 1 unit to 1 meter isn't the norm Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); AquaObject aqp; AquaNode aqn = new AquaNode(); if (isNGS) { aqp = new NGSAquaObject(); } else { aqp = new ClassicAquaObject(); } //Construct Materials Dictionary <string, int> matNameTracker = new Dictionary <string, int>(); foreach (var aiMat in aiScene.Materials) { string name; if (matNameTracker.ContainsKey(aiMat.Name)) { name = $"{aiMat.Name} ({matNameTracker[aiMat.Name]})"; matNameTracker[aiMat.Name] += 1; } else { name = aiMat.Name; matNameTracker.Add(aiMat.Name, 1); } AquaObject.GenericMaterial genMat = new AquaObject.GenericMaterial(); List <string> shaderList = new List <string>(); AquaObjectMethods.GetMaterialNameData(ref name, shaderList, out string alphaType, out string playerFlag); genMat.matName = name; genMat.shaderNames = shaderList; genMat.blendType = alphaType; genMat.specialType = playerFlag; genMat.texNames = new List <string>(); genMat.texUVSets = new List <int>(); //Texture assignments. Since we can't rely on these to export properly, we dummy them or just put diffuse if a playerFlag isn't defined. //We'll have the user set these later if needed. if (genMat.specialType != null) { AquaObjectMethods.GenerateSpecialMaterialParameters(genMat); } else if (aiMat.TextureDiffuse.FilePath != null) { genMat.texNames.Add(Path.GetFileName(aiMat.TextureDiffuse.FilePath)); } else { genMat.texNames.Add("tex0_d.dds"); } genMat.texUVSets.Add(0); AquaObjectMethods.GenerateMaterial(aqp, genMat, true); } //Default to this so ids can be assigned by order if needed Dictionary <string, int> boneDict = new Dictionary <string, int>(); if (aiScene.RootNode.Name == null || !aiScene.RootNode.Name.Contains("(") || preAssignNodeIds == true) { int nodeCounter = 0; BuildAiNodeDictionary(aiScene.RootNode, ref nodeCounter, boneDict); } IterateAiNodesAQP(aqp, aqn, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform)), baseScale); //Assimp data is gathered, proceed to processing model data for PSO2 AquaUtil.ModelSet set = new AquaUtil.ModelSet(); set.models.Add(aqp); aquaUtil.aquaModels.Add(set); aquaUtil.ConvertToNGSPSO2Mesh(false, false, false, true, false, false, true); //AQPs created this way will require more processing to finish. //-Texture lists in particular, MUST be generated as what exists is not valid without serious errors return(aqp); }
public static List <Item> ImportFromFile(string filePath, EditorCamera camera, out bool errorFlag, out string errorMsg, EditorItemSelection selectionManager, OnScreenDisplay osd, bool multiple = false) { List <Item> createdItems = new List <Item>(); if (!File.Exists(filePath)) { errorFlag = true; errorMsg = "File does not exist!"; return(null); } DirectoryInfo filePathInfo = new DirectoryInfo(filePath); bool importError = false; string importErrorMsg = ""; Vector3 pos = camera.Position + (-20 * camera.Look); switch (filePathInfo.Extension) { case ".sa1mdl": ModelFile mf = new ModelFile(filePath); NJS_OBJECT objm = mf.Model; osd.ClearMessageList(); osd.AddMessage("Importing models, please wait...", 3000); osd.ClearMessageList(); createdItems.AddRange(ImportFromHierarchy(objm, selectionManager, osd, multiple)); osd.AddMessage("Stage import complete!", 100); break; case ".obj": case ".objf": LevelItem item = new LevelItem(filePath, new Vertex(pos.X, pos.Y, pos.Z), new Rotation(), levelItems.Count, selectionManager) { Visible = true }; createdItems.Add(item); break; case ".txt": NodeTable.ImportFromFile(filePath, out importError, out importErrorMsg, selectionManager); break; case ".dae": case ".fbx": Assimp.AssimpContext context = new Assimp.AssimpContext(); Assimp.Configs.FBXPreservePivotsConfig conf = new Assimp.Configs.FBXPreservePivotsConfig(false); context.SetConfig(conf); Assimp.Scene scene = context.ImportFile(filePath, Assimp.PostProcessSteps.Triangulate); for (int i = 0; i < scene.RootNode.ChildCount; i++) { osd.ClearMessageList(); osd.AddMessage("Importing model " + i.ToString() + " of " + scene.RootNode.ChildCount.ToString() + "...", 3000); Assimp.Node child = scene.RootNode.Children[i]; List <Assimp.Mesh> meshes = new List <Assimp.Mesh>(); foreach (int j in child.MeshIndices) { meshes.Add(scene.Meshes[j]); } bool isVisible = true; for (int j = 0; j < child.MeshCount; j++) { if (scene.Materials[meshes[j].MaterialIndex].Name.Contains("Collision")) { isVisible = false; break; } } ModelFormat mfmt = ModelFormat.Basic; if (isVisible) { switch (geo.Format) { case LandTableFormat.SA2: mfmt = ModelFormat.Chunk; break; case LandTableFormat.SA2B: mfmt = ModelFormat.GC; break; } } NJS_OBJECT obj = AssimpStuff.AssimpImport(scene, child, mfmt, TextureBitmaps[leveltexs].Select(a => a.Name).ToArray(), !multiple); { //sa2 collision patch if (obj.Attach.GetType() == typeof(BasicAttach)) { BasicAttach ba = obj.Attach as BasicAttach; foreach (NJS_MATERIAL mats in ba.Material) { mats.DoubleSided = true; } } //cant check for transparent texture so i gotta force alpha for now, temporary else if (obj.Attach.GetType() == typeof(ChunkAttach)) { ChunkAttach ca = obj.Attach as ChunkAttach; foreach (PolyChunk polys in ca.Poly) { if (polys.GetType() == typeof(PolyChunkMaterial)) { PolyChunkMaterial mat = polys as PolyChunkMaterial; mat.SourceAlpha = AlphaInstruction.SourceAlpha; mat.DestinationAlpha = AlphaInstruction.InverseSourceAlpha; } else if (polys.GetType() == typeof(PolyChunkStrip)) { PolyChunkStrip str = polys as PolyChunkStrip; //str.UseAlpha = true; } } } } obj.Attach.ProcessVertexData(); LevelItem newLevelItem = new LevelItem(obj.Attach, new Vertex(obj.Position.X + pos.X, obj.Position.Y + pos.Y, obj.Position.Z + pos.Z), obj.Rotation, levelItems.Count, selectionManager) { Visible = isVisible }; createdItems.Add(newLevelItem); } osd.ClearMessageList(); osd.AddMessage("Stage import complete!", 100); break; default: errorFlag = true; errorMsg = "Invalid file format!"; return(null); } StateChanged(); errorFlag = importError; errorMsg = importErrorMsg; return(createdItems); }
private Scene LoadScene() { //var mesh2 = new MeshGeometry3D //{ // Positions = new FreezableCollection<Point3D> // { // (0, 0, 0), (100, 0, 0), (100, 100, 0), (0, 100, 0) // }, // Indices = new FreezableCollection<uint> // { // 0, 1, 2, 2, 3, 0 // } //}; var dstScene = new Scene(); #if false var bitmap = BitmapDecoder.Create(File.OpenRead(Path.Combine(@"Content\", "heart.png"))); var frame = bitmap.Frames[0]; var brush = new ImageBrush { Source = frame }; for (int i = 0; i < 5; i++) { dstScene.Add(new Visual3D { Geometry = new BoxGeometry3D { Width = 10, Height = 2, Depth = 20 }, Material = new Material <StandardShaderParameters> { Shader = new StandardShadersGroup(), Parameters = new StandardShaderParameters { MainTexture = brush } } }); } #else var context = new Assimp.AssimpContext(); var scene = context.ImportFile(@"Content\Reimu\reimu_Sheep3D_0.957.fbx", Assimp.PostProcessSteps.GenerateSmoothNormals | Assimp.PostProcessSteps.GenerateUVCoords); foreach (var src in scene.Meshes) { var mesh = new MeshGeometry3D { Positions = new FreezableCollection <Point3D>(from v in src.Vertices select new Point3D(v.X, v.Y, v.Z)), Normals = new FreezableCollection <Vector3>(from v in src.Normals select new Vector3(v.X, v.Y, v.Z)), TextureCoordinates = new FreezableCollection <Point>(from v in src.TextureCoordinateChannels[0] select new Point(v.X, v.Y)), Indices = new FreezableCollection <uint>(from f in src.Faces from i in f.Indices select(uint) i) }; var srcMaterial = scene.Materials[src.MaterialIndex]; Brush mainTexture; if (srcMaterial.HasTextureDiffuse) { var bitmap = BitmapDecoder.Create(File.OpenRead(Path.Combine(@"Content\Reimu\", srcMaterial.TextureDiffuse.FilePath))); var frame = bitmap.Frames[0]; mainTexture = new ImageBrush { Source = frame }; } else { mainTexture = new SolidColorBrush { Color = Colors.Black } }; var visual = new Visual3D { Geometry = mesh, Material = new Material <StandardShaderParameters> { Shader = new StandardShadersGroup(), Parameters = new StandardShaderParameters { MainTexture = mainTexture } } }; dstScene.Add(visual); } #endif //Console.WriteLine($"Total Vertex Count: { dstScene.Sum(o => ((MeshGeometry3D)o.Geometry).Positions.Count) }"); return(dstScene); }
private void ConvertModelIntoMapModel(string modelFile, MapGenConfig config) { logger.Debug($"Loading 3D model file \"{modelFile}\" using Assimp."); var assimp = new Assimp.AssimpContext(); var scene = assimp.ImportFile(modelFile, Assimp.PostProcessSteps.PreTransformVertices); bigMeshContainer = new BigMeshContainer(); var scale = config.scale; Matrix4x4 matrix = Matrix4x4.Identity; if (config.applyMatrix != null) { var m = config.applyMatrix; if (m.Length == 16) { matrix = new Matrix4x4( m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15] ); logger.Debug($"Apply matrix: {matrix}"); } } else { matrix *= scale; } logger.Debug($"Starting triangle strip conversion for {scene.Meshes.Count} meshes."); foreach (var inputMesh in scene.Meshes) { logger.Debug($"Mesh: {inputMesh.Name} ({inputMesh.FaceCount:#,##0} faces, {inputMesh.VertexCount:#,##0} vertices)"); var modelMat = scene.Materials[inputMesh.MaterialIndex]; var matDef = config.FindMaterial(modelMat.Name ?? "default") ?? MaterialDef.CreateFallbackFor(modelMat.Name); if (matDef.ignore) { logger.Info($"This mesh \"{inputMesh.Name}\" is not rendered due to ignore flag of material \"{modelMat.Name}\"."); continue; } var kh2Mesh = bigMeshContainer.AllocateBigMeshForMaterial(matDef); var diffuseTextureFile = modelMat.TextureDiffuse.FilePath; if (!string.IsNullOrEmpty(diffuseTextureFile)) { if (config.reuseImd) { logger.Debug($"The mesh \"{inputMesh.Name}\" material \"{matDef.name}\" has filepath \"{diffuseTextureFile}\" for diffuse texture. It will be associated with material's fromFile3. Setting preferable imd file to fromFile2 due to reuseImd flag."); matDef.fromFile2 = Path.ChangeExtension(diffuseTextureFile, ".imd"); matDef.fromFile3 = diffuseTextureFile; } else { logger.Debug($"The mesh \"{inputMesh.Name}\" material \"{matDef.name}\" has filepath \"{diffuseTextureFile}\" for diffuse texture. It will be associated with material's fromFile2."); matDef.fromFile3 = diffuseTextureFile; } } var kh2BaseVert = kh2Mesh.vertexList.Count; List <int> vertexToLocal = new List <int>(); foreach (var inputVertex in inputMesh.Vertices) { var vertex = Vector3.Transform( new Vector3(inputVertex.X, inputVertex.Y, inputVertex.Z), matrix ); var index = kh2Mesh.vertexList.IndexOf(vertex); if (index < 0) { index = kh2Mesh.vertexList.Count; kh2Mesh.vertexList.Add(vertex); } vertexToLocal.Add(index); } var localFaces = inputMesh.Faces .Select( set => set.Indices .Select(index => new VertPair { uvColorIndex = index, vertexIndex = vertexToLocal[index] }) .ToArray() ) .ToArray(); var inputTexCoords = inputMesh.TextureCoordinateChannels.First(); var inputVertexColorList = inputMesh.VertexColorChannels.First(); var hasVertexColor = inputMesh.VertexColorChannelCount >= 1; var maxIntensity = matDef.maxColorIntensity ?? config.maxColorIntensity ?? 128; var maxAlpha = matDef.maxAlpha ?? config.maxAlpha ?? 128; var triConverter = config.disableTriangleStripsOptimization ? (TriangleFansToTriangleStripsConverter)TriangleFansToTriangleStripsNoOpts : (TriangleFansToTriangleStripsConverter)TriangleFansToTriangleStripsOptimized; foreach (var triStripInput in triConverter(localFaces)) { var triStripOut = new BigMesh.TriangleStrip(); foreach (var vertPair in triStripInput) { triStripOut.vertexIndices.Add(kh2BaseVert + vertPair.vertexIndex); triStripOut.uvList.Add(Get2DCoord(inputTexCoords[vertPair.uvColorIndex])); if (hasVertexColor) { triStripOut.vertexColorList.Add(ConvertVertexColor(inputVertexColorList[vertPair.uvColorIndex], maxIntensity, maxAlpha)); } else { triStripOut.vertexColorList.Add(new Color(maxIntensity, maxIntensity, maxIntensity, maxAlpha)); } } kh2Mesh.triangleStripList.Add(triStripOut); } logger.Debug($"Output: {kh2Mesh.vertexList.Count:#,##0} vertices, {kh2Mesh.triangleStripList.Count:#,##0} triangle strips."); } logger.Debug($"The conversion has done."); logger.Debug($"Starting mesh splitter and vif packets builder."); mapModel = new Mdlx.M4 { VifPackets = new List <Mdlx.VifPacketDescriptor>(), }; foreach (var bigMesh in bigMeshContainer.MeshList .Where(it => it.textureIndex != -1) ) { foreach (var smallMesh in BigMeshSplitter.Split(bigMesh)) { var dmaPack = new MapVifPacketBuilder(smallMesh); smallMeshList.Add(smallMesh); bigMesh.vifPacketIndices.Add(Convert.ToUInt16(mapModel.VifPackets.Count)); smallMesh.vifPacketIndices.Add(Convert.ToUInt16(mapModel.VifPackets.Count)); mapModel.VifPackets.Add( new Mdlx.VifPacketDescriptor { VifPacket = dmaPack.vifPacket.ToArray(), TextureId = smallMesh.textureIndex, DmaPerVif = new ushort[] { dmaPack.firstVifPacketQwc, 0, }, IsTransparentFlag = smallMesh.matDef.transparentFlag ?? 0, } ); } } logger.Debug($"Output: {mapModel.VifPackets.Count:#,##0} vif packets."); logger.Debug($"The builder has done."); logger.Debug($"Starting vifPacketRenderingGroup builder."); // first group: render all mapModel.vifPacketRenderingGroup = new List <ushort[]>( new ushort[][] { Enumerable.Range(0, mapModel.VifPackets.Count) .Select(it => Convert.ToUInt16(it)) .ToArray() } ); logger.Debug($"Output: {mapModel.vifPacketRenderingGroup.Count:#,##0} groups."); mapModel.DmaChainIndexRemapTable = new List <ushort>( Enumerable.Range(0, mapModel.VifPackets.Count) .Select(it => Convert.ToUInt16(it)) .ToArray() ); }
public override IDisposable Load(Type resourceType, string identifier) { using (var assimpContext = new Assimp.AssimpContext()) { var scene = assimpContext.ImportFile(identifier); var meshes = new List<Graphics.Mesh>(); foreach (var mesh in scene.Meshes) { var bytesPerVertex = 12; if (mesh.HasNormals) { bytesPerVertex += 12; } if (mesh.HasTextureCoords(0)) { bytesPerVertex += 8; } var vertexCount = mesh.VertexCount; var meshSizeInBytes = vertexCount * bytesPerVertex; using (var stream = new SlimDX.DataStream(meshSizeInBytes, true, true)) { for (var i = 0; i < vertexCount; ++i) { stream.Write(mesh.Vertices[i]); if (mesh.HasNormals) { stream.Write(mesh.Normals[i]); } if (mesh.HasTextureCoords(0)) { stream.Write(mesh.TextureCoordinateChannels[0][i].X); stream.Write(mesh.TextureCoordinateChannels[0][i].Y); } } var vertexBuffer = new Graphics.VertexBuffer(device.Handle, stream, bytesPerVertex, vertexCount, SlimDX.Direct3D11.PrimitiveTopology.TriangleList); var indices = mesh.GetIndices(); if (indices != null && indices.Count() > 0) { var indexBuffer = new Graphics.IndexBuffer(device.Handle, indices); return new Graphics.Mesh(vertexBuffer, indexBuffer); } var result = new Graphics.Mesh(vertexBuffer); if (resourceType.Equals(typeof(Graphics.Mesh))) { return result; } else { meshes.Add(result); } } } if (meshes.Count > 0) { return new Graphics.MeshGroup(meshes); } else { throw new KeyNotFoundException("Failed to load mesh: " + identifier); } } }