views:

400

answers:

1

Hi,

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.

+2  A: 

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.

Eric Bainville