Here is the javascript code for this program along with my comments. Feel free to use this code and if you add some other cool functions to change things up, let me know! I would be interested to see what you accomplished.
var W = 600, H = 600; //variables for size of canvas
var step = {amnt: 0.5};
var MODEL_MIN_X = -2, MODEL_MAX_X = 2;
var MODEL_MIN_Y = -2, MODEL_MAX_Y = 2;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var points = []; //points array instantiation
var theta = 0;//start point for theta angle
/*The values below all can influence speed of rotation - larger values increase speed*/
var dtheta = 0.01;//MAIN CONTROL OF ROTATION SPEED
var yRotate = 1.0;//controls rotation around y axis
var xRotate = 0.5;//controls rotation around x axis
//listens for x_rotation update
document.getElementById('x_rotation').addEventListener('change',xRotation);
//changes the xRotate value
function xRotation(){
var x = document.getElementById('x_rotation').value;
xRotate = x*1.0; //multiplied by 1.0 to force decimal number usage
}
//listens for y_rotation update
document.getElementById('y_rotation').addEventListener('change', yRotation);
//changes the yRotate value
function yRotation(){
var y = document.getElementById('y_rotation').value;
yRotate = y*1.0;
}
//listens for dtheta change or update
document.getElementById('speed_rotation').addEventListener('change',speedRotation);
//changes the value of dtheta
function speedRotation(){
var speed = document.getElementById('speed_rotation').value;
dtheta = speed*1.0;
}
//listens for update of edgedots value
document.getElementById('edge_dots').addEventListener('change', numEdgeDots);
//update number of points along edge
function numEdgeDots(){
var edgedots = document.getElementById('edge_dots').value;
step.amnt = edgedots*1.0;//Multiply by 1.0 to make sure decimal num
points = [];
initGeometry();
}
document.getElementById('edge_dots2').addEventListener('change', numEdgeDots2);
function numEdgeDots2(){
var edgedots2 = document.getElementById('edge_dots2').value;
step.amnt = edgedots2*1.0;
initGeometry();
}
//default values on page opening, for distance, color, and background color
var perspective_distance = {amnt: 2.5};
var color = {colordots: 'white'};
var background_color = {backcolor: 'black'};
//all the addEventListener below listen for changes in corresponding id:
document.getElementById('color_change2').addEventListener('change', colorBackground);
document.getElementById('color_change').addEventListener('change', colorDots);
document.getElementById('view_distance').addEventListener('change', perspectiveDistance);
function perspectiveDistance(){
var x = document.getElementById('view_distance').value;
perspective_distance.amnt = x*1.0;
}
function pauseProgram(){
alert("Program paused. Click OK to continue.");
}
function colorDots(){
//alert("stop");
var col = document.getElementById('color_change').value;
color.colordots = col;
}
function colorBackground(){
var col_b = document.getElementById('color_change2').value;
background_color.backcolor = col_b;
}
function theParameters(){
//perspective_distance.amnt = 2.5;
step.amnt = 0.3;
}
//vars were here previously, but moved them up to top of page.
//1. this function gives numbers for x,y,z in points[]
function initGeometry(){
for(var x = -1; x <= 1; x += step.amnt){
for(var y = -1; y <= 1; y += step.amnt){
for(var z = -1; z <= 1; z += step.amnt){
points.push([x,y,z]);
}
}
}
}
//5.
function perspectiveProjection(point){
var x = point[0],
y = point[1],
z = point[2];
return [//i believe this is the homogeneous effect he's doing here
x/(z + perspective_distance.amnt),//z + 1 is distance from camera to viewing screen
y/(z + perspective_distance.amnt)
];
}
//4.
function project(point){//this function takes coordinates from the model space, which is the 3D space,
//and projects them into 2dimension space - this should also remove the z component
//because only x,y shows on 2D canvas
//so basically takes 3d point and makes it 2dimension
var perspectivePoint = perspectiveProjection(point);
var x = perspectivePoint[0],
y = perspectivePoint[1];
return [
//this below takes from -2 to 2 and gives value of from 0 to min or max canvas dimensions
W*(x - MODEL_MIN_X)/(MODEL_MAX_X - MODEL_MIN_X),
H*(1 - (y - MODEL_MIN_Y)/(MODEL_MAX_Y - MODEL_MIN_Y))//1- added so to convert canvas y direction
//to 3d y direction (positive up)
];
}
//3. this function is used by render() and
//gets help from project(point)
function renderPoint(point){//this function takes a point and draws it
var projectedPoint = project(point);
var x = projectedPoint[0],
y = projectedPoint[1];
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x + 2, y + 2);//both these were 1
ctx.lineWidth = 2;//this was 4
ctx.strokeStyle = color.colordots;//this was white
ctx.stroke();
}
//2.5. row_box
function rotateY(point, theta){
var x = point[0],
y = point[1],
z = point[2];
return [
Math.cos(theta)*x - Math.sin(theta)*z,//this is new x value
y,//this is same y value as previous
Math.sin(theta)*x + Math.cos(theta)*z//this is the new z value
];
}
//2.5. row_box
function rotateX(point, theta){
var x = point[0],
y = point[1],
z = point[2];
return [
x,
Math.cos(theta)*y + Math.sin(theta)*z,//this is new x value
//this is same y value as previous
-Math.sin(theta)*y + Math.cos(theta)*z//this is the new z value
];
}
/*
//original values:
var theta = 0;
var dtheta = 0.01; */
//2. this function puts points on canvas, with
//help from other functions
function render(){
ctx.fillStyle = background_color.backcolor;//was black
ctx.fillRect(0,0,W,H);
//ctx.clearRect(0, 0, W, H);//x value, y value, width of canvas, height of canvas
theta += dtheta;
points.forEach((point) => {
//point = rotateY(point, theta);//original one
point = rotateY(point, yRotate*theta);//HIGHER NUMBER MULTIPLIED BY THETA MEANS THIS IS PRIMARY AXIS OF ROTATION
//point = rotateX(point, 0.43*theta);//original one
point = rotateX(point, xRotate*theta);//LOWER NUMBER MULTIPLIED BY THETA IS LESSER AXIS OF ROTATION
renderPoint(point);//will have x,y,z
});
requestAnimationFrame(render);//this will call render function again
//NOTE: requestAnimationFrame is a js window doc function
//see here: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
//this function must be placed within the function calling it - recursive function?
}
function refreshPage(){
window.location.reload();
}
initGeometry();//call this first
render(); //then call this function