Turning a Poster into a Window: Perspective-Correct AR Clipping
Point your phone at a printed poster and the poster becomes a window into a small 3D room that sits behind the paper. Move your phone and the view through the window shifts the way a real window would. That is the Magic Window experiment in our AR Fun section, and getting it to look right took more than we expected.
The setup
Magic Window is an image-target experience. The browser watches the camera feed for a known picture (the poster), and once it finds it, the engine reports the poster's position and rotation in 3D space every frame. We use the open-source 8th Wall engine for tracking and three.js for rendering, all running in a plain web page with nothing to install.
Tracking gives us a flat rectangle floating in the world. The trick is to make that rectangle behave like a hole. We place a 3D room behind the poster's plane and then hide everything that is not inside the rectangle's outline as seen from the camera.
The obvious approach, and why it fails
three.js supports clipping planes, which cut away any geometry on one side of an infinite plane. The natural first attempt is four planes fixed to the poster: one at the left edge, one at the right, one at the top and one at the bottom. Straight on, it looks perfect.
Step to the side and it falls apart. Those four planes describe a rectangular tunnel extending straight back from the poster. A real window does not work that way. What you can see through a window is a cone of sight lines starting at your eye and passing through the frame. Stand at an angle and a sight line can enter the tunnel through its side wall without ever crossing the frame's outline on screen, so you see room content in places where the paper should have been solid.
Covering the gap with a big invisible blocker panel, the trick we used in an earlier doorway experiment, only hides part of the problem. There is always some angle it does not cover.
The fix: rebuild the planes every frame from the camera
The correct clipping volume is a pyramid with its tip at the camera and its base on the poster's four corners. Each side of that pyramid is a plane defined by three points: the camera position and two adjacent corners of the poster. So on every frame we take the camera's current world position and each pair of corners and build four fresh planes from them.
// once per frame, after the marker pose is updated
plane.setFromCoplanarPoints(eye, cornerA, cornerB);
Because the planes are derived from the eye itself, there is no angle at which a gap can appear. Point order matters: swap two corners and the plane faces the wrong way and inverts the whole effect. A quick sanity test is to check a point at the window's center (it must count as inside all four planes) and a point beyond each edge (it must be clipped by exactly the matching plane). A fifth, ordinary plane fixed to the poster's surface keeps room content from poking out toward the viewer.
Smaller details that mattered
- Marker units. The tracking engine treats the larger dimension of the marker image as 1.0 unit and scales the other by the aspect ratio. Read the width and height from the generated target data and build the room from them instead of hard-coding one poster shape.
- Size the room from the marker. A room built to arbitrary dimensions gets discarded wherever it falls outside the clip window, which looks like missing walls. Also, local
y = 0is the marker's vertical center, so the floor belongs at the bottom edge, not at zero. - The seam. Even with everything sized correctly, a thin line of camera passthrough can flicker where the picture frame meets the room. Making the frame's inner opening about five percent smaller than the room's opening means solid frame material overlaps the room's edge and hides the seam.
- Pose smoothing. Single-camera pose estimation is noisy, so raw readings make the room jitter. Blending each new pose a quarter of the way from the previous one keeps it steady, as long as you reset the blend when tracking is reacquired so the room does not slide across the gap.
What we learned
Each of these pieces looked fine in a desktop test and turned out wrong on a real phone, held at real angles, in real lighting. Perspective effects especially need to be tested from many viewpoints, not just head-on. The result is a small experiment, but the per-frame clipping idea works for any "look through a frame" effect, not just this poster.
You can try it yourself from the AR Fun section on a phone with a rear camera.