Procedural Mesh Guide
Learn how to generate meshes at runtime using S1MAPI's fluent API.
Creating Basic Shapes
The ProceduralMeshBuilder class provides methods for creating common geometric shapes:
Box
// Simple box at origin, 1 meter cube
GameObject cube = new ProceduralMeshBuilder("Cube")
.AddBox(Vector3.zero, Vector3.one)
.Build();
// Box at custom position and size
GameObject box = new ProceduralMeshBuilder("MyBox")
.AddBox(new Vector3(5, 2, 3), new Vector3(2, 1, 3))
.Build();
Sphere
// Low-poly sphere (few subdivisions = blocky)
GameObject lowPolySphere = new ProceduralMeshBuilder("LowPoly")
.AddSphere(Vector3.zero, 0.5f, subdivisions: 4)
.Build();
// Smooth sphere (default subdivisions = 12)
GameObject smoothSphere = new ProceduralMeshBuilder("Smooth")
.AddSphere(new Vector3(0, 1, 0), 1.0f)
.Build();
Cylinder
// Vertical cylinder from point A to B
Vector3 bottom = new Vector3(0, 0, 0);
Vector3 top = new Vector3(0, 3, 0);
GameObject cylinder = new ProceduralMeshBuilder("Pillar")
.AddCylinder(bottom, top, radius: 0.2f, segments: 8)
.Build();
Capsule
// Capsule = cylinder + two hemispheres
Vector3 bottom = new Vector3(0, 0, 0);
Vector3 top = new Vector3(0, 2, 0);
GameObject capsule = new ProceduralMeshBuilder("Capsule")
.AddCapsule(bottom, top, radius: 0.3f)
.Build();
Combining Shapes
Chain multiple shape methods to create complex geometries:
GameObject tower = new ProceduralMeshBuilder("Tower")
.AddCylinder(new Vector3(0, 0, 0), new Vector3(0, 2, 0), 0.3f, 8) // Base cylinder
.AddSphere(new Vector3(0, 2.3f, 0), 0.4f, 6) // Top sphere
.SetColor(Color.gray)
.Build();
Applying Materials and Colors
Set a Specific Material
Material metalMaterial = MaterialPresets.Metal(Color.gray, metallic: 0.9f);
GameObject metalBox = new ProceduralMeshBuilder("MetalBox")
.AddBox(Vector3.zero, Vector3.one)
.SetMaterial(metalMaterial)
.Build();
Set a Solid Color
GameObject redBox = new ProceduralMeshBuilder("RedBox")
.AddBox(Vector3.zero, Vector3.one)
.SetColor(Color.red)
.Build();
// Custom color
Color purple = new Color(0.5f, 0, 0.5f);
GameObject purpleSphere = new ProceduralMeshBuilder("PurpleSphere")
.AddSphere(Vector3.zero, 0.5f)
.SetColor(purple)
.Build();
Flat Shading
Apply flat shading for a low-poly aesthetic:
GameObject lowPolyTree = new ProceduralMeshBuilder("LowPolyTree")
.AddCylinder(new Vector3(0, 0, 0), new Vector3(0, 1, 0), 0.2f, 6) // Trunk
.AddSphere(new Vector3(0, 1.5f, 0), 1.0f, subdivisions: 4) // Foliage
.SetColor(new Color(0.3f, 0.5f, 0.2f))
.ApplyFlatShading()
.Build();
Building Without a GameObject
If you only need the Mesh object (not a GameObject):
Mesh mesh = new ProceduralMeshBuilder("MyMesh")
.AddBox(Vector3.zero, Vector3.one)
.AddSphere(new Vector3(2, 0, 0), 0.5f)
.BuildMesh();
// Use the mesh manually
MeshFilter filter = gameObject.AddComponent<MeshFilter>();
filter.mesh = mesh;
MeshRenderer renderer = gameObject.AddComponent<MeshRenderer>();
renderer.material = MaterialPresets.Opaque(Color.blue);
Example: Complete Object
using S1MAPI.ProceduralMesh;
using S1MAPI.Utils;
using UnityEngine;
public static class ProceduralObjects
{
public static GameObject CreateCrate(Vector3 position, Color woodColor)
{
return new ProceduralMeshBuilder("WoodenCrate")
.AddBox(Vector3.zero, new Vector3(1, 1, 1)) // Main body
.AddBox(new Vector3(0, 0.51f, 0), new Vector3(1.05f, 0.05f, 1.05f)) // Lid rim
.SetColor(woodColor)
.ApplyFlatShading()
.Build();
}
public static GameObject CreateBeacon(Vector3 position)
{
// Metal pole
GameObject beacon = new ProceduralMeshBuilder("Beacon")
.AddCylinder(position, position + Vector3.up * 3, 0.1f, 8)
.SetMaterial(MaterialPresets.Metal(Color.gray))
.Build();
// Glowing light at top
GameObject light = new ProceduralMeshBuilder("BeaconLight")
.AddSphere(position + Vector3.up * 3.2f, 0.2f, 6)
.SetMaterial(MaterialPresets.Emissive(Color.yellow, intensity: 3f))
.Build();
light.transform.SetParent(beacon.transform);
return beacon;
}
}
Performance Tips
Combine shapes: Adding multiple shapes to one builder is more efficient than creating separate meshes.
Use flat shading wisely: Flat shading requires recalculating normals. Apply it only when needed.
Consider vertex limits: Unity's Mesh uses 16-bit indices by default (65,535 vertices). For larger meshes, set
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32.
Next Steps
- Building Guide - Create structured buildings
- GLTF Loading - Import external models
- API Reference - Full API docs