## The Escher Stripes Project

by Arina Rivkin Introduction:

The works of the famous Dutch graphic artist M.C. Escher had become the great interest of many people working in Computer Graphics field. On his drawing Escher presents variety of graphical effects and illusions. The main challenge for Computer Graphics people is to create the models that look like so-called impossible structures on his drawings.

Project description:

This project concentrated on one of the Escher's works called "Rind". The goal was to take a general 3D computer model and create the stripe that envelops it, the same way the stripe encloses the head on the original picture.
The problem was solved by two different approaches, using two well known Computer Graphics techniques, Ray Tracing and Volumetric Texture Mapping. The algorithms for creating the stripe are presented in the next section.

The project was written using IRIT solid modeling system.

Algorithms:

Two algorithms, that achieve the stripe effect, were offered and implemented in this project.

But first, a little bit of mathematics. The shape of the stripe resembles a helix. The helix with radius r and rotational axis  Z, can be described by the parametric curve c(t) = (r*cos(t), r*sin(t), t). Both methods are based on this representation.

• The first algorithm uses Ray Tracing.

In general, Ray Tracing is a rendering method. It traces rays of light from the eye back through the image plane into the scene. Then the rays are tested against all objects in the scene to determine if they intersect any of objects. In our application we've used ray tracing a little differently.

For now, we suppose that the scene (the model) consists the only one object and also that object must have rotational axis. That is, if we place the object in coordinate system's origin, at least one of the axes will pass through the whole object. For example, if you look at the handle of the teapot, you won't find the axis that will pass through the whole handle, on the contrary, the for the body of the teapot all axes are rotational. For the coming explanations we will relate to a rotational axis as the Z axis.

First thing that must be done is deciding which axis will be the rotational axis. Then, the algorithm sends rays that originate at infinity towards the rotational axis. The algorithm is shooting rays from the bottom of the object and gradually moving toward it's top. The direction of  each ray is perpendicular to rotational axis, while the XY direction depends on the height of ray's origin relatively to object bottom. We calculate the XY direction accordingly to the helix equation c(t) = (cos(t), sin(t), t), while t is the rays height. Each ray is traced against the object and if the ray intersects the object, we know that this intersection point is lying on the stripe's lower boundary. To get points on the stripe's upper boundary, we are shooting a second set of the rays with some displacement above the first set. This way we collect points on both stripe's boundaries. The only task left, is triangulating the stripe. In this algorithm we do this concurrently with collecting the points on stripe's boundary. That is, we search for alternate points from lower and upper boundaries. Each new point generates a new triangle along with two former points that we found.

This approach won't work for all kind of models, like those consist from several objects or with no trivial rotational axis..

To solve the problem of several objects in one model, we change our algorithm a bit. Now, when we test the ray for intersections with objects, among all ray-object intersection points that we find, we will choose the farthest of all from the rotational axis.

What if we have an object that don't have any rotational axis? We offer for the user to define that kind of axis curve for ill-defined objects, like the teapot handle and spout, and than instead of moving up on axis the ray, will move along the curve.

• The second algorithm uses Volumetric Texture Mapping.

Every application, that uses a volumetric texture mapping technique, goes through all the points on the object's surface and on each point applies a function. This function can make some manipulations on the point's color or on the normal of the surface in that point etc.

Here we assume that the model has a rotational axis. No other models were treated by this algorithm.

In our application we define such a function to decide whether the point is lying on one of the stripe's boundaries or not. Like in the first algorithm, the user must define the rotational axis (we'll assume that Z is a rotational axis). The coordinates of the points on the lower stripe boundary must be (a*cos(t), a*sin(t), t). And similarly, the coordinates of the points on the upper stripe boundary must be          (a*cos(t), a*sin(t), t+Δ). Therefore, the mapping function checks the point's coordinates and if they meet one of the demands above, mark the point as one on the boundary. This way we collect the points on the stripe's boundaries. In this algorithm there is no way to triangulate the stripe in the same time that we searching for new points and also the points we find are not distributed uniformly on both stripe, that makes it harder to perform trivial triangulation, like in the first algorithm, by taking alternating points from upper and lower stripe one after another. Thus, here we make some estimations of distances between last point participating in triangulation and the new candidate point, to achieve optimal triangulation.

As one can see, the requirement for a point to have the (a*cos(t), a*sin(t), t) coordinates is just another way to demand a ray, that origin at (0, 0, t) and is directed at (cos(t), sin(t), 0),  intersect the surface at the given point. So, as it was said earlier, the two algorithms just approach the problem from the different views.

Once we created the stripe, we add some "noise" to it. The noise makes the stripe to look more like a texture stripe, i.e. more "wavy". The user can set the magnitude and the frequency of the noise.

Examples:

EscherStripesRayIntr -i teapot1.itd -r y -w 0.2 -a 10 -p 0.4 -f 30 -c tpotCrvs.itd -o teapotStripe1.itd EscherStripesRayIntr  -i pawns.itd -w 0.04 -n 0.007 -a 3 -p 0.06 -f 10 -o pawnsStripe.itd EscherStripesRayIntr -i teapot2.itd -r x  -n 0.0 -f 100 -s -o teapotStripe2.itd EscherStripesVolTextureMap -i orange.itd -w 0.4 -n 0.07  -p 0.25 -f 100 -o orangeStripe.itd EscherStripesVolTextureMap -i glass.itd -w 0.2 -n 0.08  -p 0.25 -f 70 -o glassStripe.itd User Manual:

The applications are command line applications, so there are number of options that can be set by the user.

The possible options for both applications are:

[-i string] [-r "x" "y" "z"] [-w float] [-n double] [-p double] [-f integer] [-o string]

• -i:     input file name
• -r:    "x" or "y" or "z" : specify the rotational axis [default value: "z"]
• -w:   width of the stripe, in the object scale [default value: 0.1]
• -n:    maximal magnitude of the noise [default value: 0.05]
• -p:    advance per 360 degrees of the stripe, i.e. pitch [default value: 0.2]
• -f:     fineness, i.e. resolution of the created stripe [default value: 50]
• -o:    output file name

The additional three switches for the application that uses ray tracing are:

[-a integer] [-c string] [-s]

• -a:    noise frequency, means how many "waves" will be on stripe per 360 degrees [default value: 5]
• -c:    specifies the file name of rotational curve(s) data.
• -s :   specifies that the model, if consists of several objects, will be treated as one object [default is false]

Also, stripe width, stripe pitch and noise magnitude can be set separately for each object of the original model. The user can add these three attributes directly to the data file. The names of the attributes are [stripe_width ...], [stripe_pitch ...] and [stripe_noise ...]. The values of these attributes will be treated as RELATIVE values, i.e. the value that was set by the command line or default value will be multiplied by the attribute value for each object of the model, if that attribute appear in the data file.