interactive

Rolling a sphere with the keyboard

Wednesday, January 14th, 2009 | examples | Comments

Jim Foley pinged me and said he’s running a contest about creating a pv3d soccer ball:

http://madvertices.yuku.com/topic/11/master/1/?page=1

The contest made me think up this little example (make sure you click on the .swf to give it keyboard focus):


source

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
 
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.core.math.Number3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.objects.primitives.Sphere;
	import org.papervision3d.view.BasicView;
 
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class RollingASphereWithTheKeyboard extends BasicView
	{
		private static const UP:Number3D = new Number3D(0, 1, 0);
 
		private var sphere:Sphere;
		private var velocity:Number3D = new Number3D();
		private var friction:Number = .98;
 
		private var isDown:Boolean = false;
		private var isUp:Boolean = false;
		private var isLeft:Boolean = false;
		private var isRight:Boolean = false;
 
		public function RollingASphereWithTheKeyboard()
		{
			//move camera up to look down on sphere
			camera.y = 300;
 
			//create a faux horizon line
			var whiteBackground:Sprite = new Sprite();
			whiteBackground.graphics.beginFill(0xeeeeee);
			whiteBackground.graphics.drawRect(0, 0, width, 140);
			whiteBackground.graphics.endFill();
			addChildAt(whiteBackground, 0);
 
			var light:PointLight3D = new PointLight3D();
			var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0xcc0000, 0x222222);
			sphere = new Sphere(flatShadeMaterial, 100, 16, 8);
 
			scene.addChild(sphere);
			startRendering();
 
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}
 
		private function keyDownHandler(event:KeyboardEvent):void
		{
			switch(event.keyCode)
			{
				case Keyboard.DOWN:
					isDown = true;
					break;
				case Keyboard.UP:
					isUp = true;
					break;
				case Keyboard.LEFT:
					isLeft = true;
					break;
				case Keyboard.RIGHT:
					isRight = true;
					break;
			}
		}
 
		private function keyUpHandler(event:KeyboardEvent):void
		{
			switch(event.keyCode)
			{
				case Keyboard.DOWN:
					isDown = false;
					break;
				case Keyboard.UP:
					isUp = false;
					break;
				case Keyboard.LEFT:
					isLeft = false;
					break;
				case Keyboard.RIGHT:
					isRight = false;
					break;
			}
		}
 
		override protected function onRenderTick(event:Event=null):void
		{
			if(isDown) velocity.z -= .5;
			if(isUp) velocity.z += .5;
			if(isLeft) velocity.x -= .5;
			if(isRight) velocity.x += .5;
 
			//gradually slow down velocity
			velocity.multiplyEq(friction);
 
			sphere.x += velocity.x;
			sphere.z += velocity.z;
 
			//where the ball is headed
			var distance:Number = Math.sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
 
 			//Since the ball is rolling around back, forth, left, right
 			//it's rolling on the "XZ plane". Ignore the ball and think how
 			//the XZ plane would rotate around the y-axis (just like rotationY) 
 			//which is defined here as "UP". So you find the "cross" (the axis
 			//the ball will rotate around) by finding where the ball
 			//is heading and the axis the of the plane the ball is rolling on.
 			//I hope that makes sense :)
			var rotationAxis:Number3D = Number3D.cross(velocity, UP);
			rotationAxis.normalize();
 
			//create a matrix from the axis and the angle 
			var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, rotationAxis.y, rotationAxis.z, distance/100);
 
 			//apply the rotation to the ball
			sphere.transform.calculateMultiply3x3(rotationMatrix, sphere.transform);
 
			super.onRenderTick(event);
		}
	}
}

Tags: ,

Carousel with proper rotation and reflection

Monday, December 1st, 2008 | examples | Comments

I’m going to go out on a limb and say that this post will be popular ;)


source

