Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      CastingWithBlendingExample.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# 
    //
    //  Run a reduction process on a geometry that has a multi layered material.
    //  The multi layered material has multiple textures and a blend type for 
    //  how each should blend (add/multiply/subtract etc.).
    //  Then perform a material cast onto the LOD, where the multi layered
    //  material is baked into a single texture.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    
    void MultiLayeredTextureMapping( 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();
    
            // Run the example code
            MultiLayeredTextureMapping(assetPath + "multi.obj", "multi_out");
    
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    void MultiLayeredTextureMapping( const std::string& readFrom, const std::string& writeTo )
        {
        // Run a reduction process on a geometry that has a multi layered material.
        // Then perform a material cast onto the LOD, where the multi layered
        // material is baked into a single texture.
    
        std::string assetPath = GetAssetPath();
        std::string exePath = GetExecutablePath();
    
        std::string output_geometry_filename = exePath + writeTo + ".obj";
        std::string output_diffuse_filename = exePath + writeTo + "_diffuse.png";
        std::string output_normals_filename = exePath + writeTo + "_normals.png";
    
        // Load from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetImportFilePath( readFrom.c_str() );
        if( !objReader->RunImport() )
            throw std::exception("Failed to load input file!");
    
        spScene scene = objReader->GetScene();
        spMaterialTable sceneMaterials = scene->GetMaterialTable();
        spTextureTable sceneTextures = scene->GetTextureTable();
    
        sceneMaterials->Clear();
        sceneTextures->Clear();
    
        spMaterial diffuseMaterial = sg->CreateMaterial();
    
        //set the number of layers the diffuse channel will use
        spShadingLayeredBlendNode diffuseExitNode = sg->CreateShadingLayeredBlendNode();
        diffuseExitNode->SetInputCount( 4 );
    
        diffuseMaterial->SetShadingNetwork( SG_MATERIAL_CHANNEL_DIFFUSE, diffuseExitNode );
    
        if( true )
            {
            std::string diffuseBaseFile = assetPath + "base.jpg";
    
            //import diffuse layer 0 texture (base)
            spImageDataImporter imp = sg->CreateImageDataImporter();
            imp->SetImportFilePath( diffuseBaseFile.c_str() );
            if( !imp->RunImport() )
                throw std::exception("Failed to load input file!");
    
            spTexture tex = sg->CreateTexture();
            tex->SetName( "base" );
            tex->SetImageData( imp->GetImage() );
            sceneTextures->AddTexture( tex );
    
            spShadingTextureNode texNode = sg->CreateShadingTextureNode();
            texNode->SetTextureName( "base" );
            texNode->SetTextureWrapMode(SG_TEXTUREWRAPMODE_CLAMP);
            texNode->SetTextureLevel( 0 );
    
            //set the diffuse material layer 0 (base texture)
            diffuseExitNode->SetInput( 0, texNode );
            diffuseExitNode->SetPerInputBlendType( 0, SG_TEXTUREBLEND_REPLACE );
            }
        if( true )
            {
            std::string diffuseAddFile = assetPath + "add.jpg";
    
            //import diffuse layer 1
            spImageDataImporter imp = sg->CreateImageDataImporter();
            imp->SetImportFilePath( diffuseAddFile.c_str() );
            if( !imp->RunImport() )
                throw std::exception("Failed to load input file!");
    
            spTexture tex = sg->CreateTexture();
            tex->SetName( "add" );
            tex->SetImageData( imp->GetImage() );
            sceneTextures->AddTexture( tex );
    
            spShadingTextureNode texNode = sg->CreateShadingTextureNode();
            texNode->SetTextureName( "add" );
            texNode->SetTextureWrapMode(SG_TEXTUREWRAPMODE_CLAMP);
            texNode->SetTextureLevel( 0 );
    
            //set the diffuse material layer 1 
            diffuseExitNode->SetInput( 1, texNode );
            diffuseExitNode->SetPerInputBlendType( 1, SG_TEXTUREBLEND_ADD );
            }
        if( true )
            {
            std::string diffuseSubtractFile = assetPath + "subtract.jpg";
    
            //load layer 2 texture
            spImageDataImporter imp = sg->CreateImageDataImporter();
            imp->SetImportFilePath( diffuseSubtractFile.c_str() );
            if( !imp->RunImport() )
                throw std::exception("Failed to load input file!");
    
            spTexture tex = sg->CreateTexture();
            tex->SetName( "sub" );
            tex->SetImageData( imp->GetImage() );
            sceneTextures->AddTexture( tex );
    
            spShadingTextureNode texNode = sg->CreateShadingTextureNode();
            texNode->SetTextureName( "sub" );
            texNode->SetTextureWrapMode(SG_TEXTUREWRAPMODE_CLAMP);
            texNode->SetTextureLevel( 0 );
    
            //set the diffuse material layer 1 
            diffuseExitNode->SetInput( 2, texNode );
            diffuseExitNode->SetPerInputBlendType( 2, SG_TEXTUREBLEND_SUBTRACT );
            }
        if( true )
            {
            std::string diffuseMultiplyFile = assetPath + "multiply.jpg";
    
            //load layer 3 texture
            spImageDataImporter imp = sg->CreateImageDataImporter();
            imp->SetImportFilePath( diffuseMultiplyFile.c_str() );
            if( !imp->RunImport() )
                throw std::exception("Failed to load input file!");
    
            spTexture tex = sg->CreateTexture();
            tex->SetName( "mult" );
            tex->SetImageData( imp->GetImage() );
            sceneTextures->AddTexture( tex );
    
            spShadingTextureNode texNode = sg->CreateShadingTextureNode();
            texNode->SetTextureName( "mult" );
            texNode->SetTextureWrapMode(SG_TEXTUREWRAPMODE_CLAMP);
            texNode->SetTextureLevel( 0 );
    
            //set the diffuse material layer 1 
            diffuseExitNode->SetInput( 3, texNode );
            diffuseExitNode->SetPerInputBlendType( 3, SG_TEXTUREBLEND_MULTIPLY );
            }
    
        sceneMaterials->AddMaterial( diffuseMaterial );
    
        spReductionProcessor red = sg->CreateReductionProcessor();
        red->SetScene( scene );
    
    
        // Find length of the diagonal of the geometry.
        scene->CalculateExtents();
    
        float inf[3], sup[3];
        scene->GetInf( inf );
        scene->GetSup( sup );
    
        float geom_diameter = 0.0f;
        geom_diameter += (inf[0] - sup[0])*(inf[0] - sup[0]);
        geom_diameter += (inf[1] - sup[1])*(inf[1] - sup[1]);
        geom_diameter += (inf[2] - sup[2])*(inf[2] - sup[2]);
    
        geom_diameter = sqrt( geom_diameter );
    
        // Set the Repair Settings.
        spRepairSettings repair_settings = red->GetRepairSettings();
        // Will take care of holes that are of size 0.2 or less, so small gaps etc are removed.
        repair_settings->SetWeldDist( 0.2f );
        repair_settings->SetTjuncDist( 0.2f );
    
        // Set the Reduction Settings.
        spReductionSettings reduction_settings = red->GetReductionSettings();
    
        // The geometry will be reduced to be optimally displayed when the diagonal on-screen-size is around 40 pixels
        // or less. More in detail: the max error of the geometry will be one hundredth of the geometry's size.
        reduction_settings->SetMaxDeviation( geom_diameter / 40.f );
    
        // Set the Normal Calculation Settings.
        spNormalCalculationSettings normal_settings = red->GetNormalCalculationSettings();
        normal_settings->SetReplaceNormals( true );
        normal_settings->SetHardEdgeAngleInRadians( 3.14159f * 90.f / 180.0f );
    
        // Set the Image Mapping Settings.
        spMappingImageSettings mapping_settings = red->GetMappingImageSettings();
        // Without this we cannot fetch data from the original geometry, and thus not
        // generate diffuse and normalmaps later on.
        mapping_settings->SetGenerateMappingImage( true );
    
        // Set to generate new texture coordinates.
        mapping_settings->SetUseFullRetexturing( true );
        mapping_settings->SetGenerateTexCoords( true );
        // The higher the number, the fewer texture-borders.
        mapping_settings->SetParameterizerMaxStretch( 0.6f );
        // Buffer space for when texture is mip-mapped, so color values dont blend over.
        mapping_settings->SetGutterSpace( 4 );
    
        mapping_settings->SetWidth( 512 );
        mapping_settings->SetHeight( 512 );
        mapping_settings->SetMultisamplingLevel( 2 );
    
        red->RunProcessing();
    
        // Mapping image is needed later on for texture casting.
        spMappingImage mapping_image = red->GetMappingImage();
    
        // Cast diffuse texture and normal map data into a new material
        // Create new material table.
        spMaterialTable output_materials = sg->CreateMaterialTable();
        spTextureTable output_textures = sg->CreateTextureTable();
        //  Create new material for the table.
        spMaterial output_material = sg->CreateMaterial();
        output_material->SetName( "example_material" );
        output_materials->AddMaterial( output_material );
    
        // Cast diffuse texture data
        {
        // Cast the data using a color caster
        spColorCaster cast = sg->CreateColorCaster();
        cast->SetColorType( SG_MATERIAL_CHANNEL_DIFFUSE );
        cast->SetSourceMaterials( sceneMaterials );
        cast->SetSourceTextures( sceneTextures );
        cast->SetMappingImage( mapping_image ); // The mapping image we got from the remeshing process.
        cast->SetOutputChannels( 3 ); // RGB, 3 channels! (1 would be for gray 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 as well.
        cast->SetOutputFilePath( output_diffuse_filename.c_str() ); // Where the texture map will be saved to file.
        cast->RunProcessing(); // Fetch!
    
        // Set material to point to created texture filename.
        AddSimplygonTexture( output_material, output_textures, SG_MATERIAL_CHANNEL_DIFFUSE, output_diffuse_filename.c_str() );
        }
    
        //Copy the new material table to the reduced scene
        scene->GetMaterialTable()->Copy( output_materials );
        scene->GetTextureTable()->Copy( output_textures );
    
        spWavefrontExporter objexp = sg->CreateWavefrontExporter();
    
        objexp->SetExportFilePath( output_geometry_filename.c_str() );
        objexp->SetScene( scene );
        objexp->RunExport();
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft