Custom Registerer
Before reading this page, make sure you've read System Overview to understand how prototypes, render signatures, chunks, and pools work together.
BRGRegisterer is an abstract MonoBehaviour base class for building your own instance registration components. It wraps a BRGRegistrationTracker internally, which handles the BRG singleton lifecycle, prototype reference counting, chunk tracking with automatic cleanup, overflow management, and editor support — so your subclass only needs to focus on what to register and where.
For non-MonoBehaviour usage (ECS, static managers, etc.), use BRGRegistrationTracker directly.
Both built-in registerers (BRG GameObject Group and BRG Terrain Registerer) extend this class.
For a working example, see Registerer Example.
Creating a Custom Registerer
Extend BRGRegisterer and implement two methods:
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
namespace BRGInstancedRenderer
{
public class MyRegisterer : BRGRegisterer
{
[SerializeField] GameObject _prefab;
int _protoIndex = -1;
ChunkLink _chunk;
protected override void OnInitialize()
{
// 1. Register your render signature
_protoIndex = RegisterRenderSignatureFromPrefab(_prefab);
if (_protoIndex < 0) return;
// 2. Allocate a chunk
_chunk = AllocChunk();
if (!_chunk.IsValid) return;
// 3. Build instance data
var instances = new NativeArray<InstanceData>(100, Allocator.TempJob);
for (int i = 0; i < 100; i++)
{
instances[i] = new InstanceData
{
position = new float3(i * 2f, 0f, 0f),
rotation = quaternion.identity,
scale = new float3(1f),
signatureIndex = _protoIndex,
color = new Color32(255, 255, 255, 255)
};
}
// 4. Write to the chunk
var bounds = new Bounds(Vector3.zero, new Vector3(200f, 10f, 10f));
WriteChunk(_chunk, instances, bounds);
instances.Dispose();
}
protected override void OnShutdown()
{
// Clean up local state only.
// Do NOT free chunks or unregister render signatures - the base class does that.
_chunk = ChunkLink.Invalid;
_protoIndex = -1;
}
}
}
The base class automatically:
- Acquires the
BRGRenderersingleton - Calls
OnInitialize()on enable,OnShutdown()on disable - Frees all chunks allocated via
AllocChunk()on shutdown - Unregisters all render signatures registered via
RegisterRenderSignatureFromPrefab()on shutdown - Handles editor lifecycle (
[ExecuteAlways]with deferred initialization)
Structs
See BRGRegistrationTracker / Structs for full documentation of InstanceData, PrototypeData, RenderSignature, ChunkLink, and InstanceLink.
Properties
| Property | Access | Type | Description |
|---|---|---|---|
| BRGSystem | protected | BRGRenderer | Reference to the singleton. Set before OnInitialize() is called, cleared after OnShutdown() returns. Use it freely during those methods. |
| Registration | public | BRGRegistrationTracker | The underlying tracker. Created lazily on first access — available before Initialize(). |
| _registered | protected | bool | true while the registerer is initialized. Check this before performing operations. |
Manual Lifecycle
By default, BRGRegisterer initializes on OnEnable and shuts down on OnDisable. If you need manual control (e.g., a button-driven workflow), override OnEnable/OnDisable and call these methods directly:
| Method | Description |
|---|---|
void Initialize() |
Acquire the singleton and call OnInitialize(). Safe to call multiple times — does nothing if already registered. |
void Shutdown() |
Call OnShutdown(), free all tracked chunks and prototypes, and release the singleton. |
See the Registerer Example for a working example of manual lifecycle using _autoRegister.
API
These methods are forwarded to the underlying BRGRegistrationTracker. For full descriptions of each method (parameters, edge cases, etc.), see the BRGRegistrationTracker page.
Lifecycle methods (Register*, AllocChunk, WriteChunk, ReleaseChunk, AddInstance*, Get*, and the OnChunkWritten callback) are protected — intended to be used from within your subclass. Visibility controls (SetChunkEnabled, SetRenderEnabled) and the Stage* / *Unsafe modification methods are public, so other code can drive instance updates after the registerer is initialized.
Render Signature Registration
| Method | Description |
|---|---|
RenderSignature ExtractRenderSignature(GameObject) |
Extract without registering — useful for modifying settings before registration. |
int RegisterRenderSignatureFromPrefab(GameObject) |
Register a single signature from a prefab. Tracked. |
int[] RegisterRenderSignaturesFromPrefab(GameObject) |
Register multiple signatures from a multi-renderer prefab. Tracked. |
int RegisterRenderSignature(RenderSignature) |
Register an explicit signature. Tracked. |
void UnregisterRenderSignature(int globalIdx) |
Manually unregister a prototype. |
Chunk Management
| Method | Description |
|---|---|
int MaxInstancesPerChunk |
Maximum instances per chunk (driven by Max Pool Refs Per Chunk × 16). |
ChunkLink AllocChunk() |
Allocate a new chunk. Tracked. |
void WriteChunk(ChunkLink, NativeArray<InstanceData>, Bounds, float cullDistance, float instanceCullDistance) |
Write instances. Auto-overflows. |
void ReleaseChunk(ChunkLink) |
Free a chunk and all its overflows. |
void RecalculateChunkBounds(ChunkLink, Bounds) |
Update chunk culling bounds. |
void SetChunkEnabled(ChunkLink, bool) |
Enable/disable a chunk for rendering. |
bool GetChunkEnabled(ChunkLink) |
Check chunk enabled state. |
void SetRenderEnabled(bool) |
Enable/disable rendering for ALL chunks this registerer owns. |
Instance Lifecycle
| Method | Description |
|---|---|
InstanceLink AddInstance(ChunkLink, InstanceData) |
Add a single instance, with automatic overflow. |
InstanceLink[] AddInstances(ChunkLink, NativeArray<InstanceData>, int count) |
Add multiple. |
InstanceLink MoveInstanceToChunk(InstanceLink source, ChunkLink dest, InstanceData) |
Move between chunks. |
Lookups
| Method | Description |
|---|---|
InstanceLink GetInstanceLink(ChunkLink, int localIndex) |
Resolve a logical index (spanning primary + overflow) into a current InstanceLink. |
int GetTotalChunkInstanceCount(ChunkLink) |
Sum across primary + overflow chunks. |
int GetOverflowChunkCount(ChunkLink) |
Number of overflow chunks attached. |
void GetPerChunkInstanceCounts(ChunkLink, List<int>) |
Counts per sub-chunk. |
Tracked Staging
The Stage* methods buffer per-slot writes and merge updates to the same instance within a frame into a single GPU write. This is the recommended path for runtime modifications. See Tracked Staging for the full list.
Both InstanceLink and int globalSlot overloads are provided for every staging method. StageTRSBatch / StageColorBatch submit a whole NativeArray of entries in one call while keeping the per-slot merge.
Unsafe Direct Modification
The *Unsafe methods skip the staging buffer and write directly to BRGRenderer. Use only when you've already deduplicated writes yourself or need writes to land immediately. See Unsafe Direct Modification.
SetTRSBatchUnsafe / SetColorBatchUnsafe are the fastest path at scale — they bulk-stage a NativeArray (typically filled by a Burst job) straight into the core staging buffers. See Batched Unsafe Writes. For a working example of all three submission paths, see Instance Link Example.
Mixing staged and unsafe writes on the same slot within a frame is undefined — pick one path per slot.
Callbacks
| Method | Description |
|---|---|
virtual void OnChunkWritten(int chunkId) |
Override to react when a primary chunk and all of its overflows have finished writing to GPU. Useful for caching InstanceLink handles after WriteChunk. |
Notes
- Always use
RegisterRenderSignature*/AllocChunk/ReleaseChunkinstead of callingBRGSystem.RegisterPrototype/BRGSystem.AllocateChunk/BRGSystem.FreeChunkdirectly. The base class tracks these for automatic cleanup. - Do not free chunks or unregister prototypes in
OnShutdown(). The base class handles all BRG resource cleanup afterOnShutdown()returns. - The
BRGSystemproperty is set beforeOnInitialize()and cleared afterOnShutdown(). Use it freely during those methods. BRGRegistereris marked[ExecuteAlways], so it works in the editor outside of play mode.- When a
WriteChunkexceedsMaxInstancesPerChunk, overflow chunks are allocated automatically and share the primary chunk's bounds. All queries (GetInstanceLink,GetTotalChunkInstanceCount, etc.) span primary + overflows transparently.