rotation
Dragging an object to rotate
The cool thing about this example is you can really just drop any DisplayObject3D in to rotate it around. It’s not super exciting, but I bet many of you will find it useful.
package { import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; 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 Trackball extends BasicView { private static const FORWARD:Number3D = new Number3D(0, 0, 1); private var sphere:Sphere; private var previousMousePoint:Point = new Point(); private var isMouseDown:Boolean = false; public function Trackball() { var light:PointLight3D = new PointLight3D(); var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0xcc0000, 0x222222); sphere = new Sphere(flatShadeMaterial, 500, 32, 24); scene.addChild(sphere); startRendering(); stage.addEventListener(MouseEvent.MOUSE_DOWN, stage_mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler); } private function stage_mouseDownHandler(event:MouseEvent):void { isMouseDown = true; } private function stage_mouseUpHandler(event:MouseEvent):void { isMouseDown = false; } override protected function onRenderTick(event:Event=null):void { var currentMousePoint:Point = new Point(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY); if(isMouseDown) { var difference:Point = currentMousePoint.subtract(previousMousePoint); var vector:Number3D = new Number3D(difference.x, difference.y, 0); var rotationAxis:Number3D = Number3D.cross(vector, FORWARD); rotationAxis.normalize(); var distance:Number = Point.distance(currentMousePoint, previousMousePoint); var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, -rotationAxis.y, rotationAxis.z, distance/250); sphere.transform.calculateMultiply3x3(rotationMatrix, sphere.transform); } previousMousePoint = currentMousePoint; super.onRenderTick(event); } } }
Rolling a Sphere with Keyboard and Box2DFlash Physics
You really didn’t think I was just going to leave yesterday’s example with just one ball rolling around, did you?
Remember to click the .swf to give it focus. The main rolling ball is randomized, so the .swf will look different each time you open it.
The source is a mess. I basically copied and pasted code from my other Box2DFlash examples. The only real new stuff here is using the “gravityOffset” to cancel out gravity and the m_linearVelocity to set the velocity within Box2DFlash.
package { import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Collision.b2AABB; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2World; 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.DisplayObject3D; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.view.BasicView; [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")] public class RollingASphereWithTheKeyboardAndBox2D extends BasicView { private static const FORWARD:Number3D = new Number3D(0, 0, 1); private var WORLD_SCALE:Number = 30; private var WIDTH:Number = 640; private var HEIGHT:Number = 480; private var world:b2World; private var iterations:int = 10; private var timeStep:Number = 1.0/30.0; private var mainBody:b2Body; private var isDown:Boolean = false; private var isUp:Boolean = false; private var isLeft:Boolean = false; private var isRight:Boolean = false; public function RollingASphereWithTheKeyboardAndBox2D() { setupPapervision3D(); createWorld(); createFloor(); createCeiling(); createWalls(); createShapes(); 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; } } private function createWalls():void { var wallShapeDef:b2PolygonDef = new b2PolygonDef(); var wallBodyDef:b2BodyDef = new b2BodyDef(); var wall:b2Body; //Left and Right Shape Definition wallShapeDef.SetAsBox(100/WORLD_SCALE, (HEIGHT+40)/WORLD_SCALE/2); // Left wallBodyDef.position = new b2Vec2(-95 / WORLD_SCALE, HEIGHT/WORLD_SCALE/2); wall = world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // Right wallBodyDef.position = new b2Vec2((WIDTH+95) / WORLD_SCALE, HEIGHT/WORLD_SCALE/2); wall = world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); } private function setupPapervision3D():void { camera.y = -300; camera.z = -300; } private function createWorld():void { var worldBounds:b2AABB = new b2AABB(); worldBounds.lowerBound = new b2Vec2( 0, 0 ); worldBounds.upperBound = new b2Vec2(WIDTH/WORLD_SCALE, HEIGHT/WORLD_SCALE); var gravity:b2Vec2 = new b2Vec2(0.0, 10.0); var sleep:Boolean = true; world = new b2World(worldBounds, gravity, sleep); } private function createFloor():void { // Create border of boxes var floorShapeDef:b2PolygonDef = new b2PolygonDef(); var floorBodyDef:b2BodyDef = new b2BodyDef(); var floor:b2Body; //bottom shape definition floorShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE); // Bottom floorBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, (HEIGHT+95)/WORLD_SCALE); floor = world.CreateBody(floorBodyDef); floor.CreateShape(floorShapeDef); floor.SetMassFromShapes(); } private function createCeiling():void { var ceilingShapeDef:b2PolygonDef = new b2PolygonDef(); var ceilingBodyDef:b2BodyDef = new b2BodyDef(); var ceiling:b2Body; //Top and bottom shape definition ceilingShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE); // Top ceilingBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, -95/WORLD_SCALE); ceiling = world.CreateBody(ceilingBodyDef); ceiling.CreateShape(ceilingShapeDef); } private function createShapes():void { var light:PointLight3D = new PointLight3D(); for (var i:Number = 0; i < 20; i++) { //radius for physics circle and sphere var radius:Number = Math.random() * 50 + 10; var bodyDef:b2BodyDef = new b2BodyDef(); //random position toward the top of the stage bodyDef.position = new b2Vec2(Math.random() * WIDTH / WORLD_SCALE, Math.random() * HEIGHT /WORLD_SCALE); var body:b2Body = world.CreateBody(bodyDef); var shapeDef:b2CircleDef = new b2CircleDef(); shapeDef.radius = radius/WORLD_SCALE; shapeDef.density = 1; shapeDef.friction = .7; shapeDef.restitution = .7; body.CreateShape(shapeDef); body.SetMassFromShapes(); var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, Math.random() * 0xffffff, 0x111111); var sphere:Sphere = new Sphere(flatShadeMaterial, radius); scene.addChild(sphere); body.m_userData = sphere; mainBody = body; } } override protected function onRenderTick(event:Event=null):void { if(isDown) mainBody.m_linearVelocity.y += .2; if(isUp) mainBody.m_linearVelocity.y -= .2; if(isLeft) mainBody.m_linearVelocity.x -= .2; if(isRight) mainBody.m_linearVelocity.x += .2; //sets the position of any DisplayObject3D to the body position for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next) { var gravityOffset:b2Vec2 = world.m_gravity.Copy(); gravityOffset.Multiply(-bb.m_mass); bb.ApplyForce(gravityOffset, bb.GetWorldCenter() ); if (bb.m_userData is DisplayObject3D) { bb.m_userData.x = bb.GetPosition().x * WORLD_SCALE - WIDTH * .5; bb.m_userData.y = -bb.GetPosition().y * WORLD_SCALE + HEIGHT * .5; var distance:Number = Math.sqrt(bb.m_linearVelocity.x * bb.m_linearVelocity.x + bb.m_linearVelocity.y * bb.m_linearVelocity.y); var rotationAxis:Number3D = Number3D.cross(new Number3D(bb.m_linearVelocity.x, bb.m_linearVelocity.y, 0), FORWARD); rotationAxis.normalize(); var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, -rotationAxis.y, rotationAxis.z, distance/30); bb.m_userData.transform.calculateMultiply3x3(rotationMatrix, bb.m_userData.transform); } } renderer.renderScene(scene, camera, viewport); world.Step(timeStep, iterations); } } }
Rolling a sphere with the keyboard
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):
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); } } }
Carousel with proper rotation and reflection
I’m going to go out on a limb and say that this post will be popular
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(); } } }
Search
Recommended Books
Speaking at FITC Toronto
Recent Posts
- FDT Super Awesome March Deal
- FDT Theme Designer
- 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
- End dump
- Test if a plane is within the view of the camera (aka testing if culled)
Recent Comments
- KD on ActionScript 3 – Model View Controller (MVC)
- BAM5 on haXe Tutorial
- AlexG on Finding 2D Coordinates of a DisplayObject3D
- Josh on ActionScript 3 – Model View Controller (MVC)
- martin everett on requests
- martin everett on requests
- lillacska on Dragging Spheres
- Guy Ritchie on MXML without the Flex framework
- Pedro on ActionScript 3 – Namespaces
- daveevolve on AS3DMod Perlin Noise
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





