Simple 3D without Canvas or WebGL

I’ve been always fascinated by 3D and 3D presentation on the web space, well, since the tragic VRML(http://en.wikipedia.org/wiki/VRML). During the time in the university, I poked around Direct3D and OpenGL a little bit and after then anything with 3D on its name attracted my attention but haven’t achieved anything serious thanks to my laziness.

And one day, there came a chance that I needed to do some, admittedly nothing fancy like what you can see on http://www.chromeexperiments.com/, 3D action in an actual project.

My project was a simple coin tossing in 3D and didn’t require complicated physics or lighting or anything that may come with many 3D Javascript libraries. 

During the search, I came across Sprite3D.js (https://github.com/boblemarin/Sprite3D.js/tree/v2) that gave me an idea to use CSS3 3D transform instead of canvas or WebGL.

Sprite3D.js is a very simple light-weight Javascript library that bridges between Javascript and CSS3 3D transform so the code is more readable. It doesn’t have physics engine or any prebuilt 3D primitive objects out of box except box or cube, and that was all I needed.

Surprisingly, I struggled to find any articles explaining how to draw a simple 3D object with code from scratch (that I could just copy and paste easily...), such as a closed cylinder for my coin in this case.

So I planned to use a shallow box as a base of the coin, texture the top and bottom face with the coin’s face and tail, and then place a reasonably smoothly segmented cylinder between the top and the bottom face to make the coin. 

 

What is underneath…

The image below shows the basic of how CSS3 3D space looks like.

axis

If the centre of your screen is the origin of the 3D space, it’s positive x toward your right, positive y toward up, and positive z toward you. The camera’s position is represented by perspective.

Lower perspective usually produces dramatically exaggerated distance look so called perspective distortion like using wide angle lens, and higher perspective vice versa. 

It can be quite fiddly job to find the right perspective to work on different situations but normally between 700px and 1000px is acceptable. Sprite3D.js uses 800px as default.

 

A Box that is...

After the stage is set, I made a box to use it as the base of the coin.

basic_box

http://jsfiddle.net/musshush/GdFJ6/

Easy!

 

Lots of triangles...

The next is to make a cylinder and this gets a bit trickier.

Let’s start with 8-facet cylinder so it’s easier to illustrate.

octagon

[gist id="4943805" file="draw-8-facet-cylinder-part.js"]

In short, to draw a polygon like above, we need “w” that is the width of each facets, angle “d” of the first facet to be used to find "p(x, y)", and then duplicate the facet and rotate angle “d” until fill the full circle.

First, we need “d” that is the angle of the facet and convert it to radian to be used with Math.sin() and Math.cos().

And get “w”, width of the facet

And get the distance between “o” and “p” to get the position of the first facet

And then rotate it for each facets

box_cylinder

http://jsfiddle.net/musshush/cRxML/

With 80-facet cylinder it looks a lot smoother.

box_smooth_cylinder

http://jsfiddle.net/musshush/xXHrg/

And now texture the cylinder and make it a bit thinner so it looks more like a coin.

coin_textured

http://jsfiddle.net/musshush/VnU63/

 

Finally...

Now it’s the time to toss it and add a shadow layer for the finishing touch..

coin_shadow

http://jsfiddle.net/musshush/4ELHK/

With a bit of randomness with Math.random() and an easing function, it’s possible to create a convincing animation without physics engine.