package
{
	import flash.display.Bitmap;
	import flash.events.Event;
	import flash.filters.BlurFilter;
 
	import org.papervision3d.core.effects.view.ReflectionView;
	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;
 
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class ClickThenRotateCarousel extends ReflectionView
	{
		[Embed(source="assets/pic.jpg")]
		private var picAsset:Class;
 
		private const RADIUS:Number = 400;
		private const NUM_OF_PLANES:int = 9;
		private var carousel:DisplayObject3D = new DisplayObject3D();
 
		private var currentQuat:Quaternion = new Quaternion();		
		private var targetQuat:Quaternion = new Quaternion();
		private var slerp:Number = 0;
 
 
		public function ClickThenRotateCarousel()
		{
			viewportReflection.filters = [new BlurFilter(3,3,3)];
			viewport.interactive = true;
			surfaceHeight = -100; 
			camera.z = 800; //move camera to the front
 
			var pic:Bitmap = Bitmap(new picAsset());
 
			for(var i:int = 0; i < NUM_OF_PLANES; i++)
			{
				var material:BitmapMaterial = new BitmapMaterial(pic.bitmapData, true);
				material.doubleSided = true;
				material.interactive = true;
 
				var plane:Plane = new Plane(material, 100, 100);
				plane.rotationY = 360 / NUM_OF_PLANES * i;
				plane.moveForward(RADIUS);
 
				plane.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, objectOverHandler);
				plane.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, objectOutHandler);
				plane.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, objectClickHandler);
 
				carousel.addChild(plane);
			}
 
			scene.addChild(carousel);
 
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
 
		private function objectOverHandler(event:InteractiveScene3DEvent):void
		{
			viewport.buttonMode = true;
		}
 
		private function objectOutHandler(event:InteractiveScene3DEvent):void
		{
			viewport.buttonMode = false;
		}
 
		private function objectClickHandler(event:InteractiveScene3DEvent):void
		{
			var radians:Number = (carousel.rotationY - event.displayObject3D.rotationY) * Quaternion.DEGTORAD;
 
			slerp = 0;
			currentQuat = Quaternion.createFromMatrix(carousel.transform);
			targetQuat = Quaternion.createFromAxisAngle(0, 1, 0, radians);
		}
 
		private function enterFrameHandler(event:Event):void
		{
			slerp += (1 - slerp) * .05;
			var quat:Quaternion = Quaternion.slerp(currentQuat, targetQuat, slerp);
 
			carousel.transform = quat.matrix;
 
			singleRender();
		}
	}
}

Tags: , , , ,

Mouse follower

Tuesday, November 25th, 2008 | examples | Comments

Saw this question come up on the mailing list. I thought it would make a nice demo:


source

package
{
	import flash.events.Event;
 
	import org.papervision3d.core.utils.Mouse3D;
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.objects.primitives.Plane;
	import org.papervision3d.view.BasicView;
	import org.papervision3d.view.layer.ViewportLayer;
	import org.papervision3d.view.layer.util.ViewportLayerSortMode;
 
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class Mouse3DFloor extends BasicView
	{
		private var mouse3D:Mouse3D;
		private var follower:Plane;
 
		public function Mouse3DFloor() 
		{
			viewport.interactive = true;
			Mouse3D.enabled = true;
			mouse3D = viewport.interactiveSceneManager.mouse3D;
 
			var redColorMaterial:ColorMaterial = new ColorMaterial(0xcc0000);
			redColorMaterial.interactive = true; 
			//10, 10 represent the number of segments in the plane
			var floor:Plane = new Plane(redColorMaterial, 2000, 2000, 10, 10);			
			floor.rotationX = 90;
 
			var greenColorMaterial:ColorMaterial = new ColorMaterial(0x00cc00);
			follower = new Plane(greenColorMaterial, 300, 300);
			follower.rotationX = 90;			
			scene.addChild(floor);			
			scene.addChild(follower);
 
			camera.y = 1000;
			camera.lookAt(floor);
 
			var floorViewportLayer:ViewportLayer = new ViewportLayer(viewport, floor);
			var followerViewportLayer:ViewportLayer = new ViewportLayer(viewport, follower);
 
			viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;	
			floorViewportLayer.layerIndex = 0;
			followerViewportLayer.layerIndex = 1;
 
			viewport.containerSprite.addLayer(floorViewportLayer);
			viewport.containerSprite.addLayer(followerViewportLayer);
 
 
			startRendering();
		}
 
		override protected function onRenderTick(event:Event=null):void
		{
			follower.x += (mouse3D.x - follower.x) * .1;
			follower.y += (mouse3D.y - follower.y) * .1;
			follower.z += (mouse3D.z - follower.z) * .1;
			renderer.renderScene(scene, camera, viewport);
		}
 
	}
 
}

