Skip to main content
The Graphics static class provides direct access to the GPU rendering pipeline. You use it inside component render callbacks (OnRenderObject, PostProcess, etc.) where a render context is active. For GPU compute work outside the render pipeline, use ComputeShader and GpuBuffer.
Graphics methods (except FlushGPU) must be called from within an active render scope. Calling them outside a render callback throws an exception.

Graphics static class

State properties

IsActive
bool
true when a render scope is active and Graphics methods are safe to call.
Viewport
Rect
The current render viewport in pixel coordinates. Get or set to change the rendering region.
Attributes
RenderAttributes
The current render context’s attribute set. Values set here are forwarded to the active material/shader for the duration of the current render scope.
CameraTransform
Transform
The world-space transform of the camera rendering the current view.
CameraPosition
Vector3
World-space position of the rendering camera. Shorthand for CameraTransform.Position.
FieldOfView
float
Horizontal field of view of the current camera, in degrees.
LayerType
SceneLayerType
The current rendering layer (opaque, translucent, shadow, etc.). Use this to branch behaviour inside multi-pass shaders.
RenderTarget
RenderTarget
Get or set the active render target. Setting this binds the target and updates the viewport to match.

Drawing methods

Graphics.Draw

Draw a mesh from a vertex buffer with an optional index buffer.
vertices
Span<Vertex>
required
Vertex data to draw.
vertCount
int
required
Number of vertices to use from the span.
material
Material
required
The material (shader) to render with.
attributes
RenderAttributes
Attribute overrides for this draw. Defaults to Graphics.Attributes.
primitiveType
PrimitiveType
Primitive topology. Default is Triangles.
var vertices = new List<Vertex>();
// ... populate vertices ...
Graphics.Draw( vertices, vertices.Count, Material.Load( "materials/my_material.vmat" ) );

Graphics.DrawQuad

Draw a 2D screen-space quad.
rect
Rect
required
Screen rectangle in pixels.
material
Material
required
Material to render.
color
Color
required
Tint color applied to the quad.
Graphics.DrawQuad(
    new Rect( 100, 100, 256, 256 ),
    Material.Load( "materials/hud_element.vmat" ),
    Color.White
);

Graphics.Blit

Draw a full-screen quad using a screen-space material. Useful for post-processing passes.
material
Material
required
A screen-space material. The shader receives the current frame color via FrameTexture if you call GrabFrameTexture first.
// Grab the current frame, then run a post-process pass
Graphics.GrabFrameTexture( "FrameTexture" );
Graphics.Blit( _postProcessMaterial );

Graphics.Render

Render a SceneObject with an optional transform, color, or material override.
Graphics.Render( mySceneObject );
Graphics.Render( mySceneObject, transform: overrideTransform, color: Color.Red );

Graphics.Clear

Clear the current render target.
Graphics.Clear( Color.Black, clearColor: true, clearDepth: true, clearStencil: false );

Texture helpers

Graphics.GrabFrameTexture

Copies the current viewport’s color buffer into a render target and sets it as an attribute.
targetName
string
Attribute name to bind the grabbed texture to. Default is "FrameTexture".
renderAttributes
RenderAttributes
Target attribute set. Defaults to Graphics.Attributes.
downsampleMethod
DownsampleMethod
Optional mip-chain generation for blur effects.
// Inside a post-process component
public override void OnRender( SceneCamera camera )
{
    Graphics.GrabFrameTexture( "PreviousFrame" );
    Graphics.Blit( _motionBlurMaterial );
}

Graphics.GrabDepthTexture

Copies the current depth buffer into a render target.
Graphics.GrabDepthTexture( "DepthBuffer" );

Graphics.CopyTexture

Copy pixel data between two GPU textures. Source and destination must have the same format and size.
Graphics.CopyTexture( sourceTexture, destinationTexture );

Primitive types

ValueDescription
PrimitiveType.TrianglesStandard triangle list. Default.
PrimitiveType.TriangleStripTriangle strip — efficient for quads.
PrimitiveType.LinesLine list — pairs of vertices form segments.
PrimitiveType.LineStripConnected line strip.
PrimitiveType.PointsPoint sprites.

RenderAttributes

RenderAttributes is a key-value store that passes data to shaders. Access the current scope’s attributes via Graphics.Attributes, or create a standalone instance for use with compute shaders. In HLSL, bind an attribute by name:
float4 g_vMyColor < Attribute( "MyColor" ); >;
Texture2D g_tNoise < Attribute( "NoiseTexture" ); SrgbRead( false ); >;

