I drew a simple 3-coordinate graph in canvas above;
I defined a few constants to work with
var width = window.innerWidth * 0.5 , height = window.innerWidth * 0.5;
var cx = width / 2, cy = height / 2, cz = height / 2, blcx = 0, blcy = height, brcz = height, brcx = width, brcy = height;
var ySegment = height / 30;
var xSegment = width / 30;
var xSegmentRatio = xSegment / width;
var ySegmentRatio = ySegment / height;
cx and cy and cz all refer to the center of the canvas. blcx
means bottom-left-corner-x, brcy
is bottom-right-corner-y, etc. I realize this is a bit hack-ish, as this is the first attempt to do this, but if you bear with me, there is a real concept I am trying to grasp here.
and then drew the red lines like this:
(function() {
var gridCx = cx, gridCy = cy, gridCz = cz;
var gridBlCx = blcx, gridBlCy = brcy;
for (var i = cx; i < width; i++) {
gridCx += xSegment;
gridBlCx += ySegment;
gridCzx -= gridCzx * (xSegmentRatio / ySegmentRatio);
ctx.beginPath();
ctx.moveTo(gridCx, cy);
ctx.lineTo(gridBlCx, height);
ctx.strokeStyle="#FF0000";
ctx.stroke();
}
})();
I tried this:
gridCzx -= gridCzx * xSegmentRatio;
gridCzy += gridCzy * ySegmentRatio;
ctx.beginPath();
ctx.moveTo(gridCzx, gridCzy);
ctx.lineTo(width, gridCzy);
ctx.strokeStyle = "#ff0000";
ctx.stroke();
and got this:
But I realized I am missing some fundamental mathematical concept. Thanks for any insight you can give! My basic question here is: How do I select a point on the z-axis given a distance away from the center?
Axis tell us how to move
To find a point in the first dimension x, move along the x axis, from left to right. To find a point in the second dimension y you must integrate both the first and second dimensions, thus 1st x from left to right, once you have that then 2nd along the y axis down the screen.
With each dimension you rely on the positioning of the previous dimension. It also relies on the axis, the x and y axis are at 90 deg to each other, but they could be at 45 or 120, it would not make any difference to finding 2D coords of a point. First along X axis then Y along the y axis.
Vector functions
Because the display is only 2D the axis can be represented as 2D vectors. The length of the vector tells the scale of the axis. Thus for the x axis if I define the axis as a 2D (display coords) vector (2,0) then I am saying that it goes 2 across and 0 down for each unit in the x coordinate. If I want to be at x coordinate 10 I multiply it by the axis to get the screen position.
Thus to the code...
function screenCoord(x,y){ // creates a coordinate in screen space
// screen space is always in pixels
// screen space always has the origin (0,0) at the top left
return {
x : x,
y : y,
}
}
function screenVector(x,y){ // a vector in screen space it points in a direction
// and its is in pixels
return { // basically identical to the last function
x : x,
y : y,
}
}
So let's define the X axis that I had (2,0) scaled up by 2
var xAxis = screenVector(2,0);
Now a x position say 10
var xPos = 10
To find its location we need to get the screen coordinates along the x axis. We do that by multiplying xAxis by xPos. To make it easier we can create a vector multiply function
function multiply(vector, value){
var x = vector.x * value; // multiply the vector x by value
var y = vector.y * value; // multiply the vector y by value
return screenCoord(x,y)
}
Now to find the first dimensional pos of xPos
var screenPos = multiply(xAxis, xPos); // returns the screen position of x = 10
Now to do the 2nd dimension we add that to the previous. Let's define a function to add a vector to another
function add(vector1, vector2){ // adds two vectors returning a new one
var x = vector1.x + vector2.x;
var y = vector1.y + vector2.y;
return screenCoord(x,y);
}
So now lets create the y axis
var yAxis = new screenVector(0,2); // y goes down the screen and has no x change
and the y pos
var posY = 10;
So now lets do it from x
var screenPosX = multiply(xAxis,posX); // get the x position on the screen
var screenPosY = multiply(yAxis,posY); // get the y position on the screen
Now we add the results of the two coordinates
var screenXY = add(screenPosX,screenPosY);
And we have a coordinate on the screen of x = 10 and y = 10 (which in this case turns out to be at pixel location 20 across 20 down.
The 3rd dimension
Now it does not take much to guess what happens for the 3rd z dimension. For x along x axis, then y along the y axis and then z along the z axis
So define the z axis
var yAxis = new screenVector(1,-1); // z axis along the diagonal from bottom left to top right
Now the z coord
var posZ = 10;
So to find our 3d position, x along its axis, then add y along its and then add z along its axis
var screenPosX = multiply(xAxis,posX); // get the x position on the screen
var screenPosY = multiply(yAxis,posY); // get the y position on the screen
var screenPosZ = multiply(zAxis,posZ); // get the z position on the screen
need to add them together
var screenXY = add(screenPosX,screenPosY);
Then z
var screenXYZ = add(screenPosXY,screenPosZ);
and there you have how to do the conversion from one set of coordinates to another. It is called a transform
The origin
We are missing one last bit of information. The origin. This is where on the screen the the coords 0,0,0 (x,y,z) will be. It is the last part of the transform and is in screen coords (x,y)
var origin = screenCoords(100,500); // set the origin at 100 pixels across 500 down
From the last calculation we got the screenXYZ coordinate in screen space, we need to add the origin to it
screenXYZ = add(screenXYZ ,origin);
Now you can draw the pixel at coordinates (10,10,10) (x,y,z) from the origin in on the 2d screen.
The Matrix
Hope that helps, if you understand that you have just learnt how to use a 3D transformation matrix. It holds the x,y,z axis as a set of three 2D directions, and the coordinates of the origin. The matrix does the very same functional steps, just it does it in a simple array that makes it more efficient and following some matrix rules allows very complex transforms. For example if you want to rotate, all you need to do is change the direction of the axies and you have rotated the object. To change the scale just change the length of the axis, to move the object just change the position of the origin.