# Simplygon Grid
In Simplygon 9 we have simplified Grid and has removed a lot of overhead. Instead of a server/client based approach, Grid is now using mDNS broadcast to locate Grid agents.
To submit a processing job to available Grid agents on your network, all you need to do is to create a pipeline using C++, C# or Python or use the Simplygon UI in our integrations and select Grid as the distribution target.
Here is an example of a simple batch script using Grid.
This example shows how to do batch processing using Simplygon Grid.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include <string>
#include <stdlib.h>
#include <filesystem>
#include <future>
#include "SimplygonLoader.h"
void CheckLog(Simplygon::ISimplygon* sg)
{
// Check if any errors occurred.
bool hasErrors = sg->ErrorOccurred();
if (hasErrors)
{
Simplygon::spStringArray errors = sg->CreateStringArray();
sg->GetErrorMessages(errors);
auto errorCount = errors->GetItemCount();
if (errorCount > 0)
{
printf("%s\n", "Errors:");
for (auto errorIndex = 0U; errorIndex < errorCount; ++errorIndex)
{
Simplygon::spString errorString = errors->GetItem((int)errorIndex);
printf("%s\n", errorString.c_str());
}
sg->ClearErrorMessages();
}
}
else
{
printf("%s\n", "No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg->WarningOccurred();
if (hasWarnings)
{
Simplygon::spStringArray warnings = sg->CreateStringArray();
sg->GetWarningMessages(warnings);
auto warningCount = warnings->GetItemCount();
if (warningCount > 0)
{
printf("%s\n", "Warnings:");
for (auto warningIndex = 0U; warningIndex < warningCount; ++warningIndex)
{
Simplygon::spString warningString = warnings->GetItem((int)warningIndex);
printf("%s\n", warningString.c_str());
}
sg->ClearWarningMessages();
}
}
else
{
printf("%s\n", "No warnings.");
}
}
void RunReduction(Simplygon::ISimplygon* sg, std::string inputFile, std::string outputFile)
{
// Create the reduction pipeline.
Simplygon::spReductionPipeline sgReductionPipeline = sg->CreateReductionPipeline();
Simplygon::spReductionSettings sgReductionSettings = sgReductionPipeline->GetReductionSettings();
// Set reduction target to triangle ratio with a ratio of 50%.
sgReductionSettings->SetReductionTargets( Simplygon::EStopCondition::All, true, false, false, false );
sgReductionSettings->SetReductionTargetTriangleRatio( 0.5f );
// Start the reduction pipeline.
printf("%s\n", "Start the reduction pipeline.");
sgReductionPipeline->RunSceneFromFile(inputFile.c_str(), outputFile.c_str(), Simplygon::EPipelineRunMode::RunDistributedUsingSimplygonGrid);
// Check log for any warnings or errors.
printf("%s\n", "Check log for any warnings or errors.");
CheckLog(sg);
}
int main()
{
Simplygon::ISimplygon* sg = NULL;
Simplygon::EErrorCodes initval = Simplygon::Initialize( &sg );
if( initval != Simplygon::EErrorCodes::NoError )
{
printf( "Failed to initialize Simplygon: ErrorCode(%d)", (int)initval );
return int(initval);
}
std::vector<std::future<void>> jobs;
for(auto& itr: std::filesystem::recursive_directory_iterator("../../../Assets/"))
{
if (itr.path().extension().compare(".glb") != 0)
continue;
std::string inputFile = itr.path().generic_u8string();
std::string outputFile = itr.path().stem().concat("_LOD").concat( itr.path().extension().generic_u8string() ).generic_u8string();
jobs.push_back( std::async( [](Simplygon::ISimplygon * sg, std::string inputFile, std::string outputFile)
{
RunReduction(sg, inputFile, outputFile);
}, sg, inputFile, outputFile ));
}
for(auto& job: jobs)
{
job.wait();
}
Simplygon::Deinitialize(sg);
return 0;
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Threading.Tasks;
public class Program
{
static void CheckLog(Simplygon.ISimplygon sg)
{
// Check if any errors occurred.
bool hasErrors = sg.ErrorOccurred();
if (hasErrors)
{
Simplygon.spStringArray errors = sg.CreateStringArray();
sg.GetErrorMessages(errors);
var errorCount = errors.GetItemCount();
if (errorCount > 0)
{
Console.WriteLine("Errors:");
for (uint errorIndex = 0; errorIndex < errorCount; ++errorIndex)
{
string errorString = errors.GetItem((int)errorIndex);
Console.WriteLine(errorString);
}
sg.ClearErrorMessages();
}
}
else
{
Console.WriteLine("No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg.WarningOccurred();
if (hasWarnings)
{
Simplygon.spStringArray warnings = sg.CreateStringArray();
sg.GetWarningMessages(warnings);
var warningCount = warnings.GetItemCount();
if (warningCount > 0)
{
Console.WriteLine("Warnings:");
for (uint warningIndex = 0; warningIndex < warningCount; ++warningIndex)
{
string warningString = warnings.GetItem((int)warningIndex);
Console.WriteLine(warningString);
}
sg.ClearWarningMessages();
}
}
else
{
Console.WriteLine("No warnings.");
}
}
static void RunReduction(Simplygon.ISimplygon sg, string inputFile, string outputFile)
{
// Create the reduction pipeline.
using Simplygon.spReductionPipeline sgReductionPipeline = sg.CreateReductionPipeline();
using Simplygon.spReductionSettings sgReductionSettings = sgReductionPipeline.GetReductionSettings();
// Set reduction target to triangle ratio with a ratio of 50%.
sgReductionSettings.SetReductionTargets( Simplygon.EStopCondition.All, true, false, false, false );
sgReductionSettings.SetReductionTargetTriangleRatio( 0.5f );
// Start the reduction pipeline.
Console.WriteLine("Start the reduction pipeline.");
sgReductionPipeline.RunSceneFromFile(inputFile, outputFile, Simplygon.EPipelineRunMode.RunDistributedUsingSimplygonGrid);
// Check log for any warnings or errors.
Console.WriteLine("Check log for any warnings or errors.");
CheckLog(sg);
}
static int Main(string[] args)
{
using var sg = Simplygon.Loader.InitSimplygon(out var errorCode, out var errorMessage);
if (errorCode != Simplygon.EErrorCodes.NoError)
{
Console.WriteLine( $"Failed to initialize Simplygon: ErrorCode({(int)errorCode}) {errorMessage}" );
return (int)errorCode;
}
var inputFiles = Directory.EnumerateFiles("../../../Assets/", "*.glb", SearchOption.AllDirectories);
Parallel.ForEach(inputFiles, (inputFile) =>
{
string outputFile = Path.Combine(Path.GetFileNameWithoutExtension(inputFile) + "_LOD" + Path.GetExtension(inputFile));
RunReduction(sg, inputFile, outputFile);
});
return 0;
}
}
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
import math
import os
import sys
import glob
import gc
import threading
from pathlib import Path
from simplygon import simplygon_loader
from simplygon import Simplygon
def CheckLog(sg: Simplygon.ISimplygon):
# Check if any errors occurred.
hasErrors = sg.ErrorOccurred()
if hasErrors:
errors = sg.CreateStringArray()
sg.GetErrorMessages(errors)
errorCount = errors.GetItemCount()
if errorCount > 0:
print("Errors:")
for errorIndex in range(errorCount):
errorString = errors.GetItem(errorIndex)
print(errorString)
sg.ClearErrorMessages()
else:
print("No errors.")
# Check if any warnings occurred.
hasWarnings = sg.WarningOccurred()
if hasWarnings:
warnings = sg.CreateStringArray()
sg.GetWarningMessages(warnings)
warningCount = warnings.GetItemCount()
if warningCount > 0:
print("Warnings:")
for warningIndex in range(warningCount):
warningString = warnings.GetItem(warningIndex)
print(warningString)
sg.ClearWarningMessages()
else:
print("No warnings.")
def RunReduction(sg: Simplygon.ISimplygon, inputFile, outputFile):
# Create the reduction pipeline.
sgReductionPipeline = sg.CreateReductionPipeline()
sgReductionSettings = sgReductionPipeline.GetReductionSettings()
# Set reduction target to triangle ratio with a ratio of 50%.
sgReductionSettings.SetReductionTargets( Simplygon.EStopCondition_All, True, False, False, False )
sgReductionSettings.SetReductionTargetTriangleRatio( 0.5 )
# Start the reduction pipeline.
print("Start the reduction pipeline.")
sgReductionPipeline.RunSceneFromFile(inputFile, outputFile, Simplygon.EPipelineRunMode_RunDistributedUsingSimplygonGrid)
# Check log for any warnings or errors.
print("Check log for any warnings or errors.")
CheckLog(sg)
if __name__ == '__main__':
sg = simplygon_loader.init_simplygon()
if sg is None:
exit(Simplygon.GetLastInitializationError())
jobs = list()
inputFiles = glob.glob('../../../Assets/' + '/**/*.glb', recursive=True)
for inputFile in inputFiles:
outputFile = Path(inputFile).stem + '_LOD' + Path(inputFile).suffix
job = threading.Thread(target=RunReduction, args=(sg, inputFile, outputFile))
jobs.append(job)
job.start()
for job in jobs:
job.join()
sg = None
gc.collect()