Perlin Noise in 3D (WebGL)

Working from of the 2D experiment using Perlin Noise, I put together a 3D WebGL-based renderer.  The example below is a simple heightmap with the vertex z-coordinates determined by a weight combination of several octaves of Perlin noise.

The live demo is available, but it’s fairly limited as its still a work-in-progress.

Optical Illusion

Are the rows straight in this image?

This is a just one rather extreme output from another experiment in procedural graphics.

The seamless brick texture generator has been added to the tech site.  The algorithm uses a simple brick tile algorithm then mixes in some Perlin noise based variations in the color and dimensions of the bricks to give it slightly more realistic feel.  Could use some work still, but sufficient for a gratifying demo.

 

Seamless Perlin Noise

Updated the Perlin Noise demo to include generation of seamless 2d noise textures.

The implementation is in Javascript and based on a standard implementation.  The process of generating a seamless 2d texture is simultaneously reasonably straightforward and brilliant — and certainly nothing I invented myself.

The plain English explanation works like this:  imagine you had a large 3D block of wood (in the real world) and have a flat piece of paper that you can slide “inside” the block and take a 2D image of the wood grain at that point in the block.  You’ll end up with a nice 2d texture of wood texture — but it won’t be seamless.

Now, imagine you curl the paper into a cylinder along one axis and slide it “into” the block again and take another snapshot.  When you unfurl the paper, the image will be seamless on one axis (since the end edges were touching the same point “inside” the block).

The trick to the create a texture that’s seamless in both dimensions is realizing you can’t fold the 2D paper into a cylinder along two axes without folding / distorting / ripping the paper — at least not in 3D space.  However, you can curl it into “two cylinders” if you’re in 4D — the XY space contains one cylinder and the ZW space independently contains the other curvature.

So by mapping a 2D texture into a 4D block of Perlin Noise….you can end up with a seamless 2D texture.  This works for any continuous 4D function.

Check out the Perlin Noise demo page for the simple code that does this.

Web Workers & Ray Tracing

“Web Workers” – i.e. Threads  for Javascript

I’ve been doing a lot of Javascript and web programming lately.  It has the major advantage of having “immediate” results.  Embedded in HTML page, it’s trivial to create a decent UI and display environment and demonstrate something without asking a viewer download, install, or –worse — build something.

The downside is that all the fun, really exacting, high-performance coding of, say C++, generally doesn’t apply.  That’s also a plus at times — but it can be disappointing that some of the challenges of C++ aren’t there.

My ignorance got the better of me and I never really looked into “Web Workers,” which for the purposes of this article basically mean a simple way to do multi-threading in the browser.  There’s a lot of handholding that imposes limitations like no shared memory — but still I decided to play with it. Noticing Stephen Boyer’s article on Real-Time Ray Tracing in Javascript was really the kick necessary to try web workers out.

Updated Ray Tracer

Here’s a demo of a multi-threaded in-browser ray tracer that I put together.

The code does use a lot of libraries, both internal and external, but is fairly well organized and the code is available.  Feel free to ask questions or request that more detail be added to the descriptions.  (Also, if you really find it interesting, check out our company’s home page — we’re trying to work our way towards more technical programming work, especially in the area of custom, higher-end web graphics.)

 

Perlin Noise

Added a new Perlin noise demo on the web site.

It’s a standard Perlin noise implementation implemented in Javascript and rendering to an HTML5 CANVAS element.  The demo has a few UI controls — mostly just for demostration purposes.

 

Would be nice if it also had an option for seamless Perlin noise…

Ray Tracer Demo

Updated the PusherTech website with a new ray tracer demo: http://tech.pusherhq.com/demo/raytracer_architecture.

While the “old” demo is far more functional — with multi-sampling, soft shadows, and reflections, for example — this new demo is built on a much cleaner code base.  It uses a engine-based architecture making it easier to pause / resume the rendering, to ensure the browser interactivity is not bogged down, to swap between different scene definitions, and other practical features that come from, well, a better architecture.

The documentation isn’t perfect, but there’s a bit of it — would love to hear some feedback.

pusher.color v0.2.3

The pusher.color library has been released.

A few minor bug fixes were included, but the big change is the library has been ported to a standalone git repository and been packaged up as a NPM module.

I’m hoping the conversion to an NPM-compatible module makes the library more developer friendly — and encourages further use of the library.

Adding Borders

From the developers point of view, I’m not a huge fan of Squarespace 6. Long story short, at this point in time there’s a lot “promised” to be coming soon that sounds great, but the fact is that local development is simply not possible — that’s a red flag for good development processes…

That said, here’s a snippet of one-off, hacky code to overlay a border on Squarespace’s YUI-driven image grid slider since a simple “border” CSS property isn’t possible with that element!

    //===========================================================================//
    //  Add borders to Squarespace "grid slide" images
    //===========================================================================//
    /*
        The YUI layout of the slide grid uses relative positioning and overlaps
        that make straightforward CSS rules to apply a border impossible.

        The solution is to overlay an empty DIV with a border on top of the base 
        element instead.

        There are a couple complications (of course), noted in the code below...
    */
    (function() {

        /*
            Browser resizes may change the size of the images, so potentially
            need to recreate the borders at the new size.

            This implementation demands the dynamically created border 
            elements and marks the host images as needing reprocessing.

            It would be more efficient to mark each element as *potentially*
            needing a new border, and then in the processing loop check if the
            size has actually changed, replace the old border....but we'll 
            save that for some other day.
        */
        $(window).resize(function() {
            $(".dynamic-addBorder").remove();
            $(".dynamic-addBorderHost").addClass("dynamic-addBorderResized").removeClass("dynamic-addBorderHost");
        });

        /*
            Since we don't know, nor have an event to link into, on new images
            being loaded into the grid...we poll every short while.
         */
        window.setInterval(function() {

            // The A element has the "visible" size of the image.  The actual IMG itself
            // does not, since YUI potentially crops the IMG via overlapping elements.
            //
            $(".sqs-gallery-design-grid-slide").find("a").each(function() {

                // First check if this element has already been processed via a class
                // we attach.
                var $this = $(this);
                var processed = $this.hasClass("dynamic-addBorderHost");
                if (!processed)
                {
                    // Denote this element has now been processed
                    $this.addClass("dynamic-addBorderHost");

                    // innerHeight is required due to the relative positioning usage
                    var width = $this.width();
                    var height = $this.innerHeight();
                    var isResize = $this.hasClass("dynamic-addBorderResized");

                    // Create the actual "border" element that gets overlaid
                    var $border = $("<div/>").addClass("dynamic-addBorder").css({
                        position            : "relative",
                        top                 : 0 - height,
                        left                : 0,
                        width               : width - 8,
                        height              : height - 8,
                        "z-index"           : 10,
                        "background-color"  : "transparent",
                        "border"            : "solid 4px #444",
                        opacity             : (isResize ? 1 : 0.5)
                    });
                    $this.after($border);

                    // Note: we treat the re-creation of the border via a resize slightly
                    // differently since we want to fade the border in on the initial 
                    // load, but want the resized border ASAP.
                    if (!isResize)
                        $this.after($border.animate({ opacity : 0.9 }, 2000));
                }
            });
        }, 250);
    });