Ejemplo n.º 1
0
        public BScene OptimizeScene(BScene bScene)
        {
            List <BInstance> newInstances = new List <BInstance>();

            // Create collections of meshes with similar materials
            using (SceneAnalysis analysis = new SceneAnalysis(bScene)) {
                int lastInstanceCount = newInstances.Count;
                if (ConvOAR.Globals.parms.P <bool>("SeparateInstancedMeshes"))
                {
                    newInstances.AddRange(SeparateMeshInstances(bScene, analysis));
                }
                // Any shared meshes have been gathered into instances in 'newInstances'
                //     and the meshes have been removed from the shared materials in the analysis.
                int instancesAdded = newInstances.Count - lastInstanceCount;
                ConvOAR.Globals.log.DebugFormat("{0} OptimizeScene: BInstances added by mesh instances = {1}", _logHeader, instancesAdded);

                lastInstanceCount = newInstances.Count;
                if (ConvOAR.Globals.parms.P <bool>("MergeSharedMaterialMeshes"))
                {
                    newInstances.AddRange(MergeSharedMaterialMeshes(bScene, analysis));
                }
                instancesAdded = newInstances.Count - lastInstanceCount;
                ConvOAR.Globals.log.DebugFormat("{0} OptimizeScene: BInstances added by material sharing = {1}", _logHeader, instancesAdded);
            }

            return(bScene);
        }
Ejemplo n.º 2
0
            // Find all the meshes in passed Displayable and add them to the lists indexed by their material
            //     mesh hashes.
            private void MapMaterialsAndMeshes(BScene pBs, BInstance pInst, Displayable disp)
            {
                RenderableMeshGroup rmg = disp.renderable as RenderableMeshGroup;

                if (rmg != null)
                {
                    foreach (RenderableMesh rMesh in rmg.meshes)
                    {
                        InvertedMesh imesh = new InvertedMesh(pBs, pInst, disp, rmg, rMesh);

                        BHash meshHash = rMesh.mesh.GetBHash();
                        if (!sharedMeshes.ContainsKey(meshHash))
                        {
                            sharedMeshes.Add(meshHash, new List <InvertedMesh>());
                        }
                        sharedMeshes[meshHash].Add(imesh);

                        BHash materialHash = rMesh.material.GetBHash();
                        if (!meshByMaterial.ContainsKey(materialHash))
                        {
                            meshByMaterial.Add(materialHash, new List <InvertedMesh>());
                        }
                        meshByMaterial[materialHash].Add(imesh);
                    }
                }
                foreach (Displayable child in disp.children)
                {
                    MapMaterialsAndMeshes(pBs, pInst, child);
                }
            }
Ejemplo n.º 3
0
 public void BuildAnalysis(BScene bScene)
 {
     foreach (BInstance inst in bScene.instances)
     {
         MapMaterialsAndMeshes(bScene, inst, inst.Representation);
     }
 }
Ejemplo n.º 4
0
 public InvertedMesh(BScene pBs, BInstance pInst, Displayable pDisp, DisplayableRenderable pDisprend, RenderableMesh pRm)
 {
     containingScene                 = pBs;
     containingInstance              = pInst;
     containingDisplayable           = pDisp;
     containingDisplayableRenderable = pDisprend;
     renderableMesh = pRm;
     // Compute the global position of the Displayable
     globalPosition = containingDisplayable.offsetPosition * containingInstance.Rotation + containingInstance.Position;
     globalRotation = containingDisplayable.offsetRotation * containingInstance.Rotation;
 }