Tags: ,

Switching parents at runtime

Wednesday, November 19th, 2008 | examples | Comments

This example comes from a conversation I had with Andy. You can actually do a lot of neat tricks by swapping parents, especially when you start rotating the parents.


source

package
{
	import gs.TweenMax;
 
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.events.InteractiveScene3DEvent;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.objects.primitives.Sphere;
	import org.papervision3d.view.BasicView;
 
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class SwitchingParentsAtRuntime extends BasicView
	{
		private var parent1:Sphere;
		private var parent2:Sphere;
		private var childSphere:Sphere;
 
		private var light:PointLight3D;
 
		public function SwitchingParentsAtRuntime()
		{
			var headerText:headerContainer = new headerContainer();
			headerText.header.text = "Click a red sphere to set as parent";
			addChild(headerText);
 
			viewport.interactive = true;
			light = new PointLight3D();
 
			var parentMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0xcc0000);
			parentMaterial.interactive = true;
			var childMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0x00cc00);
 
			parent1 = new Sphere(parentMaterial, 300, 10, 10);
			parent1.x = -500;
			parent1.y = 500;
			parent1.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, objectPressHandler);
			parent1.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, objectOverHandler);
			parent1.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, objectOutHandler);
 
			parent2 = new Sphere(parentMaterial, 300, 10, 10);
			parent2.x = 500;
			parent2.y = -500;
			parent2.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, objectPressHandler);
			parent2.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, objectOverHandler);
			parent2.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, objectOutHandler);
 
			childSphere = new Sphere(childMaterial, 100, 10, 10);
			childSphere.name = "child";
 
			scene.addChild(parent1);
			scene.addChild(parent2);
			parent1.addChild(childSphere);
 
			childSphere.x = 500;
 
			TweenMax.to(parent1, 2, {y:-500, yoyo:true});
			TweenMax.to(parent2, 2, {y:500, yoyo:true});
 
			startRendering();
		}
 
		private function objectPressHandler(event:InteractiveScene3DEvent):void
		{
			var parentSphere:Sphere = Sphere(event.target);
			if(childSphere.parent == parentSphere)
			{
				//do nothing
			}else
			{
				var childSphereWorldMatrix:Matrix3D = childSphere.world;
				var inverse:Matrix3D = new Matrix3D();
				var tempParentMatrix:Matrix3D = new Matrix3D();
 
				inverse.calculateInverse(parentSphere.world);
 
				tempParentMatrix.calculateMultiply(inverse, childSphereWorldMatrix);
 
				childSphere.copyTransform(tempParentMatrix);
				//get the parent of the child to
				//remove the child from the parent :)
				childSphere.parent.removeChild(childSphere);
				parentSphere.addChild(childSphere);
			}
		}
 
		private function objectOverHandler(event:InteractiveScene3DEvent):void
		{
			viewport.buttonMode = true;	
		}
 
		private function objectOutHandler(event:InteractiveScene3DEvent):void
		{
			viewport.buttonMode = false;	
		}
	}
}

Tags: , , ,

Search

Recommended Books

Speaking at FITC Toronto

 

February 2012
M T W T F S S
« May    
 12345
6789101112
13141516171819
20212223242526
272829  

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

Loading ... Loading ...