Monthly Archive for November, 2008

FlexPV3D - Flex UIComponents in Papervision w/ Source

Word. I’ve been trying to figure out how to make a 3D Flex UIComponent with Papervision 2 for a while now and have come up with a system that seems to work. I learned a lot from the YahooMapInPV3D AIR example, as well as a ton of other random posts. Check out this demo and see the source code:

Flex UIComponent in Papervision

Source

How it Works…
The important class is the FlexBasicView. This extends Papervision’s BasicView, making it easy to just add whatever 3D objects you want and to apply MovieMaterials to them all in one place, separate from the main Flex application. In this class, a few things happen.

First, you create a main DisplayObject3D called sceneManipulationContainer into which you are going to add your Flex-skinned Papervision 3D objects (planes, cubes, etc.) for easy manipulation. You add that to the FlexBasicView. The next thing is the most important: renderMovieClips(). This packages your UIComponents, which themselves can only be instantiated 3 children down from the main application (for now at least), into a movieClip that is used to create the MovieMaterial. Once that movieClip is made, you then pass it to the MovieMaterial. Then you create your DisplayObject3D (Plane in this case), and add your material, which is basically a thick nest => material(movie(uiComponent)).

The movie movieClip (the one used for the material) is then added to a parent movieClip, called movieParent. And this movieParent is added to the FlexBasicView.

After this, another important step must take place, and this is straight from the YahooMapInPV3D example. You first add an event listener for the plane (InteractiveScene3DEvent.OBJECT_MOVE). Then once the object is created and there is movement, this event is handled by the method skinDisplayObject3D(). What this does is align the movieClip/bundle/material into the right place on the Plane. Strange… But it works!!!

All you have to do now to add custom Flex UIComponents onto this plane is to 1) get a reference to your uiComponent which is 3 levels down from the main application, and 2) pass them into a movieClip which then is passed into the “movie” movieClip:

var newMovieClip:MovieClip() = new MovieClip();
newMovieClip(Application.application.myUIComponent);
movie.addChild(newMovieClip);

Better Design Patterns for the Future
I would like to have separated this FlexBasicView into more well defined classes, but I don’t have the time right now to dig that deep. Basically, you would create a UIComponentMaterial class that did all the movieClip configuration, and this would take in a UIComponent from the 3-level-down location. To make this so you don’t have to do Application.application.myComponent, it would be nice to create this on the main app, and to have a method like UIComponentMaterial.addUIComponent(myComponent) that took care of everything for you. However, the UIComponent you use for the MovieMaterial skin must also have a reference to the DisplayObject3D in order to become the correct width and height and whatnot, so this might get tricky. John Grden’s WinterWonderland screencast, which is a pretty hardcore example of what papervision can do, has an excellent example of how to let the movieClip used to make a MovieMaterial have reference to its parent MovieMaterial AND the DisplayObject3D it’s skinning. It’s pretty neat, and maybe that can be applied in this situation.

The goal would be a scenario something like this:

-In the main application mxml file, add the 2 canvases and make the 3rd layer “FlexBasicView”

<Application>
	<Canvas id="pv3dContainer">
		<me:FlexBasicView id="flexBasicView">
		</me:FlexBasicView>
	</Canvas>
</Application>

-Then it would be nice to be able to just put some MXML nested in the FlexBasicView tag that created Papervision components skinned with your UIComponent. Something like this:

<Application>
	<Canvas id="pv3dContainer">
		<me:FlexBasicView id="flexBasicView">
			<me:sceneManipulationContainer>
				<me:FlexPlane id="extendsDisplayObject3D" material="{myUIComponent}">
				</me:FlexPlane>
				<me:FlexCube id="alsoExtendsDisplayObject3D">
					<me:MaterialList>
						<Lots of Materials with UIComponent references>
					</me:MaterialList>
				</me:FlexCube>
			</me:sceneManipulationContainer>
		</me:FlexBasicView>
		<Canvas id="2ndLayer">
			<me:CommentBox id="myCommentUIComponent"/>
			<me:ProfileBox id="myProfileUIComponent"/>
			<me:CustomBox id="myUIComponent"/>
		</Canvas>
	</Canvas>
</Application>

Another way of doing that would be to stop at the level, and then do the rest in Actionscript so you could have a little more control. If any of you guys have any ideas or suggestions, please comment!

Now for the glitches…
Some things I’ve noticed.

  • 1) You’ll notice I have a custom Font in the assets folder. This is because, for some reason, the Text appears in the top left corner if you use Flex’s default font. The main glitch you get in all cases is something unexpected appearing in the left corner.
  • 2) If you nest things too deeply, you will get a white box appearing in the top left corner. This seems to be somewhat arbitrary and I haven’t pinpointed the reason why it happens. For example, if you add another nested DataGrid into the CommentBox that comes with the source code, nesting it into a FormItem (just for testing purposes), the white box glitch appears. Maybe I am missing something about the way Flex UIComponents are supposed to be nested? This also happens in more normal cases.
  • 3) Sometimes there are differences between Flex Boxes vs. Panels/Canvases. I’ve had HBoxes show the white box in the corner too…
  • 4) In the renderMovieClips() function in FlexBasicView, there are many ways to addChild the movieClips. Sometimes it works with just one. Sometimes every nested UIComponent should get their own newMovieClip, and then you add all of them in the order you want to a main movieClip as shown above.
  • 5) Things with Popups don’t work well, such as the ComboBox. And there’s no way to capture the Popup from that class unless you change either the PopupManager or create a CustomComboBox. You can grab the Combobox.dropdown, but it also tweens, so it’s sketchy.
  • 6) The scrollbar is jumpy.
  • 7) In some situations you can comment out //movieParent.addChild(movie) and //addChild(movieParent) and you’ll still see it work, in other situations you won’t.
  • 8) If the width of your component is not a % (like width=”100%”), it may create that white box in the corner. That is, if your width is an absolute value.
  • 9) Sometimes, if you add your UIComponent in MXML it won’t work. So you just do it in actionscript. But sometimes you can also add your UIComponent in MXML, and also say “addChild(myComponent)” in actionscript at it will work.

Flex and Papervision Don’t Mix Well…
But with enough time, it’s definitely possible

As you can see, this is very rough; there’s no real system for making Papervision Flex UIComponents yet, though I wish there was! Maybe the guys from OutSmart can shed some of their wisdom… I have just found that there are no examples on the internet of this being successfully done, and done in such a way that you can switch out components easily and apply it to different DisplayObject3D’s. So I’m throwin this out there for everyone to mess around with ;)

Needless to say, Flex doesn’t play very well with Papervision, at least in my experience. Sure there are a few examples on the web of using Sprites in Flex, like the 3d product gallery, but the real goal is to have 3D Flex UIComponents. If anyone knows of a better way to do this, by all means let us know. I’m looking forward to seeing how this can be done better.

Cheers,
Lance

Share This Post

If you enjoyed this post, make sure you subscribe to my RSS feed!




Technorati Profile http://rpc.technorati.com/rpc/ping
Warning: stristr() [function.stristr]: Empty delimiter in /home/.zwingli/lancorn411/systemsofseven.com/blog/wp-content/plugins/wassup/wassup.php on line 2093