Ejemplo n.º 5
0
        // Load the OARfile specified in Globals.params.InputOAR.
        // Parameters are in 'ConvOAR.Globals.params'.
        // For the moment, the OAR file must be specified with a string because of how OpenSimulator
        //     processes the input files. Note that the filename can be an 'http:' type URL.
        public async Task <BScene> LoadOAR(IAssetService assetService, AssetManager assetManager)
        {
            BScene ret = null;

            try {
                OarConverter converter = new OarConverter(Globals.log, Globals.parms);
                ret = await converter.ConvertOarToScene(assetService, assetManager);
            }
            catch (Exception e) {
                ConvOAR.Globals.log.ErrorFormat("{0} LoadOAR exception: {1}", _logHeader, e);
                throw (e);
            }
            return(ret);
        }
Ejemplo n.º 6
0
        // Return a new scene whos instances have been created by combining meshes that share
        //    materials.
        public BScene RebuildSceneBasedOnSharedMeshes(BScene bScene)
        {
            List <BInstance> newInstances = new List <BInstance>();

            // Create collections of meshes with similar materials
            using (SceneAnalysis analysis = new SceneAnalysis(bScene)) {
                newInstances.AddRange(MergeSharedMaterialMeshes(bScene, analysis));
            }

            BScene newScene = new BScene(bScene);

            newScene.instances = newInstances;

            return(newScene);
        }
Ejemplo n.º 7
0
        private List <BInstance> SeparateMeshInstances(BScene bScene, SceneAnalysis analysis)
        {
            List <BInstance> ret = new List <BInstance>();

            try {
                // If there are lots of instances of the same mesh, it is better to have multiple instances
                //    that point to the same mesh. If a mesh is not shared, consolidating the meshes
                //    into a single instance is best. It's a balance of transferring vertices vs fewer draws.

                // Any meshes that are used more than 'MeshShareThreshold' will be sent out with their
                //    instances rather than being combined.
                // The GLTF output code will not send out duplicate meshes and combining the meshes to
                //    share materials destroys the duplicatable mesh shapes.
                // The duplicated meshes usually share a material so pull them together into meshes
                //    in one instance.
                // Note: the 'SelectMany' is used to flatten the list of lists
                int meshShareThreshold = ConvOAR.Globals.parms.P <int>("MeshShareThreshold");
                ConvOAR.Globals.log.DebugFormat("{0} SeparateMeshes: Separating instanced meshes. threshold={1}",
                                                _logHeader, meshShareThreshold);

                /*
                 * foreach (BHash key in analysis.sharedMeshes.Keys) {     // DEBUG DEBUG
                 *  ConvOAR.Globals.log.DebugFormat("{0} SeparateMeshes: mesh hash {1} . meshes={2}",       // DEBUG DEBUG
                 *          _logHeader, key, analysis.sharedMeshes[key].Count);     // DEBUG DEBUG
                 * };      // DEBUG DEBUG
                 */

                ret.AddRange(analysis.sharedMeshes.Values.Where(val => val.Count > meshShareThreshold).SelectMany(meshList => {
                    // Creates Instances for the shared messes in this list and also takes the meshes out of 'meshByMaterial'
                    ConvOAR.Globals.log.DebugFormat("{0} MergeSharedMaterialMeshes: shared mesh hash: {1}/{2}, cnt={3}",
                                                    _logHeader, meshList.First().renderableMesh.mesh.GetBHash(),
                                                    meshList.First().renderableMesh.material.GetBHash(),
                                                    meshList.Count);
                    // Since mesh will be in this group, remove it from the meshes with shared materials
                    analysis.MeshUsed(meshList);
                    return(CreateInstancesForSharedMeshes(meshList));
                }).ToList());
            }
            catch (Exception e) {
                ConvOAR.Globals.log.DebugFormat("{0} SeparateMeshInstances: exception: {1}", _logHeader, e);
            }

            return(ret);
        }