Set methods

All Set overloads accept a string or StringToken as the key.
Set(string key, T value)
void
Supported value types: bool, int, float, double, Vector2, Vector3, Vector4, Angles, Matrix, string, Texture, GpuBuffer, SamplerState.
Graphics.Attributes.Set( "MyColor", new Color( 1, 0, 0 ) );
Graphics.Attributes.Set( "Intensity", 2.5f );
Graphics.Attributes.Set( "NoiseTexture", Texture.Load( "textures/noise.vtex" ) );
Graphics.Attributes.Set( "ResultBuffer", myGpuBuffer );

SetData — constant buffer upload

SetData<T>(string key, T value)
void
Upload an unmanaged struct directly into a constant buffer slot. T must be a blittable POD type.
SetData<T>(string key, Span<T> values)
void
Upload an array of structs into a constant buffer.
struct MyParams
{
    public float Time;
    public float Scale;
    public Vector2 Offset;
}

Graphics.Attributes.SetData( "Params", new MyParams
{
    Time = Time.Now,
    Scale = 2.0f,
    Offset = Vector2.Zero
} );

Get methods

GetTexture(string key, Texture defaultValue)
Texture
Retrieve a texture attribute by name.
GetFloat(string key, float defaultValue)
float
Retrieve a float attribute.
GetVector(string key, Vector3 defaultValue)
Vector3
Retrieve a Vector3 attribute.
GetBool(string key, bool defaultValue)
bool
Retrieve a bool attribute.
GetInt(string key, int defaultValue)
int
Retrieve an int attribute.

Combo values

Shader combos are compile-time switches that select between shader permutations.
// Enable a shader combo
Graphics.Attributes.SetCombo( "D_USE_DETAIL_TEXTURE", 1 );
Graphics.Attributes.SetCombo( "D_BLEND_MODE", 2 );

Clear

// Remove all attributes from this instance
Graphics.Attributes.Clear();

ComputeShader

ComputeShader wraps a compute material compiled from an HLSL shader file. Load it once, set attributes on Attributes, then dispatch.
public class ParticleSystem : Component
{
    ComputeShader _updateShader;

    protected override void OnAwake()
    {
        _updateShader = new ComputeShader( "shaders/particles_update" );
    }
}

Dispatch

threadsX
int
required
Number of threads to dispatch in X. The engine divides this by the shader’s declared thread group size.
threadsY
int
required
Number of threads to dispatch in Y.
threadsZ
int
required
Number of threads to dispatch in Z.
_updateShader.Attributes.Set( "DeltaTime", Time.Delta );
_updateShader.Attributes.Set( "Particles", _particleBuffer );
_updateShader.Dispatch( 1024, 1, 1 ); // 1024 threads in X

DispatchIndirect

Dispatch thread counts stored in a GPU buffer instead of supplying them from the CPU. Use this for GPU-driven rendering where particle counts are determined on the GPU.
indirectBuffer
GpuBuffer
required
A buffer containing dispatch arguments. Must have UsageFlags.IndirectDrawArguments and element size of 12 bytes (uint3).
indirectElementOffset
uint
Index into the buffer of the argument entry to use. Default is 0.
_updateShader.Attributes.Set( "Particles", _particleBuffer );
_updateShader.DispatchIndirect( _indirectBuffer );

DispatchWithAttributes

Dispatch with a custom RenderAttributes instance, bypassing ComputeShader.Attributes.
var attrs = new RenderAttributes();
attrs.Set( "InputData", _inputBuffer );
_computeShader.DispatchWithAttributes( attrs, 512, 1, 1 );

GpuBuffer

GpuBuffer<T> is a typed GPU-accessible buffer. Use it to upload data to compute shaders or read results back to the CPU.
// Declare a struct (must be blittable / POD)
struct Particle
{
    public Vector3 Position;
    public Vector3 Velocity;
    public float Life;
    public float _pad; // keep 16-byte aligned
}

// Allocate a buffer of 1024 particles
using var buffer = new GpuBuffer<Particle>( 1024 );

Constructor

elementCount
int
required
Number of elements the buffer holds.
flags
GpuBuffer.UsageFlags
Controls buffer semantics. Default is Structured.
debugName
string
Optional label visible in GPU debuggers.

UsageFlags

