reckfellENGINE

Rendering compositor

Forward+ and Mobile stages, camera override, an executed C# callback and buffer ownership.

On this page

Compositor attaches custom effects to stages of 3D rendering. Use it for frame-buffer work beyond object materials and Environment settings. Forward+ and Mobile support this path; Compatibility does not.

Attach an effect

  1. Create a Compositor resource in a WorldEnvironment’s Compositor property.
  2. Add your CompositorEffect to Compositor Effects. An empty array slot does not create an effect.
  3. Select Effect Callback Type, keep Enabled on and check the active Camera3D.
  4. If that camera has its own compositor, it takes precedence: camera and world lists are not merged. Even an empty camera compositor replaces the world compositor. Clearing the camera property restores the world compositor.

Effects within a stage execute in array order. Different stages follow rendering order regardless of resource positions in the array. The CompositorEffects getter returns a new container holding shared effect references. Assign it back after changing array contents. Editing effect.Enabled works without reassigning the array.

Choose an available stage

StageForward+Current MobileCallback timing
PreOpaqueYesYesBefore opaque geometry; not the completed frame color.
PostOpaqueYesNo, warningAfter opaque geometry.
PostSkyYesNot dispatchedAfter the sky; the stage for separate specular.
PreTransparentYesYesBefore transparent geometry.
PostTransparentYesYesAfter transparent geometry, before subsequent postprocessing and tonemapping.

A Windows/Vulkan test confirmed these calls. Mobile emits Post opaque rendering effect callback is not supported in the mobile renderer when a PostOpaque effect is present. Check stage availability when moving between renderers. Max is an enum sentinel, not a stage.

Verify the connection from C#

Save this class as BufferProbeEffect.cs, build the C# project and add this resource to Compositor Effects. It checks dimensions and color/depth RIDs for every view. It does not change the image and is not a finished filter.

C#
using System.Threading;
using Reckfell;

[GlobalClass]
public partial class BufferProbeEffect : CompositorEffect
{
    private int callbacks;
    private int validFrames;
    public int CallbackCount => Volatile.Read(ref callbacks);
    public int ValidFrameCount => Volatile.Read(ref validFrames);

    public BufferProbeEffect()
    {
        EffectCallbackType = EffectCallbackTypeEnum.PostTransparent;
    }

    public override void _RenderCallback(int effectCallbackType, RenderData renderData)
    {
        if (effectCallbackType != (int)EffectCallbackTypeEnum.PostTransparent)
            return;

        Interlocked.Increment(ref callbacks);
        if (renderData.GetRenderSceneBuffers() is not RenderSceneBuffersRD buffers)
            return;

        Vector2I size = buffers.GetInternalSize();
        if (size.X <= 0 || size.Y <= 0 || buffers.GetViewCount() == 0)
            return;

        for (uint view = 0; view < buffers.GetViewCount(); view++)
        {
            if (!buffers.GetColorLayer(view).IsValid || !buffers.GetDepthLayer(view).IsValid)
                return;
        }
        Interlocked.Increment(ref validFrames);
    }
}

After several rendered frames, CallbackCount and ValidFrameCount should increase. Read them from an ordinary script retaining a reference to the assigned effect. Setting Enabled=false stops the increase after queued frames finish. This separates an attachment problem from a failure in your shader.

Buffers and additional data

The renderer owns RenderData and its buffers. Use them inside the callback; do not retain RenderData for another frame or release borrowed RIDs through FreeRid. Use GetInternalSize(), not window dimensions: render scaling can make them different. Iterate GetViewCount() and every view’s layers; one layer does not cover XR stereo. A valid RID does not guarantee completed-scene contents at an early stage.

FlagPurpose
AccessResolvedColorRequests ordinary color on an intermediate stage with MSAA; does not disable MSAA.
AccessResolvedDepthRequests resolved depth with MSAA; support depends on renderer and device.
NeedsMotionVectorsRequests motion-vector preparation in Forward+.
NeedsNormalRoughnessAffects Forward+ normal/roughness prepass preparation.
NeedsSeparateSpecularSeparate specular in Forward+ at PostSky; hidden for other stages.

All flags initially default to false. Inspector hides resolved color/depth settings for PostTransparent. Request only data you use: preparation can add passes and memory. Mobile need not provide Forward+ additional buffers.

Threads and ownership

The callback runs on the rendering path. Do not modify the Entity tree, UI or resources concurrently used by the main thread. This example exchanges only atomic counters; prepare a consistent snapshot for your own parameters.

Use the main device from RenderingServer.GetRenderingDevice(): a separate local device does not own frame-buffer RIDs. Create and release owned GPU resources on the render thread, using RenderingServer.CallOnRenderThread where needed. Reuse shaders/pipelines; recreate size-dependent textures and uniform sets when internal dimensions change. Release only RIDs you created, after they are no longer used.

Diagnostics

  • No callbacks: check Enabled, active camera, camera override, effect array and stage availability.
  • No data: check stage, dimensions, RenderSceneBuffersRD type and required flags. PreOpaque does not contain the completed opaque scene.
  • Effect in one eye: process all views and layers.
  • Errors after resize: check dispatch dimensions, shader bounds and recreation of owned resources.
  • Result changes after tonemapping: PostTransparent does not mean “after all effects.”

Actual callbacks, RID availability, Enabled, container copying and camera override were checked on Windows/Vulkan Forward+ and Mobile. Compute shaders, pixel modification, MSAA, XR, resizing, reflection probes, performance and other backends were not tested. Current source excludes reflection probes from ordinary callback dispatch.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.