Rotating 3D cube perspective problem
3d, cube, graphics, svg
Solution
Usually, projection is done on the Z=0 plane from an eye position behind this plane. The projected point is the intersection of the line (Pt,Eye) with the Z=0 plane. At the end you get something like:
screenX = scaling * pointX / (1 + pointZ/eyeDist)
screenY = scaling * pointY / (1 + pointZ/eyeDist)
I assume here the camera is at (0,0,0) and eye at (0,0,-eyeDist). If eyeDist becomes infinite, you obtain a parallel projection.
Problem
Since I was 13 and playing around with AMOS 3D I've been wanting to learn how to code 3D graphics. Now, 10 years later, I finally think I have have accumulated enough maths to give it a go. I have followed various tutorials, and defined screenX (and screenY, equivalently) as ``` screenX = (pointX * cameraX) / distance ``` (Plus offsets and scaling.) My problem is with what the distance variable actually refers to. I have seen distance being defined as the difference in z between the camera and the point. However, that cannot be completely right though, since x and y have the same effect as z on the actual distance from the camera to the point. I implemented distance as the actual distance, but the result gives a somewhat skewed perspective, as if it had "too much" perspective. My "actual distance" implementation was along the lines of: ``` distance = new Vector(pointX, pointY, cameraZ - pointZ).magnitude() ``` Playing around with the code, I added an extra variable to my equation, a perspectiveCoefficient as follows: ``` distance = new Vector(pointX * perspectiveCoefficient, pointY * perspectiveCoefficient, cameraZ - pointZ).magnitude() ``` For some reason, that is beyond me, I tend to get the best result setting the perspectiveCoefficient to 1/sqrt(2). My 3D test cube is at http://vega.soi.city.ac.uk/~abdv866/3dcubetest/3dtest.svg. (Tested in Safari and FF.) It prompts you for a perspectiveCoefficient, where 0 gives a perspective without taking x/y distance into consideration, and 1 gives you a perspective where x, y and z distance is equally considered. It defaults to 1/sqrt(2). The cube can be rotated about x and y using the arrow keys. (For anyone interested, the relevant code is in update() in the View.js file.) Grateful for any ideas on this.