Skip to content

Instantly share code, notes, and snippets.

@hholst80
Last active August 14, 2022 10:33
Show Gist options
  • Save hholst80/fd306df23fca0795234f97b4fd4a7ba2 to your computer and use it in GitHub Desktop.
Save hholst80/fd306df23fca0795234f97b4fd4a7ba2 to your computer and use it in GitHub Desktop.
crystal dreams 2 - see inside a cube effect

Crystal Dreams 2 - View the inside of a cube through a magic block

The effect

There is a rotating cube on the screen. There is also a magic block that enables us to view inside the Cube. The block is a plane with a thickness that always cuts through the center of the Cube. The two shapes rotates around a fixed center point during the entire effect (although the view frustum movies up and beyond). There are some of the usual pixel dust on screen as well, that interacts with the alpha channel but besides that nothing special. The focus of my analysis is of course on the magic block itself.

The effect is shown here: https://www.youtube.com/watch?v=7mWbnVPwX4U&t=142s

image

How to implement this?

I do not think they do triangle tessellation. As fun as it sounds to implement that I will try another approach.

Rendering pipeline

Note that the only thing about rendering I know I know from DOS mode 13h and VESA. I do not know the first thing about how a shader pipeline works.

I will assume we use an explicit render pipeline that emits triangles with a fixed color, using a Z-buffer and distance computed from the x,y,z render space coordinate to the block plane.

Step 1: Rendering the Cube

As a first step, how could the Cube be rendered?

As a rendering primitive I will assume a scanline that renders to the screen and to a depth buffer. The depth buffer should be able to hold z values or an approximation of such.

Casey calles this approach "implicit rendering" where each pixel on the screen is computed from the scene. Actually, this is not quite true as we will render each side first and then compute the scanlines from those so its an "explicit-implicit" rendering loop.

From every scanline we need a mapping (u,v) "screen space" to (x,y,z) from the view plane to the Cube side plane. This should be pretty straight forward with a frustum calculation (orthographic / perspective). There is also another mapping needed that takes a point in 3D and computes the distance to the Plane. Let p = (x,y,z) and define w: p :-> dist(p, Plane) If n is a unit normal for the rotating Plane then w(p) = dot(p,n) where the distance is defined as the smallest distance from p to the Plane. In the effect it is quite clear that the plane is not affine, that is, it always intersects origo, dist can be formulated as dot(n, p) and that will give us a signed distance function, such that points on the back side of the Plane will have a negative distance, and positive values of dot(n, p) will correspond to points on the positive side.

So for the Cube we render each side and in the scanline render we only render pixles that has a distance larger than "d" the width of the magic block oriented as the Plane. When I say "render" I mean render both to the screen and to the Z-buffer. Any render element that has a distance to the Plane within the width of the block are simply ignored during rendering.

Rendering the magic block

After the Cube has been rendered which a magic see-through cut-out, the magic block should be rendered. The block itself is transparent, so it needs to be rendered with Z-buffer for sure. The alpha-blending looks pretty straightforward to implement directly on the color pixels directly, without an explicit alpha channel.

Henrik Holst

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment