Annotation System Architecture
Overview
The Annotation System provides instance segmentation coloring for distinguishing multiple objects in camera captures. The system supports two annotation strategies: Direct mode (CustomPrimitiveData) and Proxy mode (AnnotationComponent), each with different performance characteristics and use cases.
Header: Source/UnrealCV/Public/Controller/ObjectAnnotator.h
Architecture Diagram
+---------------------+
| FObjectAnnotator | <-- Static Facade
+---------------------+
| + AnnotateWorld() |
| + DeannotateWorld() |
| + SetAnnotationMode()|
+--------+------------+
|
v
+---------------------+ +---------------------+
| FDirectAnnotator | | FProxyAnnotator |
+---------------------+ +---------------------+
| CustomPrimitiveData | | AnnotationComponent |
| (Fast, Per-actor) | | (Batch, Component) |
+--------+------------+ +--------+------------+
| |
v v
+---------------------+ +---------------------+
| FColorGenerator | | FColorGenerator |
+---------------------+ +---------------------+
| |
v v
+---------------------+ +---------------------+
| StencilBPLib | | AnnotationComponent|
| (CustomDepth) | | (Scene Proxy) |
+---------------------+ +---------------------+
FObjectAnnotator (Static Facade)
FObjectAnnotator is a static facade that delegates to either Direct or Proxy annotator
implementation based on the current annotation mode.
Header: Source/UnrealCV/Public/Controller/ObjectAnnotator.h
Public API
Initialize
static void Initialize();
Initializes the annotation system and sets up the color generator.
Note: Called automatically on plugin startup.
Shutdown
static void Shutdown();
Cleans up annotation resources.
AnnotateWorld
static void AnnotateWorld(UWorld* World);
Applies annotation colors to all actors in the world.
Parameters:
World(UWorld*): World to annotate
Process:
Iterates all actors in the world
Generates unique color for each actor
Applies color using current annotation mode
DeannotateWorld
static void DeannotateWorld(UWorld* World);
Removes all annotation data from actors.
Parameters:
World(UWorld*): World to deannotate
SetAnnotationColor
static int32 SetAnnotationColor(AActor* Actor, const FColor& AnnotationColor);
Sets a specific annotation color for an actor.
Parameters:
Actor(AActor*): Actor to annotate
AnnotationColor(FColor): Color to assign
Returns: Number of primitives annotated
GetAnnotationColor
static void GetAnnotationColor(AActor* Actor, FColor& AnnotationColor);
Retrieves the annotation color for an actor.
Parameters:
Actor(AActor*): Actor to query
AnnotationColor(FColor&): Output color
GetAnnotationColors
static TMap<FString, FColor> GetAnnotationColors();
Gets all annotation color mappings.
Returns: Map of actor names to colors
SetAnnotationMode
static void SetAnnotationMode(bool bUseDirect);
Switches between Direct and Proxy annotation modes.
Parameters:
bUseDirect(bool): true for Direct mode, false for Proxy mode
See Also: annotation-mode-comparison
IsUsingDirectAnnotation
static bool IsUsingDirectAnnotation();
Checks current annotation mode.
Returns: true if using Direct mode
FDirectAnnotator
Direct mode uses CustomPrimitiveData to store annotation colors directly on
actor primitives. This approach is fast and has minimal overhead.
Header: Source/UnrealCV/Private/Controller/DirectAnnotator.h
Implementation Details
Direct annotator stores annotation data in CustomPrimitiveDataVector4 slots:
Slot 4: (R, G, B, ActorID)
- R: Red channel of annotation color
- G: Green channel of annotation color
- B: Blue channel of annotation color
- ActorID: Unique actor identifier
Key Methods
AnnotateWorld
void AnnotateWorld(UWorld* World);
Iterates all actors and applies colors via CustomPrimitiveData.
Process:
Get all actors from world
Generate or retrieve color for each actor
Set CustomPrimitiveDataVector4 on all primitive components
Enable CustomDepth via StencilBPLib for stencil-based masking
SetAnnotationColor
int32 SetAnnotationColor(AActor* Actor, const FColor& AnnotationColor);
Sets annotation data on all primitive components of an actor.
Process:
Get all PrimitiveComponents from actor
Set CustomPrimitiveDataVector4(4, AnnotationData)
Store color in AnnotationColors map
GetAnnotationColor
void GetAnnotationColor(AActor* Actor, FColor& AnnotationColor);
Retrieves color from CustomPrimitiveData.
Process:
Check AnnotationColors cache first
If not cached, read from PrimitiveComponent CustomPrimitiveData
DeannotateWorld
void DeannotateWorld(UWorld* World);
Clears all CustomPrimitiveData values.
Process:
Iterate all actors
Set CustomPrimitiveDataVector4(4, Zero) on all primitives
Clear AnnotationColors map
FProxyAnnotator
Proxy mode uses AnnotationComponent to render annotation colors via a
material-based approach. This supports complex actors with multiple meshes.
Header: Source/UnrealCV/Private/Controller/ProxyAnnotator.h
Implementation Details
Proxy annotator attaches UAnnotationComponent to each mesh component.
The component renders a solid color using a custom material.
Batch Processing:
Proxy annotator uses batch processing with FlushRenderingCommands every
N actors to improve performance during world annotation.
Key Methods
AnnotateWorld
void AnnotateWorld(UWorld* World);
Attaches AnnotationComponents to all actors.
Process:
Iterate all actors
Create AnnotationComponent for each mesh
Set annotation color via material parameter
Batch process with FlushRenderingCommands (BatchSize=1)
SetAnnotationColor
int32 SetAnnotationColor(AActor* Actor, const FColor& AnnotationColor);
Creates or updates AnnotationComponent on actor.
Process:
Check for existing AnnotationComponent
If none, create new AnnotationComponent
If exists, update existing component
Store color in AnnotationColors map
CreateAnnotationComponent
void CreateAnnotationComponent(AActor* Actor, FColor AnnotationColor);
Attaches new AnnotationComponent to mesh components.
Process:
Get all MeshComponents from actor
Create AnnotationComponent for each mesh
Attach as child component
Set annotation color via material parameter
Skeletal Mesh Handling:
Can be disabled via
FUnrealcvServer::Config.DisableSKMAnnotationSupports SkeletalMeshComponent annotation when enabled
UpdateAnnotationComponent
void UpdateAnnotationComponent(AActor* Actor, FColor AnnotationColor);
Updates color on existing AnnotationComponent.
DeannotateWorld
void DeannotateWorld(UWorld* World);
Destroys all AnnotationComponents.
Process:
Find all AnnotationComponents
Destroy each component
Clear AnnotationColors map
Flush rendering commands
UAnnotationComponent
Component that renders annotation color via material.
Header: Source/UnrealCV/Public/Component/AnnotationComponent.h
Public Methods
SetAnnotationColor
void SetAnnotationColor(FColor AnnotationColor);
Sets the annotation color.
GetAnnotationColor
FColor GetAnnotationColor();
Gets the current annotation color.
ForceUpdate
void ForceUpdate();
Forces render state update.
Scene Proxy
The component creates scene proxies for different mesh types:
CreateSceneProxy(UStaticMeshComponent*)CreateSceneProxy(USkeletalMeshComponent*)CreateSceneProxy(UGroomComponent*)
FColorGenerator
Generates deterministic annotation colors from object indices.
Header: Source/UnrealCV/Public/Controller/ObjectAnnotator.h
Algorithm
ColorGenerator uses bit manipulation to create channel-wise distinct colors:
class FColorGenerator
{
public:
FColor GetColorFromColorMap(int32 ObjectIndex);
private:
int32 GetChannelValue(uint32 Index);
void GetColors(int32 MaxVal, bool Fix1, bool Fix2, bool Fix3,
TArray<FColor>& ColorMap);
};
Color Generation Strategy:
Each color channel varies at different bit positions
Ensures colors are visually distinct across indices
Deterministic: same index always produces same color
Example Colors:
Index 0: R=1, G=2, B=4 (1, 2, 4 = 0x010204) Index 1: R=1, G=4, B=8 (1, 4, 8 = 0x010408) Index 2: R=1, G=8, B=16 (1, 8, 16 = 0x010810) …
Annotation Mode Comparison
Feature |
Direct Mode |
Proxy Mode |
|---|---|---|
Storage |
CustomPrimitiveData |
AnnotationComponent |
Performance |
Faster |
Slower |
Memory Overhead |
Low |
High |
Multi-mesh Actors |
One-shot set |
Per-mesh component |
Complex Skeletal Meshes |
Supported |
Configurable |
Groom Support |
No |
Yes |
Dynamic Updates |
Immediate |
Requires update |
When to Use Each Mode
- Direct Mode (Recommended):
Large number of static objects
Performance-critical scenarios
Simple mesh hierarchy
Actors with few primitive components
- Proxy Mode (Recommended):
Complex skeletal meshes
Groom (hair/fur) annotation
Dynamic actors requiring frequent updates
When material-based rendering is needed
Blueprint Integration
Use UAnnotationBPLib for Blueprint annotation control:
// Get annotation colors
TMap<FString, FColor> Colors = FObjectAnnotator::GetAnnotationColors();
// Check current mode
bool bDirect = FObjectAnnotator::IsUsingDirectAnnotation();
// Switch mode
FObjectAnnotator::SetAnnotationMode(true); // Direct
FObjectAnnotator::SetAnnotationMode(false); // Proxy
See Also
Sensor System Architecture - Sensor system (reads annotation colors)
Sensor Data Formats Reference - Annotation sensor output formats