Wait/Loading Animation Spheres |
|||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|||||||||||||||||||||
Tutorial:
|
|
||||||||||||||||||||
A 2D circular Wait/Loading Animation has been developed. To get the circle to break out into a 3D effect imagine looking at a sphere. This tutorial will start developing a lighting model to create a spherical background to mix with the existing animation. Move your mouse around: it should be acting as a very simple 'light source' for the following drawing (which is generated using four lines of code):
The following picture is drawn, it is not a downloaded html image: As with all of these tutorial pages, you can see how the image is drawn simply by viewing the source for this page on your browser.This has been done using very simple maths (simple for the computer to calculate). This tutorial will focus on understanding what is happening and how to develop this into a useful lighting model.
At each pixel (x,y) within the circle, a z coordinate can easily be calculated for the height of the hemisphere at that point. There is an equation that maps 2D points onto a unit sphere, so an x and y that vary in the range [0,1] are required and a z coordinate in the range [0,1] is returned:
var z=Math.sqrt(Math.abs(1-x*x-y*y)); // Get the third coordinate using a spherical modelThe calculation of the background sphere will be done in a subroutine. The x and y that are used in the current code vary across the canvas pixels [0,Radius]. These need to be converted to Signed Unit Intervals which are zero in the middle of the circle. Fortunatelydx
anddy
are nearly there, having the range[-Radius,Radius] so to get a Signed Unit Interval simply involves a division by Radius, which can be done in the subroutine call:GetSphereShade(dx/Radius, dy/Radius);This results in a shaded circle that extends a little beyond the radius:The following picture is drawn, it is not a downloaded html image: As with all of these tutorial pages, you can see how the image is drawn simply by viewing the source for this page on your browser.
Since this drawing draws outside of Radius, the Antialias routine could be used to clip the drawing within Radius as was done for the original circle in the Wait/Loading animation. But this z 'height-map' is too simple. A real sphere has more interesting lighting effects.
Surprisingly, the mouse-controlled image at the top of this page simply mixes the mouse coordinates with the sphere's coordinates.
function GetSphereShade(x,y) { var z=Math.sqrt(Math.abs(1-x*x-y*y)); // Get the third coordinate using a spherical model var dx=((xMouse-xMid)/Radius); // Get a displacement from the middle of the circle in units of Radius. var dy=((yMouse-yMid)/Radius); return Saturate(Unsigned((dx*x+dy*y+3*z)/(1+Math.abs(dx)+Math.abs(dy)))); }The main calculation is this:(dx*x+dy*y+3*z)
which is each element (x,y,z) scaled to locate the light source. Think of the light source as being 3 radius' out of the page (the3*z
) and the (x,y) position varies withdx,dy
.x,y and z are Signed Unit Intervals [-1,1] and three additions have occurred. To keep the result as a Signed Unit Interval it should be scaled down. If all parts were Signed Unit Intervals it would simply be a division by three, but
dx
anddy
can be any size: if the mouse is three radius' away from the middle of the circle, they will be three. The division must includedx
anddy
but since they can be positive or negative the scale factor must use the absolute value of each:(Math.abs(dx)+Math.abs(dy)+1)
. The+1
is to ensure that something is always visible. Without it the sphere image is entirely white when the mouse is directly over the middle.The result is a Signed Unit Interval and the final drawing requires an Unsigned Unit Interval, so the
Unsigned
function is called to convert the result. Since the sum doesn't only contain Unit Intervals the result should be treated with suspicion and clamped to the range [0,1] using theSaturate
function. These together finish the long line of code in GetSphereShade's return:return Saturate(Unsigned((dx*x+dy*y+3*z)/(1+Math.abs(dx)+Math.abs(dy))));
This tutorial showed a way to manipulate a light source around a sphere. The next tutorial will take several of these light positions and mix then to produce specular highlights on the sphere.