Archive for December, 2008
Happy New Year!
Click to party
Oh, and the code’s a mess.

source
package { import flash.events.MouseEvent; import org.flintparticles.common.actions.Age; import org.flintparticles.common.counters.Blast; import org.flintparticles.common.counters.Steady; import org.flintparticles.common.energyEasing.Quadratic; import org.flintparticles.common.events.EmitterEvent; import org.flintparticles.common.events.ParticleEvent; import org.flintparticles.common.initializers.Lifetime; import org.flintparticles.threeD.actions.Accelerate; import org.flintparticles.threeD.actions.LinearDrag; import org.flintparticles.threeD.actions.Move; import org.flintparticles.threeD.actions.RandomDrift; import org.flintparticles.threeD.emitters.Emitter3D; import org.flintparticles.threeD.geom.Vector3D; import org.flintparticles.threeD.initializers.Position; import org.flintparticles.threeD.initializers.Rotation; import org.flintparticles.threeD.initializers.ScaleAllInit; import org.flintparticles.threeD.initializers.Velocity; import org.flintparticles.threeD.papervision3d.PV3DRenderer; import org.flintparticles.threeD.papervision3d.initializers.PV3DObjectClasses; import org.flintparticles.threeD.particles.Particle3D; import org.flintparticles.threeD.zones.ConeZone; import org.flintparticles.threeD.zones.LineZone; import org.flintparticles.threeD.zones.PointZone; import org.flintparticles.threeD.zones.SphereZone; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.view.BasicView; [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")] public class HappyNewYear extends BasicView { private var flintRenderer:PV3DRenderer; private var rocket:Emitter3D; private var cameraTarget:DisplayObject3D = DisplayObject3D.ZERO; private var previousMouseX:Number = 0; private var cameraYaw:Number = 0; public function HappyNewYear() { flintRenderer = new PV3DRenderer( scene ); setupRocket(); startRendering(); stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler); } private function setupRocket():void { rocket = new Emitter3D(); rocket.counter = new Steady( 1 ); rocket.addInitializer( new PV3DObjectClasses([HappyWord, NewWord, YearWord]) ); rocket.addInitializer( new ScaleAllInit(.9, 1.4)); rocket.addInitializer( new Position( new LineZone( new Vector3D( 0, -500, 0 ), new Vector3D( 0, -500, 0) ) ) ); rocket.addInitializer( new Velocity( new ConeZone( Vector3D.ZERO, Vector3D.AXISY, 1, 500, 330 ) ) ); rocket.addInitializer( new Lifetime( 3.3 ) ); rocket.addAction( new Age() ); rocket.addAction( new Move() ); rocket.addAction( new Accelerate( new Vector3D( 0, -50, 0 ) ) ); rocket.addAction( new LinearDrag( 0.5 ) ); rocket.addAction( new RandomDrift( 200, 200, 200 ) ); rocket.addEventListener( ParticleEvent.PARTICLE_DEAD, rocket_particleDeadHandler, false, 0, true ); flintRenderer.addEmitter(rocket); rocket.start(); } private function rocket_particleDeadHandler(event:ParticleEvent):void { var explode:Emitter3D = new Emitter3D(); explode.counter = new Blast( 10 ); explode.addInitializer( new PV3DObjectClasses([HappyWord, NewWord, YearWord]) ); explode.addInitializer( new ScaleAllInit(.3, .6)); explode.addInitializer( new Rotation(Vector3D.AXISX, 1, 360)); explode.addInitializer( new Rotation(Vector3D.AXISZ, 1, 360)); explode.addInitializer( new Position( new PointZone( Particle3D( event.particle ).position ) ) ); explode.addInitializer( new Velocity( new SphereZone( Vector3D.ZERO, 1000 ) ) ); explode.addInitializer( new Lifetime( 3 ) ); explode.addAction( new Age( Quadratic.easeIn ) ); explode.addAction( new Move() ); explode.addAction( new Accelerate( new Vector3D( 0, -500, 0 ) ) ); explode.addAction( new LinearDrag( 0.5 ) ); explode.addEventListener( EmitterEvent.EMITTER_EMPTY, explode_emitterEmptyHandler, false, 0, true ); flintRenderer.addEmitter( explode ); explode.start(); } private function explode_emitterEmptyHandler(event:EmitterEvent):void { Emitter3D( event.target ).removeEventListener( EmitterEvent.EMITTER_EMPTY, explode_emitterEmptyHandler ); flintRenderer.removeEmitter( Emitter3D( event.target ) ); } private function stage_mouseMoveHandler(event:MouseEvent):void { var differenceX:Number = event.stageX - previousMouseX; cameraYaw += differenceX; cameraYaw %= 360; previousMouseX = event.stageX; camera.orbit(90, cameraYaw, true, cameraTarget); } } } import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.typography.Text3D; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.core.geom.TriangleMesh3D; class HappyWord extends TriangleMesh3D { public function HappyWord() { super( null, new Array(), new Array(), null ); var word:Text3D = new Text3D("Happy", new HelveticaBold(), new Letter3DMaterial(0xfe5555)); addChild(word); } } import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.typography.Text3D; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.core.geom.TriangleMesh3D; class NewWord extends TriangleMesh3D { public function NewWord() { super( null, new Array(), new Array(), null ); var word:Text3D = new Text3D("New", new HelveticaBold(), new Letter3DMaterial(0x91c0ff)); addChild(word); } } import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.typography.Text3D; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.core.geom.TriangleMesh3D; import org.papervision3d.typography.fonts.HelveticaBold; class YearWord extends TriangleMesh3D { public function YearWord() { super( null, new Array(), new Array(), null ); var word:Text3D = new Text3D("Year", new HelveticaBold(), new Letter3DMaterial(0xfffbbb)); addChild(word); } }
Slerp Explorer
Slerp allows you to find the quickest path from one rotation to another rotation. In Papervision3D, slerp is a static function of the Quaternion class. The following code shows all the pieces you’ll need to use slerp in your projects:
//the values from your start axis and rotation (x,y,z,rotation) startQuaternion = new Quaternion(0, 1, 0, 1); //the values from your end axis and rotation endQuaternion = new Quaternion(0, 1, 0, 1); /* the next section would go in an update event, like Event.ENTER_FRAME or TimerEvent.TIMER */ //if slerp is 0, the rotation will reflect the startQuaternion //if slerp is 1, the rotation will reflect the endQuaternion //any value between 0 and 1 will be a percentage of the rotation //between the start and end. For example, .5 would be halfway between //start and end. slerp = 0; //transition this up to 1, something like slerp += .01; //the main quaternion that you copy the rotation from quaternion = Quaternion.slerp(startQuaternion, endQuaternion, slerp); //Copies the rotation from the main quaternion into the cube's matrix cube.transform.copy3x3(quaternion.matrix);
To use this example:
- Move the axis and rotation sliders then click “set start”.
- Move the axis and rotation sliders and click “set end”
- Click “slerp from start to end” and you’ll see the cube rotate from the start rotation to the end rotation.
Focus on how the cube is rotating and how you could use that in your projects. Don’t get distracted by the reference axis.
Quaternion Explorer
The definition of Quaternion is a little more complex, but the use-case of a Quaternion is actually pretty easy to show. In this explorer, you’ll see how you define an axis with the sliders on the left then define the rotation around that axis with the slider on the right. This essentially shows you everything you need to create a Quaternion: an axis defined by three variables (x, y, z) and a rotation around that axis.
Please note that no matter what the axis is, if the rotation is zero, then the “Back” face of Cube looks straight at you. So try changing the axis sliders, scrub the rotation slider from 0 to 360 and back. Then change the axis sliders again, scrub from 0 to 360 again and you’ll notice how the rotation around the axis differs. Also, (0,0,0) isn’t an axis, so you can’t rotate around it ![]()
*update
Allow me to explain this a bit more. Here’s a few things to try to “orient” yourself
rotationX (x:1, y:0, z:0)
Move all the axis sliders to those values, then move the rotation slider from 0 – 360 and you’ll see your traditional rotationX (since it rotates around the X axis). You may be thinking to yourself, “Why do I need this? Why don’t I just use rotationX?” I would answer, “Because this way, you don’t limit yourself to just rotationX. You can define ANY rotation with these four numbers.” If you’ve ever tried to control a combination of rotationX, rotationY, and rotationZ at the same time, I’m sure you’ve run into difficulty.
Here are two other axes you’re familiar with:
rotationY (x:0, y:1, z:0)
rotationZ (x:0, y:0, z:1)
As a follow-up post, I’m working on a slerp explorer that will show you how to transition from any rotation to any other rotation which is where the power of Quaternions really shine.
As a final note, try leaving the rotation slider at 180 then adjusting the axis sliders. You will see the cube move at the same time as the axis, but it may look like it’s “lagging behind”. This effect comes from the cube adjusting itself to be rotated 180 around the axis. The cube is not following the axis in any way.
Don’t be distracted by the axis, it’s only there for reference. What’s important is the cube rotates around the axis.
Click then Tween Camera to Plane
I posted a similar example in the archive over a year ago now that turned out to be quite popular. Since that’s now outdated, here’s a quick n’ dirty updated version:
All images come from dryicons.com/
package { import flash.display.Bitmap; import flash.display.Sprite; import flash.events.MouseEvent; import gs.TweenMax; import gs.easing.Cubic; import org.papervision3d.core.math.Quaternion; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.BasicView; [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")] public class TweenToSpatialPlanes extends BasicView { [Embed(source="assets/1.jpg")] private var oneAsset:Class; [Embed(source="assets/2.jpg")] private var twoAsset:Class; [Embed(source="assets/3.jpg")] private var threeAsset:Class; [Embed(source="assets/4.jpg")] private var fourAsset:Class; [Embed(source="assets/5.jpg")] private var fiveAsset:Class; [Embed(source="assets/6.jpg")] private var sixAsset:Class; private var assets:Array = [oneAsset, twoAsset, threeAsset, fourAsset, fiveAsset, sixAsset]; private static const NUM_PLANES:int = 40; private static const TWEEN_TIME:Number = 2; private static const DISTANCE_FROM_PLANE:Number = 500; private var cameraWithSlerp:CameraWithSlerp = new CameraWithSlerp(); private var cameraStart:DisplayObject3D = new DisplayObject3D(); private var cameraTarget:DisplayObject3D = new DisplayObject3D(); private var startQuaternion:Quaternion = null; private var endQuaternion:Quaternion = null; private var currentQuaternion:Quaternion = null; public function TweenToSpatialPlanes() { setupPapervision3D(); setupBackground(); setupPlanes(); singleRender(); } private function setupPapervision3D():void { viewport.interactive = true; cameraWithSlerp.target = null; cameraWithSlerp.slerp = 0; cameraStart.z = -1000; scene.addChild(cameraStart); } private function setupBackground():void { //the background is for the "click outside" events var backgroundSprite:Sprite = new Sprite(); backgroundSprite.graphics.beginFill(0x000000); backgroundSprite.graphics.drawRect(0, 0, width, height); backgroundSprite.graphics.endFill(); addChildAt(backgroundSprite, getChildIndex(viewport)); backgroundSprite.addEventListener(MouseEvent.CLICK, backgroundSprite_clickHandler); } private function setupPlanes():void { for(var i:int = 0; i < NUM_PLANES; i++) { var bitmapMaterial:BitmapMaterial = createRandomBitmapMaterial(); bitmapMaterial.interactive = true; bitmapMaterial.doubleSided = true; bitmapMaterial.precise = true; var plane:Plane = new Plane(bitmapMaterial); plane.x = Math.random() * 5000 - 2500; plane.y = Math.random() * 5000 - 2500; plane.z = Math.random() * 2500; plane.rotationX = Math.random() * 180 -90; plane.rotationY = Math.random() * 180 -90; plane.rotationZ = Math.random() * 180 -90; scene.addChild(plane); plane.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, plane_objectClickHandler); } } private function createRandomBitmapMaterial():BitmapMaterial { //grab a bitmapAsset from the array (this is very ugly, but not important to the concept :) ) var bitmap:Bitmap = Bitmap(new assets[Math.floor(Math.random() * assets.length)]); var bitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData); return bitmapMaterial; } private function plane_objectClickHandler(event:InteractiveScene3DEvent):void { var plane:Plane = Plane(event.target); //put the target behind the plane cameraTarget.copyTransform(plane); cameraTarget.moveBackward(DISTANCE_FROM_PLANE); createTween(cameraTarget); } private function backgroundSprite_clickHandler(event:MouseEvent):void { createTween(cameraStart); } private function createTween(displayObject3d:DisplayObject3D):void { //when "slerping", this value is a range from 0 to 1 //0 being the starting total rotation (AKA transformation) //1 being the ending total rotation cameraWithSlerp.slerp = 0; var tweenObject:Object = {}; tweenObject.x = displayObject3d.x; tweenObject.y = displayObject3d.y; tweenObject.z = displayObject3d.z; tweenObject.bezierThrough = [{x:0, y:0, z:0, slerp:.1}]; tweenObject.ease = Cubic.easeInOut; tweenObject.slerp = 1; tweenObject.onUpdate = camera_updateCallback; startQuaternion = Quaternion.createFromMatrix(cameraWithSlerp.transform); endQuaternion = Quaternion.createFromMatrix(displayObject3d.transform); TweenMax.to(cameraWithSlerp, TWEEN_TIME, tweenObject); } private function camera_updateCallback():void { currentQuaternion = Quaternion.slerp(startQuaternion, endQuaternion, cameraWithSlerp.slerp); cameraWithSlerp.transform.copy3x3(currentQuaternion.matrix); singleRender(); } override public function singleRender():void { renderer.renderScene(scene, cameraWithSlerp, viewport); } } } //a helper class whose sole purpose is to add the slerp property //I use this for the sake of brevity, but for production code //you would move this into a new ActionScript file import org.papervision3d.cameras.Camera3D; class CameraWithSlerp extends Camera3D { public var slerp:Number = 0; }
Search
Recommended Books
Speaking at FITC Toronto
Recent Posts
- Moving to johnlindquist.com
- AsyncCommand with Robotlegs, Signals, Flight, MinimalComps
- Search Widget – Robotlegs, Signals, Flight, Minimal Comps, Yahoo Astra
- FDT Super Awesome March Deal
- haXe Tutorial
- AS3 Signals Tutorial
- Preferred Video Tutorial Resolution?
- TweenMax – Tweening a timeline (Advanced Tweening)
- Robotlegs + Flight + Union Platform
- Back in the saddle
- Eclipse Theme Designer Preview
- RobotLegs Hello World Video Tutorial
- 10 Things Every Senior Flash Developer Should Know
- Efflex – 3D Effects for Flex
- MorphController – Mighty Morphing Papervision3D
Recent Comments
- Hosting company on archive
- aanbae on Back in the saddle
- Domain registration on Looking around the inside of a Sphere
- website designing company on Looking around the inside of a Sphere
- Honda Motor on Augmented Reality – Recursive Webcam
- Zena on Augmented Reality – Recursive Webcam
- web hosting on Augmented Reality – Recursive Webcam
- web hosting on Twitter + Papervision3D (using Tweetr)
- web hosting on Efflex – 3D Effects for Flex
- web hosting on TweenMax – Tweening a timeline (Advanced Tweening)
Categories
Archives
Preferred Video Tutorial Resolution
- 1024x768 (53%, 85 Votes)
- 1280x1024 (15%, 24 Votes)
- 1920x1080 (15%, 24 Votes)
- 800x600 (13%, 20 Votes)
- 480x320 (4%, 6 Votes)
- 640x480 (0%, 2 Votes)
Total Voters: 160




