Tuesday, January 11, 2011

Tunnel effect explained in WebGL





The tunnel effect builds on the circle equation we covered in the introductory XOR bitplasma. However, this time we need to add a two more concepts. First, we need to calculate the angle of each point on the screen, relative to the origin (center of screen). To find this we can use the properties of right-angle triangles, namely the tangent function (tan). That is, the tangent of the angle is equal to opposite over adjacent.

Visualization of the angle for each pixel
By plugging in our pixel x/y coordinates we get a range from zero to pi of angles. Dividing by pi gives us a range from zero to one. In code this is:

float a = atan(p.y,p.x);
result = a/(3.1416);


Tunnel depth
Second, we need to find the "depth" of each point in the tunnel. Luckily this is easy to do, as projecting a 3d point to a 2d viewer is just a "divide by z" operation (objects that are further away appear smaller than objects that are closer - a nicer explanation will follow in future posts). So we can just generate a gradient of circles which we can treat as the distance from the viewer (our "z" value) and invert this (ie: 1/z).

Finally to get a good effect we need to apply a texture map. So combining the two coordinates we use the angular coordinate for the "v" coordinate and the depth coordinate as out "u" value.

So the complete code for our tunnel-shader is:


uniform vec2 resolution;
uniform float time;
uniform sampler2D tex;

void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
vec2 uv;

float a = atan(p.y,p.x);
float r = sqrt(dot(p,p));

uv.x = 0.1/r;
uv.y = a/(3.1416);

vec3 col = texture2D(tex,uv).xyz;

gl_FragColor = vec4(col,1.0);
}


You can see the result below! (You will need a WebGL enabled browser)
Your browser doesn't appear to support the HTML5 <canvas> element.

As a small extension to this we can progressively change the power of the square function in the circle equation to generate a less and less round "curve", progressively changing the circular tunnel into a square tunnel.
Graph of increasing squares

So starting from:

float power = 1.0;
float r = pow( pow(p.x*p.x,power) + pow(p.y*p.y,power), 1.0/(2*power) );


We can slowly increase the power until we get a square-like tunnel. The image shows the effect of increasing the power term, the final bottom right two images show the contrast between the round and square-like tunnels.

Sunday, January 09, 2011

XOR Demoeffect in WebGL





I wanted to do a series on a set of demoeffects, inspired by Shader Toy (and Denthor!). The majority of the shader toy effects are either raytraced, or polar/circle-based. So I thought I would begin with polar/circles and work my way from there. Most of the effects are based on a number of "oldschool" democoder tricks that are easy to understand once you have the background knowledge.

I won't be covering the basics behind writing shaders, but I might do so at a later point.

All of iq's shaders are rendered using a pixel shader (or fragment shader in OpenGL talk). The first step is to calculate the position of the pixel on the screen (or canvas in case of WebGL) normalised from -1 to 1. In a picture this is:

To visualise this in the shader we could write:

void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
gl_FragColor = vec4(p.x,p.y,0.0,1.0);
}

Now each horizontal value will get an increasing value of red, and each vertical value will get an increasing value of green (we are using the RGBA color space)

We can use the cartesian equation of a circle to generate a gradient of circles.

Again, to visualise this in the shader we could write:

void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
float radius = sqrt(p.x*p.x + p.y*p.y);
gl_FragColor = vec4(radius,0.0,0.0,1.0);
}


If we want to generate concentric circles we could set a boolean value on or off depending on a modulo operation. If we take the modulo of a value and then test whether it is above half-way then we can generate an on-off pulse. For example, if we get a value ranging from 0 to 1, module 0.1, we can generate a on/off pulse by testing if it is greater than 0.05.

In shader code this would be:

void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;

float radius = sqrt(p.x*p.x + p.y*p.y);
float modulo = mod(radius,0.1);
bool toggle = false;
if (modulo > 0.05) toggle = true;
if (toggle)
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
else
gl_FragColor = vec4(0.0,0.0,0.0,1.0);
}


This is a bit long-handed, we can shorten this by directly setting the toggle value, and using the dot product to perform the square operations.
ie:

float radius = sqrt(dot(p,p));
bool toggle = mod(radius,0.1)>0.05;