FlagHLSL typeDescription
StructuredStructuredBuffer<T> / RWStructuredBuffer<T>General-purpose read/write structured buffer. Default.
AppendAppendStructuredBuffer<T>Append-consume buffer with hidden atomic counter.
ByteAddressByteAddressBufferRaw 32-bit aligned byte access.
IndexIndex bufferVertex index buffer (element size must be 2 or 4 bytes).
IndirectDrawArgumentsStores draw/dispatch arguments for indirect calls.

Properties

ElementCount
int
Number of elements the buffer was created with.
ElementSize
int
Size in bytes of a single element.
Usage
GpuBuffer.UsageFlags
The usage flags the buffer was created with.

SetData

Upload data from the CPU to the GPU. Synchronous.
var particles = new Particle[1024];
// ... fill particles ...
buffer.SetData( particles.AsSpan() );

// With an element offset
buffer.SetData( updateSpan, elementOffset: 512 );

GetData

Download data from the GPU to the CPU. Synchronous — blocks until the GPU finishes.
var results = new Particle[1024];
buffer.GetData( results.AsSpan() );

GetDataAsync

Download data asynchronously. The callback receives a ReadOnlySpan<T> that is only valid during the callback.
buffer.GetDataAsync<Particle>( data =>
{
    foreach ( var p in data )
        Log.Info( $"Particle at {p.Position}, life={p.Life}" );
} );

Clear

Fill the entire buffer with a repeated uint32 value (default 0).
buffer.Clear();        // Zero the buffer
buffer.Clear( 0xFFFF_FFFF ); // Fill with all-ones

Dispose

GpuBuffer implements IDisposable. Always dispose when you are done to release GPU memory.
using var buffer = new GpuBuffer<Particle>( 1024 );
// ... use buffer ...
// Automatically disposed at end of using block

Practical rendering example

The following example shows a component that runs a compute shader every frame to update particle positions and then renders them with a custom material.
public sealed class GpuParticleEffect : Component, Component.ExecuteInEditor
{
    [Property] public int ParticleCount { get; set; } = 4096;
    [Property] public Material ParticleMaterial { get; set; }

    ComputeShader _updateShader;
    GpuBuffer<ParticleData> _particleBuffer;
    Material _renderMaterial;

    struct ParticleData
    {
        public Vector3 Position;
        public float Life;
        public Vector3 Velocity;
        public float _pad;
    }

    protected override void OnAwake()
    {
        _updateShader = new ComputeShader( "shaders/particles_update" );
        _particleBuffer = new GpuBuffer<ParticleData>( ParticleCount );
        _renderMaterial = ParticleMaterial ?? Material.Load( "materials/particle.vmat" );

        // Seed initial positions on CPU
        var initial = new ParticleData[ParticleCount];
        for ( int i = 0; i < ParticleCount; i++ )
        {
            initial[i] = new ParticleData
            {
                Position = WorldPosition + Game.Random.VectorInSphere() * 200f,
                Velocity = Vector3.Up * Game.Random.Float( 50f, 150f ),
                Life = Game.Random.Float( 0f, 5f )
            };
        }
        _particleBuffer.SetData( initial.AsSpan() );
    }

    protected override void OnUpdate()
    {
        // Update positions on GPU
        _updateShader.Attributes.Set( "Particles", _particleBuffer );
        _updateShader.Attributes.Set( "DeltaTime", Time.Delta );
        _updateShader.Attributes.Set( "Gravity", Scene.PhysicsWorld.Gravity );
        _updateShader.Dispatch( ParticleCount, 1, 1 );
    }

    protected override void OnRenderObject()
    {
        if ( !Graphics.IsActive ) return;

        // Pass the buffer to the render material and draw
        Graphics.Attributes.Set( "ParticleBuffer", _particleBuffer );
        Graphics.Attributes.Set( "ParticleCount", ParticleCount );

        // Build a vertex buffer — one point per particle
        var vertices = new Vertex[ParticleCount];
        for ( int i = 0; i < ParticleCount; i++ )
        {
            vertices[i] = new Vertex( WorldPosition );
        }

        Graphics.Draw(
            vertices.AsSpan(),
            ParticleCount,
            _renderMaterial,
            primitiveType: Graphics.PrimitiveType.Points
        );
    }

    protected override void OnDestroy()
    {
        _particleBuffer?.Dispose();
    }
}
For high-frequency compute-driven effects, prefer DispatchIndirect to avoid GPU-CPU synchronization points when the particle count is variable.

Build docs developers (and LLMs) love