Here is the source code for the Flash experiment I posted on Thursday.
package { import away3d.containers.ObjectContainer3D; import away3d.containers.View3D; import away3d.debug.AwayStats; import away3d.entities.Sprite3D; import away3d.filters.BloomFilter3D; import away3d.filters.BlurFilter3D; import away3d.filters.DepthOfFieldFilter3D; import away3d.lights.DirectionalLight; import away3d.lights.LightBase; import away3d.lights.PointLight; import away3d.materials.BitmapMaterial; import away3d.materials.ColorMaterial; import away3d.materials.methods.FogMethod; import away3d.primitives.Cube; import away3d.primitives.Plane; import away3d.primitives.Sphere; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.ColorTransform; import flash.geom.Vector3D; import flash.utils.getTimer; /** * Cubes01 Stage3D Demo by Felix Turner - www.airtight.cc * Modified by John Winkelman - www.eccesignum.org */ [SWF( backgroundColor='0xffffff', frameRate='60', width='800', height='600')] public class Cubes02 extends Sprite { private var CUBE_COUNT:int = 500; private var MATERIAL_COUNT:int = 30; private var CUBE_SIZE:int = 10; private var view : View3D; private var cubes:Array = []; private var cubeHolder : ObjectContainer3D; private var theta:Number = 0; private var radius:Number = 150; private var orbitSteps:Number = 1000; // number of steps necessary to complete one orbit private var orbitSpeed:Number = Math.PI*2/orbitSteps; //amount by which theta will be incremented at each interval private var objectInterval:Number = orbitSteps/CUBE_COUNT; // distance between objects on the curve private var objectPosition:Number; private var direction:Number = 1; // or -1 - controls direction of orbit public function Cubes02(){ super(); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; //init 3D world view = new View3D(); view.camera.z = -1000; addChild(view); //init object to hold cubes and rotate cubeHolder = new ObjectContainer3D(); view.scene.addChild(cubeHolder); //add lights var light:PointLight = new PointLight(); light.position = new Vector3D(-1000,1000,-1000); light.color = 0xffeeaa; view.scene.addChild(light); var light2:PointLight = new PointLight(); light2.position = new Vector3D(1000,1000,1000); light2.color = 0xFFFFFF; view.scene.addChild(light2); //init materials var materials:Array = []; for (var i:int = 0 ; i < MATERIAL_COUNT; i ++ ){ var material : ColorMaterial = new ColorMaterial(Math.random()*0xFFFFFF,1); //material.blendMode = BlendMode.ADD; material.lights = [light,light2]; materials.push(material); } for (var j:int = 0 ; j < CUBE_COUNT; j ++ ){ var s:Number = CUBE_SIZE; var cube:Cube = new Cube(materials[j % MATERIAL_COUNT], s,s,s); cubeHolder.addChild(cube); cube.x = 0; cube.y = 0; cube.z = 0; cubes.push(cube); } //add stats addChild(new AwayStats(view)); this.addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(Event.RESIZE, onStageResize); onStageResize(null); } private function onStageResize(event : Event) : void{ view.width = stage.stageWidth; view.height = stage.stageHeight; } private function onEnterFrame(ev : Event) : void{ cubeHolder.rotationX+=.2; cubeHolder.rotationY+=.4; cubeHolder.rotationZ+=.8; for(var i:int=0; i < CUBE_COUNT; i++) { objectPosition = orbitSpeed*objectInterval*i; // each object is individually updated /* OBJECT MOVEMENT CODE GOES HERE */ cubes[i].x = radius * (Math.cos(theta + objectPosition) * (Math.pow(5,Math.cos(theta+objectPosition)) - 2 * Math.cos(4 * (theta+objectPosition)) - Math.pow(Math.sin((theta+objectPosition)/12),4))); cubes[i].y = radius * (Math.sin(theta + objectPosition) * (Math.pow(5,Math.cos(theta+objectPosition)) - 2 * Math.cos(4 * (theta+objectPosition)) - Math.pow(Math.sin((theta+objectPosition)/12),4))); cubes[i].z = radius * Math.sin(theta + objectPosition) - radius*1*(Math.sin((radius/radius + 3) * (theta + objectPosition))); /* OBJECT MOVEMENT CODE GOES HERE */ } theta += (orbitSpeed*direction); view.render(); } } }
Most everything is a duplication of a block of code I snagged from Airtight Interactive’s Stage3D vs. WebGL demo. In addition to finally understanding something of how programming for 3d interfaces works, this gave me an opportunity to dive back into some of the trigonometry experiments I built back in the day.
In the code above, look at the method onEnterFrame. In it, inside the for loop, are three lines which update the x, y, and z coordinates of each block. Those blocks have some scary looking math attached to them; lots of sin and cos and radii, and thetas. I cheated – I actually wrote that code almost three years ago for my Simple Trigonometric Curves Tutorial over on Kongregate. X and Y positions are set using a transcendental Butterfly curve. The Z position is set using a variation on an Epicycloid curve. For fun, grab some of the other curves out of the tutorial, and plug them in in place of the current formulae. If you come up with something interesting, post it.