Carousel with proper rotation and reflection

Monday, December 1st, 2008 | examples

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: , , , ,

21 Comments to Carousel with proper rotation and reflection

Allan
December 1, 2008

Pretty nice but I would recommend the carousels at http://www.gotoandlearn.com/ unless you need the full Papervision3D api.
They should perform a bit better and be easier to implement.

John Lindquist
December 1, 2008

@Allan - This post shows a full 3D Carousel in Flash Player 9 that rotates in the proper direction when clicked and has a simple reflection.

Lee’s tutorials offer solutions for simpler carousels.

bartekd
December 1, 2008

@Allan I am not 100% convinced that FP10 built in 3D performs so much better than PV3D. During my experiments I found out the performance is mainly dependent on how a tool is used and not which tool you choose. In this case, the above example seems to run much smoother that the carousel on gotoandlearn.

The usability is much better here too. This has, of course, nothing to do with which 3d engine was used, but adds a lot to the final effect.

Seb
December 2, 2008

@Allan - if you have the time to spare to get to grips with PV3D, then it will offer you a world of possibilities that the FP10 3D classes do not offer.

Bas
December 17, 2008

Hi,
Thanks for the reflection code. I used in my project the same,where i got the actual plane image turned up-side down. Could anyone tell me the suggestion?
Thanks in advance.
Bas.S

Kyle
December 19, 2008

Hi,

I’ve noticed that using an enter frame event with singleRender() can really slow down performance. Is there are way to use ReflectionView with startRendering()?

Piet
January 6, 2009

This code works exactly the other way around for me than it does on this site. So all my images move to the back instead of to the front. So this makes my front images mirrored. Anyone?

John Lindquist
January 6, 2009

@Piet - did you set the camera.z to the front?

rd
January 8, 2009

Hi, this example is awesome and I´m trying to run it, but I haven´t find the way, I just want to know what version of papervision3D was used. In the rev851 from google code, the ReflectionView.as is missed. Thanks.

John Lindquist
January 8, 2009

@rd - if you open the source files, in the “lib” folder you’ll see Papervision3D_rev804.swc. That means this example uses rev 804. That being said, ReflectionView is not missing from 851.

lmg
January 9, 2009

nice one!

did you test this with materials showing text?
I tried with both images containing text and TextFields in MovieMatarial. not quite sure if this is what Piet is talking about, but using the code -as is- the materials appear mirrored horizontically. a bug in pv3d? used rev 858.

a quick’n'dirty fix:
plane.moveBackward(RADIUS); // instead of forward -> “fixes” the mirroring
var radians:Number = (carousel.rotationY - event.displayObject3D.rotationY + 180) * Quaternion.DEGTORAD; // “fixes” the target rotation that breaks when moving backwards

Lee Boone
January 9, 2009

@img - I fixed the mirroring with
plane.scaleX = -1;
Mainly because I couldn’t figure out the math for the rotation. =(
thanks!

Lee Boone
January 9, 2009

does anyone know how (or where I can find how) to make this scale when the stage is resized?
Thank you.

Joe
March 10, 2009

ermm what if we wanted to have only some object reflective in the viewport and not everyth?

Vovik
March 17, 2009

Could you please recommend a simple practical explanation or tutorial about the use of Quaternion for the rotation in Papervision3d?
All I was able to find on the web is either code or abstract math lectures and nothing in between. Both are very hard to understand for a beginner.
Thank you.

Morf
April 7, 2009

Hey John,
Excellent, excellent!

I’ve fallen a few months behind on my pv3d and had a project like this (though a bit more elaborate) in mind just before my hiatus. This will make it much easier! I’ll re-post when it’s functional some weeks from now.

joe
May 3, 2009

Why is everything shown only in flex!!!! SO frustrating! How would I implement in the flash cs3 IDE and please don’t say document class. That is so limiting. I tried the code and i get tons of error because Flex imports images differently (among other things). Flash IDE freaks when you use embed.

Joe
May 3, 2009

Can you guys post something that you don’t have to use flex for? I mean really. Its either flex or the document class.

[...] -http://pv3d.org/2008/12/01/carousel-with-proper-rotation-and-reflection/comment-page-1/ [...]

whoa
May 19, 2009

Yes, I do agree. With the threat of Silverlight in the horizon, we as a community should help each other. The strength of FLASH lies in the designers and developers banded together. There are designers who wants to dip their hands into programming once in a while and they prefer using Flash CS3 or CS4 IDE. Papervision should be for both. I hope that every Flex (Flash Builder)sample should come with a Flash example, hope I am not asking too much.

I hope to see more real-world examples. thanks

ZeRaW
June 11, 2009

Recently I was playing with this tutorial and I wanted a way to keep the carousel planes front facing, the other front facing tutorial is not that helpful, so i added some stuff to this one, I am assuming we are creating 5 planes, planes is an array, and planesRotations is another array:

plane.rotationY = 360 / 5 * i;
if (plane.rotationY > 0 && plane.rotationY < 0.01)
plane.rotationY = 0;
planesRotations.push(plane.rotationY);
plane.y = 100;
plane.moveForward(400);
plane.rotationY = 0;
planes.push(plane);

—————————————
Notice the planes are saved in an array and their corresponding rotations too, then they are reset to 0 so they are front facing.
Now when a plane is clicked, the carousel is rotated, to keep the planes front facing, a small hack is needed to apply the inverse of the quaternion rotation to each plane:

private function objectClickHandler(event:InteractiveScene3DEvent):void
{
var idx:int = planes.indexOf(event.displayObject3D);
//use the saved original rotation
var radians:Number = (carousel.rotationY - planesRotations[idx]) * 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;
var nb:Number3D = (quat.toEuler());
nb.x *= 180 / Math.PI; //this is the rotation angle transformed to degrees
for (var i:int = 0; i < planes.length; ++i)
{
planes[i].rotationY = -(nb.x);
}
singleRender();
}

Leave a comment