Ejemplo n.º 8
0
        private List <BInstance> MergeSharedMaterialMeshes(BScene bScene, SceneAnalysis analysis)
        {
            List <BInstance> ret = new List <BInstance>();

            try {
                // 'analysis.meshByMaterial' has all meshes/instances grouped by material used
                // 'analysis.sharedMeshes' has all meshes grouped by the mesh
                ConvOAR.Globals.log.DebugFormat("{0} MergeShareMaterialHashes: number of materials = {1}",
                                                _logHeader, analysis.meshByMaterial.Count);

                // Merge the meshes and create an Instance containing the new mesh set
                ret.AddRange(analysis.meshByMaterial.Keys.SelectMany(materialHash => {
                    ConvOAR.Globals.log.DebugFormat("{0} MergeShareMaterialHashes: material hash {1} . meshes={2}",
                                                    _logHeader, materialHash, analysis.meshByMaterial[materialHash].Count);
                    return(CreateInstancesFromSharedMaterialMeshes(materialHash, analysis.meshByMaterial[materialHash]));
                }).ToList());
            }
            catch (Exception e) {
                ConvOAR.Globals.log.DebugFormat("{0} MergeShareMaterialHashes: exception: {1}", _logHeader, e);
            }

            return(ret);
        }
Ejemplo n.º 9
0
        // If run from the command line, create instance and call 'Start' with args.
        // If run programmatically, create instance and call 'Start' with parameters.
        public async Task Start(CancellationToken cancelToken, string[] args)
        {
            Globals = new GlobalContext()
            {
                log = new LoggerLog4Net(),
                // log = new LoggerConsole(),
                stats = new ConvoarStats()
            };
            Globals.parms = new ConvoarParams(Globals.log);

            // A single parameter of '--help' outputs the invocation parameters
            if (args.Length > 0 && args[0] == "--help")
            {
                System.Console.Write(Invocation());
                return;
            }

            // 'ConvoarParams' initializes to default values.
            // Over ride default values with command line parameters.
            try {
                // Note that trailing parameters will be put into "InputOAR" parameter
                Globals.parms.MergeCommandLine(args, null, "InputOAR");
            }
            catch (Exception e) {
                Globals.log.ErrorFormat("ERROR: bad parameters: " + e.Message);
                Globals.log.ErrorFormat(Invocation());
                return;
            }

            if (Globals.parms.P <bool>("Verbose"))
            {
                Globals.log.SetVerbose(Globals.parms.P <bool>("Verbose"));
            }

            if (!Globals.parms.P <bool>("Quiet"))
            {
                System.Console.WriteLine("Convoar v" + Globals.version
                                         + " built " + Globals.buildDate
                                         + " commit " + Globals.gitCommit
                                         );
            }

            // Validate parameters
            if (String.IsNullOrEmpty(Globals.parms.P <string>("InputOAR")))
            {
                Globals.log.ErrorFormat("An input OAR file must be specified");
                Globals.log.ErrorFormat(Invocation());
                return;
            }
            if (String.IsNullOrEmpty(Globals.parms.P <string>("OutputDir")))
            {
                _outputDir = "./out";
                Globals.log.DebugFormat("Output directory defaulting to {0}", _outputDir);
            }

            // Base asset storage system -- 'MemAssetService' is in-memory storage
            using (MemAssetService memAssetService = new MemAssetService()) {
                // 'assetManager' is the asset cache and fetching code -- where all the mesh,
                //    material, and instance information is stored for later processing.
                using (AssetManager assetManager = new AssetManager(memAssetService, Globals.log, Globals.parms)) {
                    try {
                        BScene bScene = await LoadOAR(memAssetService, assetManager);

                        Globals.contextName = bScene.name;

                        Globals.log.DebugFormat("{0} Scene created. name={1}, instances={2}",
                                                _logHeader, bScene.name, bScene.instances.Count);
                        Globals.log.DebugFormat("{0}    num assetFetcher.images={1}", _logHeader, assetManager.Assets.Images.Count);
                        Globals.log.DebugFormat("{0}    num assetFetcher.materials={1}", _logHeader, assetManager.Assets.Materials.Count);
                        Globals.log.DebugFormat("{0}    num assetFetcher.meshes={1}", _logHeader, assetManager.Assets.Meshes.Count);
                        Globals.log.DebugFormat("{0}    num assetFetcher.renderables={1}", _logHeader, assetManager.Assets.Renderables.Count);

                        if (ConvOAR.Globals.parms.P <bool>("AddTerrainMesh"))
                        {
                            ConvOAR.Globals.log.DebugFormat("{0} Adding terrain to scene", _logHeader);
                            bScene.instances.Add(bScene.terrainInstance);
                        }

                        if (ConvOAR.Globals.parms.P <bool>("TerrainOnly"))
                        {
                            ConvOAR.Globals.log.DebugFormat("{0} Clearing out scene so there's only terrain (TerrainOnly)", _logHeader);
                            bScene.instances.Clear();
                            bScene.instances.Add(bScene.terrainInstance);
                        }

                        /*
                         * // Perform any optimizations on the scene and its instances
                         * if (Globals.parms.P<bool>("DoMeshSimplification")) {
                         *  // TODO:
                         * }
                         * if (Globals.parms.P<bool>("DoSceneOptimizations")) {
                         *  using (BSceneManipulation optimizer = new BSceneManipulation()) {
                         *      bScene = optimizer.OptimizeScene(bScene);
                         *      Globals.log.DebugFormat("{0} merged BScene. numInstances={1}", _logHeader, bScene.instances.Count);
                         *  }
                         * }
                         */
                        if (Globals.parms.P <bool>("MergeSharedMaterialMeshes"))
                        {
                            using (BSceneManipulation optimizer = new BSceneManipulation(Globals.log, Globals.parms)) {
                                bScene = optimizer.RebuildSceneBasedOnSharedMeshes(bScene);
                                Globals.log.DebugFormat("{0} merged meshes in scene. numInstances={1}", _logHeader, bScene.instances.Count);
                            }
                        }

                        // Output the transformed scene as Gltf version 2
                        Gltf gltf = new Gltf(bScene.name, Globals.log, Globals.parms);

                        try {
                            gltf.LoadScene(bScene);

                            Globals.log.DebugFormat("{0}   num Gltf.nodes={1}", _logHeader, gltf.nodes.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.meshes={1}", _logHeader, gltf.meshes.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.materials={1}", _logHeader, gltf.materials.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.images={1}", _logHeader, gltf.images.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.accessor={1}", _logHeader, gltf.accessors.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.buffers={1}", _logHeader, gltf.buffers.Count);
                            Globals.log.DebugFormat("{0}   num Gltf.bufferViews={1}", _logHeader, gltf.bufferViews.Count);
                        }
                        catch (Exception e) {
                            Globals.log.ErrorFormat("{0} Exception loading GltfScene: {1}", _logHeader, e);
                        }

                        try {
                            if (gltf.scenes.Count > 0)
                            {
                                string gltfFilename = gltf.GetFilename(gltf.IdentifyingString);
                                using (var outm = new MemoryStream()) {
                                    using (var outt = new StreamWriter(outm)) {
                                        gltf.ToJSON(outt);
                                    }
                                    await assetManager.AssetStorage.Store(gltfFilename, outm.ToArray());
                                }
                                gltf.WriteBinaryFiles(assetManager.AssetStorage);

                                if (Globals.parms.P <bool>("ExportTextures"))
                                {
                                    gltf.WriteImages(assetManager.AssetStorage);
                                }
                            }
                            else
                            {
                                Globals.log.ErrorFormat("{0} Not writing out GLTF because no scenes", _logHeader);
                            }
                        }
                        catch (Exception e) {
                            Globals.log.ErrorFormat("{0} Exception writing GltfScene: {1}", _logHeader, e);
                        }

                        /*
                         * // Output all the instances in the scene as individual GLTF files
                         * if (Globals.parms.P<bool>("ExportIndividualGltf")) {
                         *  bScene.instances.ForEach(instance => {
                         *      string instanceName = instance.handle.ToString();
                         *      Gltf gltf = new Gltf(instanceName);
                         *      gltf.persist.baseDirectory = bScene.name;
                         *      // gltf.persist.baseDirectory = PersistRules.JoinFilePieces(bScene.name, instanceName);
                         *      GltfScene gltfScene = new GltfScene(gltf, instanceName);
                         *      gltf.defaultScene = gltfScene;
                         *
                         *      Displayable rootDisp = instance.Representation;
                         *      GltfNode rootNode = GltfNode.GltfNodeFactory(gltf, gltfScene, rootDisp, assetFetcher);
                         *      rootNode.translation = instance.Position;
                         *      rootNode.rotation = instance.Rotation;
                         *
                         *      gltf.BuildAccessorsAndBuffers();
                         *      gltf.UpdateGltfv2ReferenceIndexes();
                         *
                         *      // After the building, get rid of the default scene name as we're not outputting a scene
                         *      gltf.defaultScene = null;
                         *
                         *      PersistRules.ResolveAndCreateDir(gltf.persist.filename);
                         *
                         *      using (StreamWriter outt = File.CreateText(gltf.persist.filename)) {
                         *          gltf.ToJSON(outt);
                         *      }
                         *      gltf.WriteBinaryFiles();
                         *
                         *      if (Globals.parms.P<bool>("ExportTextures")) {
                         *          gltf.WriteImages();
                         *      }
                         *  });
                         * }
                         */
                    }
                    catch (Exception e) {
                        Globals.log.ErrorFormat("{0} Global exception converting scene: {1}", _logHeader, e);
                        // A common error is not having all the DLLs for OpenSimulator. Print out what's missing.
                        if (e is ReflectionTypeLoadException refE)
                        {
                            foreach (var ee in refE.LoaderExceptions)
                            {
                                Globals.log.ErrorFormat("{0} reference exception: {1}", _logHeader, ee);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 10
0
 // Create a new scene based on an existing scene.
 // NOTE: this is NOT a clone. Instances are not copied and other things just
 //    have their pointers moved so the items are shared.
 public BScene(BScene bScene)
 {
     name            = bScene.name;
     attributes      = bScene.attributes;
     terrainInstance = bScene.terrainInstance;
 }
Ejemplo n.º 11
0
        public Promise <BScene> ConvertOarToScene(IAssetService assetService, IAssetFetcher assetFetcher)
        {
            Promise <BScene> prom = new Promise <BScene>();

            // Assemble all the parameters that loadoar takes and uses
            Dictionary <string, object> options = new Dictionary <string, object>();

            // options.Add("merge", false);
            options.Add("displacement", ConvOAR.Globals.parms.P <OMV.Vector3>("Displacement"));
            string optRotation = ConvOAR.Globals.parms.P <string>("Rotation");

            if (optRotation != null)
            {
                options.Add("rotation", float.Parse(optRotation, System.Threading.Thread.CurrentThread.CurrentCulture));
            }
            // options.Add("default-user", OMV.UUID.Random());
            // if (optSkipAssets != null) options.Add('skipAssets', true);
            // if (optForceTerrain != null) options.Add("force-terrain", true);
            // if (optNoObjects != null) options.Add("no-objects", true);
            string optSubRegion = ConvOAR.Globals.parms.P <string>("SubRegion");

            if (optSubRegion != null)
            {
                List <float> bounds = optSubRegion.Split(',').Select <string, float>(x => { return(float.Parse(x)); }).ToList();
                options.Add("bounding-origin", new OMV.Vector3(bounds[0], bounds[1], bounds[2]));
                options.Add("bounding-size", new OMV.Vector3(bounds[3] - bounds[0], bounds[4] - bounds[1], bounds[5] - bounds[2]));
            }

            // Create an OpenSimulator region and scene to load the OAR into
            string regionName = "convoar";

            if (String.IsNullOrEmpty(ConvOAR.Globals.parms.P <String>("RegionName")))
            {
                // Try to build the region name from the OAR filesname
                regionName = Path.GetFileNameWithoutExtension(ConvOAR.Globals.parms.P <string>("InputOAR"));
            }
            else
            {
                regionName = ConvOAR.Globals.parms.P <string>("RegionName");
            }
            Scene scene = CreateScene(assetService, regionName);

            // Load the archive into our scene
            ArchiveReadRequest archive = new ArchiveReadRequest(scene, ConvOAR.Globals.parms.P <string>("InputOAR"), Guid.Empty, options);

            archive.DearchiveRegion(false);

            // Convert SOGs from OAR into EntityGroups
            // ConvOAR.Globals.log.Log("Num assets = {0}", assetService.NumAssets);
            LogBProgress("Num SOGs = {0}", scene.GetSceneObjectGroups().Count);

            PrimToMesh mesher = new PrimToMesh();

            // Convert SOGs => BInstances
            Promise <BInstance> .All(
                scene.GetSceneObjectGroups().Select(sog => {
                return(ConvertSogToInstance(sog, assetFetcher, mesher));
            })
                )
            .Done(instances => {
                ConvOAR.Globals.log.DebugFormat("{0} Num instances = {1}", _logHeader, instances.ToList().Count);
                List <BInstance> instanceList = new List <BInstance>();
                instanceList.AddRange(instances);

                // Add the terrain mesh to the scene
                BInstance terrainInstance = null;
                if (ConvOAR.Globals.parms.P <bool>("AddTerrainMesh"))
                {
                    ConvOAR.Globals.log.DebugFormat("{0} Creating terrain for scene", _logHeader);
                    // instanceList.Add(ConvoarTerrain.CreateTerrainMesh(scene, mesher, assetFetcher));
                    terrainInstance = ConvoarTerrain.CreateTerrainMesh(scene, mesher, assetFetcher);
                    CoordAxis.FixCoordinates(terrainInstance, new CoordAxis(CoordAxis.RightHand_Yup | CoordAxis.UVOriginLowerLeft));
                }

                // Twist the OpenSimulator Z-up coordinate system to the OpenGL Y-up
                foreach (var inst in instanceList)
                {
                    CoordAxis.FixCoordinates(inst, new CoordAxis(CoordAxis.RightHand_Yup | CoordAxis.UVOriginLowerLeft));
                }

                // package instances into a BScene
                BScene bScene          = new BScene();
                bScene.instances       = instanceList;
                RegionInfo ri          = scene.RegionInfo;
                bScene.name            = ri.RegionName;
                bScene.terrainInstance = terrainInstance;
                bScene.attributes.Add("RegionName", ri.RegionName);
                bScene.attributes.Add("RegionSizeX", ri.RegionSizeX);
                bScene.attributes.Add("RegionSizeY", ri.RegionSizeY);
                bScene.attributes.Add("RegionSizeZ", ri.RegionSizeZ);
                bScene.attributes.Add("RegionLocX", ri.RegionLocX);
                bScene.attributes.Add("RegionLocY", ri.RegionLocY);
                bScene.attributes.Add("WorldLocX", ri.WorldLocX);
                bScene.attributes.Add("WorldLocY", ri.WorldLocY);
                bScene.attributes.Add("WaterHeight", ri.RegionSettings.WaterHeight);
                bScene.attributes.Add("DefaultLandingPorint", ri.DefaultLandingPoint);

                prom.Resolve(bScene);
            }, e => {
                ConvOAR.Globals.log.ErrorFormat("{0} failed SOG conversion: {1}", _logHeader, e);
                // prom.Reject(new Exception(String.Format("Failed conversion: {0}", e)));
            });

            return(prom);
        }
Ejemplo n.º 12
0
 public SceneAnalysis(BScene bScene)
 {
     this.scene = bScene;
     BuildAnalysis(bScene);
 }