Manifold
Madness
Adventures in Topological
Transformation
Forrest Reiling
Manifold Madness is a relatively simple puzzle game designed to uniquely challenge the player by requiring them to navigate to a goal which can only be reached by changing the curvature of the game space in which the player and goal exist. The world is composed of a network of checkered tiles on which the player can drive, as well as gaps on which they cannot drive, in the usual euclidean 3-space with which we are all very familiar.
The map is small, and the user cannot drive beyond its edge - as there are no tiles there - and thus cannot reach the goal (marked by the green cone). However, above some of the tiles float triggers which project the game space into one of five 2-manifolds (details on how this is done coming up). When the player drives under them it projects the game space onto the associated manifold, thereby closing the edges of the map against one another and allowing the player to move around the map in ways that they could not before. These triggers are shaped like the manifold onto which they project the space, as they are created by passing the vertices of a flat triangle network into the same function which projects the game space at runtime, and are placed around the map such that the player must trigger them in a specific sequence in order to reach the goal.
[Figure 2: Manifold triggers. From left to right: sphere, torus, klien bottle, real projective plane]
The manifolds onto which the game space is projected are embedded in the euclidean 3-space to allow the user to see and understand the curvature they are navigating. Because the game space is 3D and the manifolds are only 2D, the mapping between the game space and the manifold space cannot be affine, and the dimensionality of the game space must be reduced. However, the surface created by embedding the manifold in the euclidean 3-space is continuously differentiable and therefore has a well defined normal at all points, which can be used as the third dimension of the projected game space. This in essence wraps the 3D game space around the embedded 2-manifold such that the XZ plane of the game space forms the surface of the embedded manifold, stretching and compressing the geometry as necessary.
The game space can be projected onto one of five unique 2-manifolds: the plane, sphere, torus, klien bottle, and real projective plane. Projection is performed by a special function which takes as input a 3 dimensional position in the game space and an integer manifold constant indicating which manifold is desired and returns a 4x4 matrix whose first three columns are the basis vectors of the local flat manifold tangent space and whose forth column is the position of the input point on the surface formed by embedding the desired manifold in 3-space. Once this matrix is resolved, one can use the matrix to transform vectors into the tangent space by multiplying them into the matrix, as well as points by multiplying the origin into the same matrix. The projection function is linked into the C++ program controlling user interaction, allowing projection of uniform constants like light and camera positions, in addition to being linked into the vertex shader, allowing efficient projection of vertices and their normals into the tangent space in parallel (which is the primary motivation behind returning a matrix containing both position and vector transformations from the manifold function, as each vertex has a normal which exists in the same tangent space, which avoids computing the tangent space twice per vertex) .
In general, the manifold function calculates the tangent space by mapping the X and Z components of the input point into the two parameters of whatever parameterization is chosen to embed the manifold in 3-space (which of course means only parameterizations on two variables can be used). Plugging these two parameters into the parameterization yields a 3D point on the surface of the embedded manifold (flattening the Y component of the point, since only the X and Z components are considered). The parameterized gradient function of this surface parameterization with respect to each of its parameters is calculated beforehand, and plugging these same parameters into these two gradient parameterizations yields two vectors representing the gradient of the surface with respect to its parameters at the input point. Since one parameter is mapped to X and the other to Z these two vectors represent the X and Z basis vectors of the tangent space at this point. Crossing the X and Z basis vectors gives the Y basis vector (which is normal to the surface at that point), and multiplying the Y component of the input point into this normal vector and adding the result to the point on the surface calculated earlier gives the full, un-flattened position in of the point in the manifold tangent space. The three basis vectors and this position then become the columns of the returned matrix. There is nothing notable about the parameterizations used for the plane. sphere, or torus, but it is worth noting here that the for the klien bottle I used the so called “figure 8 immersion” and for the real projective plane I used the Bryant-Kusner immersion of Boy's surface (Which gave me a great deal of trouble as it is parameterized over the area of the unit circle in the complex number plane and GLSL has no complex number operators, requiring me to implement complex number operation on the the vec2 type)
[Figure 3: Game space wrapped onto (clockwise from top left) plane, sphere, torus, klien bottle]
In addition to the manifold projection technology discussed here I also implemented a number of other, more common graphics technologies to improve appearance and game play. All of the geometry in the game space is hierarchically modeled inside a tree of CModel objects, each containing a transformation matrix, material, texture, mesh, and of course a list vector of CModel children. Faces are colored with full per-pixel Phong shading on top of the sampled texture color. Maps are inflated from integer arrays, and collision with the edge of the navigable tile network is calculated based on this map. In addition, when the player tries to drive off the tiles, instead of simple disallowing this and stopping the vehicle, the engine projects the players attempted movement onto the edge they were not allowed to cross, and moves the vehicle by this projection. This allows the vehicle to “slide” along the edge of the tile network, making high-speed navigation of curved spaces marginally less frustrating. Other spit-and-polish visual effects include exponentially interpolating vehicle orientation onto camera orientation, so that when the user rotates the camera the vehicle follows smoothly along a curve. Manifold transitions are also interpolated by handing the vertex shader the manifold constant for the new manifold as well as the old manifold, as well as an interpolation value between 0 and 1, allowing each vertex to calculate its interpolated position between where it was on the old manifold and where it will be on the new manifold. This means that when a transition is triggered all the vertices move in a straight line from their old position to their new position, creating the effect of one manifold folding and twisting onto the other without interrupting game play. When not transitioning, the interpolation value is held at -1, and the vertex shader ignores the old manifold, thereby avoiding detrimental effects on performance.