Great! Now we have all the background knowledge we need to make our first interesting effect. This will be based on the XOR operation:
XOR Truth Table
Input Output
A B
0 0 0
0 1 1
1 0 1
1 1 0

First, lets generate two different circles.

void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;

vec2 offset2 = vec2(0.3,0.3);

float radius1 = sqrt(dot(p,p));
float radius2 = sqrt(dot(p-offset2,p-offset2));

bool toggle1 = mod(radius1,0.1)>0.05;
bool toggle2 = mod(radius2,0.1)>0.05;

gl_FragColor = vec4(toggle1,toggle2,0.0,1.0);
}



Wonderfull! Now if we add in the XOR truth table:

//xor via if statements
float col = 0.0;
if (toggle1) col = 1.0;
if (toggle2) col = 1.0;
if ((toggle1) && (toggle2)) col = 0.0;

gl_FragColor = vec4(col,0.0,0.0,1.0);

And we get a wonderful overlapping pattern.

Add in a bit of animation and we have our first demoeffect! Click the button below in a WebGL enabled browser (Firefox, Chrome, Safari). (view source for full code)

Your browser doesn't appear to support the HTML5 <canvas> element.

Friday, January 07, 2011

Future CPU/GPU architectures and OpenCL

For a while x86 CPUs were just aimed at getting faster, more and more ticks. Then, there was a shift from faster to more efficient (in terms of power used / heat generated vs. performance) in the Pentium 3/4 era. Then, another shift towards multiple cores. Now, the next shift has occurred: CPU and GPU fusion. (Despite AMD talking about it for longer than I can recall. I think I was talking to an AMD VP shortly before they purchased ATI about how GPU and CPU fusion was the future.)

Recently Intel released Sandy Bridge their CPU/GPU processor, and AMD's fusion APU's have been around. Interestingly, both are targeted at laptops (the bulk of the market), and still expect discrete GPU's for high-end performance. The fusion is just a bit of a bonus.

Interestingly all those 2009 rumours about nVidia building an x86 chip turned out to be wrong, with the real product being far more interesting. An nVidia fusion product of an ARM CPU with nVidia GPU's. This might prove to be a very interesting result considering the amount of effort being put into improving the ARM architecture and the power usage concerns in both smartphones/tablets and supercomputing. With the next version of windows running on ARM there will certainly be interesting times ahead.

Intel/AMD aren't standing still on the CPU front and are pushing ahead with AVX but the real interesting part is that OpenCL is being pushed across the board. Recent publications from the UK GPU computing conference demonstrate that ARM are pushing OpenCL as their platform of choice (for both CPU and their Mali GPU, it is Clang/LLVM based), and AMD and Intel have been strong supporters of OpenCL too. Did you know Samsung supports OpenCL too?

It would seem that OpenCL has a very strong support base, and is likely the platform of choice for developers on Intel, AMD, ARM, Apple, IBM, etc. What hope does CUDA stand? It seems nVidia will eventually be forced to drop CUDA, or invest heavily into CPU-based CUDA (Hello Ocelot!) or OpenCL translation. Eventually people will tire of writing and re-writing CUDA programs as they swap between platforms.

Envision the not-so-far future where you have a workstation with multiple CPU/GPU fusion cores [non-CUDA], and a discrete fusion GPU (GPU [CUDA]/ARM [non-CUDA] core) - are you really willing to write a specific CUDA routine for just the nVidia GPU, or are you more likely to try a less optimal OpenCL routine that will then also then run on the CPU, CPU SIMD, CPU/GPU fusion and ARM cores?

It seems that the argument being put forward by nVidia to write everything in CUDA for optimal performance will not hold as you will gain more from all the other devices helping out in the computation compared to the loss from using OpenCL over CUDA.

Of course there are other choices out there such as Accelerator and RapidMind.

The UK conference reveals Microsoft's GPGPU language "Accelerator" has made progress, and now is no longer only GPU limited (it now supports SSE3 on modern CPU's). I'm still not aware of anyone using this for anything practical though, which seems to be a bit of a shame. And ever since Intel bought RapidMind (now Array Building Blocks) the tech became very Intel-specific. So neither of those choices sound too promising.

