Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# Stereo Image Display in visionOS

> ## Status (2025): superseded by `ImagePresentationComponent`
>
> This project dates from **June 2024 (visionOS 2.0, Xcode 16.2)**, before the SDK had a purpose-built
> stereo-image API. At the time, driving a `ShaderGraphMaterial` + `CameraIndexSwitch` to feed each eye a
> separate `TextureResource` was a reasonable way to show a stereo pair — but it carries real costs that
> are visible in this code: texture-swap **memory leaks** (worked around by stashing the pair's `id` in the
> entity's `name`), **synchronous `TextureResource.load` on the render thread**, the **grayscale-load bug
> (FB13733823)** patched by painting a blue streak on the NASA Ames frames, **no depth/convergence control**
> (wide-baseline pairs such as several of the Middlebury 2021 scenes are uncomfortably deep with no remedy),
> and a fixed plane whose aspect ratio is locked to the first image.
>
> **As of visionOS 26, prefer `ImagePresentationComponent` with `.spatialStereo`.** Hand it a single spatial
> photo (stereo-pair-group HEIC) via `ImagePresentationComponent(contentsOf:)` and set
> `desiredViewingMode = .spatialStereo`; RealityKit then does per-eye presentation, sizing, and edge
> feathering for you, with comfortable depth driven by the file's baked-in camera metadata (baseline / FOV).
> The grayscale problem is handled once, at conversion time, by producing an RGB spatial HEIC. I've since
> built a productized take on this — a data-driven, multi-app stereo viewer on `ImagePresentationComponent`
> with a pipeline that bakes per-scene calibration and an edge matte into spatial HEICs (reusing these same
> Middlebury scenes) — in a separate `Stereography` project.
>
> This repo is kept as a historical reference for the pre-`ImagePresentationComponent` shader-graph
> technique. The one idea still worth borrowing is the `CameraIndexSwitch` "Mono" fallback for pairs that
> are missing one eye.

This sample project shows my current approach to displaying stereographic image pairs in visionOS. There are a few hiccups.

The shader graph is pretty straightforward. Two named `ImageFile` nodes ("LeftImage" and "RightImage") accept the names of the left and right images, feed to a pair of `Image` nodes, which then feed a `CameraIndexSwitch`. I feed the right image to the "Mono" input, because in the image pairs I'm working with I'll occasionally encounter a missing left image. This pipeline then feeds a named output "StereoImage". In releases through visionOS 2.2, and still in Xcode 16.2's visionOS 2.2 SDK, `TextureResource.load` fails with pure grayscale images, so you will have to convert them to an RGB-based color space (Apple FB 13733823). Size limit is 8192x8192 pixels.
Expand Down
2 changes: 1 addition & 1 deletion ShaderGraph Stereo/StereoPair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import Foundation

struct StereoPair: Codable, Identifiable {
struct StereoPair: Codable, Identifiable, Equatable {
let id: String
let leftImageName: String
let rightImageName: String
Expand Down