Awesome implementation, actually no advanced feature is used, this code could easily ported even to assembler in any device where you can set pixels in RGB format.
And indeed it is pretty impressive how fast the rendering happens given that the code operates at such lower level... Even selecting the color of every pixel requires non trivial work in the inner loop.
I would argue that this is terrible code. It's not using the appropriate tools (webGL), it's badly structured, uncommented and unmaintainable (seriously, why on earth would anyone name their variables zd, _zd and __zd?). The Minecraft source code is also of notoriously poor quality. I honestly don't understand how you came to your conclusion.
It's an handful amount of lines of code doing a world generation, texture map generation, and ray casting rendering with a few tricks like a simple lightning model that still looks good.
All this using nothing more than a frame buffer, so you could port this easily from a C64 to any other computer. This code contains a lot of knowledge VS use of pre-build APIs.
If a programmer reads this code and understands how every part works, he or she ends knowing a lot more about computer graphics than before.
Indeed, writing straightforward code with no dynamic memory allocations, and simple and predictable types, lets the VM do wonders with optimization and JITting. Good stuff.
Such a great example of what can be done in javascript/canvas. As it is, I was completely blown away by how little code it actually took to do that. My only gripe would be, why couldn't he have used descriptive variable names, so I can better go through and understand it? :-)
This code uses zero canvas / javascript specific functions. It is using basic trigonometric functions and is using canvas only to write RGB pixels. Canvas are much more powerful and high level than that, but this is not a good example as Notch just needed to set pixels.
Having watched Notch write Prelude of the Chambered (which I then ported to JRuby) it seems he really loves this direct pixel manipulation style - as do I!
The sad part, though, is it doesn't particularly scale well with canvas (yet) and using sprites, shape primitives, or even WebGL is way to get full speed at a regular resolution. (Imagine a 640x480 pixel field of randomized colors, you can get hundreds of FPS for that in Java without a sweat. Not so in the browser and most certainly not in JRuby.. my PotC port struggled to hit 12fps with equivalent code.)
The title of "ChamberedTest" here makes me wonder if notch is planning to use JS and canvas in the forthcoming Ludum Dare 25 (the gamedev contest where he created Prelude of the Chambered). I hope so!
Please do NOT write code like this. It was originally written for the Java4k
competition, which focuses on executable code size, and is as a result almost
intentionally poorly written. It got even worse when I ported it to JS.
It was mainly meant as a test for me to see what HTML5/JS can do, and an
exercise in porting code over.
It would run a bit smoother if it was written in C++ (mainly due to not having
to rely on the GC, and having it precompiled gets rid of the warmup time), and
modern OpenGL would help quite a lot as well. A lot of the stuff done in CPU
now could be moved to a shader, which both makes code simpler, and gets rid of
the slow JNI calls required now.
The main reason why Minecraft is slow is mainly 1) There's a LOT of polygons,
combined with 2) The difficulty of making an efficient culling algorithm in a
dynamic world.
If someone solves #2, very interesting things could be made with a game similar
to Minecraft.
No, they don't get merged because the textures are all pulled from the same atlas
to avoid texture swapping. With GLSL, they could be merged, saving quite a lot of
polygons. For a while, I did attempt switching the atlas from a 16 x 16 grid to a
1 x 256 grid and merging horizontal runs of the same texture, but the resulting
texture size was to tall some graphics cards (on low end computers) would
automatically downsample it.
The problem with the occlusion culling is not about knowing what parts are static,
but rather figuring out what occluders there are. It would be very beneficial not
to have to render caves under ground below the player, for example, or not to
render the entire outside when a player is inside a small closed house. Figuring
this out in runtime on the fly as the player moves around is.. expensive.
This would be a great demo to see running in a responsive programming environment, ala Bret Victor's amazing Inventing on Principle talk (http://vimeo.com/36579366). I want to be able to click on hex values and get a color picker that updates the demo in realtime, and be able to click on various magic numbers and drag a slider to change them.
Edit: I managed to get this running in livecoding.io, which does some of what Bret Victor was talking about (basic sliders and color pickers): http://livecoding.io/4191583. Not sure why it's running so much slower though...
Press play in the bottom left to have it go, and scrub numbers/colors to your hearts content!
Part of the reason it slows down in livecoding is because of the way the original code uses setInterval, and every change reevaluates the code which polutes the scope and starts way too many threads going. I've added optional functionality to Tributary which gives you a run loop (using requestAnimationFrame) that doesn't polute anything.
Very awesome:) It's _almost_ fast enough to feel like you're modifying it in realtime on my macbook air. This is a great demo of what might be possible with this responsive programming approach.
This "responsive programming environment" you speak of has been around for a really long time. Don't expect sliders and colorpickers to do cool stuff, but this should be a good jumping off point for you to start learning from: http://stackoverflow.com/questions/3305164/how-to-modify-mem...
Thanks, I'm plenty aware of gdb and debuggers:) (ex-google software engineer, etc etc) Go watch the video. Bret presents a very cogent vision for a dramatic improvement on most of today's standard engineering/design tools.
Thanks for the livecoding link. I assume there's some overhead in constantly checking for and applying code changes - that's probably the reason for the lower frame rate.
Good point, I hadn't thought about the fact they might be polling for changes. Might be better if livecoding used an event based model to check for updates...
Correct me if I'm wrong but does this procedurally generate the textures for each block. I can't see any code for loading assets and the init function, has some quite complicated color code. If so that is awesome!
Yes, the procedure generates the texture of every "type" of block, the first loops after the init() function. 16 different types of blocks are generated.
Then a random map is created, with the "center" that is set to empty blocks with high probability. Finally a function traces the map on the screen at every tick of the clock.
I enjoy that everything is procedural generated. The software rasterizing is pretty cool too. I don't mind that he uses short variable names, sometimes it's nice to have multiple lines line up perfectly. But this is just silly...
for ( var x = 0; x < w; x++) {
var ___xd = (x - w / 2) / h;
for ( var y = 0; y < h; y++) {
var __yd = (y - h / 2) / h;
var __zd = 1;
var ___zd = __zd * yCos + __yd * ySin;
var _yd = __yd * yCos - __zd * ySin;
var _xd = ___xd * xCos + ___zd * xSin;
var _zd = ___zd * xCos - ___xd * xSin;
I assume because there's four different "xd" variables differing only in the number of underscores prefixed ("xd", "_xd", "__xd" and "___xd"). (Same for "yd" and "zd").
I don't enjoy comparing the length of relatively similar lines. Why not use xa, xb, xc, etc... instead of xd, _xd, __xd, ___xd, yd, _yd, __yd, ___yd, zd, _zd, __zd, ___zd?
And indeed it is pretty impressive how fast the rendering happens given that the code operates at such lower level... Even selecting the color of every pixel requires non trivial work in the inner loop.
AWESOME code.
[1] https://twitter.com/notch/status/275329867984302081
All this using nothing more than a frame buffer, so you could port this easily from a C64 to any other computer. This code contains a lot of knowledge VS use of pre-build APIs.
If a programmer reads this code and understands how every part works, he or she ends knowing a lot more about computer graphics than before.
low level = close to hardware, high level = high abstraction, like JS
Javascript is high level, but here notch is using it as a low level framebuffer.
The sad part, though, is it doesn't particularly scale well with canvas (yet) and using sprites, shape primitives, or even WebGL is way to get full speed at a regular resolution. (Imagine a 640x480 pixel field of randomized colors, you can get hundreds of FPS for that in Java without a sweat. Not so in the browser and most certainly not in JRuby.. my PotC port struggled to hit 12fps with equivalent code.)
The title of "ChamberedTest" here makes me wonder if notch is planning to use JS and canvas in the forthcoming Ludum Dare 25 (the gamedev contest where he created Prelude of the Chambered). I hope so!
Spent most of today learning new stuff. Ported Minecraft4k. Code is awful due to the nature of the project, but here: http://jsdo.it/notch/dB1E
[1] https://twitter.com/notch/status/275329867984302081
ctx = document.getElementById('game').getContext('2d');
pixels = ctx.createImageData(w, h);
ctx.putImageData(pixels, 0, 0);
EDIT: Thanks for the clarification!
it'd be also great to do an analysis of the geometry data as well, if you can!
http://www.reddit.com/r/programming/comments/146v69/how_notc...
http://www.reddit.com/r/programming/comments/146v69/how_notc...http://www.reddit.com/r/programming/comments/146v69/how_notc...Incidentally, Bret Victor's talk was the starting point for Khan Academy's CS curriculum that John Resign led (http://ejohn.org/blog/introducing-khan-cs/).
Edit: I managed to get this running in livecoding.io, which does some of what Bret Victor was talking about (basic sliders and color pickers): http://livecoding.io/4191583. Not sure why it's running so much slower though...
Press play in the bottom left to have it go, and scrub numbers/colors to your hearts content!
Part of the reason it slows down in livecoding is because of the way the original code uses setInterval, and every change reevaluates the code which polutes the scope and starts way too many threads going. I've added optional functionality to Tributary which gives you a run loop (using requestAnimationFrame) that doesn't polute anything.
Hope this helps!
the problem is from calling setInterval every time the code is evaluated, leading to way too many function calls/second
Then a random map is created, with the "center" that is set to empty blocks with high probability. Finally a function traces the map on the screen at every tick of the clock.
Deleted Comment