This is an older demo I did a while ago but haven't published yet.
It's pretty slow unoptimized and hackish and the projection is wrong and I don't feel like fixing it.
But it still looks cool! So thought I should publish it anyway.
What does it do? It simulates a spiral galaxy with 5000 stars.
Demo
Click the screenshot to start the demo. It's pretty slow in firefox, works well in chrome.
How it works
Doing calculating the gravitational forces for 5000 particles in realtime using javascript is hard, and
it would probably be quite hard to get stable spirals. So I cheated a little (a lot actually). To simulate
the slowdown of the motion of stars in more dense areas I'm simply using a texture:
That's pretty much it: Generate a bunch of stars spinning around a center and modulate their speed according to the density map. Feel free to take a look at the source,
but remember, I told you that it's a mess and all wrong.
The Mandelbulb is a 3D Version of the Mandelbrot fractal. I have
written my own renderer for this a little while back. I don't think
the source is of much interest, as you can find better implementations
around.
If that caught your interest you can find more information and pictures of the Mandelbulb on the website of Daniel White.
Yes we can! Thanks to the performance of modern javascript engines like
V8 it is now possible to do realtime raytracing in javascript.
Demo
This demo requires a quick modern browser with support for the canvas tag and a fast computer. Google chrome seems to work best. Firefox is too slow. If it doesn't work make sure that your browser is not zooming in (hit ctrl+0 in chrome and firefox).
How it works
The frames are renderer using a technique called raytracing. The environment is mapped using cube mapping. I store all the values of the cubemap as floats. I increase the definition range by multiplying all values bigger than 0.95 with 2. This makes sure that the bright parts of the image are also very bright in the reflections. You can think of this as faking hdr. I do not calculate any lighting, it is all coming from the environment map. To make the animation look a bit more fluid and hide the aliasing I apply some fake motion blur by blending the current frame with the previous one. Feel free to ask questions if you want to know more.
Source
You can view the sourcecode here: rtrt.js. Feel free to copy from it, but please let me know if you use it for something cool. :) Also beware that the code is pretty hacky and unpolished.
The environment map was created by Paul Debevec of the ICT Graphics lab. You can find his collection of light probes here. Thanks for letting me use it.
Last Saturday I have released my little javascript pathtracer that rendered a very simple scene.
This time I want to show off some of the more advanced effects that can be simulated nicely using path tracing.
I decided to set up a scene similar to the well known Cornell Box
to demonstrate effects such as soft shadows, color bleeding, reflection, refraction and caustics. I did not include Depth of Field in this experiment because it didn't fit the scene well in my opinion.
The experiment
Click the image to start the rendering. Warning, this experiment is slow. Run it using a fast web browser (google chrome) and be a little bit patient. Opera won't work because it doesn't support web workers.
You might also want to check out my previous path tracing experiment.
Path tracing
Path tracing is a way of solving the rendering equation using monte carlo integration. It is a form of ray tracing. According to wikipedia 'Path tracing is the simplest, most physically-accurate and slowest rendering method'. Sounds like the perfect target for a javascript experiment!
Implementation
The implementation is basically an extended version of the path tracer in my last post. It is using html5 web workers to render the image on up to 4 cores without locking up the page. One of the cool things I came up with is jittering the points on the view plane for each pixel to get rid of aliasing. I also changed the color of the light to that of warm sunlight (~5400k). I probably got the fresnel equations wrong and generally things are quite rough. I'm not an expert in the field of raytracing and I probably did a lot of things in a suboptimal way. But feel free to have a look at the source code (~300 LOC) and ask questions. I think the code should be quite easy to understand.
Please write a comment if you've got anything to say. If you think my experiments are interesting, follow me on twitter or subscribe to my atom feed.
An improved version of this path tracer is available here.
The experiment
Click to start. If it doesn't work in your browser and it's not IE or Opera, please write a comment. The output of the javascript error console would be very helpful too.
Path tracing
Path tracing is a way of solving the rendering equation using monte carlo integration. It is a form of ray tracing. According to wikipedia 'Path tracing is the simplest, most physically-accurate and slowest rendering method'. Sounds like the perfect target for a javascript experiment!
Implementation
My implementation is currently only calculating the diffuse term of the rendering equation. The only light source is the sky. The big sky speeds up the rendering and convergence quite a lot.
The sourcecode is split up into two files. main.js is the glue for initializing the workers and aggregating the results. worker.js is where you'll find the real meat. I'm spawning four workers right now to take advantage of modern multicore cpus. Feel free to ask questions if something is unclear.
Performance
As you can tell from the sourcecode it is clearly not optimized for performance.
What is still interesting though is how various webbrowsers perform. On my Intel Core i7 machine google chrome (4.1) is roughly 26 times faster than firefox (3.6)! Chrome does 13 iterations/s, Firefox does 0.5. Also firefox seems to support only 3 workers, this leaves one core almost idle. The dev version of chrome is even faster at 18.75 iterations/s. My congratulations to the chrome and v8 developers. I hope firefox will catch up soon.
Twitter
On a side note, I created a twitter account for those who prefer it over the rss/atom feeds.
Update
I found a little bug in the code that affected the performance. I'm now getting more than 20.5 iterations/s in chrome dev. I think a faster random function would make it even faster.
I decided to release some of JS WARS graphics and sounds under a creative commons attribution share alike license.
If you want to use any of the other media please ask me.
This is another javascript effect I did. I might use it on the loading
screen of my next javascript game as it doesn't need any textures
(just like the starfield in jswars). It's based on an effect I wrote
about 6? years ago. Sadly the canvas tag doesn't support palettes
natively and mapping the colors in javscript too slow so the colors
look less than optimal. Also chrome seems to render the result differently from firefox.
This could be related to this issue.
Demo
Click the image to start the effect
How it works
Basically there are two maps, the heat map and the cooldown map.
The cooldown map is generated using a noise function similar to
perlin noise.
The noise texture is generated by first randomizing the alpha values
and then drawing scaled versions of the noise texture onto itself.
The high frequency noise was increased to create more flickering in the
flames. The heat map is what you see before you click on the example.
The algorithm then basically works like this:
Noise is draw on top of image to cool it down
The whole image is shifted up one row
The heat map is applied to 'heat up' the pixels
For more details just read the source and feel free to ask questions.
I made a little experiment with normal mapping and phong shading in javascript which turned out to work quite well.
I think with a little bit of tweaking it could be used in a real time game. Just move your mouse over the images bellow to see it in action. You'll need a modern browser supporting the canvas tag for this to work. Google Chrome seems to be the fastest.
Demo
Source
You can view the source code here: light.js.
Feel free to copy from it, but please notify me if you use it for something cool. :) Also beware that the code is pretty hacky and unpolished.
How it works
The 3D effect is basically created using 2 textures. One contains the color of each pixel and the other the surface normal. The color image is rendered using only indirect lighting (ambient occlusion in that case). The direct light is then calculated in real time using phong shading without the diffuse part. For a more accurate description, read the source. ;)
I played around with 2d lighting for a game I'm working on. I'll probably post how it's done once it's a bit refined (and quicker!). It's currently written in C and running on the CPU. I'm looking for a way to do it using glsl though.
For an upcoming game I'm working on I want the lines to look hand drawn.
I found a nice paper on the subject.
My algorithm is inspired by that paper, but not an exact implementation. But the results look good anyway. I also wrote a method to draw circles, but it needs improvement.
Please let me know if you use it anywhere. :)
// randomize a variablefunctionfuzz(x,f){returnx+Math.random()*f-f/2;}// estimate the movement of the arm// x0: start// x1: end// t: step from 0 to 1functionhandDrawMovement(x0,x1,t){returnx0+(x0-x1)*(15*Math.pow(t,4)-6*Math.pow(t,5)-10*Math.pow(t,3))}// hand draw a circle// ctx: Context2D// x, y: Coordinates// r: radiusfunctionhandDrawCircle(ctx,x,y,r){varsteps=Math.ceil(Math.sqrt(r)*3);// fuzzyness dependent on radiusvarf=0.12*r;// distortion of the circlevarxs=1.0+Math.random()*0.1-0.05;varys=2.0-xs;ctx.moveTo(x+r*xs,y);for(vari=1;i<=steps;i++){vart0=(Math.PI*2/steps)*(i-1);vart1=(Math.PI*2/steps)*i;varx0=x+Math.cos(t0)*r*xs;vary0=y+Math.sin(t0)*r*ys;varx1=x+Math.cos(t1)*r*xs;vary1=y+Math.sin(t1)*r*ys;ctx.quadraticCurveTo(fuzz(x0,f),fuzz(y0,f),x1,y1);ctx.moveTo(x1,y1);}}// inspired by this paper http://iwi.eldoc.ub.rug.nl/FILES/root/2008/ProcCAGVIMeraj/2008ProcCAGVIMeraj.pdffunctionhandDrawLine(ctx,x0,y0,x1,y1){ctx.moveTo(x0,y0)vard=Math.sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0))varsteps=d/25;if(steps<4){steps=4;}// fuzzynessvarf=8.0;for(vari=1;i<=steps;i++){vart1=i/steps;vart0=t1-1/stepsvarxt0=handDrawMovement(x0,x1,t0)varyt0=handDrawMovement(y0,y1,t0)varxt1=handDrawMovement(x0,x1,t1)varyt1=handDrawMovement(y0,y1,t1)ctx.quadraticCurveTo(fuzz(xt0,f),fuzz(yt0,f),xt1,yt1)ctx.moveTo(xt1,yt1)}}