True Isometric Projection with Opengl

true isometric projection with opengl

Try using gluLookAt

glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

/* use this length so that camera is 1 unit away from origin */
double dist = sqrt(1 / 3.0);

gluLookAt(dist, dist, dist, /* position of camera */
0.0, 0.0, 0.0, /* where camera is pointing at */
0.0, 1.0, 0.0); /* which direction is up */
glMatrixMode(GL_MODELVIEW);

glBegin(GL_LINES);

glColor3d(1.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(1.0, 0.0, 0.0);

glColor3d(0.0, 1.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 1.0, 0.0);

glColor3d(0.0, 0.0, 1.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 1.0);

glEnd();

glFlush();

Results in

alt text

We can draw a cube to check that parallel lines are indeed parallel

glPushMatrix();
glTranslated(0.5, 0.5, 0.5);
glColor3d(0.5, 0.5, 0.5);
glutWireCube(1);
glPopMatrix();

alt text

OpenGL isometric projection clipping

By closer look at frustum near and far planes you can see they are set badly

    N: Plane[ [ 0.57735026, 0.57735026, 0.57735026 ], 0.0], 
F: Plane[ [ -0.57735026, -0.57735026, -0.57735026 ], 1.9999998]],

solution is easy set ortho projection first with correct near/far values and then multiply it with lookat function matrix

    pmv.glMatrixMode(PMVMatrix.GL_PROJECTION);
pmv.glLoadIdentity();
pmv.glOrthof(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
float dist = (float)Math.sqrt(1 / 3.0f);
pmv.gluLookAt(dist, dist, dist,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);

results in:

    N: Plane[ [ -0.57735026, -0.57735026, -0.57735026 ], 1.9999998], 
F: Plane[ [ 0.57735026, 0.57735026, 0.57735026 ], 0.0]],

Isometric Projection using Opengl

Actually your code is correct. You just went for some misconception of OpenGLs default coordinate system. In OpenGL's standard coordinate system X goes right, Y goes up and Z points out of the screen. Your yellow line goes from (1,0,0) to (1,0,0), i.e. from a point to the right to a point up. It's perfectly correct.

Isometric view in OpenGL

For a perfect isometric view, the point of view has to be on a diagonal of a cube. This means if the target of the view is (0, 0, 0) then the absolute value of the x, y and z coordinate of the eye position has to be equal.

When you look at the formula which calculates x, y, and z:

self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
self.y = cos(radians(self.theta)) + self.dy

This means you've to find a phi and theta that result in equal x, y and z.

For phi this is easy. Phi is only use do calculate x and z. x depends on cos(phi) and z depends on sin(phi) since sin(45) == cos(45), phi has to be 45°.

sin(45) is equal 1/sqrt(2).

So it has to be found a theta, where x, y and z are equal when

x = sin(theta) * 1/sqrt(2)
z = sin(theta) * 1/sqrt(2)
y = cos(theta)

This means

sin(theta) * 1/sqrt(2) = cos(theta) 

From Pythagoras we know that:

cos²(theta) + sin²(theta) = 1

So

sin(theta) = cos(theta) * sqrt(2) and sin²(theta) = 1 - cos²(theta)

1 - cos²(theta) = cos²(theta) * 2

1 = cos(theta) * sqrt(3)

theta = acos(1/sqrt(3))

At the end phi and theta have to be:

self.phi   = 45
self.theta = 54.735610317245345684622999669982

How to render with isometric perspective?

It is easier to use glOrtho then rotate the axes:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(35.264f, 1.0f, 0.0f, 0.0f);
glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);

Coloring for 3D Isometric projection

Your code uses the format verb %x to print the hex values to the SVG's fill attribute:

fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g' fill='#%x%x%x'/>\n",
ax, ay, bx, by, cx, cy, dx, dy, r, g, b)

This causes some numbers like 0 and 1 to be formatted with one hex digit. For example RGB (254, 0, 1) would be formatted as fe01. The browser then render colors incorrectly.

Change the format verbs to %02x to ensure the RGB is always printed with two hex digits.

Now RGB (254, 0, 1) is printed as fe0001, which is the correct hex color.

Output:

Sample Image

Switching from perspective orthographic projection in OpenGL

It seems like you're having trouble understanding orthographic projections.

There are several reasons why your scene doesn't look right in an orthographic view:

  • The perspective projection gives the appropriate
    depth to the floor so it can be seen; objects look bigger when they're closer to you. But the orthographic projection doesn't change their size according to their depth. Moreover, the reason the floor "disappears" in the orthographic projection is that the floor
    is "infinitely thin" and oriented horizontally.
  • Your orthographic projection resizes the screen so that one pixel in window space
    corresponds to 1 unit in object space. Since the rings are (it seems) about 12 units in size, they will look rather small on the screen. One solution may be to use a smaller size in CreateOrthographic. But this won't solve everything; for instance, the floor will still remain "invisible".

Note also:

  • If you use an orthographic projection, you can even use negative values for zNear,
    but probably not 0. This isn't the case for a perspective projection.
  • The orthographic projection can form the basis for a 3D-like projection called the isometric projection.


Related Topics



Leave a reply



Submit