Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      FoliageExample.cpp
    //  Language:  C++
    //
    //  Copyright (c) 2019 Microsoft. All rights reserved.
    //
    //  This is private property, and it is illegal to copy or distribute in
    //  any form, without written authorization by the copyright owner(s).
    //
    ///////////////////////////////////////////////////////////////////////////
    //
    //  #Description# 
    //
    //  RunExampleBillboards:
    //
    //  Vegetation type objects are replaced by a set of static billboards that 
    //  maintains the visual perception of depth and volume regardless of orientation.
    //
    //  The foliage processor divides the vegetation asset into a trunk and a foliage 
    //  part. The trunk geometry retains the original materials and have its triangle 
    //  count reduced. The foliage part is replaced by a set of billboards that 
    //  receives a newly generated material.
    //
    //  There are a number of settings that determine the complexity and quality of 
    //  the optimized vegetation such as the permitted distance (maximum deviation) 
    //  between the original leaves and their projection on a billboard. If the 
    //  maximum deviation is set to a low value (same as having a high on screen pixel 
    //  size), more billboards would need to be created in order to satisfy the low 
    //  error tolerance. However, the user can also set a maximum number of billboards 
    //  allowed to make sure there's a certain geometry complexity limit. If the maximum 
    //  billboard count is reached but there are still leaves further away from any 
    //  billboard than than the permitted projection distance the leaves will be 
    //  projected to the most suitable billboard.
    //
    //
    //  RunExampleFlipbook:
    //  
    //  The flip book generator replaces the scene with a single quad that when rendered 
    //  should always be oriented towards the viewer around the up-vector. The quad 
    //  should be textured with the original scene rendered from a similar view.
    //  
    //  The flip book generator renders the input scene from a number of views and 
    //  concatenates the images into an atlas (per channel). Every view is rendered at 
    //  the same size making indexing a view from the finished atlas predictable. The 
    //  generator also  creates a single square quad positioned at the center of the 
    //  scene scaled to fit an orthographic projection of the scene from any angle.
    //  
    //  The user decides the amount of views to render. The output texture is always a
    //  square therefore the number of views is also a square number. When rendering 
    //  the quad, select the view from the texture atlas that closest corresponds to the
    //  current direction.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    void RunExampleBillboards(const std::string& readFrom, const std::string& writeTo);
    void RunExampleFlipbook(const std::string& readFrom, const std::string& writeTo);
    
    int main( int argc, char* argv[] )
        {
        try
        {
            InitExample();
    
            // Set global variable. Using Orthonormal method for calculating
            // tangentspace.
            sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
    
            std::string assetPath = GetAssetPath();
    
            RunExampleBillboards(assetPath + "Tree/Tree.obj", "TreeBillboards");
            RunExampleFlipbook(assetPath + "Tree/Tree.obj", "TreeFlipbook");
    
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    void RunExampleBillboards(const std::string& readFrom, const std::string& writeTo)
        {
        std::string exePath = GetExecutablePath();
        std::string outputGeometryFilename = exePath + writeTo + ".obj";
    
        //Load object from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetUseAlphaAsOpacity(true);
        objReader->SetImportFilePath(readFrom.c_str());
    
        if (!objReader->RunImport())
            throw std::exception("Failed to load input file!");
    
        //Get the scene
        spScene originalScene = objReader->GetScene();
    
        spScene lodScene = sg->CreateScene();
        lodScene->DeepCopy(originalScene);
    
        spFoliageProcessor foliageProcessor = sg->CreateFoliageProcessor();
        foliageProcessor->SetScene(lodScene);
        foliageProcessor->GetMappingImageSettings()->SetWidth(1024);
        foliageProcessor->GetMappingImageSettings()->SetHeight(1024);
        foliageProcessor->GetMappingImageSettings()->SetMaximumLayers(10);
        foliageProcessor->GetMappingImageSettings()->SetMultisamplingLevel(2);
    
        spFoliageSettings foliageSettings = foliageProcessor->GetFoliageSettings();
        foliageSettings->SetBillboardDensity(0.2f);
        foliageSettings->SetBillboardTrunkReductionRatio(0.5f);
        foliageSettings->SetFoliageType(SG_FOLIAGETYPE_BILLBOARDS);
        foliageSettings->SetBillboardFavorVerticalPlanes(false);
        foliageSettings->SetBillboardMaxPlaneCount(20);
        foliageSettings->SetBillboardSubdividePlanes(true);
        foliageSettings->SetBillboardAllowConvexPolygons(true);
        foliageSettings->SetBillboardTwoSided(true);
        foliageSettings->SetBillboardUseVisibilityWeights(true);
        foliageSettings->SetSeparateFoliageTriangleRatio(0.5f);
    
        foliageProcessor->RunProcessing();
    
        spMappingImage foliageMappingImage = foliageProcessor->GetMappingImage();
    
    
        ///////////////////////////////////////////////////////////////////////////////////////////////
        // cast materials
    
        spMaterialTable originalMaterialTable = originalScene->GetMaterialTable();
        spTextureTable originalTextures = originalScene->GetTextureTable();
    
        // Now, for each channel, we want to cast the input materials into a single output material, with one texture per channel. 
        // First, clear the lod materials (as they are copies from the original initially)
    
        spMaterialTable lodMaterialTable = lodScene->GetMaterialTable();
        spTextureTable lodTextureTable = lodScene->GetTextureTable();
    
        // Get the newly created foliage material 
        spMaterial foliageMaterial = lodMaterialTable->GetMaterial(foliageProcessor->GetFoliageMaterialID());
    
        // Cast diffuse and specular texture data with a color caster
        {
        // Cast the data using a color caster
        spColorCaster colorCaster = sg->CreateColorCaster();
        colorCaster->SetSourceMaterials(originalMaterialTable);
        colorCaster->SetSourceTextures(originalTextures);
        colorCaster->SetMappingImage(foliageMappingImage); //The mapping image we got from the reduction process.
        colorCaster->SetOutputChannelBitDepth(8); //8 bits per channel. So in this case we will have 24bit colors RGB.
        colorCaster->SetDilation(10); //To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well.
        colorCaster->SetBakeOpacityInAlpha(false);
        colorCaster->SetUseMultisampling(true);
        colorCaster->SetFillMode(SG_ATLASFILLMODE_INTERPOLATE);
        colorCaster->SetOutputSRGB(true);
    
        colorCaster->SetColorType(SG_MATERIAL_CHANNEL_DIFFUSE);
        colorCaster->SetOutputChannels(3); //RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.)
        colorCaster->SetOutputFilePath("BillboardsDiffuseMap.png"); //Where the texture map will be saved to file.
        colorCaster->RunProcessing(); //Do the actual casting and write to texture.
    
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_DIFFUSE, "BillboardsDiffuseMap.png");
        }
    
        // Cast normal map texture data with the normal caster. This also compensates for any geometric errors that have appeared in the reduction process.
        {
        // cast the data using a normal caster
        spNormalCaster normalCaster = sg->CreateNormalCaster();
        normalCaster->SetSourceMaterials(originalMaterialTable);
        normalCaster->SetSourceTextures(originalTextures);
        normalCaster->SetMappingImage(foliageMappingImage);
        normalCaster->SetOutputChannels(3); // RGB, 3 channels! (But really the x, y and z values for the normal)
        normalCaster->SetOutputChannelBitDepth(8);
        normalCaster->SetDilation(10);
        normalCaster->SetOutputFilePath("BillboardsNormalMap.png");
        normalCaster->SetFlipBackfacingNormals(false);
        normalCaster->SetGenerateTangentSpaceNormals(true);
        normalCaster->RunProcessing();
    
        // Set normal map of the created material to point to the combined normal map
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_NORMALS, "BillboardsNormalMap.png");
        }
    
        // Cast normal map texture data with the normal caster. This also compensates for any geometric errors that have appeared in the reduction process.
        {
        // cast the data using a normal caster
        spOpacityCaster opacityCaster = sg->CreateOpacityCaster();
        opacityCaster->SetSourceMaterials(originalMaterialTable);
        opacityCaster->SetSourceTextures(originalTextures);
        opacityCaster->SetMappingImage(foliageMappingImage);
        opacityCaster->SetOutputChannels(1); // RGB, 3 channels! (But really the x, y and z values for the normal)
        opacityCaster->SetOutputChannelBitDepth(8);
        opacityCaster->SetOutputFilePath("BillboardsOpacityMap.png");
        opacityCaster->SetDilation(0);
        opacityCaster->SetFillMode(SG_ATLASFILLMODE_NONE); //Important to set to NONE so that the opacity just covers the geometry projected on the billboard
        opacityCaster->RunProcessing();
    
        // Set normal map of the created material to point to the combined normal map
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_OPACITY, "BillboardsOpacityMap.png");
        }
    
        // END CASTING
        ///////////////////////////////////////////////////////////////////////////////////////////////
    
        //Create an .obj exporter to save our result
        spWavefrontExporter objExporter = sg->CreateWavefrontExporter();
    
        // Generate the output filenames
        std::string outputGeomFilename = GetExecutablePath() + writeTo + ".obj";
    
        // Do the actual exporting
        objExporter->SetExportFilePath(outputGeomFilename.c_str());
        objExporter->SetScene(lodScene); //This is the geometry we set as the processing geom of the reducer, retaining the materials in the original scene
        objExporter->RunExport();
        }
    
    
    void RunExampleFlipbook(const std::string& readFrom, const std::string& writeTo)
        {
        std::string exePath = GetExecutablePath();
        std::string outputGeometryFilename = exePath + writeTo + ".obj";
    
        //Load object from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetUseAlphaAsOpacity(true);
        objReader->SetImportFilePath(readFrom.c_str());
        if (!objReader->RunImport())
            throw std::exception("Failed to load input file!");
    
        //Get the scene
        spScene originalScene = objReader->GetScene();
        spScene lodScene = sg->CreateScene();
        lodScene->DeepCopy(originalScene);
    
        spFoliageProcessor foliageProcessor = sg->CreateFoliageProcessor();
        foliageProcessor->SetScene(lodScene);
        foliageProcessor->GetMappingImageSettings()->SetWidth(256); //The dimension is set per view (so with 9 = 3x3 views we get 3*256 = 768 pixels
        foliageProcessor->GetMappingImageSettings()->SetHeight(256);
        foliageProcessor->GetMappingImageSettings()->SetMaximumLayers(10);
        foliageProcessor->GetMappingImageSettings()->SetMultisamplingLevel(2);
    
        // Set the Repair Settings.
        spFoliageSettings foliageSettings = foliageProcessor->GetFoliageSettings();
        foliageSettings->SetFoliageType(SG_FOLIAGETYPE_FLIPBOOK);
        foliageSettings->SetFlipbookNumberOfViews(9);
        foliageSettings->SetFlipbookVerticalAngleInRadians(0.0f);
    
        foliageProcessor->RunProcessing();
        spMappingImage foliageMappingImage = foliageProcessor->GetMappingImage();
    
        ///////////////////////////////////////////////////////////////////////////////////////////////
        // cast materials
    
        spMaterialTable originalMaterialTable = originalScene->GetMaterialTable();
        spTextureTable originalTextures = originalScene->GetTextureTable();
    
        // Now, for each channel, we want to cast the input materials into a single output material, with one texture per channel. 
        // First, clear the lod materials (as they are copies from the original initially)
    
        spMaterialTable lodMaterialTable = lodScene->GetMaterialTable();
        spTextureTable lodTextureTable = lodScene->GetTextureTable();
        lodMaterialTable->Clear();
        lodTextureTable->Clear();
    
        // Get the newly created foliage material 
        spMaterial foliageMaterial = sg->CreateMaterial();
        foliageMaterial->SetName("FlipbookMaterial");
        lodMaterialTable->AddMaterial(foliageMaterial);
    
        // Cast diffuse and specular texture data with a color caster
        {
        // Cast the data using a color caster
        spColorCaster colorCaster = sg->CreateColorCaster();
        colorCaster->SetSourceMaterials(originalMaterialTable);
        colorCaster->SetSourceTextures(originalTextures);
        colorCaster->SetMappingImage(foliageMappingImage); //The mapping image we got from the reduction process.
        colorCaster->SetOutputChannelBitDepth(8); //8 bits per channel. So in this case we will have 24bit colors RGB.
        colorCaster->SetDilation(10); //To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well.
        colorCaster->SetBakeOpacityInAlpha(false);
        colorCaster->SetUseMultisampling(true);
        colorCaster->SetFillMode(SG_ATLASFILLMODE_INTERPOLATE);
        colorCaster->SetOutputSRGB(true);
    
        colorCaster->SetColorType(SG_MATERIAL_CHANNEL_DIFFUSE);
        colorCaster->SetOutputChannels(3); //RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.)
        colorCaster->SetOutputFilePath("FlipbookDiffuseMap.png"); //Where the texture map will be saved to file.
        colorCaster->RunProcessing(); //Do the actual casting and write to texture.
    
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_DIFFUSE, "FlipbookDiffuseMap.png");
        }
    
        // Cast normal map texture data with the normal caster. This also compensates for any geometric errors that have appeared in the reduction process.
        {
        // cast the data using a normal caster
        spNormalCaster normalCaster = sg->CreateNormalCaster();
        normalCaster->SetSourceMaterials(originalMaterialTable);
        normalCaster->SetSourceTextures(originalTextures);
        normalCaster->SetMappingImage(foliageMappingImage);
        normalCaster->SetOutputChannels(3); // RGB, 3 channels! (But really the x, y and z values for the normal)
        normalCaster->SetOutputChannelBitDepth(8);
        normalCaster->SetDilation(10);
        normalCaster->SetOutputFilePath("FlipbookNormalMap.png");
        normalCaster->SetFlipBackfacingNormals(false);
        normalCaster->SetGenerateTangentSpaceNormals(false);
        normalCaster->RunProcessing();
    
        // Set normal map of the created material to point to the combined normal map
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_NORMALS, "FlipbookNormalMap.png");
        }
    
        // Cast normal map texture data with the normal caster. This also compensates for any geometric errors that have appeared in the reduction process.
        {
        // cast the data using a normal caster
        spOpacityCaster opacityCaster = sg->CreateOpacityCaster();
        opacityCaster->SetSourceMaterials(originalMaterialTable);
        opacityCaster->SetSourceTextures(originalTextures);
        opacityCaster->SetMappingImage(foliageMappingImage);
        opacityCaster->SetOutputChannels(1); // RGB, 3 channels! (But really the x, y and z values for the normal)
        opacityCaster->SetOutputChannelBitDepth(8);
        opacityCaster->SetOutputFilePath("FlipbookOpacityMap.png");
        opacityCaster->SetDilation(0);
        opacityCaster->SetFillMode(SG_ATLASFILLMODE_NONE); //Important to set to NONE so that the opacity just covers the geometry projected on the billboard
        opacityCaster->RunProcessing();
    
        // Set normal map of the created material to point to the combined normal map
        AddSimplygonTexture(foliageMaterial, lodTextureTable, SG_MATERIAL_CHANNEL_OPACITY, "FlipbookOpacityMap.png");
        }
    
        // END CASTING
        ///////////////////////////////////////////////////////////////////////////////////////////////
    
        //Store the finished processed scene
        spWavefrontExporter objexp = sg->CreateWavefrontExporter();
        objexp->SetExportFilePath(outputGeometryFilename.c_str());
        objexp->SetScene(lodScene);
        objexp->RunExport();
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft