/// <summary> /// Converts a FBX file into a temp scene representation (which may already contain meshes and materials, don't care) /// </summary> /// <param name="_FileName">The name of the FBX file to load</param> /// <param name="_Scene">The cirrus scene into which we should store the data</param> /// <param name="_ScaleFactor">The scale factor to apply to the entire scene /// By default, internal MAX units can be considered as centimeters so if you create a scene whose dimensions of a one meter box are 100x100x100, you /// will want to use a scale factor of 0.01. /// FBX offers the possibility of scaling but does a shitty job at it as it doesn't even rescale other dimensions like near/far clips or ranges for lights /// and camera, which plain sucks.</param> /// <param name="_Materials">An optional materials database containing informations about materials required by the scene</param> public void Load(FileInfo _FileName, FBX.Scene.Scene _Scene, float _ScaleFactor, MaterialsDatabase _Materials) { if (_FileName == null) { throw new Exception("Invalid file name!"); } if (!_FileName.Exists) { throw new Exception("Scene file \"" + _FileName + "\" does not exist!"); } if (_Scene == null) { throw new Exception("Invalid Scene to load into!"); } m_Scene = _Scene; m_TempMesh2FinalMesh.Clear(); m_ScaleFactor = _ScaleFactor; m_MaterialsDatabase = _Materials; FBXImporter.Scene FBXScene = null; try { FBXScene = new FBXImporter.Scene(); FBXScene.Load(_FileName.FullName); // Process materials ProcessMaterials(FBXScene.Materials); // Process the scene nodes RecurseProcessNode(FBXScene.RootNode, null); // Attach camera & light targets PostProcessNodes(m_Scene.RootNode); // Build actual optimized and consolidated meshes BuildConsolidatedMeshes(); // Propagate state once so Local2World matrices are up to date m_Scene.RootNode.PropagateState(); } catch (Exception _e) { throw new Exception("An error occurred while importing the FBX file \"" + _FileName + "\"!", _e); } finally { FBXScene.Dispose(); } }
/// <summary> /// Convert from FBX /// </summary> /// <param name="_Scene"></param> public Scene(FBX.Scene.Scene _Scene) { // Create materials FBX.Scene.Materials.MaterialParameters[] SourceMaterials = _Scene.MaterialParameters; foreach (FBX.Scene.Materials.MaterialParameters SourceMaterial in SourceMaterials) { m_Materials.Add(new Material(SourceMaterial, MapMaterial)); } // Create nodes if (_Scene.RootNode != null) { m_RootNode = new Node(this, _Scene.RootNode); } }
/// <summary> /// Converts a FBX file into a temp scene representation (which may already contain meshes and materials, don't care) /// </summary> /// <param name="_FileName">The name of the FBX file to load</param> /// <param name="_Scene">The cirrus scene into which we should store the data</param> /// <param name="_ScaleFactor">The scale factor to apply to the entire scene /// By default, internal MAX units can be considered as centimeters so if you create a scene whose dimensions of a one meter box are 100x100x100, you /// will want to use a scale factor of 0.01. /// FBX offers the possibility of scaling but does a shitty job at it as it doesn't even rescale other dimensions like near/far clips or ranges for lights /// and camera, which plain sucks.</param> /// <param name="_Materials">An optional materials database containing informations about materials required by the scene</param> public void Load( FileInfo _FileName, FBX.Scene.Scene _Scene, float _ScaleFactor, MaterialsDatabase _Materials ) { if ( _FileName == null ) throw new Exception( "Invalid file name!" ); if ( !_FileName.Exists ) throw new Exception( "Scene file \"" + _FileName + "\" does not exist!" ); if ( _Scene == null ) throw new Exception( "Invalid Scene to load into!" ); m_Scene = _Scene; m_TempMesh2FinalMesh.Clear(); m_ScaleFactor = _ScaleFactor; m_MaterialsDatabase = _Materials; FBXImporter.Scene FBXScene = null; try { FBXScene = new FBXImporter.Scene(); FBXScene.Load( _FileName.FullName ); // Process materials ProcessMaterials( FBXScene.Materials ); // Process the scene nodes RecurseProcessNode( FBXScene.RootNode, null ); // Attach camera & light targets PostProcessNodes( m_Scene.RootNode ); // Build actual optimized and consolidated meshes BuildConsolidatedMeshes(); // Propagate state once so Local2World matrices are up to date m_Scene.RootNode.PropagateState(); } catch ( Exception _e ) { throw new Exception( "An error occurred while importing the FBX file \"" + _FileName + "\"!", _e ); } finally { FBXScene.Dispose(); } }
/// <summary> /// Loads a FBX scene and converts it (in the same folder) into its GCX equivalent /// </summary> /// <param name="_File"></param> public void LoadScene( FileInfo _SourceFile, FileInfo _TargetFile ) { FBX.SceneLoader.SceneLoader Loader = new FBX.SceneLoader.SceneLoader(); FBX.SceneLoader.MaterialsDatabase Materials = new FBX.SceneLoader.MaterialsDatabase(); // Materials.BuildFromM2( new DirectoryInfo( @"D:\Workspaces\Arkane\m2" ) ); FBX.Scene.Scene Scene = new FBX.Scene.Scene(); Loader.Load( _SourceFile, Scene, 1.0f, Materials ); // Start writing // FileInfo Target = new FileInfo( Path.Combine( Path.GetDirectoryName( _SourceFile.FullName ), Path.GetFileNameWithoutExtension( _SourceFile.FullName ) + ".gcx" ) ); using ( FileStream S = _TargetFile.OpenWrite() ) using ( BinaryWriter W = new BinaryWriter( S ) ) { GCXFormat.Scene GCX = new GCXFormat.Scene( Scene ); GCX.Save( W ); } // Write infos List<string> Infos = new List<string>(); Infos.Add( "Textures:" ); foreach ( FBX.Scene.Materials.Texture2D Texture in Scene.Textures ) Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Texture.URL ); Infos.Add( "" ); // Here, I write an array mapping texture IDs to names, assuming textures have been converted to POM format using PNG2POM (or HDR2POM) // This way I can simply copy this "code friendly" list and paste it in my C++ code (e.g. const char* ppID2TextureName[] = { PasteHere }; ) Infos.Add( "Texture Flat Names:" ); Infos.Add( "" ); string DirectoryHeader = Path.GetDirectoryName( _SourceFile.ToString() ); DirectoryHeader = DirectoryHeader.Replace( "\\", "\\\\" ); // Double antislashes foreach ( FBX.Scene.Materials.Texture2D Texture in Scene.Textures ) // Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Path.GetFileNameWithoutExtension( Texture.URL ) ); Infos.Add( "\"" + DirectoryHeader + @"\\TexturesPOM\\" + Path.GetFileNameWithoutExtension( Texture.URL ) + ".pom\"," ); Infos.Add( "" ); Infos.Add( "=============================" ); Infos.Add( "Materials:" ); foreach ( FBX.Scene.Materials.MaterialParameters Mat in Scene.MaterialParameters ) Infos.Add( "ID #" + Mat.ID + " => " + Mat.Name + " (shader=" + Mat.ShaderURL + ")" ); Infos.Add( "" ); Infos.Add( "=============================" ); Infos.Add( "Meshes:" ); foreach ( FBX.Scene.Nodes.Mesh Mesh in Scene.Meshes ) Infos.Add( "ID #" + Mesh.ID + " => " + Mesh.Name + " (primsCount=" + Mesh.PrimitivesCount + ")" ); Infos.Add( "" ); Infos.Add( "=============================" ); Infos.Add( "Lights:" ); foreach ( FBX.Scene.Nodes.Light Light in Scene.Lights ) Infos.Add( "ID #" + Light.ID + " => " + Light.Name + " (type=" + Light.Type + ")" ); Infos.Add( "" ); Infos.Add( "=============================" ); Infos.Add( "Cameras:" ); foreach ( FBX.Scene.Nodes.Camera Camera in Scene.Cameras ) Infos.Add( "ID #" + Camera.ID + " => " + Camera.Name + " (FOV=" + (Camera.FOV * 180.0f / Math.PI) + ")" ); Infos.Add( "" ); if ( Materials != null ) { FBX.SceneLoader.MaterialsDatabase.Material[] QueriedMaterials = Materials.QueriedMaterials; List<string> QueriedTextures = new List<string>(); // Here I'm generating the XCOPY batch commands to copy original textures from a complex directory structure // into a flattened directory where they'll further be converted into POM files using PNG2POM Infos.Add( "=============================" ); Infos.Add( "Queried database materials:" ); foreach ( FBX.SceneLoader.MaterialsDatabase.Material M in QueriedMaterials ) { Infos.Add( M.Name ); if ( M.TextureDiffuse != null ) QueriedTextures.Add( "xcopy \"" + M.TextureDiffuse.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" ); if ( M.TextureNormal != null ) QueriedTextures.Add( "xcopy \"" + M.TextureNormal.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" ); if ( M.TextureSpecular != null ) QueriedTextures.Add( "xcopy \"" + M.TextureSpecular.Replace( '/', '\\' ) + "\" \"..\\POMTextures\\\" /Y/U/S" ); } Infos.Add( "" ); Infos.Add( "=============================" ); Infos.Add( "Queried textures:" ); Infos.AddRange( QueriedTextures ); } textBoxReport.Lines = Infos.ToArray(); }
/// <summary> /// Loads a FBX file into a temp scene representation (which may already contain meshes and materials, don't care) /// </summary> /// <param name="_FileName">The name of the FBX file to load</param> /// <param name="_Scene">The cirrus scene into which we should store the data</param> public void Load(FileInfo _FileName, FBX.Scene.Scene _Scene) { Load(_FileName, _Scene, 1.0f, null); }
/// <summary> /// Loads a FBX scene and converts it (in the same folder) into its GCX equivalent /// </summary> /// <param name="_File"></param> public void LoadScene(FileInfo _SourceFile, FileInfo _TargetFile) { FBX.SceneLoader.SceneLoader Loader = new FBX.SceneLoader.SceneLoader(); FBX.SceneLoader.MaterialsDatabase Materials = new FBX.SceneLoader.MaterialsDatabase(); // Materials.BuildFromM2( new DirectoryInfo( @"D:\Workspaces\Arkane\m2" ) ); FBX.Scene.Scene Scene = new FBX.Scene.Scene(); Loader.Load(_SourceFile, Scene, 1.0f, Materials); // Start writing // FileInfo Target = new FileInfo( Path.Combine( Path.GetDirectoryName( _SourceFile.FullName ), Path.GetFileNameWithoutExtension( _SourceFile.FullName ) + ".gcx" ) ); using (FileStream S = _TargetFile.OpenWrite()) using (BinaryWriter W = new BinaryWriter(S)) { GCXFormat.Scene GCX = new GCXFormat.Scene(Scene); GCX.Save(W); } // Write infos List <string> Infos = new List <string>(); Infos.Add("Textures:"); foreach (FBX.Scene.Materials.Texture2D Texture in Scene.Textures) { Infos.Add("ID #" + Texture.ID.ToString("D3") + " URL=" + Texture.URL); } Infos.Add(""); // Here, I write an array mapping texture IDs to names, assuming textures have been converted to POM format using PNG2POM (or HDR2POM) // This way I can simply copy this "code friendly" list and paste it in my C++ code (e.g. const char* ppID2TextureName[] = { PasteHere }; ) Infos.Add("Texture Flat Names:"); Infos.Add(""); string DirectoryHeader = Path.GetDirectoryName(_SourceFile.ToString()); DirectoryHeader = DirectoryHeader.Replace("\\", "\\\\"); // Double antislashes foreach (FBX.Scene.Materials.Texture2D Texture in Scene.Textures) { // Infos.Add( "ID #" + Texture.ID.ToString( "D3" ) + " URL=" + Path.GetFileNameWithoutExtension( Texture.URL ) ); Infos.Add("\"" + DirectoryHeader + @"\\TexturesPOM\\" + Path.GetFileNameWithoutExtension(Texture.URL) + ".pom\","); } Infos.Add(""); Infos.Add("============================="); Infos.Add("Materials:"); foreach (FBX.Scene.Materials.MaterialParameters Mat in Scene.MaterialParameters) { Infos.Add("ID #" + Mat.ID + " => " + Mat.Name + " (shader=" + Mat.ShaderURL + ")"); } Infos.Add(""); Infos.Add("============================="); Infos.Add("Meshes:"); foreach (FBX.Scene.Nodes.Mesh Mesh in Scene.Meshes) { Infos.Add("ID #" + Mesh.ID + " => " + Mesh.Name + " (primsCount=" + Mesh.PrimitivesCount + ")"); } Infos.Add(""); Infos.Add("============================="); Infos.Add("Lights:"); foreach (FBX.Scene.Nodes.Light Light in Scene.Lights) { Infos.Add("ID #" + Light.ID + " => " + Light.Name + " (type=" + Light.Type + ")"); } Infos.Add(""); Infos.Add("============================="); Infos.Add("Cameras:"); foreach (FBX.Scene.Nodes.Camera Camera in Scene.Cameras) { Infos.Add("ID #" + Camera.ID + " => " + Camera.Name + " (FOV=" + (Camera.FOV * 180.0f / Math.PI) + ")"); } Infos.Add(""); if (Materials != null) { FBX.SceneLoader.MaterialsDatabase.Material[] QueriedMaterials = Materials.QueriedMaterials; List <string> QueriedTextures = new List <string>(); // Here I'm generating the XCOPY batch commands to copy original textures from a complex directory structure // into a flattened directory where they'll further be converted into POM files using PNG2POM Infos.Add("============================="); Infos.Add("Queried database materials:"); foreach (FBX.SceneLoader.MaterialsDatabase.Material M in QueriedMaterials) { Infos.Add(M.Name); if (M.TextureDiffuse != null) { QueriedTextures.Add("xcopy \"" + M.TextureDiffuse.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S"); } if (M.TextureNormal != null) { QueriedTextures.Add("xcopy \"" + M.TextureNormal.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S"); } if (M.TextureSpecular != null) { QueriedTextures.Add("xcopy \"" + M.TextureSpecular.Replace('/', '\\') + "\" \"..\\POMTextures\\\" /Y/U/S"); } } Infos.Add(""); Infos.Add("============================="); Infos.Add("Queried textures:"); Infos.AddRange(QueriedTextures); } textBoxReport.Lines = Infos.ToArray(); }