Sample CodeiOS, iPadOS, Mac CatalystReviewed 2026-07-21View on Apple Developer

Implementing special rendering effects with RealityKit postprocessing

At a glance

Item Summary
Purpose Implement a variety of postprocessing techniques to alter RealityKit rendering.
App architecture AppDelegate hosts a SwiftUI-backed RealityKit view; its coordinator owns ARView setup and installs postprocess callbacks that route frames through Metal, Core Image, or Metal Performance Shaders effects.
Main patterns UIKit lifecycle composition, UI–RealityKit bridge, Session owner boundary, Delegate callback adapter, Postprocess strategy boundary
Project style Code-rich sample with 19 scanned C/Objective-C header, Metal, Swift file(s) and 1370 implementation line(s).

Project structure

Source bundle/
└── RealityKitPostProcessing/
    ├── RealityView/
    │   ├── RealityView.swift  # RealityView
    │   ├── RealityViewContainer.swift  # RealityViewContainer, Coordinator
    │   └── RealityView+CoachingView.swift
    ├── AppDelegate.swift  # AppDelegate
    ├── ContentView.swift  # ContentView, SelectionCell, ContentView_Previews
    └── Application State/
        ├── ApplicationState+Enums.swift  # CategoryEntry, ModeEntry, Category
        └── ApplicationState.swift  # ApplicationState

Structure observations

  • The runtime boundary is SwiftUI/UIKit host; the tree is pruned to lifecycle, state, framework, rendering, and ECS files.
  • The source is C/Objective-C header, Metal, Swift; role-named types and feature folders separate the major responsibilities.

Overall architecture

Reference code

RealityKitPostProcessing/AppDelegate.swift:12 — executable or app-lifecycle anchor.

class AppDelegate: UIResponder, UIApplicationDelegate {
    // ...
}

The diagram is a responsibility flow, not a claim that every adjacent node directly calls the next. It separates lifecycle, presentation, stable state, framework/session work, and the RealityKit entity graph.

Ownership and state

Ownership evidence

RealityKitPostProcessing/RealityView/RealityView.swift:48 — representative stored state or nearest verified lifecycle anchor.

    var skRenderer: SKRenderer!
    
    // MARK: - Initializers
    
    required init(frame: CGRect) {
        super.init(frame: frame)
    }
Owner Object or state Relationship Mutation authority
RealityView SKRenderer as skRenderer stores and coordinates The owning type coordinates writes
AppDelegate UIWindow as window stores and coordinates The owning type coordinates writes
RealityView MTLTexture as alphaTexture stores and coordinates The owning type coordinates writes
RealityView MTLTexture as bloomTexture stores and coordinates The owning type coordinates writes

Ownership is intentionally narrow: environment, bindings, observed objects, weak links, and delegate callbacks do not prove lifetime ownership. Initialized stored services and wrapper-managed state do; entities added inside a RealityKit content closure belong to that entity graph.

Class and protocol design

Type Responsibility Depends on or conforms to
AppDelegate (RealityKitPostProcessing/AppDelegate.swift:12) Declares app lifecycle and top-level dependency lifetime. UIResponder, UIApplicationDelegate
RealityView (RealityKitPostProcessing/RealityView/RealityView.swift:14) Presents UI and forwards gestures or lifecycle events. ARView
Coordinator (RealityKitPostProcessing/RealityView/RealityViewContainer.swift:34) Coordinates long-lived framework or cross-view work. NSObject
ContentView (RealityKitPostProcessing/ContentView.swift:15) Presents UI and forwards gestures or lifecycle events. View

The reviewed source defines no local substitution protocol. Its App, View, delegate, renderer, ARKit, and RealityKit conformances are framework-facing contracts, so this document does not label the whole app protocol-oriented.

Access control

