This time we'll take the idea and take it in a different direction - we'll turn the evolving landscape into a texture that maps onto the surface of a 3-d object.
3-D Objects in P5JS
Normally we use p5js to create 2-d shapes like lines, rectangles and circles, painted onto a canvas. We can also use p5js to create 3-d objects and move them in 3-d space.To do that p5js uses webgl, a technology designed for efficiently rendering 3-d objects using a GPU in your computer if there is one. Lots of computer games use the same approach, taking advantage of the specially designed chips inside your computer or laptop.
In the past, using your GPU to accelerate graphics was really complex and hard - but today it has been made much easier. P5js also makes it easy.
Look at the following really simple and short code:
function setup() {
createCanvas(800, 600, WEBGL);
background('white');
}
function draw() {
box(200, 200, 200);
}
In the setup() function the first thing we notice is that the canvas is created with an extra WEBGL parameter - that tells p5js to create a special canvas the can render webgl objects. We then create a white background - easy.
In the draw function we have only one command and the name box() gives us a clue as to what it does - it creates a 3-dimensional box. Our box(200, 200, 200) creates a box with width, height and depth 200, a cube in other words.
Let's see the results:
That doesn't look like a 3-d cube, it looks like a flat square. The reason is that we're looking at the cube straight on. To see more than one face we need to rotate the cube. Let's do that:
function draw() {
rotateX(1.0);
box(200, 200, 200);
}
Let's see the results:
That's much more like a 3-dimensional object. Let's see what happens if we combine a rotate about the x-axis as well as a rotation about the y-axis.
function draw() {
rotateX(1.0);
rotateY(1.0);
box(200, 200, 200);
}
And the result:
Nice! Now let's animate the cube by drawing frames with the cube at different rotations. We looked at animation previously.
Have a look at the code which has only grown a small bit:
// counter used to determine how much we rotate the 3-d world
var counter = 0;
function setup() {
createCanvas(800, 600, WEBGL);
}
function draw() {
// blank canvas for animation
background('white');
// rotate world
rotateX(counter);
rotateY(counter);
// draw box
box(200, 200, 200);
// increase counter
counter += 0.01;
}
We're blanking the canvas before we draw a frame. We're using the same rotations about the x and y axes as before but this time the angle is inside the variable counter, which we set to zero at the start of the code. We draw the box, and finally we increase counter by a small amount. That means the next frame will have the box drawn at a slightly different angle.
Let's see if this works:
That's looking good.
With very simple code we've rendered an animated 3-d object using p5js, and even taken advantage of the special hardware inside our computers to help accelerate the rendering.
The code for this cube is online at:
Array To Image To Texture
We want to apply our Game of Life patterns onto the surface of our 3-d object. To do that we need to work out how to turn an array of numbers into a texture. There isn't a direct way to do that - that I know of - we need to first turn the numbers into an "image" before it can be applied as a texture.Let's do this with a simpler set of numbers first. Look at the following code, most of which should be familiar.
var img;
var counter = 0;
function setup() {
// create a WEBGL canvas
createCanvas(800, 600, WEBGL);
// create empty image and fill pixel by pixel
img = createImage(400, 100);
img.loadPixels();
for(var x = 0; x < img.width; x++) {
for(var y = 0; y < img.height; y++) {
// use noise() values 0-255 to create greyscale pixels
img.set(x, y, noise(x/40,y/10)*255);
}
}
img.updatePixels();
}
function draw() {
background('white');
// animate a 3-d box
push();
rotateX(counter);
rotateY(counter);
texture(img);
box(200, 200, 200);
pop();
// increase counter which determines rotation of box
counter += 0.01;
}
The new code near the top creates that image img. Let's look at it more closely. We first create an empty image of size 400 by 100 using createImage(400, 100). To access the actual pixels, we need to use loadPixels() to expose them. We then use a loop with in a loop to visit every pixel and set it's value, which we do using the noise() function, which creates a less random randomness. Finally we need to use updatePixels() to apply those changes and commit them to the image.
That looks very hopeful.
The code for this textured cube is at:
Artificial Life as Texture
We've done all the hard work .. all we need to do is apply these ideas to the array that holds the population of the creatures that we modelled using Conway's Game of Life rules.While we're at it, let's change the shape from a box() to a torus().
To make sure the texture changes as the Game of Life patterns change, we need to update the texture image every frame.
The code is a little longer so we'll just point to it. It doesn't do anything more than what we've already discussed.
And the results ...
Very cool!
Resources
- Getting Started with WebGL in P5js - https://github.com/processing/p5.js/wiki/Getting-started-with-WebGL-in-p5
No comments:
Post a Comment