Computational Design · Research

Automated
Anamorphic Sculptures

An optimizer that designs fabricable anamorphic sculptures from any two images: a single sculpture that reveals a different image from each of two viewing angles.

OptimizationResearchDifferentiable rendering
A fabricated result: one sculpture, two hidden images.

Overview

Anamorphic sculptures arrange distorted, fragmented objects so that a hidden image becomes recognizable only from one precise viewing angle. The goal of this project was to automate the design of fabricable anamorphic sculptures that form two distinct images from two different angles.

What makes this hard is the size of the design space: there are infinitely many valid solutions when you consider the number of pieces, their shapes, positions, and rotations. The two target images also constrain each other, so improving one view tends to break the other. The system treats it as an optimization problem, mixing continuous gradient descent with discrete structural changes.


Optimization pipeline

The user supplies two black-and-white target images, one per viewing angle. Everything else is automatic.

Loss function
$$L = \sum_v \left[ \operatorname{MSE}(R_v, T_v) + \lambda_n\operatorname{MSE}(\overline{R}_v, \overline{T}_v) \right] + \lambda_o L_{\text{overlap}} + \lambda_c N_{\text{pieces}}$$
Initialize

Random pieces

n sculptural pieces are created with random positions, rotations, and learnable control points defining their shapes.

Render

Differentiable rasterization

The arrangement is rendered from two fixed cameras with NVDiffRast, Nvidia's differentiable rasterizer, so the render itself can be differentiated.

Compare

Loss against both targets

Each rendered silhouette is compared to its target image, and penalties for overlap and piece count are added.

Descend

Gradient step

PyTorch Autograd backpropagates the loss through the renderer to every control point, and gradient descent nudges each piece's shape.

Rewrite

Discrete structural moves

Every m steps, stochastic rewrite descent proposes adding, deleting, restoring, or splitting pieces, and each proposal is kept only if it lowers the loss.

Repeat

Until convergence

Steps 02-05 loop until the sculpture satisfies both views with a clean, fabricable arrangement.

For each view \(v\): match the rendered silhouette \(R_v\) to the target \(T_v\), and separately match the negative space \(\overline{R}_v\) vs. \(\overline{T}_v\) so empty regions of the targets stay empty. The overlap term discourages pieces intersecting each other, and the piece-count term keeps the design minimal. Both matter for a sculpture you can actually build.


Stochastic rewrite descent

Gradient descent handles continuous changes, but some decisions are discrete: a piece may need to be added, deleted, restored, or split in two, and no gradient can express that. Every m steps the system performs stochastic rewrite descent: propose a candidate rewrite, re-render, and accept the change only if the loss improves.

Delete

Mandatory for pieces that shrink too small, violate constraints, or leave bounds; older small pieces are also stochastically culled after a lookahead test.

Add & restore

New pieces are spawned where they reduce loss, and previously removed pieces can return if they become useful again.

Split

A parent piece divides into two children, kept only when the finer granularity improves both views.


Results

Input images and optimized design, view one
Input target images and the optimized design.
Input images and optimized design, view two
The same sculpture from the second viewing angle.

PythonPyTorchNVDiffRastAutogradGradient DescentStochastic Rewrite Descent