Skip to content
This repository has been archived by the owner on Feb 11, 2024. It is now read-only.

Tutorial 3

Henry de Jongh edited this page Mar 5, 2018 · 1 revision

Coding With SabreCSG

SabreCSG is primarily a level creation tool to be used inside Unity. In addition to that however, it’s possible to create brushes, manipulate them and build geometry in the editor through scripting. This is a quick guide to how that works.

Please note: this feature is considered beta so if you have any feedback please let us know and we’ll integrate improvements as quickly as we can.

Core Classes

A quick overview of the classes you’ll work with in order to use SabreCSG programatically. This is in a top down order, where each class object can hold several of the following (the CSGModel can hold many brushes, which in turn hold multiple polygons which are made up of multiple vertices).

CSGModel

The CSGModel is a representation that stores a series of brushes as well as build settings and contextual information. The CSGModel must be created in order to add brushes and build them into final geometry.

PrimitiveBrush

A primitive brush holds a series of polygons that make up a convex 3D shape, it also holds whether the brush is additive or subtractive as well as other settings like if it should have collision.

Polygon

A polygon is a flat shape that contains multiple vertices.

Vertex

A vertex is a point in space that holds: its 3D position, it’s direction (surface normal) and a mapping to a texture coordinate (UV).

Simple Example

using Sabresaurus.SabreCSG;
using UnityEngine;
 
public class CSGExampleScript : MonoBehaviour 
{
	[ContextMenu("Execute")]
	void Execute()
	{
		// Grab or create the CSG model
		CSGModel csgModel = FindObjectOfType<CSGModel>();
		if(csgModel == null)
		{
			GameObject csgModelGameObject = new GameObject("CSGModel");
			csgModel = csgModelGameObject.AddComponent<CSGModel>();
		}
 
		// Remove any existing brushes beneath it
		csgModel.transform.DestroyChildrenImmediate();
 
		// Create a brush
		GameObject brushObject = new GameObject("Brush");
		// Anchor the brush beneath the CSG Model
		brushObject.transform.parent = csgModel.transform;
 
		PrimitiveBrush brushComponent = brushObject.AddComponent<PrimitiveBrush>();
 
		Polygon[] polygons = PolygonFactory.GeneratePrism(6);
 
		// Change the polygons on the brush
		brushComponent.SetPolygons(polygons);
 
		csgModel.Build();
	}
}

If you add this script to a game object you will then be able to run it at editor type by clicking the cog from the Inspector and selecting “Execute”.

You should then see a prism appear with built geometry:

Another Example

A slightly more complicated example would be to create a series of brushes and then programatically move them, in this case in to a horizontal circle of 8. The only change in the below code from the previous code example is the new for loop.

using Sabresaurus.SabreCSG;
using UnityEngine;
 
public class CSGExampleScript : MonoBehaviour 
{
	[ContextMenu("Execute")]
	void Execute()
	{
		// Grab or create the CSG model
		CSGModel csgModel = FindObjectOfType<CSGModel>();
		if(csgModel == null)
		{
			GameObject csgModelGameObject = new GameObject("CSGModel");
			csgModel = csgModelGameObject.AddComponent<CSGModel>();
		}
 
		// Remove any existing brushes beneath it
		csgModel.transform.DestroyChildrenImmediate();
 
		for (int i = 0; i < 8; i++) 
		{
			// Create a brush
			GameObject brushObject = new GameObject("Brush");
			// Anchor the brush beneath the CSG Model
			brushObject.transform.parent = csgModel.transform;
 
			float angle = i * (360f / 8);
			brushObject.transform.position = Quaternion.Euler(0,angle,0) * Vector3.forward * 3;
 
			PrimitiveBrush brushComponent = brushObject.AddComponent<PrimitiveBrush>();
 
			Polygon[] polygons = PolygonFactory.GenerateCube();
 
			// Change the polygons on the brush
			brushComponent.SetPolygons(polygons);
		}
 
		csgModel.Build();
	}
}

Running this code through the same method as above will produce something like this:

Notes

Polygons cache their plane when created for performance reasons. So if you modify vertex positions after creating the polygon you should call polygon.CalculatePlane() to recalculate the plane, or instead provide the new vertices via polygon.SetVertices() which automatically calls CalculatePlane itself.

Vertices track their own surface normal (so that you can have smooth normals on cylinders, or faceted normals on prisms). So if you modify vertex positions you will need to update the surface normal too. For faceted polygons you can just call polygon.ResetVertexNormals()

In the future we hope to add support for building brushes at runtime too (wiki author note: this may already be the case).

More Examples

Example Script 1 - A simple example of using runtime CSG.

Example Script 2 - Another example showing a simple maze-like generator.