Example #1
0
        private static void RunHighQualityReduction(ISimplygonSDK SDK, string writeTo)
        {
            const int vertex_count   = 12;
            const int triangle_count = 4;

            // 4 triangles x 3 indices ( or 3 corners )
            int[] corner_ids = { 0,  1, 2,
                                 3,  4, 5,
                                 6,  7, 8,
                                 9, 10, 11 };

            // 12 vertices with values for the x, y and z coordinates.
            float[] vertex_coordinates = { 0.0f, 0.0f, 0.0f,
                                           1.0f, 0.0f, 0.0f,
                                           1.0f, 1.0f, 0.0f,

                                           1.0f, 1.0f, 0.0f,
                                           0.0f, 1.0f, 0.0f,
                                           0.0f, 0.0f, 0.0f,

                                           1.0f, 0.0f, 0.0f,
                                           2.0f, 0.0f, 0.0f,
                                           2.0f, 1.0f, 0.0f,

                                           2.0f, 1.0f, 0.0f,
                                           1.0f, 1.0f, 0.0f,
                                           1.0f, 0.0f, 0.0f };

            spGeometryData g      = SDK.CreateGeometryData();
            spRealArray    coords = g.GetCoords();
            spRidArray     ids    = g.GetVertexIds();

            g.SetVertexCount(vertex_count);
            g.SetTriangleCount(triangle_count);
            for (int i = 0; i < vertex_count; ++i)
            {
                //coords.SetTuple(i, vertex_coordinates[i * 3]);
                //coords[i] = vertex_coordinates[i * 3];
                float[] v = { 0.0f, 0.0f, 0.0f };
                for (int j = 0; j < 3; ++j)
                {
                    v[j] = vertex_coordinates[i * 3 + j];
                }

                coords.SetTuple(i, v);
            }
            for (int i = 0; i < corner_ids.Length; ++i)
            {
                ids.SetItem(i, corner_ids[i]);
            }

            // Create the reduction-processor, and set which scene to reduce
            using (var reductionProcessor = SDK.CreateReductionProcessor())
            {
                spScene     scene    = SDK.CreateScene();
                spSceneNode root     = scene.GetRootNode();
                spSceneMesh meshNode = SDK.CreateSceneMesh();
                meshNode.SetGeometry(g);
                //auto meshTransform = meshNode->GetRelativeTransform();
                //meshTransform->SetToTranslationTransform(100, 0, 0);
                root.AddChild(meshNode);
                reductionProcessor.SetSceneRoot(root);


                ///////////////////////////////////////////////////////////////////////////////////////////////
                // SETTINGS - Most of these are set to the same value by default, but are set anyway for clarity

                // The reduction settings object contains settings pertaining to the actual decimation
                var reductionSettings = reductionProcessor.GetReductionSettings();
                reductionSettings.SetKeepSymmetry(true);                                                               //Try, when possible to reduce symmetrically
                reductionSettings.SetUseAutomaticSymmetryDetection(true);                                              //Auto-detect the symmetry plane, if one exists. Can, if required, be set manually instead.
                reductionSettings.SetUseHighQualityNormalCalculation(true);                                            //Drastically increases the quality of the LODs normals, at the cost of extra processing time.
                reductionSettings.SetReductionHeuristics((uint)ReductionHeuristics.SG_REDUCTIONHEURISTICS_CONSISTENT); //Choose between "fast" and "consistent" processing. Fast will look as good, but may cause inconsistent
                //triangle counts when comparing MaxDeviation targets to the corresponding percentage targets.

                // The reducer uses importance weights for all features to decide where and how to reduce.
                // These are advanced settings and should only be changed if you have some specific reduction requirement
                //reductionSettings.SetShadingImportance(2.f); //This would make the shading twice as important to the reducer as the other features./

                // The actual reduction triangle target are controlled by these settings
                reductionSettings.SetStopCondition((uint)StopCondition.SG_STOPCONDITION_EITHER_IS_REACHED); //The reduction stops when any of the targets below is reached
                reductionSettings.SetReductionRatio(0.5f);                                                  //Targets at 50% of the original triangle count
                reductionSettings.SetMaxDeviation(float.MaxValue);                                          //Targets when an error of the specified size has been reached. As set here it never happens.

                // The repair settings object contains settings to fix the geometries
                var repairSettings = reductionProcessor.GetRepairSettings();
                repairSettings.SetTjuncDist(0.0f); //Removes t-junctions with distance 0.0f
                repairSettings.SetWeldDist(0.0f);  //Welds overlapping vertices

                // The normal calculation settings deal with the normal-specific reduction settings
                var normalSettings = reductionProcessor.GetNormalCalculationSettings();
                normalSettings.SetReplaceNormals(false); //If true, this will turn off normal handling in the reducer and recalculate them all afterwards instead.
                //If false, the reducer will try to preserve the original normals as well as possible
                //normalSettings.SetHardEdgeAngle( 60.f ); //If the normals are recalculated, this sets the hard-edge angle./

                //END SETTINGS
                ///////////////////////////////////////////////////////////////////////////////////////////////

                // Run the actual processing. After this, the set geometry will have been reduced according to the settings
                reductionProcessor.RunProcessing();

                // For this reduction, the LOD will use the same material set as the original, and hence no further processing is required

                //Create an .obj exporter to save our result
                using (var objExporter = SDK.CreateWavefrontExporter())
                {
                    // Generate the output filenames
                    string      outputGeomFilename = writeTo + ".obj";
                    spSceneMesh topmesh            = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0), false);


                    // Do the actual exporting
                    objExporter.SetExportFilePath(outputGeomFilename);
                    objExporter.SetSingleGeometry(topmesh.GetGeometry()); //This is the geometry we set as the processing geom of the reducer, retaining the materials in the original scene
                    objExporter.RunExport();

                    //Done! LOD created.
                }
            }
        }
