Isometric projection

39 views
Skip to first unread message

Andrey Kleshchenko

unread,
Jan 20, 2016, 5:45:36 AM1/20/16
to PlayN
Hi!

I need help. Spend a half of night in experiments with matrix transformations. I tried to get correct isometric rotation matrix. Unfortunately did not get it. So bad.

According to the wiki, I need :
"The isometric transform from a point a_{x,y,z} in 3D space to a point b_{x,y} in 2D space looking into the first octant can be written mathematically with rotation matrices as:

\begin{bmatrix}
   \mathbf{c}_x \\
   \mathbf{c}_y \\
   \mathbf{c}_z \\
\end{bmatrix}=\begin{bmatrix}
   1 & 0 & 0  \\
   0 & {\cos\alpha} & {\sin\alpha}  \\
   0 & { - \sin\alpha} & {\cos\alpha}  \\
\end{bmatrix}\begin{bmatrix}
   {\cos\beta } & 0 & { - \sin\beta }  \\
   0 & 1 & 0  \\
   {\sin\beta } & 0 & {\cos\beta }  \\
\end{bmatrix}\begin{bmatrix}
   \mathbf{a}_x \\
   \mathbf{a}_y \\
   \mathbf{a}_z \\
\end{bmatrix}=\frac{1}{\sqrt{6}}\begin{bmatrix}
   \sqrt{3} & 0 & -\sqrt{3}  \\
   1 & 2 & 1  \\
   \sqrt{2} & -\sqrt{2} & \sqrt{2}  \\
\end{bmatrix}\begin{bmatrix}
   \mathbf{a}_x \\
   \mathbf{a}_y \\
   \mathbf{a}_z \\
\end{bmatrix}

where \alpha = \arcsin(\tan30^\circ)\approx35.264^\circ and \beta = 45^\circ. As explained above, this is a rotation around the vertical (here y) axis by \beta, followed by a rotation around the horizontal (here x) axis by \alpha. This is then followed by an orthographic projection to the x-y plane:


\begin{bmatrix}
   \mathbf{b}_x \\
   \mathbf{b}_y \\
   0 \\
\end{bmatrix}=
\begin{bmatrix}
   1 & 0 & 0  \\
   0 & 1 & 0  \\
   0 & 0 & 0  \\
\end{bmatrix}\begin{bmatrix}
   \mathbf{c}_x \\
   \mathbf{c}_y \\
   \mathbf{c}_z \\
\end{bmatrix}
"


I've tried like this:

Vector3 isoPosition = new Vector3(10,2,0);
       
Matrix3 matrix3 = new Matrix3()
               
.setToRotation(35.264F, 1, 0, 0)
               
.setToRotation(    45F, 0, 1, 0);
       
Vector3 result = matrix3.transform(isoPosition);
       
Vector screenPosition = new Vector(result.x, result.y)
It does completely wrong calculations.


To test transformation I use conversion from iso to screen and back from screen to iso (without z usage).

Vector3 isoPosition = new Vector3(10,2,0);
       
Matrix3 matrix3 = new Matrix3()
               
.setToRotation(35.264F, 1, 0, 0)
               
.setToRotation(    45F, 0, 1, 0);
       
Vector3 result = matrix3.transform(isoPosition);
       
Vector screenPosition = new Vector(result.x, result.y);

       
Matrix3 inversion = matrix3.invert();
       
Vector point = new Vector(screenPosition);
       
Vector toIso = inversion.transformPoint(point);
       
       
System.out.println("IsoToScreenMatrix [" + isoPosition + " -> " + screenPosition + "]");
       
System.out.println("IsoToScreenMatrix back [" + point + " -> " + toIso + "]");
And what I see :
IsoToScreenMatrix [[10.0, 2.0, 0.0] -> +5.253+2.0]
IsoToScreenMatrix back [+5.253+2.0 -> +1.908+2.0]
Correct values here are: (10.0, 2.0, 0.0) -> (8.0, 6.0); (8.0, 6.0) --> (10.0, 2.0, 0.0)


I've tested with different axis rotation but didn't find right pair :) I'm not good with matrices.



BTW, I have correct functions to do transformations like that. I've got them from one old ActionScript book. But having matrix is more comfortable to me, today.

Functions bellow helps me to test calculations with matrices. They work correct in all cases.

    public static final float Z_CORRECTION = (float) (Math.cos(-Math.PI / 6) * Math.sqrt(2));

   
/**
     * Converts a 3D position in iso space to a screen 2D point.
     *
     * @param position 3D position in iso space
     * @param target object which will contain returned values. If null a new object will created.
     * @return Vector which contains screen 2D point
     */

   
public static Vector isoToScreen(@Nonnull Vector3 position, @Nullable Vector target) {
       
float screenX = position.x - position.y;
       
float screenY = position.z * Z_CORRECTION + (position.x + position.y) * 0.5F;
       
return null == target ? new Vector(screenX, screenY) : target.set(screenX, screenY);
   
}

   
/**
     *Converts a 2D screen point to a 3D position in iso space, assuming z = 0.
     *
     * @param point the 2D point
     * @param target returned object. If null a new object will created
     * @return Vector3 which contains 3D iso position
     */

   
public static Vector3 screenToIso(@Nonnull Vector point, @Nullable Vector3 target) {
       
float positionX = point.y + point.x * 0.5F;
       
float positionY = point.y - point.x * 0.5F;
       
float positionZ = 0;
       
return null == target ? new Vector3(positionX, positionY, positionZ) : target.set(positionX, positionY, positionZ);
   
}


If someone has experience in isometric calculations or in rotation matrices, please, help!

Andrey Kleshchenko

unread,
May 5, 2016, 2:43:55 PM5/5/16
to PlayN
BTW, I found the solution:

import pythagoras.f.Matrix4;
import pythagoras.f.Vector;
import pythagoras.f.Vector3;

public class IsoUtil {

   
private static final Matrix4 ISOMETRIC_TRANSFORMATION_MATRIX;
   
private static final Matrix4 INVERTED_ISOMETRIC_TRANSFORMATION_MATRIX;

   
static {
        ISOMETRIC_TRANSFORMATION_MATRIX
= new Matrix4().setToIdentity()
               
.mult(new Matrix4().setToScale((float) (Math.sqrt(2.0) / 2.0), (float) (Math.sqrt(2.0) / 4.0), 1F))
               
.mult(new Matrix4().setToRotation((float) Math.toRadians(-45.0), 0F, 0F, 1F));
       
// inverted matrix for reverse translation
        INVERTED_ISOMETRIC_TRANSFORMATION_MATRIX
= ISOMETRIC_TRANSFORMATION_MATRIX.invert();
   
}

   
public static Vector isoToScreen(Vector3 position) {
       
Vector3 transform = ISOMETRIC_TRANSFORMATION_MATRIX.transformPoint(position, new Vector3());
       
return new Vector(transform.x, transform.y);
   
}

   
public static Vector3 screenToIso(Vector screenPosition) {
       
return INVERTED_ISOMETRIC_TRANSFORMATION_MATRIX.projectPoint(new Vector3(screenPosition.x, screenPosition.y, 0));
   
}

}

Enjoy!

Reply all
Reply to author
Forward
0 new messages