Symbol Access Verified effect Likely rationale
private func postProcessUsingMetalShader(context: ARView.PostProcessCon... (RealityKitPostProcessing/RealityView/RealityView+Metal.swift:105) private Use stays inside the declaration and same-file extensions permitted by Swift. Inference: Hide lifecycle-sensitive state or an implementation step.
public init() { (RealityKitPostProcessing/RealityView/RealityViewContainer.swift:17) public The symbol is available to importing modules, subject to its containing type’s visibility. Inference: Expose an intentional package or cross-target surface.

No reviewed Swift access example uses fileprivate, private(set), open; declarations without a modifier are internal.

Objective-C/C header and implementation visibility is documented separately from Swift lexical access control.

Reference code

RealityKitPostProcessing/RealityView/RealityView+Metal.swift:105 — representative visibility boundary.

    private func postProcessUsingMetalShader(context: ARView.PostProcessContext,
                                             pipeline: MTLComputePipelineState,
                                             parameterHandler: MetalParameterSetup?) {
        // ...
    }

Logic ownership and placement

Logic Owning type or file Placement rationale
Application/command lifecycle AppDelegate The executable boundary determines app, controller, scene, or command lifetime.
Presentation and user intent RealityView The view/controller forwards input and owns only presentation-local work.
Framework/session/render coordination Coordinator The role-named collaborator isolates long-lived or per-frame work from presentation code.
GPU and low-level resource work RealityKitPostProcessing/RealityView/RealityView.swift:64 Buffer, texture, shader, or frame-resource mutation stays in a rendering/compute boundary.

Design patterns

Pattern Source evidence Purpose or tradeoff
UIKit lifecycle composition RealityKitPostProcessing/AppDelegate.swift:12 Uses the application delegate and view controller as the explicit lifecycle and scene-ownership boundary.
UI–RealityKit bridge RealityKitPostProcessing/RealityView/RealityView.swift:121 Builds or hosts the RealityKit entity graph from SwiftUI or a platform view/controller lifecycle.
Session owner boundary RealityKitPostProcessing/RealityView/RealityViewContainer.swift:34 Keeps authorization, session lifetime, and framework callbacks in a stable model, manager, or controller.
Delegate callback adapter RealityKitPostProcessing/AppDelegate.swift:12 Inverts imperative framework callbacks into the sample’s owning controller, coordinator, or model.
Postprocess strategy boundary RealityKitPostProcessing/RealityView/RealityView.swift:38 Lets one coordinator choose and run interchangeable GPU image effects after RealityKit renders the frame.

Naming conventions

  • Role suffixes are evidence, not decoration: Coordinator: Coordinator; View: ContentView, RealityView.
  • Protocols: no app-defined protocol in the reviewed source.
  • Commands use verb-led methods: postProcessSetupCallback, configureWorldTracking, setUpCoachingOverlay, loadScene, setupPostProcessing, postProcess, postEffectNone, application.
  • Files and folders use primary-type or responsibility names such as Views, Models, Rendering, Components, Systems, Packages, or feature names where those boundaries exist.

Architecture takeaways

  • Treat AppDelegate as the owner of executable or scene lifecycle, not automatically as the owner of every entity created later.
  • Keep view/controller input near presentation, but move sessions, reconstruction, capture, rendering, shared game state, or documents into stable owners when their lifetime exceeds one callback or render pass.

Source map

Source file Relevant symbols
RealityKitPostProcessing/RealityView/RealityView.swift:14 RealityView
RealityKitPostProcessing/AppDelegate.swift:12 AppDelegate
RealityKitPostProcessing/ContentView.swift:15 ContentView, SelectionCell, ContentView_Previews
RealityKitPostProcessing/Application State/ApplicationState+Enums.swift:11 CategoryEntry, ModeEntry, Category, Mode
RealityKitPostProcessing/RealityView/RealityViewContainer.swift:15 RealityViewContainer, Coordinator
RealityKitPostProcessing/RealityView/RealityView+CoachingView.swift:1 Feature implementation
RealityKitPostProcessing/Application State/ApplicationState.swift:11 ApplicationState