Great Horned Owl

Great Horned Owl

This is a Great Horned Owl which was chased into my yard by a red-tail hawk. It stayed in a freshly-budded cottonwood tree from late afternoon until after dark.

Great Horned Owl and Crows

Two crows periodically stopped by to harrass the owl, but it did little other than to flinch and hiss at its tormenters. I think it might have been injured by the hawk, but there was no evidence that I could see, other than its unwillingness to leave the tree until after dark.

Click either of the photos to see the rest in the set over at Flickr. Over on YouTube I also have a couple of videos of the crows and the owl. Video 1. Video 2.

Langton’s Ant in 3d, Using Javascript and Three.js

Langton's Ant in 3d, using Javascript and Three.js

Click the screenshot to launch the demo. You will need to use the latest version of Chrome, Firefox or Safari if you want to see it running.

This is a re-creation of a Flash experiment from several years ago. Back before I started playing around with 3d, I created a series of experiments exploring cellular automata, the majority of which were variations on the Langton’s Ant algorithm. The most advanced version was one in pseudo-3d, and that was the last for over three years. Now with the advent of easy-to-use 3d libraries (like Three.js, used here), and the option of hardware acceleration to allow for complex animations, I felt it was time to re-visit some of the old experiments.

Here is the source code for the 3d ant:

window.requestAnimFrame = (function(){
	return  window.requestAnimationFrame	|| 
		window.webkitRequestAnimationFrame || 
		window.mozRequestAnimationFrame    || 
		window.oRequestAnimationFrame      || 
		window.msRequestAnimationFrame     || 
		function( callback ){
			window.setTimeout(callback, 1000 / 60);
		};
})();

var canvas,
	stage,
	container,
	scene,
	camera,
	renderer,
	projector,
	light;
	
var WIDTH = 640,
	HEIGHT = 640;
	VIEW_ANGLE = 45,
	ASPECT = WIDTH/HEIGHT,
	NEAR = .1,
	FAR = 10000,
	centerX = 0,
	centerY = 0,
	centerZ = 0,
	cameraX = 0,
	cameraY = 200,
	cameraZ = 400;
	
var antX = 32,
	antY = 32,
	antZ = 32,
	nextX,
	nextY,
	nextZ,
	cellsX = 64,
	cellsY = 64,
	cellsZ = 64,
	cellWidth = 8,
	cellHeight = 8,
	cellDepth = 8,
	antSize = 7,
	maxDirections = 8,
	colorMultiplier = Math.round(256/cellsX),
	xOff = cellsX/2*cellWidth,
	yOff = cellsY/2*cellHeight,
	zOff = cellsZ/2*cellDepth,
	base,
	objects,
	antDirection = 1,
	filledCells=0,
	
	isRotating=true,
	isPaused=false;
	
	function init() {
		canvas = document.getElementById("myCanvas");
		scene = new THREE.Scene();
		camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR );
		camera.position.x = cameraX;
		camera.position.y = cameraY;
		camera.position.z = cameraZ;
		camera.lookAt(scene.position);
		scene.add( camera );
		projector = new THREE.Projector();
		renderer = new THREE.WebGLRenderer( { antialias: true } );
		renderer.setSize( WIDTH, HEIGHT );
		light = new THREE.SpotLight();
		light.position.set( cameraX, cameraY, cameraZ );
		scene.add(light);
		canvas.appendChild( renderer.domElement );
		renderer.render(scene,camera);
		
		base = new THREE.Object3D();
		base.position.x = centerX;
		base.position.y = centerY;
		base.position.x = centerZ;
		base.rotation.y = 45;
		scene.add(base);
		camera.lookAt(base.position);
		objects = new Array(cellsX);
		for(var i=0;i<objects.length;i++) {
			objects[i] = new Array(cellsY);
			for(var j=0;j<objects[i].length;j++) {
				objects[i][j] = new Array(cellsZ);
			}
		}
		onEnterFrame();
	}
	
	function onEnterFrame() {
		requestAnimFrame(onEnterFrame);
		renderer.render(scene,camera);
		if(isPaused==true) return;
		if(!objects[antX][antY][antZ]) {
			antDirection++;
			if(antDirection == maxDirections) antDirection = 0;
			addObject(antX,antY,antZ);
		} else {
			removeObject(antX,antY,antZ);
			antDirection--;
			if(antDirection == -1) antDirection = maxDirections-1;
		}
		switch(antDirection) {
			case 0:
				antZ--;
				break;
			case 1:
				antX++;
				break;
			case 2:
				antY++;
				break;
			case 3:
				antX--;
				break;
			case 4:
				antZ++;
				break;
			case 5:
				antX++;
				break;
			case 6:
				antY--;
				break;
			case 7:
				antX--;
				break;
			default:
				break;
		}
		if(antY < 0) antY += cellsY;
		if(antY >= cellsY) antY -= cellsY;
		if(antX < 0) antX += cellsX;
		if(antX >= cellsX) antX -= cellsX;
		if(antZ < 0) antZ += cellsZ;
		if(antZ >= cellsZ) antZ -= cellsZ;
		if(isRotating==true) base.rotation.y +=.01;
		document.getElementById("count").value = filledCells;
	}
	function addObject(x,y,z) {
		var sphereMaterial = new THREE.MeshPhongMaterial({
			color: getRGB(x,y,z),
			opacity:1
		});	
		var obj = new THREE.Mesh(
		   new THREE.CubeGeometry(antSize,antSize,antSize),
		   sphereMaterial);
		obj.position.x = x*cellWidth-xOff;
		obj.position.y = y*cellHeight-yOff;
		obj.position.z = z*cellDepth-zOff;
		obj.overdraw = true;
		base.add(obj);
		objects[x][y][z] = obj;
		filledCells++;
	}
	function removeObject(x,y,z) {
		base.remove(objects[x][y][z]);
		objects[x][y][z] = null;
		filledCells--;
	}
	function getRGB(r,g,b) {
		var rgb = parseInt((r*colorMultiplier).toString(16) + (g*colorMultiplier).toString(16) + (b*colorMultiplier).toString(16),16);
		return rgb;
	}
	onload=init;

The above code assumes you have downloaded a copy of Three.js and have a HTML page with appropriate elements set up. To see the entirety of the code I used, right-click on the screenshot and open it in a new tab or window, then view source. It’s all one file, other than the Three.js library. Feel free to copy it in its entirety and play around.