Example #2
0
        static bool run_remeshing_for_lod(ISimplygonSDK sdk, int lod_index, uint merge_distance)
        {
            string userProfileDirectory     = System.Environment.GetEnvironmentVariable("USERPROFILE");
            string assetRoot                = userProfileDirectory + @"/Documents/SimplygonSDK/SourceCode/Assets/";
            string tempRoot                 = @"../../../../../temp/";
            string output_filename          = string.Format(tempRoot + "wall_lod{0}_merge{1}.obj", lod_index + 1, merge_distance);
            string output_material_filename = string.Format(tempRoot + "wall_lod{0}_merge{1}.mtl", lod_index + 1, merge_distance);
            string output_diffuse_filename  = string.Format(tempRoot + "wall_lod{0}_merge{1}_diffuse.png", lod_index + 1, merge_distance);
            string output_normals_filename  = string.Format(tempRoot + "wall_lod{0}_merge{1}_normals.png", lod_index + 1, merge_distance);


            // Import source geometry
            spGeometryData  geom;
            spMaterialTable materials;

            Console.WriteLine("Importing wavefront .obj file...\n");
            {
                // Run import
                spWavefrontImporter importer = sdk.CreateWavefrontImporter();
                importer.SetExtractGroups(false); // We only want one large geometry, no need to extract groups

                importer.SetImportFilePath(assetRoot + "wall.obj");
                if (!importer.RunImport())
                {
                    Console.WriteLine("Could not open input test file");
                    return(false);
                }

                // Get the only geometry and the materials
                geom      = importer.GetFirstGeometry();
                materials = importer.GetMaterials();
            }

            // Make a copy of the geometry, we need the original for texture casting later.
            // The remesher will replace the data of the geometry after it has processed it.
            spGeometryData red_geom = geom.NewCopy(true);

            // Create a Scene-object and a SceneMesh-object.
            // Place the red_geom into the SceneMesh, and then the SceneMesh as a child to the RootNode.
            spScene     scene = sdk.CreateScene();
            spSceneMesh mesh  = sdk.CreateSceneMesh();

            mesh.SetGeometry(red_geom);
            mesh.SetName(red_geom.GetName().GetText());
            scene.GetRootNode().AddChild(mesh);

            spMappingImage mapping_image;

            // Remesh it
            Console.WriteLine("Running remesher...\n");
            {
                spRemeshingProcessor remesher = sdk.CreateRemeshingProcessor();

                //  Set target on-screen size in pixels
                remesher.GetRemeshingSettings().SetOnScreenSize(lod_sizes[lod_index]);
                //  Set the on-screen merge distance in pixels. Holes smaller than this will be sealed
                //  and geometries closer to each other than this will be merged.
                remesher.GetRemeshingSettings().SetMergeDistance(merge_distance);
                //  Disable the cutting plane
                remesher.GetRemeshingSettings().SetUseGroundPlane(false);
                //	Set to generate mapping image for texture casting.
                remesher.GetMappingImageSettings().SetGenerateMappingImage(true);

                remesher.SetSceneRoot(scene.GetRootNode());
                remesher.RemeshGeometry();

                // Mapping image is needed later on for texture casting.
                mapping_image = remesher.GetMappingImage();
            }

            spSceneMesh topmesh = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0), false);

            // Cast diffuse texture and normal map data into a new material
            //	Create new material table.
            spMaterialTable output_materials = sdk.CreateMaterialTable();
            //	Create new material for the table.
            spMaterial output_material = sdk.CreateMaterial();

            output_materials.AddMaterial(output_material);

            // Cast diffuse texture data
            {
                // Cast the data using a color caster
                spColorCaster cast = sdk.CreateColorCaster();
                cast.SetColorType(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE);
                cast.SetSourceMaterials(materials);
                cast.SetMappingImage(mapping_image);             // The mapping image we got from the remeshing process.
                cast.SetOutputChannels(3);                       // RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.)
                cast.SetOutputChannelBitDepth(8);                // 8 bits per channel. So in this case we will have 24bit colors RGB.
                cast.SetDilation(10);                            // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree aswell.
                cast.SetOutputFilePath(output_diffuse_filename); // Where the texture map will be saved to file.
                cast.CastMaterials();                            // Fetch!

                // set the material properties
                // Set the diffuse multiplier for the texture. 1 means it will not differ from original texture,
                // For example: 0 would ignore a specified color and 2 would make a color twice as pronounced as the others.
                output_material.SetDiffuseRed(1);
                output_material.SetDiffuseGreen(1);
                output_material.SetDiffuseBlue(1);
                // Set material to point to created texture filename.
                output_material.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE, output_diffuse_filename);
            }

            // cast normal map texture data
            {
                // cast the data using a color caster
                spNormalCaster cast = sdk.CreateNormalCaster();
                cast.SetSourceMaterials(materials);
                cast.SetMappingImage(mapping_image);
                cast.SetOutputChannels(3); // RGB, 3 channels! (But really the x, y and z values for the normal)
                cast.SetOutputChannelBitDepth(8);
                cast.SetDilation(10);
                cast.SetOutputFilePath(output_normals_filename);
                cast.CastMaterials();

                // Set material to point to created texture filename.
                output_material.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_NORMALS, output_normals_filename);
            }

            // export the remeshed geometry to an OBJ file
            Console.WriteLine("Exporting wavefront .obj file...\n");
            {
                spWavefrontExporter exporter = sdk.CreateWavefrontExporter();
                exporter.SetExportFilePath(output_filename);
                exporter.SetSingleGeometry(topmesh.GetGeometry());
                exporter.SetMaterials(output_materials);
                if (!exporter.RunExport())
                {
                    Console.WriteLine("Failed to write result");
                    return(false);
                }
            }
            return(true);
        }