It will be interesting to see what nVidia decide to do with CUDA, how developers will adjust to fusion CPU / GPUs and what higher-level language (or language extension?) will become de-facto in the future. Stay tuned..

Sunday, January 02, 2011

2010 Summary

Looking back, 2010 was a big year. My life was dominated by three factors:
A bit of a departure from 2009 which was mostly focused on GPGPU, fluid simulations, physics engines, and computer graphics. I still have a backlog of content to write about from my GPGPU work in 2009, but its starting to be less relevant as the GPGPU world pushes ahead, but I'm aiming to post more in 2011 than I managed in 2010. Should be a good year!

Wednesday, December 29, 2010

Catchup Post: Graphics

ShaderToy
Another set of interesting links:

Friday, December 24, 2010

Humble Bundle #2 - Great indy games - name your price!

Osmos - Humble Bundle 2
The independent games humble bundle offer is back again, better than before. It is a pay-what-you-want offer for 5 indy games, all of which have support for Windows, Mac OSX and Linux. If you pay above the average, you get the previous humble-bundle pack of 6 games as well! A very good deal for whatever you want to pay! (Makes an excellent Christmas present!) Anyone studying games design or games programming should get these games to learn from them - what works, what doesn't? Braid is a fabulous example of teaching the player the game without needing to give them a tutorial, and many of these games are great examples of the scope you should aim for if you are making your own game.

The games included are:
  • Braid - a side scrolling puzzle/adventure through time. Nicely designed gameplay.
  • Cortex Command - side scroller, not very impressive.
  • Machinarium - a point and click adventure game, nice graphics, pretty decent.
  • Osmos - an ambient physics-based "eating" game (you absorb smaller entities). Good gameplay and a great "programmer-game" (nice graphics). My pick of the lot. (only $10 separately)
  • Revenge of the Titans - a tower-defense (build towers that destroy enemies) game. Nothing special.
The other games are:
  • World of Goo - a construction puzzle game. Lots of fun.
  • Aquaria - an underwater fantasy game.
  • Gish - a platform game.
  • Lugaru - 3D action adventure game.
  • Penumbrac - a FPS/adventure game.
  • Samorost 2 - a flash-based puzzle game.
If you pay 10 USD to get them all, that works out to less than a dollar a game, and I guarantee you will find at least one game you think is worth $10 in the humble (cross-platform games) bundle.

Thursday, December 23, 2010

Underground

Few updates this month because I've been underground. And I don't mean I've joined some kind of strange sub-culture or gone in hiding, I mean literally 1.5km vertically underground to commission a Transmin automated Rockbreaker (there's not much internet down there!). A few things I learnt / experienced about hard-rock underground mines (most of which are very obvious):
  • Block caving is insane. The idea is to create an extraction level under the ore body, then continuously blast the ore into smaller rocks that can be processed, leaving a massive growing "sink" hole on the surface. You also need a very very very long conveyor belt.
  • The tunnels are quite large, as some very large vehicles need to drive through the mine.
  • All the tunnels have a 'clean' look to them, largely thanks to the use of shotcrete (i.e. concrete reinforcement around the tunnel rock).
  • It takes 45 minutes to drive down to a depth of 1.5km
  • When driving, give way to larger vehicles, or vehicles with explosives.
  • Its difficult to move around quickly, you will easily break a sweat in no time.
  • Batteries weigh a lot when you need to carry them around on a belt all day
  • You use a lot more oxygen if you panic, or move around a lot
  • There is a complex system of ventilation channels with really really big fans providing all the air
  • It is really easy to get lost in a large underground mine
  • There is an underground dining area. It is called the 'crib'. I don't know why.
  • If anything bad happens, you don't have much of a chance, especially if you are not aware of all the intimate details of how the mine operates. (ie: haven't been there for more than a year)
  • Explosions are loud
  • Ground movement is bad and very very loud
  • There is an awful lot of dust
All in all an interesting experience, but all the dust certainly didn't do any good for my eyes or my lungs. I've been coughing a lot even after being out of the mine for a week as the very fine dust just gets everywhere.