开发者

Navigating though the surface of a hypersphere in OpenGL

Maybe this fits in math.stackexchange.com, but since I am programing it in OpenGL, I shall ask it here.

I had the idea of an spaceship game where the world is confined in the surface of an 4-D hypersphere (also called a 3-sphere). Thus, in seeing it from inside, it would look like a 3-D world, but by navigating in every direction, I would never leave the limited volume of the 3-sphere.

To represent the 3-shpere as a "flat" 3-D space, I use an stereographic projection, which is very simple to implement as a GLSL shader, just need to divide the input vector by one minus its w coordinate.

To represent the vertices of the objects I am using normalized 4d vectors, such that x²+y²+z²+w²=1, thus keeping them inside the 3-sphere.

The first problem to solve was rotation. But I soon figured out that ordinary 3d rotation matrices would suffice to rotate the world around the viewer in the 3d projection, since it does not mess up with the w coordinate (pretty much like rotating a sphere around the z-axis would also rotate its stereographic projection).

Then I figured out that rotating along w-axis would be equivalent of translation inside the 3d projection (just not commutative, as ordinary开发者_如何学C 3d translations on "flat" spaces), then I could translate along the axis by using a simple around axis rotation matrix (x', y') = (x * cos a - y * sin a, x * sin a + y * cos a), but variating w along with another axis.

This is so far where I got, and I could not figure out how to navigate forward, based on the position the viewer is facing from the projection. I can apply the inverse transform to derive the normalized 4-D vector (called F) the viewer is facing in the hypersphere coordinates, but I don't know how to navigate in that direction by using a 4x4 matrix (what is optimal in OpenGL). I could think on a hackish solution: for every vertex V, do V' = normalize(d*F + V), where d is the distance moved forward (in some strange unit I can not exactly precise). This way only works for small values of d, there is no direct correlation between d and the angle variation.

Thus the question is: how to move forward (using a 4x4 matrix transform) being in the surface of a 4-D hypersphere?


It turns out that I wrote some papers in this area some time ago. This one (Interactive Visualization Methods For Four Dimensions) applies most closely to your particular problem but the other documents that cite this one may also help you. In that particular application, I was rotating the object being observed in 4D, not the viewer, but the math is equivalent.

Regarding this specific question:

Thus the question is: how to move forward (using a 4x4 matrix transform) being in the surface of an 4-D hypersphere?

If you're moving around on the surface of a hypersphere, you aren't translating in w. You actually need to move in the spherical geometry around a great circle of unit radius. That means that, if you can construct the appropriate axes for your frame of reference, you can spherically interpolate between where you are and where you are going.

For example, one construction that could be used for such a slerp would be to use the unit vector that points straight ahead (your line of sight, aka p_1 in the Wikipedia equation), a vector point out of the top of your head (p_0) and a vector pointing out of your right ear (to make a right-handed coordinate system).

If you are then tracking your speed over the sphere in angular velocity rather than linear, you can just plug in a value for t (elapsed time) in the Wikipedia to find your new angular position.

Note that that equation places no limit on the number of components in the vertex p. Spherical interpolation works in any geometry.

EDIT (responding to questions in the comments):

Slerp seems not to be the case here, because I do not want to interpolate a rotation between 2 vectors over time. Instead, at each time step, I want to move every vertex into the opposite direction the viewer is moving at that moment. Thus, I am at position (0, 0, 0, 1) and I want to be at (sqrt(2)/2, sqrt(2)/2, 0, 0) next frame.

Think of it this way: your position on a sphere (of any dimension) is a vector that displaces you from the center to the surface. If you're moving around at a particular angular velocity, that puts you at p0 and time t0, p1 at time t1, etc. Slerp is a handy way of calculating those positions at a particular time.

Likewise, your line of sight is a vector at right angles to the displacement vector. Line of sight is v0 at time t0, v1 at time t1 and so forth. Slerp again is useful for for calculating that vector.

How can I build the correspondent transformation matrix, so every vertex will be multiplied by the inverse of it?

Using those two vectors, orthogonalization gives you a third and you now have a new reference frame. There is a single quaternion that defines the rotation from your original reference frame to this new one. That's what your looking for.

HOWEVER, before you can render your world onto a two dimensional screen, you first need to render it down from 4D to 3D. OpenGL (unsurprisingly) does not directly support this.

To see why, look at the perspective projection matrix. It assumes that you are rendering homogenous points in 3D space: x, y, z are in the first three components and w (a scaling factor) is in the fourth. w = 0 indicates a vector whereas w = anything else indicates a point. w = anything other than 1 is a non-normalized point.

So, there isn't a way to render a point at the 4D origin of (0, 0, 0, 0).

As you can see from the construction of the matrix, however, it isn't hard to make the 4D to 3D projection matrix. Apply that first to your geometry set independently from OpenGL's matrix pipeline. Then you can use OpenGL standard matrices for 3D to the screen.


You'll probably need 5x5 matrices, as you're operating on a 4-space. The idea of homogenous coordinates is to introduce an additional dimension to represent additive operations by application of a linear operator.

I really like your idea, but just out of curiosity: Why not simply define a cyclic 3-space, i.e. wrap coordinates at a given value. Using a geometry shader you can duplicate those vertices of primitives that wrap around (you have to clip, and move the clipped vertex together with the introduced helper vertices toward the opposite end of the space). This would result in a kind of hall of mirrors effect, so you also have to introduce some kind of horizon.


I did ask the same question on math.stackexchange.com, because the question is too math related and I could possibly get a better answer there. Look here if you are interested in the original answer I've actually used.

Being in 4D, there is not a single vector perpendicular to any rotation, but actually a whole plane of perpendicular vectors, and that was confusing me.

Also, in OpenGL, I soon figured out that I could simplify the computation of the given solution, because I could always assume I am at the 4D projection origin (0,0,0,-1), always facing (0,0,-1,0), then translate a given angle along z and w, and multiply it to the already accumulated GL_MODELVIEW_MATRIX from the previous frame. So I did MODELVIEW <= M x MODELVIEW instead of MODELVIEW <= MODELVIEW x M I would get if I simply called glMultMatrix(M).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