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
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();
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:
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 inCreateOrthographic
. 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
Is There a C++ Iterator That Can Iterate Over a File Line by Line
Gcc: Difference Between -O3 and -Os
How to "Normalize" a Pathname Using Boost::Filesystem
Segfaults in Malloc() and Malloc_Consolidate()
Do Stl Iterators Guarantee Validity After Collection Was Changed
Constructor Initialization VS Assignment
Who Defines C Operator Precedence and Associativity
Comma Operator in If Condition
Why Don't Std::Vector's Elements Need a Default Constructor
Comparing 3 Modern C++ Ways to Convert Integral Values to Strings
Implicit Conversion When Overloading Operators for Template Classes
Std::Forward_List and Std::Forward_List::Push_Back
Looking for 16-Bit X86 Compiler
Implicit VS Explicit Conversion