3D with HTML5 Canvas: Part 0

A hypercubeMy breakthrough with high-school level vector mathematics got me thinking: maybe maths isn't as hard as my math teachers made it appear? And maybe it could be used for more cool stuff... like, making a 3D game? My programming skills are such that I could make games that come from 1980 - and Battlezone was made in 1980! It's time to enter the third dimension!

It's not going to be an easy ride, I'm sure. But if I take it slowly, I think I can conquer it. The plan is to start at the beginning, figure out the minimum amount of maths and theory as possible (but, like, really figure it out - not "get a D in trigonometry" figure it out) and make something. And by something, I mean the ultimate in 1980 tech: the spinning cube. And no cheating using canvas's built-in rotations and translations: I'm talkin' about doing it the hard way. I estimate it's going to take me 6 posts to get there:

  • This introductory post - to set up viewer expectations
  • A 3D starfield - to learn how to project points in 3D
  • 2D shape rotation - gotta rotate stuff, and that seems hard
  • 3D wireframe drawing - draw a cube! Yeah!
  • 3D wireframe rotating & moving - spin it!
  • "Shaded" 3D model - colour it in.

I fear boredom will kick in before post 3, but we'll see. I'm only actually starting this because I read somewhere that projecting a 3D point to a 2D screen just required dividing the X by the Z point, and the Y by the Z point. And when I thought about it this morning, that kinda made sense, and suddenly 3D seems easy. I'm sure there will be lots of heartache and matrices along the way, but sometimes you just gotta stand up, look the third dimension straight in the eye and say "I'm not afraid of you - dimension. I'm not afraid of annnythingggg! (Except dimensions higher than you)".

If you are reading this line, then you have also accepted the challenge to understand basic 3D math. Well done. Let's conclude this introduction by setting up our Canvas element ready to draw some stuff! This is going to be used to draw our 3D starfield next lesson, so we'll namespace everything with "stars".

First up, let's add our canvas tag to the body of the document: <canvas id="screen" width="320" height="200">Gots to get a better browser, yo.</canvas>

Next, we'll set up our namespace, and our main class with the methods we'll need to do some animation:

var stars = {};
stars.main = {
	init : function(){
		if( !document.getElementById( "screen" ).getContext ) return;
		this.context = document.getElementById( "screen" ).getContext( "2d" );
		this.screenWidth = document.getElementById( "screen" ).offsetWidth;
		this.screenHeight = document.getElementById( "screen" ).offsetHeight;
		
		this.run();
	},
	
	run : function(){
		var that = this;
		
		// Run the main loop
		(function tick(){
			that.update();
			that.draw();
			setTimeout( function(){ that.run(); }, 70 );						
		})();
	},
	
	update : function(){

	},
	
	draw : function(){
		var ctx = this.context;
		ctx.fillStyle = "#000";
		ctx.fillRect( 0, 0, this.screenWidth, this.screenHeight );
	}
};

There's nothing super tricky here: just setting up a class to hold all our code. The init function will set everything up, the call the run function, which loops every 70 milliseconds (which will probably use 20% of your CPU, but there you go). You can grab the setup code if you want.

The loop calls two functions every cycle: update - where we'll do all our logic, and draw - where we'll spit it out on to the canvas element. And that's it for now: a black rectangle. A simple 2D shape - just waiting to have a new dimension thrust upon it! I'm off to find out how to do that.