ProceduralSystems are the core execution units in the Infinity Engine - complete directed acyclic graphs of interconnected components that generate procedural content. This tutorial covers everything you need to know about configuring inputs, controlling execution, and working with outputs.
Understanding Procedural Systems
A ProceduralSystem represents a complete workflow:
- Input ports: Parameters and data the system needs to operate
- Internal components: Connected graph of processing components
- Output ports: Generated results available after execution
- Execution model: Dependency-ordered component execution
- Random seed: Reproducible generation control
Basic System Operations
Loading and Inspecting a System
#include <Infinity/Engine/InfinityEngine.h>
#include <Infinity/Types/All.hpp>
void inspectSystem() {
auto system = engine.system("TerrainGenerator");
if (!system) {
std::cerr << "System not found!" << std::endl;
return;
}
std::cout << "System ID: " << system->id() << std::endl;
std::cout << "System loaded and ready for configuration" << std::endl;
}
Main entry point to the InfinityEngine API for procedural generation.
Definition InfinityEngine.hpp:26
INFINITY_API_PUBLIC void InfinityInit(void)
Initializes the Infinity Engine.
Setting Input Parameters
void configureSystemInputs() {
auto system = engine.system("TerrainGenerator");
system->setIn("Resolution", 1024);
system->setIn("Scale", 50.0f);
system->setIn("EnableErosion", true);
system->setIn("TerrainName", std::string("MyTerrain"));
system->setIn("Offset", Vec3(10.0f, 0.0f, 15.0f));
Array2D heightmapData(256, 256, 0.0f);
system->setIn("InputHeightmap", std::move(heightmapData));
}
Two-dimensional array container for grid-based data in procedural generation.
Definition Array2D.hpp:82
t_Vector3< float > Vector3
Alias for t_Vector3<float>, the default 3D vector type.
Definition Vector3.hpp:580
Executing the System
void executeSystem() {
auto system = engine.system("TerrainGenerator");
try {
system->setIn("Resolution", 512);
system->setIn("Scale", 100.0f);
system->setSeed(12345);
std::cout << "Executing system..." << std::endl;
auto start = std::chrono::high_resolution_clock::now();
system->execute();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Execution completed in " << duration.count() << " ms" << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Execution failed: " << e.what() << std::endl;
}
}
Retrieving Output Data
void retrieveSystemOutputs() {
auto system = engine.system("TerrainGenerator");
system->setIn("Resolution", 256);
system->setSeed(54321);
system->execute();
try {
using Texture = Infinity::Types::Rendering::Texture;
const auto& terrainMesh = system->getOut<Mesh>("TerrainMesh");
std::cout <<
"Generated mesh with " << terrainMesh.vertexBuffer.positions.
size()
<< " vertices" << std::endl;
const auto& heightmap = system->getOut<Array2D>("Heightmap");
std::cout << "Heightmap dimensions: " << heightmap.width() << "x"
<< heightmap.height() << std::endl;
const auto& colorMap = system->getOut<Texture>("Albedo");
std::cout << "Color texture: " << colorMap.width() << "x" << colorMap.height()
<< ", " << colorMap.channels << " channels" << std::endl;
float actualScale = system->getOut<float>("ActualScale");
int triangleCount = system->getOut<int>("TriangleCount");
std::cout << "Generated " << triangleCount << " triangles at scale "
<< actualScale << std::endl;
}
catch (const std::bad_cast& e) {
std::cerr << "Output type mismatch: " << e.what() << std::endl;
}
catch (const std::runtime_error& e) {
std::cerr << "Output retrieval error: " << e.what() << std::endl;
}
}
size_t size() const noexcept override
Gets the number of elements in the array.
Definition Array.hpp:696
Complete 3D geometry definition with vertices, indices, and material partitioning.
Definition Mesh.hpp:135
Random Seed Management
Basic Seed Control
void demonstrateSeedControl() {
auto system = engine.system("TerrainGenerator");
system->setIn("Resolution", 256);
system->setIn("Scale", 50.0f);
system->setSeed(12345);
system->execute();
system->setSeed(12345);
system->execute();
bool identical = (result1.width() == result2.width() &&
result1.height() == result2.height());
if (identical) {
for (size_t i = 0; i < result1.width() * result1.height() && identical; ++i) {
identical = (result1.data()[i] == result2.data()[i]);
}
}
std::cout << "Results with same seed are " << (identical ? "identical" : "different")
<< std::endl;
}
Systematic Seed Variation
void generateVariations() {
auto system = engine.system("TerrainGenerator");
system->setIn("Resolution", 128);
system->setIn("Scale", 25.0f);
std::vector<uint64_t> seeds = {1000, 2000, 3000, 4000, 5000};
for (size_t i = 0; i < seeds.size(); ++i) {
std::cout << "Generating variation " << (i + 1) << " with seed " << seeds[i] << std::endl;
system->setSeed(seeds[i]);
system->execute();
<< " vertices" << std::endl;
}
}
VertexBuffer vertexBuffer
Vertex attribute data for the mesh.
Definition Mesh.hpp:143
Containers::Array< Infinity::Types::Math::Vector3 > positions
Vertex positions in object/local space.
Definition VertexBuffer.hpp:117
Loop Configuration
Integer Range Loops
NOTE that the system looping feature is actively under development and subject to change.
void demonstrateIntegerLoops() {
auto system = engine.system("BatchTerrainGenerator");
system->setIn("BaseScale", 50.0f);
system->setIn("Resolution", 256);
bool loopSet = system->setLoop(0, 10, 1);
if (!loopSet) {
std::cerr << "Failed to configure loop" << std::endl;
return;
}
system->setSeed(12345);
system->execute();
std::cout << "Batch generation completed" << std::endl;
system->clearLoop();
}
Advanced Usage Patterns
Conditional System Configuration
void configureDynamicSystem() {
auto system = engine.system("AdaptiveTerrainGenerator");
enum class QualityLevel { Low, Medium, High, Ultra };
QualityLevel targetQuality = QualityLevel::High;
switch (targetQuality) {
case QualityLevel::Low:
system->setIn("Resolution", 128);
system->setIn("Subdivisions", 2);
system->setIn("EnableDetailPasses", false);
break;
case QualityLevel::Medium:
system->setIn("Resolution", 256);
system->setIn("Subdivisions", 4);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 2);
break;
case QualityLevel::High:
system->setIn("Resolution", 512);
system->setIn("Subdivisions", 6);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 4);
system->setIn("EnableErosion", true);
break;
case QualityLevel::Ultra:
system->setIn("Resolution", 1024);
system->setIn("Subdivisions", 8);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 6);
system->setIn("EnableErosion", true);
system->setIn("EnableVegetation", true);
break;
}
system->setSeed(12345);
system->execute();
std::cout << "Generated terrain at quality level "
<< static_cast<int>(targetQuality) << std::endl;
}
Pipeline System Coordination
void coordinateSystemPipeline() {
auto terrainSystem = engine.system("TerrainGeneration");
auto vegetationSystem = engine.system("VegetationPlacement");
auto weatherSystem = engine.system("WeatherSimulation");
if (!terrainSystem || !vegetationSystem || !weatherSystem) {
std::cerr << "Missing required systems" << std::endl;
return;
}
uint64_t masterSeed = 12345;
std::cout << "Stage 1: Generating terrain..." << std::endl;
terrainSystem->setSeed(masterSeed);
terrainSystem->setIn("WorldSize", 1000.0f);
terrainSystem->setIn("Resolution", 512);
terrainSystem->execute();
std::cout << "Stage 2: Placing vegetation..." << std::endl;
vegetationSystem->setSeed(masterSeed + 1);
vegetationSystem->setIn("TerrainMesh", terrainMesh);
vegetationSystem->setIn("Heightmap", heightmap);
vegetationSystem->setIn("Density", 0.7f);
vegetationSystem->execute();
std::cout << "Stage 3: Generating weather..." << std::endl;
weatherSystem->setSeed(masterSeed + 2);
weatherSystem->setIn("Terrain", terrainMesh);
weatherSystem->setIn("Temperature", 15.0f);
weatherSystem->execute();
std::cout << "World generation pipeline completed" << std::endl;
}
Error Handling and Debugging
Comprehensive Error Handling
void robustSystemExecution() {
try {
auto system = engine.system("ComplexGenerator");
if (!system) {
throw std::runtime_error("Required system not found");
}
try {
system->setIn("Resolution", 512);
system->setIn("Scale", 100.0f);
system->setSeed(12345);
}
catch (const std::exception& e) {
std::cerr << "Input configuration failed: " << e.what() << std::endl;
throw;
}
std::cout << "Starting system execution..." << std::endl;
auto startTime = std::chrono::steady_clock::now();
system->execute();
auto endTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime);
if (duration.count() > 30) {
std::cerr << "Warning: Execution took " << duration.count() << " seconds" << std::endl;
}
try {
if (mesh.vertexBuffer.positions.empty()) {
std::cerr << "Warning: Generated mesh is empty" << std::endl;
} else {
std::cout << "Successfully generated mesh with "
}
}
catch (const std::bad_cast& e) {
std::cerr << "Output type validation failed: " << e.what() << std::endl;
}
}
catch (const std::runtime_error& e) {
std::cerr << "System execution failed: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Unknown error during system execution" << std::endl;
}
}
Best Practices
- Always validate system existence before configuration
- Set inputs before calling execute() - order matters
- Use consistent seed management for reproducible results
- Handle execution exceptions gracefully
- Verify output types match your expectations
- Clear loops when switching between different execution modes
- Cache expensive system results when appropriate
- Monitor execution time for performance optimization
- Use meaningful variable names for clarity
- Document system dependencies when coordinating multiple systems
Troubleshooting
Input configuration fails:
- Verify input port names match the system definition
- Check input data types are compatible
- Ensure required inputs are provided
Execution hangs or fails:
- Check for missing input dependencies
- Verify all component plugins are available
Output retrieval fails:
- Ensure execute() completed successfully
- Verify output port names and types
- Check that the system actually produces the expected outputs
Inconsistent results:
- Verify seed is being set consistently
- Check for unintended input variations
Next Steps
Now that you understand system operations: