<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>blog.tartiflop</title>
	
	<link>http://blog.tartiflop.com</link>
	<description>post tenebras flex</description>
	<pubDate>Tue, 01 Mar 2011 19:11:08 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/tartiflop" /><feedburner:info uri="tartiflop" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>iSGL3D : 3D framework for iPhone, iPad and iPod touch</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/Rjo2l0qB0eM/</link>
		<comments>http://blog.tartiflop.com/2010/10/isgl3d-3d-framework-for-iphone-ipad-and-ipod-touch/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 17:50:36 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[iSGL3D]]></category>

		<category><![CDATA[3D]]></category>

		<category><![CDATA[iPhone]]></category>

		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=318</guid>
		<description><![CDATA[It&#8217;s been a long time since my last post on tartiflop.com but its been a busy year&#8230; and as they say: no news is good news!
I&#8217;d like to introduce here a new 3D scene graph library for the iPhone, iPad and iPod touch: iSGL3D. Built on principles of simplicity with performance, iSGL3D provides a simple [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a long time since my last post on tartiflop.com but its been a busy year&#8230; and as they say: no news is good news!</p>
<p>I&#8217;d like to introduce here a new 3D scene graph library for the iPhone, iPad and iPod touch: <a target="_blank" href="http://isgl3d.com">iSGL3D</a>. Built on principles of simplicity with performance, iSGL3D provides a simple framework for creating hardware accelerated 3D scenes in just a few lines of Objective C&#8230; without any of the complexities of OpenGL. With its rich set of features, iSGL3D provides the necessary tools to develop 3D applications in an incredibly short time frame, even with a minimum of experience in 3D graphics. </p>
<p><img src="http://blog.tartiflop.com/wp-content/uploads/2010/10/isgl3d1-300x161.png" alt="" title="isgl3d1" width="300" height="161" class="alignleft size-medium wp-image-320" /></p>
<p>With a single line of code you can add a 3D object whether it is a simple primitive, a sprite (or particle) or your own imported asset. Properties on these objects allow you to modify their appearance, position, rotation and more very simply. You can add containers too to group objects and manipulate them together. In a short period of time you can build up a complex 3D scene.</p>
<p><br/><br />
Below are just of few of the features you&#8217;ll find with iSGL3D:</p>
<ul>
<li>Simplicity with performance</li>
<li>Lighting and shading</li>
<li>Cameras</li>
<li>Meshes and particles<img src="http://blog.tartiflop.com/wp-content/uploads/2010/10/isgl3d3-300x161.png" alt="" title="isgl3d3" width="300" height="161" class="alignright size-medium wp-image-323" /></li>
<li>Primitives</li>
<li>Materials</li>
<li>Fast rendering with OpenGL ES 1.1 and ES 2.0</li>
<li>Importing of POWERVR POD scenes and 3D meshes</li>
<li>Bridging to physics libraries</li>
<li>Real-time shadows</li>
<li>Animation by Tweening</li>
<li>Skeletons and mesh skinning</li>
<li>Integrated accelerometer support</li>
<li>Touchscreen events and interactive 3D objects</li>
<li>Occlusion transparency</li>
<li>User interface creation</li>
</ul>
<p>For more information on the features available with iSGL3D check out the <a target="_blank" href="http://isgl3d.com/about/features">features page</a>. </p>
<p><img src="http://blog.tartiflop.com/wp-content/uploads/2010/10/isgl3d2-300x161.png" alt="" title="isgl3d2" width="300" height="161" class="alignleft size-medium wp-image-321" />The <a target="_blank" href="http://isgl3d.com/resources/api">iSGL3D API</a> provides a complete reference to the classes contained in the iSGL3D framework. For construction and manipulation of primitives, materials, nodes, tweens, etc&#8230; you can find all the relevant information here.</p>
<p>The growing series of <a target="_blank" href="http://isgl3d.com/resources/tutorials">iSGL3D tutorials</a> is a great starting point for developing your own iSGL3D applications: you&#8217;ll see how easy it is to produce 3D applications for the iPhone, iPad and iPod touch in just a few lines of code.</p>
<p>If you&#8217;re looking for a simple solution to writing 3D games and applications for the iPhone then look no further than <a target="_blank" href="http://isgl3d.com">iSGL3D</a>!</p>
<p><a target="_blank" href="http://isgl3d.com"><img src="http://blog.tartiflop.com/wp-content/uploads/2010/10/isgl3d.png" alt="" title="isgl3d" width="256" height="64" class="aligncenter size-medium wp-image-324" /></a></p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/Rjo2l0qB0eM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2010/10/isgl3d-3d-framework-for-iphone-ipad-and-ipod-touch/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2010/10/isgl3d-3d-framework-for-iphone-ipad-and-ipod-touch/</feedburner:origLink></item>
		<item>
		<title>Away3D Lite: fastest and smallest 3d engine in Flash</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/aDt4GD7lcW0/</link>
		<comments>http://blog.tartiflop.com/2009/09/away3d-lite-fastest-and-smallest-3d-engine-in-flash/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 18:41:31 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=313</guid>
		<description><![CDATA[Not to be missed! Check out:

Currently weighing in at under 25K, Away3D Lite can be used in projects with the most stringent bandwidth restrictions. No problem for use in banners, widgets, thumbnails… anything where filesize is a priority. But the biggest single feature offered by the new engine is it’s speed. Current tests clock framerates [...]]]></description>
			<content:encoded><![CDATA[<p>Not to be missed! Check out:</p>
<p><a href="http://away3d.com"><img src="http://blog.tartiflop.com/wp-content/uploads/2009/09/post_logolite-300x168.jpg" alt="" title="" width="300" height="168" class="aligncenter size-medium wp-image-314" /></a></p>
<blockquote><p><em>Currently weighing in at under 25K, Away3D Lite can be used in projects with the most stringent bandwidth restrictions. No problem for use in banners, widgets, thumbnails… anything where filesize is a priority. But the biggest single feature offered by the new engine is it’s speed. Current tests clock framerates up to 4 times faster than the standard Away3D library. And with more frames-per-second comes the potential for more polygons, more accessible content on slower machines, and more processing power left for other areas of a Flash application.</p>
<p>Away3D Lite is not meant as a replacement for the standard Away3D libraries. Because of it’s use of the native 3D features in the Flash 10 Player, Away3D Lite is Flash 10 only, so the development of Away3D 2.5 &#038; 3.5 will continue as usual. These engines are more of a workhorse for many different purposes and with many different features, while Away3D Lite offers the choice to be fast and small at the sacrifice of features. This is not to say that you can’t do anything with Away3D Lite! The list of main supported features in 1.0 includes:</p>
<ul>
<li>3DS, MD2, Collada &#038; Metasequoia loaders</li>
<li>Bones animation</li>
<li>Viewport clipping</li>
<li>3d mouse events</li>
<li>All standard primitive types</li>
<li>All standard camera types</li>
<li>All standard material types</li>
<li>Template classes for quick and easy setup</li>
</ul>
<p>Plus, you will already know how to use Away3D Lite if you’ve used Away3D! Everything is where you’d expect, and there have only been very minor changes made to some property names, which in time will most likely percolate back through the various engines.</em></p></blockquote>
<p>Fantastic work from the Away3D team - congratulations to everyone involved! </p>
<p>Read more, and be sure to check out the demos showing how fast it really is (believe me, if its speedy 3D rendering you&#8217;re after, you won&#8217;t do better than this!), at <a href="http://away3d.com">away3d.com</a></p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/aDt4GD7lcW0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2009/09/away3d-lite-fastest-and-smallest-3d-engine-in-flash/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2009/09/away3d-lite-fastest-and-smallest-3d-engine-in-flash/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Beck</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/1a152jziTPw/</link>
		<comments>http://blog.tartiflop.com/2009/04/musical-interlude-beck/#comments</comments>
		<pubDate>Sun, 05 Apr 2009 19:54:59 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=310</guid>
		<description><![CDATA[&#8230; just to let you know I&#8217;m still here and I&#8217;ve not forgotten &#8230;
Discover Beck!
]]></description>
			<content:encoded><![CDATA[<p>&#8230; just to let you know I&#8217;m still here and I&#8217;ve not forgotten &#8230;</p>
<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2711035&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2711035&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/beck.html'>Beck</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/1a152jziTPw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2009/04/musical-interlude-beck/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2009/04/musical-interlude-beck/</feedburner:origLink></item>
		<item>
		<title>Away3D 2.3 released</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/mMxJWofuPfU/</link>
		<comments>http://blog.tartiflop.com/2009/02/away3d-23-released/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 15:25:58 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=304</guid>
		<description><![CDATA[Great news! Away3D 2.3 has been released, featuring amongst others:

Frustum and nearfield culling, as well as object culling for standard clipping
Normalmaps tools to help with their generation and/or manipulation
BezierPatch for geometry generation allowing the creation of bezier surfaces programatically
Improved Awaybuilder with a custom parser for Maya scenes which can dramatically speed up 3D workflow
Interchangeable camera [...]]]></description>
			<content:encoded><![CDATA[<p>Great news! Away3D 2.3 has been released, featuring amongst others:</p>
<ul>
<li>Frustum and nearfield culling, as well as object culling for standard clipping</li>
<li>Normalmaps tools to help with their generation and/or manipulation</li>
<li>BezierPatch for geometry generation allowing the creation of bezier surfaces programatically</li>
<li>Improved Awaybuilder with a custom parser for Maya scenes which can dramatically speed up 3D workflow</li>
<li>Interchangeable camera lenses to allow for different types of projection</li>
<li>All values allowed for stage properties “align” and “scaleMode”</li>
<li>Improved memory management</li>
<li>Improved extrusion tools</li>
<li>ROLL_OVER/ROLL_OUT events added to MouseEvent3D</li>
<li>Billboard mesh objects for fast 2d sprites</li>
</ul>
<p><a href="http://away3d.com"><img src="http://blog.tartiflop.com/wp-content/uploads/2009/02/away3d-300x213.jpg" alt="" title="" width="300" height="213" class="aligncenter size-medium wp-image-305" /></a></p>
<p>If you haven&#8217;t checked it out already, then now is the time to do so!</p>
<p>Congrats to the whole Away3D team!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/mMxJWofuPfU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2009/02/away3d-23-released/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2009/02/away3d-23-released/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - General Elektriks</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/DZ1ppQX4VDE/</link>
		<comments>http://blog.tartiflop.com/2008/12/musical-interlude-general-elektriks/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 18:18:31 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=299</guid>
		<description><![CDATA[Discover General Elektriks!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=33039&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=33039&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/general-elektriks.html'>General Elektriks</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/DZ1ppQX4VDE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/musical-interlude-general-elektriks/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/musical-interlude-general-elektriks/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 7 - Movie and video materials</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/KrVYQkdfK4k/</link>
		<comments>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-7-movie-and-video-materials/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 17:47:33 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<category><![CDATA[animation]]></category>

		<category><![CDATA[movie material]]></category>

		<category><![CDATA[Tweener]]></category>

		<category><![CDATA[video stream]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=289</guid>
		<description><![CDATA[Having looked at the different types of texture mapped and coloured materials with different lighting aspects, I want to discuss briefly a couple of more interactive and dynamic materials. These don&#8217;t necessarily add realism to a scene but can be very useful for 3D website development to provide a richer user experience. To do this [...]]]></description>
			<content:encoded><![CDATA[<p>Having looked at the different types of texture mapped and coloured materials with different lighting aspects, I want to discuss briefly a couple of more interactive and dynamic materials. These don&#8217;t necessarily add <em>realism</em> to a scene but can be very useful for 3D website development to provide a richer user experience. To do this we use the <em>MovieMaterial</em> and <em>VideoMaterial</em>. If you&#8217;re interested here is an  equivalent tutorial for <a href="http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-8-movie-materials/">movie materials in Papervision3D</a>.</p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - Animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">First steps in Away3D : Part 3 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/">First steps in Away3D : Part 4 - Scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/">First steps in Away3D : Part 5 - Lighting and shading</a><br />
A light source is added to the scene and the materials are changed to illustrate how Away3D renders objects with different shading characteristics.
</li>
<li><a href="http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-6-normal-mapping-and-environment-mapping/">First steps in Away3D : Part 6 - Normal mapping and environment mapping</a><br />
Additional realism is added to the scene by applying normal maps (to give a higher level of shading characteristics) and environment maps (as an alternative to simple lighting models).
</li>
</ul>
<p>This article will be looking at two materials available in Away3D: the <em>MovieMaterial</em> for rendering Flash movies onto a surface and <em>VideoMaterial</em> to show Flash video streams on an object (using <em>.flv</em> files). As well as being able to show another Flash animation, mouse events are mapped to the <em>MovieMaterial</em> allowing it to be interactive, even in a 3D environment. </p>
<p>This article is taking advantage of the very latest types of materials available with Away3D: to be able to compile the examples and develop your own you may need to use the repository (SVN) version of Away3D. If you don&#8217;t have <em>away3d.materials.VideoMaterial</em> available in your Away3D source then this is the case. Here&#8217;s an article on <a href="http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/">downloading and installing Away3D from SNV</a> if you need help.</p>
<p>To illustrate these different materials we&#8217;re going to create three simple planes rotated and translated to form three sides of a cube. Two of these will be rendered using <em>MovieMaterial</em>s and the third with a Flash video stream using a <em>VideoMaterial</em>. One of the <em>MovieMaterial</em> planes will be interactive and I&#8217;ll show how a external Flash movie can be embedded in the compiled animation.</p>
<p>So let&#8217;s look at the code. For this example we will actually have three ActionScript classes: the main Away3D class and two additional classes to be used for the individual <em>MovieMaterial</em> cube faces. The latter two will be shown at the end of the article just for completeness. </p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.HoverCamera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.base.Object3D;
&nbsp; import away3d.core.render.Renderer;
&nbsp; import away3d.events.MouseEvent3D;
&nbsp; import away3d.materials.MovieMaterial;
&nbsp; import away3d.materials.VideoMaterial;
&nbsp; import away3d.primitives.Plane;
&nbsp;
&nbsp; import caurina.transitions.Tweener;
&nbsp;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp; import flash.filters.BlurFilter;
&nbsp;
&nbsp; [SWF(backgroundColor="#222222")]
&nbsp;
&nbsp; public class Example007 extends Sprite {

 &nbsp; &nbsp; private var videoURL:String = "http://www.tartiflop.com/away3d/FirstSteps/AmIWrong.flv";

&nbsp; &nbsp; [Embed(source="/../assets/DrawTool.swf")]
&nbsp; &nbsp; private var DrawToolEmbedded:Class;

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:HoverCamera3D;
&nbsp; &nbsp; private var view:View3D;

&nbsp; &nbsp; private var planeGroup:ObjectContainer3D;
&nbsp; &nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = true;
&nbsp; &nbsp;
&nbsp; &nbsp; public function Example007() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Away3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Initialise all 3D components.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new HoverCamera3D({zoom:25, focus:30, distance:200});
&nbsp; &nbsp; &nbsp; camera.yfactor = 1;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the view to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // ensure that the z-order is calculated correctly
&nbsp; &nbsp; &nbsp; view.renderer = Renderer.CORRECT_Z_ORDER;
&nbsp; &nbsp; &nbsp;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Create the objects of the scene
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Video material using a flash streaming video URL
&nbsp; &nbsp; &nbsp; var frontMaterial:VideoMaterial = new VideoMaterial({file:videoURL});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Movie material from an embedded flash animation
&nbsp; &nbsp; &nbsp; var topMaterial:MovieMaterial = new MovieMaterial(new DrawToolEmbedded(), {lockW:320, lockH:240, interactive:true, smooth:true, precision:5});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Movie material from another class
&nbsp; &nbsp; &nbsp; var leftMaterial:MovieMaterial = new MovieMaterial(new Pong(), {smooth:true, precision:5});

&nbsp; &nbsp; &nbsp; // Create three planes with different material, blurred by default
&nbsp; &nbsp; &nbsp; // and position them them to create tree sides of a cube
&nbsp; &nbsp; &nbsp; var topPlane:Plane = new Plane({material:topMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; topPlane.rotationY = -180;
&nbsp; &nbsp; &nbsp; topPlane.y = 50;
&nbsp; &nbsp; &nbsp; topPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var leftPlane:Plane = new Plane({material:leftMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; leftPlane.rotationZ = -90;
&nbsp; &nbsp; &nbsp; leftPlane.rotationY = -90;
&nbsp; &nbsp; &nbsp; leftPlane.x = 50;
&nbsp; &nbsp; &nbsp; leftPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var frontPlane:Plane = new Plane({material:frontMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; frontPlane.rotationX = -90;
&nbsp; &nbsp; &nbsp; frontPlane.rotationZ = 180;
&nbsp; &nbsp; &nbsp; frontPlane.z = 50;
&nbsp; &nbsp; &nbsp; frontPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create an object container to group the sides of the cube
&nbsp; &nbsp; &nbsp; planeGroup = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(planeGroup);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(topPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(leftPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(frontPlane);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Add mouse listeners to each plane for mouse down, over and out events
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseOut(onMouseLeavesObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseOut(onMouseLeavesObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseOut(onMouseLeavesObject);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Frame-enter event handler
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // update camera position
&nbsp; &nbsp; &nbsp; updateCamera();
&nbsp; &nbsp; &nbsp; camera.hover();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Update the camera position from mouse positions
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp; camera.targetpanangle =  (stage.stageWidth - stage.mouseX) / stage.stageWidth * 90;
&nbsp; &nbsp; &nbsp; &nbsp; camera.targettiltangle = (stage.stageHeight - stage.mouseY) / stage.stageHeight * 70
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse click on plane. Makes the camera look
&nbsp; &nbsp;  * directly at the plane and move closer to it.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseClickOnObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; doRotation = false;

&nbsp; &nbsp; &nbsp; // Calculate angles necessary for camera&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var theta:Number = Math.atan2(object.x, object.z);
&nbsp; &nbsp; &nbsp; var len:Number = Math.sqrt(object.x*object.x + object.z*object.z);
&nbsp; &nbsp; &nbsp; var phi:Number = Math.atan2(object.y, len);

&nbsp; &nbsp; &nbsp; // rotate camera position
&nbsp; &nbsp; &nbsp; camera.targetpanangle = theta * 180 / Math.PI;
&nbsp; &nbsp; &nbsp; camera.targettiltangle = phi * 180 / Math.PI;

&nbsp; &nbsp; &nbsp; // move camera towards plane
&nbsp; &nbsp; &nbsp; Tweener.addTween(camera, {distance:150, time:0.5, transition:"easeOutSine"});
&nbsp; &nbsp; }&nbsp; &nbsp; 

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse over plane. Removes the blur filter.
&nbsp; &nbsp;  */&nbsp; &nbsp;
&nbsp; &nbsp; private function onMouseOverObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; object.filters = new Array();
&nbsp; &nbsp; }&nbsp; &nbsp;
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse out of plane. Adds blur filter and moves
&nbsp; &nbsp;  * camera away from plane if it isn't already.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseLeavesObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;

&nbsp; &nbsp; &nbsp; object.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp; Tweener.addTween(camera, {distance:200, time:0.5, transition:"easeOutSine"});
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Resize the scene when the stage resizes
&nbsp; &nbsp;  */&nbsp;
&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }

&nbsp; }
&nbsp;
}
</blockquote>
</pre>
</div>
<p>This (along with the other ActionScript classes shown below) produces a cube that rotates as the mouse moves. One face shows a Flash video stream (<a href="http://www.myspace.com/etiennedecrecy">Etienne de Crécy</a> : Am I Wrong), another is an interactive drawable surface and the third a simple <a href="http://en.wikipedia.org/wiki/Pong"><em>Pong</em></a> simulation. Each face is blurred until the mouse enters it. Clicking on a face moves the camera directly above it and moves towards it. Moving the mouse outside of a face blurs the face again and the cube regains its original size. You can see the finished result by clicking on the image below.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example007.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/12/example007.png" border="0" width="480" height="320"/></a></p>
<p>As usual, the code for <em>Example007</em> follows the same style as shown in the previous articles of this series. Lets look at what has changed.</p>
<p>The constructor and initialisation of Away3D elements is virtually identical to before so not worth looking at here. Lets move onto the scene creation (<em>createScene()</em>)and see how we use these new materials. To start off with the materials are created.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Video material using a flash streaming video URL
&nbsp; &nbsp; &nbsp; var frontMaterial:VideoMaterial = new VideoMaterial({file:videoURL});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Movie material from an embedded flash animation
&nbsp; &nbsp; &nbsp; var topMaterial:MovieMaterial = new MovieMaterial(new DrawToolEmbedded(), {lockW:320, lockH:240, interactive:true, smooth:true, precision:5});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Movie material from another class
&nbsp; &nbsp; &nbsp; var leftMaterial:MovieMaterial = new MovieMaterial(new Pong(), {smooth:true, precision:5});
</blockquote>
</pre>
</div>
<p>As you can see, the <em>VideoMaterial</em> is very easy to create - simply pass the URL of the Flash video stream in the initialisation parameters and its ready! Compared to Papervision3D this is much easier (in fact, the internet connection and creation of the video stream is encapsulated in the <em>VideoMaterial</em> class). If you want the video to loop you can set the <em>loop</em> parameter to true, also sent in the initialisation parameters array. If you want to pause/play the video then you can access the <em>netStream</em> object directly from the material to control the playback.</p>
<p>The <em>MovieMaterial</em> is similarly easy to create. The constructor takes a <em>Sprite</em> object which will be mapped to the surface. I show two cases here: one where the object is an instantiation of a class in the same project, another where we embed a previously compiled Flash movie. Other than the <em>smooth</em> and <em>precision</em> parameters as we discussed in the <a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">texture mapping tutorial</a>, we can indicate that the material should be interactive by specifying the <em>interactive</em> parameter to be true. Similarly we can force a size of the <em>Sprite</em> by giving the <em>lockW</em> and <em>lockH</em> parameters being the width and height - note that these have no relation to the dimensions of the object to which the material is mapped.</p>
<p>These materials are used just like all the other materials presented in this series of articles: simply create an object and pass the material to it.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create three planes with different material, blurred by default
&nbsp; &nbsp; &nbsp; // and position them them to create tree sides of a cube
&nbsp; &nbsp; &nbsp; var topPlane:Plane = new Plane({material:topMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; topPlane.rotationY = -180;
&nbsp; &nbsp; &nbsp; topPlane.y = 50;
&nbsp; &nbsp; &nbsp; topPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var leftPlane:Plane = new Plane({material:leftMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; leftPlane.rotationZ = -90;
&nbsp; &nbsp; &nbsp; leftPlane.rotationY = -90;
&nbsp; &nbsp; &nbsp; leftPlane.x = 50;
&nbsp; &nbsp; &nbsp; leftPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var frontPlane:Plane = new Plane({material:frontMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; frontPlane.rotationX = -90;
&nbsp; &nbsp; &nbsp; frontPlane.rotationZ = 180;
&nbsp; &nbsp; &nbsp; frontPlane.z = 50;
&nbsp; &nbsp; &nbsp; frontPlane.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create an object container to group the sides of the cube
&nbsp; &nbsp; &nbsp; planeGroup = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(planeGroup);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(topPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(leftPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(frontPlane);
</blockquote>
</pre>
</div>
<p>As you can see, three planes are created, as shown in previous articles, and a different material passed to each one. These planes are then rotated and translated to form three faces of a cube. I also added a <em>BlurFilter</em> just to show how adding effects to Away3D objects is very simple as well.</p>
<p>Moving onto the mouse event listeners, for this example I don&#8217;t have a stage mouse listener to rotate the scene, only listeners for the <em>MouseEvent3D</em> events. Here, for each face, I add a mouse down, mouse over and mouse up listener that are triggered only when the mouse interacts with a specific 3D object.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Add mouse listeners to each plane for mouse down, over and out events
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseDown(onMouseClickOnObject);
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseOver(onMouseOverObject);
&nbsp; &nbsp; &nbsp; topPlane.addOnMouseOut(onMouseLeavesObject);
&nbsp; &nbsp; &nbsp; leftPlane.addOnMouseOut(onMouseLeavesObject);
&nbsp; &nbsp; &nbsp; frontPlane.addOnMouseOut(onMouseLeavesObject);
</blockquote>
</pre>
</div>
<p>Looking first at the mouse down listener, the objective is to make the camera look directly at a cube face.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse click on plane. Makes the camera look
&nbsp; &nbsp;  * directly at the plane and move closer to it.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseClickOnObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; doRotation = false;

&nbsp; &nbsp; &nbsp; // Calculate angles necessary for camera&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var theta:Number = Math.atan2(object.x, object.z);
&nbsp; &nbsp; &nbsp; var len:Number = Math.sqrt(object.x*object.x + object.z*object.z);
&nbsp; &nbsp; &nbsp; var phi:Number = Math.atan2(object.y, len);

&nbsp; &nbsp; &nbsp; // rotate camera position
&nbsp; &nbsp; &nbsp; camera.targetpanangle = theta * 180 / Math.PI;
&nbsp; &nbsp; &nbsp; camera.targettiltangle = phi * 180 / Math.PI;

&nbsp; &nbsp; &nbsp; // move camera towards plane
&nbsp; &nbsp; &nbsp; Tweener.addTween(camera, {distance:150, time:0.5, transition:"easeOutSine"});
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>From the object location we can calculate a camera <em>tilt</em> and <em>pan</em> angle. Using the properties <em>targetpanangle</em> and <em>targettiltangle</em> the camera moves gently towards the desired position. To move the camera towards the object I&#8217;ve added a <em>Tweener</em> call (as we looked at in <a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/">scene interaction</a>). In this function we also turn off the automatic camera movement (the camera follows the mouse otherwise as shown below).</p>
<p>Moving on to the mouse over event listener, here we simply remove the <em>BlurFilter</em> making the face come into focus.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse over plane. Removes the blur filter.
&nbsp; &nbsp;  */&nbsp; &nbsp;
&nbsp; &nbsp; private function onMouseOverObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; object.filters = new Array();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Finally for the listeners, the mouse out event listener adds the <em>BlurFilter</em>, ensures that the camera moves freely with the mouse movement again and executes another <em>Tweener</em> call to take the camera back to its original distance.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse out of plane. Adds blur filter and moves
&nbsp; &nbsp;  * camera away from plane if it isn't already.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseLeavesObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;

&nbsp; &nbsp; &nbsp; object.filters.push(new BlurFilter(8, 8));
&nbsp; &nbsp; &nbsp; Tweener.addTween(camera, {distance:200, time:0.5, transition:"easeOutSine"});
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>That leaves us with just the event loop and the camera update function. You&#8217;ll notice that the update loop is very similar to before - there is no rotation applied to the scene objects this time but we do update the camera position.</p>
<p>To move the camera automatically, the relative mouse position on the screen is simply converted into pan and tilt angles and applied to the camera target angles as shown below. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Update the camera position from mouse positions
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp; camera.targetpanangle =  (stage.stageWidth - stage.mouseX) / stage.stageWidth * 90;
&nbsp; &nbsp; &nbsp; &nbsp; camera.targettiltangle = (stage.stageHeight - stage.mouseY) / stage.stageHeight * 70
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Note that if the user has clicked on a cube face then the <em>doRotation</em> boolean is false allowing the user to interact more easily with the different movie or video stream material.</p>
<p>And that&#8217;s all there is to it! As you&#8217;ll see, mouse events are mapped effectively to the embedded Flash animations, even in 3D, and the streaming of video is very clean and very simple to implement. Hopefully this has provided a useful introduction to these types of materials, don&#8217;t hesitate to look into the code itself to understand them more. As always comments, questions and suggestions are very welcome too!</p>
<p>As promised, just for completeness, you&#8217;ll find the source for the drawing tool movie and the automated Pong game below - going into the detail of these is out of the scope of this article !</p>
<p>DrawTool.as :</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import flash.display.Sprite;
&nbsp; import flash.events.MouseEvent;
&nbsp; import flash.text.TextField;
&nbsp; import flash.text.TextFieldAutoSize;
&nbsp; import flash.text.TextFormat;
&nbsp; 

&nbsp; public class DrawTool extends Sprite {

&nbsp; &nbsp; private var isDrawing:Boolean = false;
&nbsp; &nbsp; private var sprite:Sprite;

&nbsp; &nbsp; public function DrawTool() {

&nbsp; &nbsp; &nbsp; // create a drawing surface
&nbsp; &nbsp; &nbsp; sprite = new Sprite();
&nbsp; &nbsp; &nbsp; sprite.graphics.beginFill(0xEEEEEE);
&nbsp; &nbsp; &nbsp; sprite.graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; sprite.graphics.lineTo(320, 0);
&nbsp; &nbsp; &nbsp; sprite.graphics.lineTo(320, 240);
&nbsp; &nbsp; &nbsp; sprite.graphics.lineTo(0, 240);
&nbsp; &nbsp; &nbsp; sprite.graphics.endFill();
&nbsp; &nbsp; &nbsp; addChild(sprite);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create text and format
&nbsp; &nbsp; &nbsp; var textFormat:TextFormat = new TextFormat();
&nbsp; &nbsp; &nbsp; textFormat.size = 30;
&nbsp; &nbsp; &nbsp; textFormat.font = "Arial";
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var text:TextField = new TextField();
&nbsp; &nbsp; &nbsp; text.x = 50;
&nbsp; &nbsp; &nbsp; text.y = 100;
&nbsp; &nbsp; &nbsp; text.textColor = 0x222222;
&nbsp; &nbsp; &nbsp; text.text = "click to draw!";
&nbsp; &nbsp; &nbsp; text.setTextFormat(textFormat);
&nbsp; &nbsp; &nbsp; text.autoSize = TextFieldAutoSize.LEFT;
&nbsp; &nbsp; &nbsp; text.selectable = false;
&nbsp; &nbsp; &nbsp; addChild(text);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // listen to mouse events
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse down event. Starts drawing circles.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; isDrawing = true;
&nbsp; &nbsp; &nbsp; drawCircle(this.mouseX, this.mouseY);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse up event. Stops drawing circles.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; isDrawing = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Event listener for mouse move event. Draws a circle.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseMove(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; if (isDrawing) {
&nbsp; &nbsp; &nbsp; &nbsp; drawCircle(this.mouseX, this.mouseY);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Function to draw a circle.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function drawCircle(x:int, y:int):void {
&nbsp; &nbsp; &nbsp; sprite.graphics.beginFill(Math.random() * 0xFFFFFF, 0.5);
&nbsp; &nbsp; &nbsp; sprite.graphics.drawCircle(x, y, 5);
&nbsp; &nbsp; &nbsp; sprite.graphics.endFill();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>Pong.as :</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import flash.display.Sprite;
&nbsp; import flash.events.Event;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]

&nbsp; /**
&nbsp;  * Simple computerised Pong copy.
&nbsp;  */
&nbsp; public class Pong extends Sprite {

&nbsp; &nbsp; private static const COURT_WIDTH:Number = 320;
&nbsp; &nbsp; private static const COURT_HEIGHT:Number = 240;
&nbsp; &nbsp; private static const BALL_WIDTH:Number = 5;
&nbsp; &nbsp; private static const BAT_WIDTH:Number = 5;
&nbsp; &nbsp; private static const BAT_HEIGHT:Number = 30;
&nbsp; &nbsp; private static const COLOUR:Number = 0xDDDDDD;

&nbsp; &nbsp; private var player1:Sprite;
&nbsp; &nbsp; private var player2:Sprite;
&nbsp; &nbsp; private var ball:Sprite;
&nbsp; &nbsp;
&nbsp; &nbsp; private var ballSpeedX:Number;
&nbsp; &nbsp; private var ballSpeedY:Number;
&nbsp; &nbsp; private var activePlayer:int;
&nbsp; &nbsp; private var playerIsMoving:Boolean = false;
&nbsp; &nbsp; private var playerSpeed:Number;
&nbsp; &nbsp; private var playerDestination:Number;

&nbsp; &nbsp; public function Pong() {

&nbsp; &nbsp; &nbsp; createCourt();
&nbsp; &nbsp; &nbsp; addPlayer1();
&nbsp; &nbsp; &nbsp; addPlayer2();
&nbsp; &nbsp; &nbsp; addBall();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, onFrameEnter);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Creates the court with net
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function createCourt():void {
&nbsp; &nbsp; &nbsp; var background:Sprite = new Sprite();
&nbsp; &nbsp; &nbsp; background.graphics.beginFill(0x000000);
&nbsp; &nbsp; &nbsp; background.graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(COURT_WIDTH, 0);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(COURT_WIDTH, COURT_HEIGHT);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(0, COURT_HEIGHT);
&nbsp; &nbsp; &nbsp; background.graphics.endFill();
&nbsp; &nbsp; &nbsp; addChild(background);

&nbsp; &nbsp; &nbsp; var net:Sprite = new Sprite();

&nbsp; &nbsp; &nbsp; var nPoints:Number = 32;
&nbsp; &nbsp; &nbsp; var pointHeight:Number = (COURT_HEIGHT / nPoints);
&nbsp; &nbsp; &nbsp; var drawHeight:Number = pointHeight * 0.6;
&nbsp; &nbsp; &nbsp; var drawWidth:Number = drawHeight / 2;

&nbsp; &nbsp; &nbsp; // Create dashed net
&nbsp; &nbsp; &nbsp; for (var i:Number = 0; i &lt; nPoints; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; var x:Number = COURT_WIDTH / 2 - drawWidth / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var y:Number = i*pointHeight;
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.beginFill(COLOUR);
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.moveTo(x, y);
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.lineTo(x+drawWidth, y);
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.lineTo(x+drawWidth, y+drawHeight);
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.lineTo(x, y+drawHeight);
&nbsp; &nbsp; &nbsp; &nbsp; net.graphics.endFill();
&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; addChild(net);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Add left-hand player
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function addPlayer1():void {
&nbsp; &nbsp; &nbsp; player1 = new Sprite();
&nbsp; &nbsp; &nbsp; createBat(player1);
&nbsp; &nbsp; &nbsp; player1.x = 20;
&nbsp; &nbsp; &nbsp; player1.y = (COURT_HEIGHT / 2) - (BAT_HEIGHT / 2);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; addChild(player1);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Add right-hand player
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function addPlayer2():void {
&nbsp; &nbsp; &nbsp; player2 = new Sprite();
&nbsp; &nbsp; &nbsp; createBat(player2);
&nbsp; &nbsp; &nbsp; player2.x = COURT_WIDTH - 20 - BAT_WIDTH;
&nbsp; &nbsp; &nbsp; player2.y = (COURT_HEIGHT / 2) - (BAT_HEIGHT / 2);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; addChild(player2);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Create a bat
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function createBat(player:Sprite):void {
&nbsp; &nbsp; &nbsp; player.graphics.beginFill(COLOUR);
&nbsp; &nbsp; &nbsp; player.graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; player.graphics.lineTo(BAT_WIDTH, 0);
&nbsp; &nbsp; &nbsp; player.graphics.lineTo(BAT_WIDTH, BAT_HEIGHT);
&nbsp; &nbsp; &nbsp; player.graphics.lineTo(0, BAT_HEIGHT);
&nbsp; &nbsp; &nbsp; player.graphics.endFill();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Add ball to scene and initialise speeds
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function addBall():void {
&nbsp; &nbsp; &nbsp; ball = new Sprite();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; ball.graphics.beginFill(COLOUR);
&nbsp; &nbsp; &nbsp; ball.graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; ball.graphics.lineTo(BALL_WIDTH, 0);
&nbsp; &nbsp; &nbsp; ball.graphics.lineTo(BALL_WIDTH, BALL_WIDTH);
&nbsp; &nbsp; &nbsp; ball.graphics.lineTo(0, BALL_WIDTH);
&nbsp; &nbsp; &nbsp; ball.graphics.endFill();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; ball.x = 0;
&nbsp; &nbsp; &nbsp; ball.y = 20;

&nbsp; &nbsp; &nbsp; addChild(ball);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; ballSpeedX = 6;
&nbsp; &nbsp; &nbsp; ballSpeedY = 5;
&nbsp; &nbsp; &nbsp; activePlayer = 1;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Called at every frame
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onFrameEnter(event:Event):void {
&nbsp; &nbsp; &nbsp; // update ball position
&nbsp; &nbsp; &nbsp; updateBall();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // update player position
&nbsp; &nbsp; &nbsp; updateActivePlayer();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // detect hits
&nbsp; &nbsp; &nbsp; hitTest();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Updates the ball position taking into account court dimensions
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function updateBall():void {
&nbsp; &nbsp; &nbsp; ball.x = ball.x + ballSpeedX;
&nbsp; &nbsp; &nbsp; ball.y = ball.y + ballSpeedY;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Detect if ball escapes a player
&nbsp; &nbsp; &nbsp; if (ball.x &gt; COURT_WIDTH - BALL_WIDTH) {
&nbsp; &nbsp; &nbsp; &nbsp; ball.x = 0;
&nbsp; &nbsp; &nbsp; &nbsp; ball.y = COURT_HEIGHT / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; ballSpeedY = Math.random() * 10;
&nbsp; &nbsp; &nbsp; } else if (ball.x &lt; 0) {
&nbsp; &nbsp; &nbsp; &nbsp; ball.x = COURT_WIDTH - BALL_WIDTH;
&nbsp; &nbsp; &nbsp; &nbsp; ball.y = COURT_HEIGHT / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; ballSpeedY = -Math.random() * 10;
&nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; // Detect wall hits: invert ball y-direction and initiate player position calculation
&nbsp; &nbsp; &nbsp; if (ball.y &lt; 0) {
&nbsp; &nbsp; &nbsp; &nbsp; ball.y = 0;
&nbsp; &nbsp; &nbsp; &nbsp; ballSpeedY = -ballSpeedY;
&nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = false;
&nbsp; &nbsp; &nbsp; } else if (ball.y &gt; COURT_HEIGHT - BALL_WIDTH) {
&nbsp; &nbsp; &nbsp; &nbsp; ball.y = COURT_HEIGHT - BALL_WIDTH;
&nbsp; &nbsp; &nbsp; &nbsp; ballSpeedY = -ballSpeedY;
&nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = false;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Updates player position or calculates new position
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function updateActivePlayer():void {

&nbsp; &nbsp; &nbsp; var player:Sprite;
&nbsp; &nbsp; &nbsp; var calculatedTime:Number;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // calculate time for ball to reach player
&nbsp; &nbsp; &nbsp; if (activePlayer == 0) {
&nbsp; &nbsp; &nbsp; &nbsp; player = player1;
&nbsp; &nbsp; &nbsp; &nbsp; calculatedTime = Math.abs(player.x + BAT_WIDTH - ball.x) / Math.abs(ballSpeedX);
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; player = player2;
&nbsp; &nbsp; &nbsp; &nbsp; calculatedTime = Math.abs(player.x - (ball.x + BALL_WIDTH)) / Math.abs(ballSpeedX);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (playerIsMoving) {
&nbsp; &nbsp; &nbsp; &nbsp; // update player position
&nbsp; &nbsp; &nbsp; &nbsp; player.y = player.y + playerSpeed;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // ensure that player does not leave the court
&nbsp; &nbsp; &nbsp; &nbsp; if (player.y &gt; COURT_HEIGHT - BAT_HEIGHT) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; player.y = COURT_HEIGHT - BAT_HEIGHT;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = false;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (player.y &lt; 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; player.y = 0;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = false;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // determine if player is more or less in position
&nbsp; &nbsp; &nbsp; &nbsp; if (Math.abs(player.y - playerDestination) &lt; BAT_HEIGHT / 4) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = false;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; // calculate expected ball position
&nbsp; &nbsp; &nbsp; &nbsp; var calculatedY:Number = ball.y + ballSpeedY * calculatedTime;
&nbsp; &nbsp; &nbsp; &nbsp; var random:Boolean = false;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; if (calculatedY &lt; 0 || calculatedY &gt; COURT_HEIGHT) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; calculatedY = Math.random() * COURT_HEIGHT;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; random = true;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // calculate desired player position with a random element
&nbsp; &nbsp; &nbsp; &nbsp; playerDestination = calculatedY - (BAT_HEIGHT / 2) + (0.4 * (Math.random() - 0.5) * BAT_HEIGHT);
&nbsp; &nbsp; &nbsp; &nbsp; if (playerDestination &lt; 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerDestination = 0;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (playerDestination &gt; COURT_HEIGHT - BAT_HEIGHT) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerDestination = COURT_HEIGHT - BAT_HEIGHT;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // Calculate a random speed for player
&nbsp; &nbsp; &nbsp; &nbsp; if (player.y &lt; playerDestination) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerSpeed = 5 + Math.random() * 10;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerSpeed = -5 + Math.random() * -10;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // increase speed if player can't work out ball position
&nbsp; &nbsp; &nbsp; &nbsp; if (random) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerSpeed = playerSpeed * 2;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // only move player if really necessary (+ stupidity estimate)
&nbsp; &nbsp; &nbsp; &nbsp; if (Math.abs(playerDestination - player.y) &gt; BAT_HEIGHT / 2) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playerIsMoving = true;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Determine if ball hits a bat
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function hitTest():void {
&nbsp; &nbsp; &nbsp; var player:Sprite;
&nbsp; &nbsp; &nbsp; var check:Boolean = false;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // check to see if ball is at same x position as bat
&nbsp; &nbsp; &nbsp; if (activePlayer == 0) {
&nbsp; &nbsp; &nbsp; &nbsp; player = player1;
&nbsp; &nbsp; &nbsp; &nbsp; if (ball.x &gt; player1.x &#038;&#038; ball.x &lt; player1.x + BAT_WIDTH) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; check = true;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; player = player2;
&nbsp; &nbsp; &nbsp; &nbsp; if (ball.x + BALL_WIDTH &gt; player2.x &#038;&#038; ball.x + BALL_WIDTH &lt; player2.x + BAT_WIDTH) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; check = true;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; if (check) {
&nbsp; &nbsp; &nbsp; &nbsp; // verify y position
&nbsp; &nbsp; &nbsp; &nbsp; if ((ball.y + BALL_WIDTH &lt;= player.y + BAT_HEIGHT) &#038;&#038; (ball.y &gt;= player.y)) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // hit, change player
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; activePlayer = 1 - activePlayer;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // reverse ball direction
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ballSpeedX = -ballSpeedX;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // calculate new ball speed in y&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var batPosition:Number = (ball.y + (BALL_WIDTH / 2)) - (player.y + (BAT_HEIGHT / 2));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ballSpeedY =  batPosition / BAT_HEIGHT * 10 * (1 + Math.random() * 0.1);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/KrVYQkdfK4k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-7-movie-and-video-materials/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-7-movie-and-video-materials/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Art Brut</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/_OIQQwy3YCE/</link>
		<comments>http://blog.tartiflop.com/2008/12/musical-interlude-art-brut/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 19:08:26 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=287</guid>
		<description><![CDATA[Discover Art Brut!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1453317&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1453317&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/art-brut.html'>Art Brut</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/_OIQQwy3YCE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/musical-interlude-art-brut/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/musical-interlude-art-brut/</feedburner:origLink></item>
		<item>
		<title>An Alchemy speed test</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/8C9iGj6X7Vs/</link>
		<comments>http://blog.tartiflop.com/2008/12/an-alchemy-speed-test/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 18:59:14 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Alchemy]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=277</guid>
		<description><![CDATA[Following from my previous articles on setting up an Alchemy development environment in Flex Builder 3 and passing/returning objects to/from C++, I wanted to test some of the claims of the speed increase possible with the use of this tool.
With the particular interest in 3D Flash applications, I wanted to test specific mathematical operations using [...]]]></description>
			<content:encoded><![CDATA[<p>Following from my previous articles on <a href="http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/">setting up an Alchemy development environment in Flex Builder 3</a> and <a href="http://blog.tartiflop.com/2008/12/passingreturning-objects-tofrom-c-using-alchemy/">passing/returning objects to/from C++</a>, I wanted to test some of the claims of the speed increase possible with the use of this tool.</p>
<p>With the particular interest in 3D Flash applications, I wanted to test specific mathematical operations using vectors and matrices, namely cross products, normalisation, rotation matrix calculations and vector transformations.</p>
<p>I had initially aimed to create a mathematical library where these functions can be calculated on native ActionScript objects - for example create a function to calculate the cross product of two vectors. However one aspect of Alchemy that became immediately evident is that the cost of marshaling data through the AS3-C++ API is horrendously expensive. This is quite normal so I guess I was naive to expect good results from this. But to give you an example of how expensive this is, for a simple iterative calculation of the cross product of two vectors followed by a normalisation: if the mathematical functions are performed in C++, <em>ie</em> iteratively calling the Alchemy compiled functions, the result is about 1000 times slower than natively performing the calculations in AS3!</p>
<p>So, my first advice is: limit the number of Alchemy calls!!</p>
<p>Anyway, in this article I&#8217;ll concentrate on performing <em>pure</em> C++ speed tests (called from AS3)  - so computationally intensive calculations performed in a single Alchemy call - compared to the equivalent <em>pure</em> AS3 speed tests.</p>
<p>The tests performed here concentrate on vector and matrix operations. I&#8217;ve therefore created very simple Vector and Matrix classes in C++. The Vector class is used to perform dot product, normalisation and cross product operations as shown below.</p>
<p>Vector3D.h :</p>
<div id="codeSnippet">
<pre>
<blockquote>

#ifndef VECTOR3D_H_
#define VECTOR3D_H_

#include "AS3.h"

class Vector3D {

public :
&nbsp; Vector3D();
&nbsp; Vector3D(double x, double y, double z);
&nbsp; Vector3D(const AS3_Val&#038; as3Vector);
&nbsp; virtual ~Vector3D();

&nbsp; double dot(const Vector3D&#038; v) const;
&nbsp; Vector3D cross(const Vector3D&#038; v) const;
&nbsp; double modulus() const;
&nbsp; Vector3D normalise() const;

&nbsp; void setX(double x);
&nbsp; void setY(double y);
&nbsp; void setZ(double z);
&nbsp;
&nbsp; double getX() const;
&nbsp; double getY() const;
&nbsp; double getZ() const;

private :
&nbsp; double _x;
&nbsp; double _y;
&nbsp; double _z;

};

#endif /*VECTOR3D_H_*/
</blockquote>
</pre>
</div>
<p>Vector3D.cpp :</p>
<div id="codeSnippet">
<pre>
<blockquote>

#include "Vector3D.h"
#include &lt;cmath&gt;

Vector3D::Vector3D() :
&nbsp; _x(0),
&nbsp; _y(0),
&nbsp; _z(0) {
}

Vector3D::Vector3D(const AS3_Val&#038; as3Vector) {
&nbsp; AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &#038;_x, &#038;_y, &#038;_z);
}

Vector3D::Vector3D(double x, double y, double z) :
&nbsp; _x(x),
&nbsp; _y(y),
&nbsp; _z(z) {
}

Vector3D::~Vector3D() {
}

double Vector3D::dot(const Vector3D&#038; v) const {
&nbsp; return v._x*_x + v._y*_y + v._z*_z;
}

Vector3D Vector3D::cross(const Vector3D&#038; v) const {

&nbsp; Vector3D result;
&nbsp; result._x = _y*v._z - _z*v._y;
&nbsp; result._y = _z*v._x - _x*v._z;
&nbsp; result._z = _x*v._y - _y*v._x;
&nbsp;
&nbsp; return result;
}

double Vector3D::modulus() const {
&nbsp; return std::sqrt(_x*_x + _y*_y + _z*_z);
}

Vector3D Vector3D::normalise() const {
&nbsp; double mod = modulus();
&nbsp; return Vector3D(_x/mod, _y/mod, _z/mod);
}

void Vector3D::setX(double x) {
&nbsp; _x = x;
}

void Vector3D::setY(double y) {
&nbsp; _y = y;
}

void Vector3D::setZ(double z) {
&nbsp; _z = z;
}

double Vector3D::getX() const {
&nbsp; return _x;
}

double Vector3D::getY() const {
&nbsp; return _y;
}

double Vector3D::getZ() const {
&nbsp; return _z;
}
</blockquote>
</pre>
</div>
<p>One point, specific to Alchemy, is in one of the constructors for the Vector3D: the properties are extracted from the passed AS3 Vector3D object, as discussed in my previous article.</p>
<p>The Matrix3D C++ class is as follows.</p>
<p>Matrix3D.h :</p>
<div id="codeSnippet">
<pre>
<blockquote>

#ifndef MATRIX3D_H_
#define MATRIX3D_H_

#include "Vector3D.h"

class Matrix3D {

public :
&nbsp; Matrix3D();
&nbsp; virtual ~Matrix3D();

&nbsp; void setRotationX(double degrees);
&nbsp; void setRotationY(double degrees);
&nbsp; void setRotationZ(double degrees);

&nbsp; void setIdentity();

&nbsp; Vector3D transformVector(const Vector3D&#038; vector) const;

private :
&nbsp; double _M00;
&nbsp; double _M01;
&nbsp; double _M02;
&nbsp; double _M10;
&nbsp; double _M11;
&nbsp; double _M12;
&nbsp; double _M20;
&nbsp; double _M21;
&nbsp; double _M22;

};

#endif /*MATRIX3D_H_*/
</blockquote>
</pre>
</div>
<p>Matrix3D.cpp :</p>
<div id="codeSnippet">
<pre>
<blockquote>

#include "Matrix3D.h"
#include &lt;cmath&gt;

Matrix3D::Matrix3D() :
&nbsp; _M00(1),
&nbsp; _M01(0),
&nbsp; _M02(0),
&nbsp; _M10(0),
&nbsp; _M11(1),
&nbsp; _M12(0),
&nbsp; _M20(0),
&nbsp; _M21(0),
&nbsp; _M22(1) {
}

Matrix3D::~Matrix3D() {
}

void Matrix3D::setIdentity() {
&nbsp; _M00 = 1;
&nbsp; _M01 = 0;
&nbsp; _M02 = 0;
&nbsp; _M10 = 0;
&nbsp; _M11 = 1;
&nbsp; _M12 = 0;
&nbsp; _M20 = 0;
&nbsp; _M21 = 0;
&nbsp; _M22 = 1;
}

void Matrix3D::setRotationX(double degrees) {
&nbsp; setIdentity();
&nbsp; double radians = degrees / 180 * M_PI;
&nbsp;
&nbsp; _M11 = cos(radians);
&nbsp; _M12 = -sin(radians);
&nbsp; _M21 = sin(radians);
&nbsp; _M22 = cos(radians);
}

void Matrix3D::setRotationY(double degrees) {
&nbsp; setIdentity();
&nbsp; double radians = degrees / 180 * M_PI;
&nbsp;
&nbsp; _M00 = cos(radians);
&nbsp; _M02 = sin(radians);
&nbsp; _M20 = -sin(radians);
&nbsp; _M22 = cos(radians);
}

void Matrix3D::setRotationZ(double degrees) {
&nbsp; setIdentity();
&nbsp; double radians = degrees / 180 * M_PI;
&nbsp;
&nbsp; _M00 = cos(radians);
&nbsp; _M01 = -sin(radians);
&nbsp; _M10 = sin(radians);
&nbsp; _M11 = cos(radians);
}

Vector3D Matrix3D::transformVector(const Vector3D&#038; vector) const {
&nbsp; Vector3D result;
&nbsp;
&nbsp; result.setX(_M00*vector.getX() + _M01*vector.getY() + _M02*vector.getZ());
&nbsp; result.setY(_M10*vector.getX() + _M11*vector.getY() + _M12*vector.getZ());
&nbsp; result.setZ(_M20*vector.getX() + _M21*vector.getY() + _M22*vector.getZ());
&nbsp;
&nbsp; return result;
}
</blockquote>
</pre>
</div>
<p>One of the objectives of using the Matrix3D class is to test the performance of the trigonometric functions. A common source of intensive calculations in 3D graphics is the rotation of vectors so this provides a useful test directly aimed at this field.</p>
<p>Two tests are to be examined: one for cross product calculations and another for matrix transformations. These are defined in the <em>main.cpp</em> file.</p>
<div id="codeSnippet">
<pre>
<blockquote>

#include "AS3.h"
#include "Vector3D.h"
#include "Matrix3D.h"

AS3_Val speedTest1(void* self, AS3_Val args) {

&nbsp; // Declare AS3 variables
&nbsp; AS3_Val as3Vector1;
&nbsp; AS3_Val as3Vector2;
&nbsp;
&nbsp; // Extract variables from arguments array
&nbsp; AS3_ArrayValue(args, "AS3ValType, AS3ValType", &#038;as3Vector1, &#038;as3Vector2);
&nbsp;
&nbsp; // Create native C++ objects with AS3 parameters
&nbsp; Vector3D vector1(as3Vector1);
&nbsp; Vector3D vector2(as3Vector2);
&nbsp;
&nbsp; Vector3D vector3;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; // Speed test : calculate cross products and normalise
&nbsp; for (int i = 0; i &lt; 1000000; i++) {
&nbsp; &nbsp; vector3 = vector1.cross(vector2);
&nbsp; &nbsp; vector3 = vector3.normalise();
&nbsp; &nbsp; vector1 = vector2;
&nbsp; &nbsp; vector2 = vector3;
&nbsp; }

&nbsp; // Obtain a class descriptor for the AS3 Vector3D class
&nbsp; AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));
&nbsp; AS3_Val params = AS3_Array("");
&nbsp;
&nbsp; // Construct a new AS3 Vector3D object with empty parameters
&nbsp; AS3_Val result = AS3_New(vector3DClass, params);
&nbsp;
&nbsp; // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate
&nbsp; AS3_Set(result, AS3_String("x"), AS3_Number(vector3.getX()));
&nbsp; AS3_Set(result, AS3_String("y"), AS3_Number(vector3.getY()));
&nbsp; AS3_Set(result, AS3_String("z"), AS3_Number(vector3.getZ()));

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(params);
&nbsp; AS3_Release(vector3DClass);
&nbsp;
&nbsp; // return the AS3 Vector
&nbsp; return result;
}

AS3_Val speedTest2(void* self, AS3_Val args) {

&nbsp; // Declare AS3 variable
&nbsp; AS3_Val as3Vector;
&nbsp;
&nbsp; // Extract variables from arguments array
&nbsp; AS3_ArrayValue(args, "AS3ValType", &#038;as3Vector);

&nbsp; // Create native C++ object with AS3 parameters
&nbsp; Vector3D vector(as3Vector);
&nbsp;
&nbsp; Vector3D copy = vector;
&nbsp;
&nbsp; Matrix3D rotationX;
&nbsp; Matrix3D rotationY;
&nbsp; Matrix3D rotationZ;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; // Speed test : calculate rotation matrices and transform vector
&nbsp; for (int i = 0; i &lt; 1000; i++) {
&nbsp; &nbsp; vector = copy;
&nbsp; &nbsp; for (double ang = 0; ang &lt; 180; ang++) {
&nbsp; &nbsp; &nbsp; rotationX.setRotationX(ang);
&nbsp; &nbsp; &nbsp; rotationY.setRotationY(ang);
&nbsp; &nbsp; &nbsp; rotationZ.setRotationZ(ang);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; vector = rotationX.transformVector(vector);
&nbsp; &nbsp; &nbsp; vector = rotationY.transformVector(vector);
&nbsp; &nbsp; &nbsp; vector = rotationZ.transformVector(vector);
&nbsp; &nbsp; }
&nbsp; }

&nbsp; // Obtain a class descriptor for the AS3 Vector3D class
&nbsp; AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));
&nbsp; AS3_Val params = AS3_Array("");
&nbsp;
&nbsp; // Construct a new AS3 Vector3D object with empty parameters
&nbsp; AS3_Val result = AS3_New(vector3DClass, params);
&nbsp;
&nbsp; // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate
&nbsp; AS3_Set(result, AS3_String("x"), AS3_Number(vector.getX()));
&nbsp; AS3_Set(result, AS3_String("y"), AS3_Number(vector.getY()));
&nbsp; AS3_Set(result, AS3_String("z"), AS3_Number(vector.getZ()));

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(params);
&nbsp; AS3_Release(vector3DClass);
&nbsp;
&nbsp; // return the AS3 Vector
&nbsp; return result;
}

/**
 * Main entry point for Alchemy compiler. Declares all functions available
 * through the Alchemy bridge.
 */
int main() {
&nbsp; // Declare all methods exposed to AS3 typed as Function instances
&nbsp; AS3_Val speedTest1Method = AS3_Function(NULL, speedTest1);
&nbsp; AS3_Val speedTest2Method = AS3_Function(NULL, speedTest2);

&nbsp; // Construct an object that contains references to all the functions
&nbsp; AS3_Val result = AS3_Object("speedTest1:AS3ValType, speedTest2:AS3ValType", speedTest1Method, speedTest2Method);

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(speedTest1Method);
&nbsp; AS3_Release(speedTest2Method);

&nbsp; // Notify the bridge of what has been created -- THIS DOES NOT RETURN!
&nbsp; AS3_LibInit(result);

&nbsp; // Should never get here!
&nbsp; return 0;
}
</blockquote>
</pre>
</div>
<p>For an explanation of the code and the C++ API of Alchemy, I&#8217;ll refer you to my previous article on <a href="http://blog.tartiflop.com/2008/12/passingreturning-objects-tofrom-c-using-alchemy/">passing and returning objects to and from C++ using Alchemy</a>.</p>
<p>The first test, <em>speedTest1</em>, performs 1,000,000 times the cross product of two vectors (initially passed by AS3) followed by a normalisation. The resulting vector is used in the following iteration. At the end of all the iterations, the final vector is returned to AS3.</p>
<p>The second test, <em>speedTest2</em>, calculates rotation vectors around the x, y and z axes. A vector (initially passed by AS3), is then rotated by each matrix individually. This is repeated for 180 steps, increasing the angle of rotation by 1 degree at a time. This again is repeated for a total of 1,000 iterations. The final vector is returned to AS3.</p>
<p>Let&#8217;s have a look now at the ActionScript class that calls these tests, and the equivalent pure AS3 tests.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {

&nbsp; import cmodule.vector.CLibInit;
&nbsp;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.geom.Matrix3D;
&nbsp; import flash.geom.Vector3D;
&nbsp; import flash.text.TextField;
&nbsp; import flash.text.TextFieldAutoSize;
&nbsp; import flash.utils.getTimer;

&nbsp; public class AlchemySpeedTest extends Sprite {

&nbsp; &nbsp; private var vectorUtils:Object;

&nbsp; &nbsp; public function AlchemySpeedTest() {

&nbsp; &nbsp; &nbsp; // Set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Create the Alchemy bridge to C++ methods
&nbsp; &nbsp; &nbsp; var loader:CLibInit = new CLibInit;
&nbsp; &nbsp; &nbsp; vectorUtils = loader.init();

&nbsp; &nbsp; &nbsp; // Create a text field&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var timerText:TextField = new TextField();
&nbsp; &nbsp; &nbsp; timerText.autoSize = TextFieldAutoSize.LEFT;
&nbsp; &nbsp; &nbsp; addChild(timerText);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise a timer
&nbsp; &nbsp; &nbsp; var time0:int = getTimer()

&nbsp; &nbsp; &nbsp; // Perform the speed test
&nbsp; &nbsp; &nbsp; var vector:Vector3D = speedTest1();
&nbsp; &nbsp; &nbsp; //var vector:Vector3D = speedTest2();
&nbsp; &nbsp; &nbsp; //var vector:Vector3D = nativeSpeedTest1();
&nbsp; &nbsp; &nbsp; //var vector:Vector3D = nativeSpeedTest2();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Calculate the elapsed time
&nbsp; &nbsp; &nbsp; var time1:int = getTimer()
&nbsp; &nbsp; &nbsp; var totalTime:int = time1 - time0;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Display elapsed time and final vector
&nbsp; &nbsp; &nbsp; timerText.text = "Time taken = " + totalTime + " vector = (" + vector.x + ", " + vector.y + ", " + vector.z + ")";
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Speed test using C++ to iteratively calculate the cross products of two vectors
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function speedTest1():Vector3D {
&nbsp; &nbsp; &nbsp; var vector1:Vector3D = new Vector3D(0.123, 0.456, 0.789);
&nbsp; &nbsp; &nbsp; var vector2:Vector3D = new Vector3D(0.987, 0.654, 0.321);

&nbsp; &nbsp; &nbsp; return vectorUtils.speedTest1(vector1, vector2);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Speed test using C++ to iteratively calculate rotation matrices and apply these to a vector
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function speedTest2():Vector3D {
&nbsp; &nbsp; &nbsp; var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; return vectorUtils.speedTest2(vector);&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Speed test using AS3 to iteratively calculate the cross products of two vectors
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function nativeSpeedTest1():Vector3D {
&nbsp; &nbsp; &nbsp; var vector1:Vector3D = new Vector3D(0.123, 0.456, 0.789);
&nbsp; &nbsp; &nbsp; var vector2:Vector3D = new Vector3D(0.987, 0.654, 0.321);
&nbsp; &nbsp; &nbsp; var vector3:Vector3D;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var time0:int = getTimer()
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; for (var i:int = 0; i &lt; 1000000; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; vector3 = vector1.crossProduct(vector2);
&nbsp; &nbsp; &nbsp; &nbsp; vector3.normalize();
&nbsp; &nbsp; &nbsp; &nbsp; vector1 = vector2;
&nbsp; &nbsp; &nbsp; &nbsp; vector2 = vector3;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; return vector3;
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Speed test using AS3 to iteratively calculate rotation matrices and apply these to a vector
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function nativeSpeedTest2():Vector3D {
&nbsp; &nbsp; &nbsp; var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);

&nbsp; &nbsp; &nbsp; var copy:Vector3D = vector.clone();

&nbsp; &nbsp; &nbsp; var rotationX:Matrix3D = new Matrix3D();
&nbsp; &nbsp; &nbsp; var rotationY:Matrix3D = new Matrix3D();
&nbsp; &nbsp; &nbsp; var rotationZ:Matrix3D = new Matrix3D();

&nbsp; &nbsp; &nbsp; for (var i:int = 0; i &lt; 1000; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; vector = copy.clone();
&nbsp; &nbsp; &nbsp; &nbsp; for (var ang:Number = 0; ang &lt; 180; ang++) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationX.identity();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationX.appendRotation(ang, Vector3D.X_AXIS);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationY.identity();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationY.appendRotation(ang, Vector3D.Y_AXIS);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationZ.identity();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rotationZ.appendRotation(ang, Vector3D.Z_AXIS);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vector = rotationX.transformVector(vector);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vector = rotationY.transformVector(vector);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vector = rotationZ.transformVector(vector);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; return vector;
&nbsp; &nbsp; }

&nbsp; }
}
</blockquote>
</pre>
</div>
<p>Without going into too many details of the code, you&#8217;ll see that in the constructor we can choose one of four tests: speedTest1 and speedTest2, as discussed above, and nativeSpeedTest1 and nativeSpeedTest2 which perform the same calculations but using pure ActionScript classes. The time taken to perform the calculations is then displayed along with the final vector so that we can be sure that the results are the same in a <em>TextField</em>.</p>
<p>To make reasonable comparisons I&#8217;ve tried to make the object creation in both ActionScript and C++ relatively equal: creating objects takes time so can obfuscate the obtained timing results. If you find any glaring differences between the C++ and ActionScript versions then please let me know and I&#8217;ll modify this post.</p>
<p>If you&#8217;d like to take a look at the whole project (set up using automake and ant as shown in my previous article on <a href="http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/">setting up a development environment for Alchemy in Flex Builder 3</a>) then you can find all the files <a href="http://www.tartiflop.com/alchemy/AlchemySpeedTest/srcview/">here</a>.</p>
<p><strong>Results</strong><br />
The native and Alchemy speed tests were compared initially to ensure that they both produce the same results. One surprising result was that for the matrix rotation test, the resulting vector diverged progressively as the number of iterations increased. This is presumably because of rounding errors being different between C++ (which uses double floating point values) and ActionScript. To limit this, you&#8217;ll notice that the vector is reset before the inner iteration over the 180 angles.</p>
<p>More important are the timing results&#8230; and the winner is&#8230; !</p>
<p>For speedTest1 (vector cross product and normalisation) I obtained the following:<br />
Alchemy :&nbsp;1309ms (averaged from 4 runs: 1346, 1285, 1284, 1322)<br />
Native :&nbsp;1192ms (averaged from 4 runs: 1232, 1147, 1176, 12123)</p>
<p>For speedTest2 (rotation matrix creation and vector transformation) the following times were obtained:<br />
Alchemy :&nbsp;814ms (averaged from 4 runs: 803, 826, 814, 813)<br />
Native :&nbsp;792ms (averaged from 4 runs: 774, 787, 789, 816)</p>
<p><strong>Conclusion</strong><br />
As you can see, even with computationally intensive calculations, native ActionScript beats Alchemy compiled C++. Shame - I was expecting huge improvements! And don&#8217;t forget that calling Alchemy code is <em>very</em> expensive - these tests have minimised this cost.</p>
<p>But is it really surprising? After all, we&#8217;re not executing natively compiled C++ code: we&#8217;re executing C++ bytecode compiled for the ActionScript virtual machine. Plus the native ActionScript functions have already been optimised.</p>
<p>Going to some extent to explain this, this article at <a href="http://www.automatastudios.com/2008/11/21/understanding-adobe-alchemy/">Automata Studios on Understanding Adobe Alchemy</a> (who used Alchemy to port OggVorbis to ActionScript 3) provides very interesting reading. As they say in the article:</p>
<p><em>&#8220;&#8230; Knowing that Alchemy is just spitting out the same AVM2 bytecode that Flash and Flex spit out it is pretty confusing how Alchemy code could be faster than standard ActionScript. In fact, it is not faster across the board - just in specific types of operations and when the length of a task can be used to overcome Alchemy’s intrinsic overhead&#8230;.</em></p>
<p>And also:</p>
<p><em>&#8220;&#8230; Now, what are these operations that Alchemy does so well? Memory access and function calls. Alchemy compiled code utilizes new bytecodes added to FP10 for working with ByteArrays - which as you’ll remember are what make up the “RAM” in Alchemy. &#8230;&#8221;</em></p>
<p>So the result seems somewhat less attractive than that claimed by Adobe (<em>&#8220;&#8230; Ideally suited for computation-intensive use cases (&#8230;) performance can be considerably faster than ActionScript 3.0 &#8230;&#8221;</em>) and much more specific to the type of operations being performed.</p>
<p>The tests shown here are of course very limited in their scope: the idea is to provoke some discussion about where Alchemy can be beneficial rather than just stating that Alchemy will produce pure gold in all situations.</p>
<p>One area which may be of interest is that of <a href="http://en.wikipedia.org/wiki/Green_threads"><em>green threads</em></a> as stated in the above article. However these threads are platform independent and are executed in the virtual machine rather on the native OS. This limitation means that the benefits of multi-core processors cannot be tapped into&#8230; so can they really produce reasonable results when calculations are performed in parallel?</p>
<p>Anyway, I hope this has been of interest and of some use - as always comments, suggestions and questions are welcome!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/8C9iGj6X7Vs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/an-alchemy-speed-test/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/an-alchemy-speed-test/</feedburner:origLink></item>
		<item>
		<title>Passing/Returning objects to/from C++ using Alchemy</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/ynE3q_61fn0/</link>
		<comments>http://blog.tartiflop.com/2008/12/passingreturning-objects-tofrom-c-using-alchemy/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 17:06:26 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Alchemy]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=280</guid>
		<description><![CDATA[Following from my last article on setting up an Alchemy development environment in Flex Builder 3, I wanted to illustrate briefly how objects can be passed to C++ methods using Alchemy (and similarly how the ActionScript properties can be extracted) and how we can return objects to the calling AS3 code.
This article has been prompted [...]]]></description>
			<content:encoded><![CDATA[<p>Following from my last article on <a href="http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/">setting up an Alchemy development environment in Flex Builder 3</a>, I wanted to illustrate briefly how objects can be passed to C++ methods using Alchemy (and similarly how the ActionScript properties can be extracted) and how we can return objects to the calling AS3 code.</p>
<p>This article has been prompted since I found very little useful documentation on the web, so hopefully this&#8217;ll be useful for other beginners! Other than the <a href="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:C_API">C++ API for Alchemy provided by Adobe</a> (which is essential), I&#8217;ve found the following links very useful in providing concrete examples of getting started in Alchemy:</p>
<ul>
<li><a href="http://manfred.dschini.org/2008/11/20/creating-a-button-with-alchemy/">Creating a button with Alchemy</a> by Manfred Webber</li>
<li><a href="http://labs.adobe.com/wiki/index.php/Alchemy:Libraries">The OggVorbis library sources</a> to be compiled with AS3</li>
</ul>
<p>These provided the essential lines of code necessary to understand the API, and be able to pass objects to C/C++ and similarly return objects to ActionScript.</p>
<p>The following is some C code to illustrate this. Essentially a <em>flash.geom.Vector3D</em> object is passed to a function, <em>foo</em>, which then returns a copy of the object to the calling function.</p>
<div id="codeSnippet">
<pre>
<blockquote>

#include "AS3.h"

AS3_Val foo(void* self, AS3_Val args) {

&nbsp; // declare local variables
&nbsp; double x;
&nbsp; double y;
&nbsp; double z;
&nbsp;
&nbsp; // ******* Passing objects as parameters to C++ *******
&nbsp;
&nbsp; // Declare AS3 variable
&nbsp; AS3_Val as3Vector;
&nbsp;
&nbsp; // Extract variables from arguments array (in this case a flash.geom.Vector3D)
&nbsp; AS3_ArrayValue(args, "AS3ValType", &#038;as3Vector);

&nbsp; // Extract properties from object and store in local variables
&nbsp; AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &#038;x, &#038;y, &#038;z);

&nbsp; // ******* Returning objects to AS3 *******

&nbsp; // Obtain a class descriptor for the AS3 Vector3D class
&nbsp; AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));
&nbsp; AS3_Val params = AS3_Array("");
&nbsp;
&nbsp; // Construct a new AS3 Vector3D object with empty parameters
&nbsp; AS3_Val result = AS3_New(vector3DClass, params);
&nbsp;
&nbsp; // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate
&nbsp; AS3_Set(result, AS3_String("x"), AS3_Number(x));
&nbsp; AS3_Set(result, AS3_String("y"), AS3_Number(y));
&nbsp; AS3_Set(result, AS3_String("z"), AS3_Number(z));

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(params);
&nbsp; AS3_Release(vector3DClass);
&nbsp;
&nbsp; // return the AS3 flash.geom.Vector3D object
&nbsp; return result;
}

/**
 * Main entry point for Alchemy compiler. Declares all functions available
 * through the Alchemy bridge.
 */
int main() {
&nbsp; // Declare all methods exposed to AS3 typed as Function instances
&nbsp; AS3_Val fooMethod = AS3_Function(NULL, foo);

&nbsp; // Construct an object that contains references to all the functions
&nbsp; AS3_Val result = AS3_Object("foo:AS3ValType", fooMethod);

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(fooMethod);

&nbsp; // Notify the bridge of what has been created -- THIS DOES NOT RETURN!
&nbsp; AS3_LibInit(result);

&nbsp; // Should never get here!
&nbsp; return 0;
}
</blockquote>
</pre>
</div>
<p>Let&#8217;s take a look at this bit by bit. Starting with the function <em>foo</em>, all functions visible to ActionScript have to be declared in the same way:</p>
<div id="codeSnippet">
<pre>
<blockquote>

AS3_Val foo(void* self, AS3_Val args) {
</blockquote>
</pre>
</div>
<p>The return value is always an <em>AS3_Val</em> type and a function always receives a pointer along with an <em>AS3_Val</em> type argument. <em>AS3_Val</em> can be thought of as the <em>Object</em> type in AS3 - all concrete types inherit from this so utilities are needed to extract useful information from them.</p>
<p>First of all: extracting objects from the <em>args</em> parameter. Whatever, and however many, arguments are passed we always use the method <em>AS3_ArrayValue</em> to extract the real arguments: arguments are always passed in the form of an <em>Array</em>. In the example we do the following:</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // Declare AS3 variable
&nbsp; AS3_Val as3Vector;
&nbsp;
&nbsp; // Extract variables from arguments array (in this case a flash.geom.Vector3D)
&nbsp; AS3_ArrayValue(args, "AS3ValType", &#038;as3Vector);
</blockquote>
</pre>
</div>
<p>Here we declare an <em>AS3_Val</em> variable (implying that we are expecting an AS3 <em>Object</em>). If the types passed are primitive types (or String types) we could do the following:</p>
<div id="codeSnippet">
<pre>
<blockquote>

int arg0 = 0;
char* arg1 = NULL;
double arg2 = 0.0;
AS3_ArrayValue(arr, "IntType, StrType, DoubleType", &#038;arg0, &#038;arg1, &#038;arg2);
</blockquote>
</pre>
</div>
<p>Here the primitive AS3 types are converted to native C++ primitives.</p>
<p>Coming back to our example, we now have an AS3 <em>Object</em> (stored as an <em>AS3_Val</em> type) and we&#8217;d like to extract data from it. This is done by making an <em>AS3_ObjectValue</em> call.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // Extract properties from object and store in local variables
&nbsp; AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &#038;x, &#038;y, &#038;z);
</blockquote>
</pre>
</div>
<p>Here we pass the extracted <em>Object</em>, declare the identifiers and types of properties and a list of local variables to store the value in. For the <em>Vector3D</em> we want to obtain the x, y and z properties which are converted to local <em>DoubleType</em> values.</p>
<p>To return an ActionScript object, we need to perform a <em>lookup</em> for the class name with the relevant namespace. From this we can get a class descriptor which can then be instantiated. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // Obtain a class descriptor for the AS3 Vector3D class
&nbsp; AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));
</blockquote>
</pre>
</div>
<p> Here, for example, we obtain an <em>AS3_Val</em> representing the class <em>flash.geom.Vector3D</em>, using the <em>AS3_NSGet</em> function. We can then create an object from this.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; AS3_Val params = AS3_Array("");
&nbsp;
&nbsp; // Construct a new AS3 Vector3D object with empty parameters
&nbsp; AS3_Val result = AS3_New(vector3DClass, params);
</blockquote>
</pre>
</div>
<p>This object is create with no parameters using the <em>AS3_New</em> function. Again, the result is stored in the base <em>AS3_Val</em> type. Having created a new object we can then modify its properties.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate
&nbsp; AS3_Set(result, AS3_String("x"), AS3_Number(x));
&nbsp; AS3_Set(result, AS3_String("y"), AS3_Number(y));
&nbsp; AS3_Set(result, AS3_String("z"), AS3_Number(z));
</blockquote>
</pre>
</div>
<p>The <em>AS3_Set</em> function takes an AS3 <em>Object</em>, a property identifier and a value, correctly cast to the required AS3 value type, in this case an <em>AS3_Number</em> type. Note that I&#8217;ve tried to pass these values in the <em>params</em> Array but have never been successful - if anyone has any tips on doing this I&#8217;d be happy to hear from you.</p>
<p>So, now we have an AS3 object created and its properties set. Now we need to do a bit of memory management before returning the object. This is done using the <em>AS3_Release</em> function.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(params);
&nbsp; AS3_Release(vector3DClass);
</blockquote>
</pre>
</div>
<p>Finally,  we return the created object:</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; // return the AS3 flash.geom.Vector3D object
&nbsp; return result;
</blockquote>
</pre>
</div>
<p>To export the function <em>foo</em> to ActionScript, the following <em>main</em> function is called - the Alchemy compiler always looks for this function, so its here that we always declare our interface. For the above example the following is necessary:</p>
<div id="codeSnippet">
<pre>
<blockquote>

int main() {
&nbsp; // Declare all methods exposed to AS3 typed as Function instances
&nbsp; AS3_Val fooMethod = AS3_Function(NULL, foo);

&nbsp; // Construct an object that contains references to all the functions
&nbsp; AS3_Val result = AS3_Object("foo:AS3ValType", fooMethod);

&nbsp; // Release what's no longer needed
&nbsp; AS3_Release(fooMethod);

&nbsp; // Notify the bridge of what has been created -- THIS DOES NOT RETURN!
&nbsp; AS3_LibInit(result);

&nbsp; // Should never get here!
&nbsp; return 0;
}
</blockquote>
</pre>
</div>
<p>Without going into too many details, essentially we create <em>Function</em> objects containing the native C/C++ methods. These are then given an AS3 interface using the <em>AS3_Object</em> function and then passed to the <em>AS3_LibInit</em> function which provides the entry point from ActionScript.</p>
<p>The following ActionScript class shows how we call the Alchemy compiled functions, passing a Vector3D object and obtaining another one in return.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {

&nbsp; import cmodule.vector.CLibInit;
&nbsp;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.geom.Vector3D;

&nbsp; public class Test extends Sprite {

&nbsp; &nbsp; public function Test() {

&nbsp; &nbsp; &nbsp; // Create the Alchemy bridge to C++ methods
&nbsp; &nbsp; &nbsp; var loader:CLibInit = new CLibInit;
&nbsp; &nbsp; &nbsp; var alchemyTest:Object = loader.init();

&nbsp; &nbsp; &nbsp; var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);
&nbsp; &nbsp; &nbsp; var returnVector:Vector3D = alchemyTest.foo(vector);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; trace("Return vector = (" + returnVector.x + ", " + returnVector.y + ", " + returnVector.z + ")");
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; }
}
</blockquote>
</pre>
</div>
<p>Our connection to the C/C++ code is performed by creating a new <em>CLibInit</em> function and calling <em>init</em>.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create the Alchemy bridge to C++ methods
&nbsp; &nbsp; &nbsp; var loader:CLibInit = new CLibInit;
&nbsp; &nbsp; &nbsp; var alchemyTest:Object = loader.init();
</blockquote>
</pre>
</div>
<p>This creates a basic ActionScript <em>Object</em>. The functions cannot be seen at the time of compilation (at least not in Flex Builder) but are obtained at run time. The resulting function call on <em>foo</em> is shown as follows:</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);
&nbsp; &nbsp; &nbsp; var returnVector:Vector3D = alchemyTest.foo(vector);
</blockquote>
</pre>
</div>
<p>As required, we pass a Vector3D and get a new Vector3D object in return.</p>
<p>And that&#8217;s it! If you&#8217;d like to have a look at the source and the project set-up together (using the same automake and ant files as discussed in the previous article) then you can find them <a href="http://www.tartiflop.com/alchemy/AlchemyTest/srcview/">here</a>.</p>
<p>This is a very quick introduction to passing and returning objects using Alchemy. The API provides many more possibilities but this articles aims to illustrate some of the basic, but essential, functions available - for other beginners I hope this is useful! In my next article I&#8217;ll look at some of the capabilities of Alchemy.</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/ynE3q_61fn0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/passingreturning-objects-tofrom-c-using-alchemy/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/passingreturning-objects-tofrom-c-using-alchemy/</feedburner:origLink></item>
		<item>
		<title>Setting up an Alchemy development environment in Flex Builder 3</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/g8ScrZvv8I8/</link>
		<comments>http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 17:53:38 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Alchemy]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=271</guid>
		<description><![CDATA[I&#8217;ve recently been reading a lot of articles recently about the new Alchemy research project at Adobe Labs. At first glances this looks very exciting: compile optimised C/C++ code to be executed within an ActionScript 3 Flash movie. As quoting from the Alchemy home page :
&#8220;&#8230; Ideally suited for computation-intensive use cases, such as audio/video [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been reading a lot of articles recently about the new <a href="http://labs.adobe.com/technologies/alchemy/">Alchemy research project at Adobe Labs</a>. At first glances this looks very exciting: compile optimised C/C++ code to be executed within an ActionScript 3 Flash movie. As quoting from the Alchemy home page :</p>
<p><em>&#8220;&#8230; Ideally suited for computation-intensive use cases, such as audio/video transcoding, data manipulation, XML parsing, cryptographic functions or physics simulation, performance can be considerably faster than ActionScript 3.0 and anywhere from 2-10x slower than native C/C++ code.&#8221;</em></p>
<p>Sounds good! Ideal even when thinking about 3D graphics that are heavily dependent on vector and matrix calculations&#8230;</p>
<p>So, I decided to take a look and see how easy it was to integrate C++ code into an ActionScript project and what the benefits were. I discovered fairly quickly that documention on the web is fairly limited which has prompted this blog entry. Also, I&#8217;m a fan of the eclipse development environment and like all my work to be concentrated within the same window so wanted the Alchemy development to be done in parallel to the ActionScript development. </p>
<p>First off, it should be noted that this article is aimed mainly at Mac users: Hopefully there are things along the way that will be useful for Windows but I&#8217;m going to be looking at an <em>automake</em> utility to compile the Alchemy code which may not work on Windows (maybe under Cygwin, but I&#8217;ve not tried it).</p>
<p>Here are a few links to get started anyway:</p>
<ul>
<li><a href ="http://labs.adobe.com/technologies/alchemy/">The main Alchemy home page at Adobe Labs</a></li>
<li><a href ="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Getting_Started">Essential Adobe guide for installing and getting started with Alchemy</a></li>
<li><a href ="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:C_API">The C/C++ API</a></li>
<li><a href ="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:AS3_API">The ActionScript 3 API</a></li>
<li><a href ="http://labs.adobe.com/wiki/index.php/Alchemy:Libraries">A couple of libraries built with Alchemy</a></li>
</ul>
<p>First of all <a href="http://labs.adobe.com/downloads/alchemy.html">download Alchemy Toolkit</a> from Adobe. Personally I copied the extracted directory to the Applications folder in my home directory. Then follow the instruction given on the <a href="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Getting_Started"><em>Getting Started</em></a> page.</p>
<p><strong>NOTE !!</strong> I had huge trouble to start with because I was running a shell with <em>tcsh</em>: you must have <em>bash</em> (which is anyway the default for Mac) running for this to work! </p>
<p>Once I managed to compile the C code using the Alchemy tools, I went straight to Flex Builder 3 to try to integrate the ActionScript and compiled <em>swf</em> together.</p>
<p>In Flex Builder (or the Eclipse plugin as I&#8217;m using), create a new ActionScript project called EchoTest, as is the case for the ActionScript class shown on the Alchemy <em>Getting Started</em> page. Now we need to ensure that the project is compiled for Flash Player 10 (this is easily possible if you have Flex Builder 3.0.2 installed). Go to the project <em>Properties</em> menu item, select <em>ActionScript Compiler</em> and for <em>Require Flash Player version</em> enter 10.0.0 and click <em>OK</em>.</p>
<p>In the newly created <em>EchoTest</em> class, copy the code from the <em>GettingStarted</em> page that is linked to compiled C.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import flash.display.Sprite;
&nbsp; import cmodule.stringecho.CLibInit;
&nbsp;
&nbsp; public class EchoTest extends Sprite {
&nbsp;
&nbsp; &nbsp; public function EchoTest() {
&nbsp;
&nbsp; &nbsp; &nbsp; var loader:CLibInit = new CLibInit;
&nbsp; &nbsp; &nbsp; var lib:Object = loader.init();
&nbsp; &nbsp; &nbsp; trace(lib.echo("foo"));
&nbsp; &nbsp; }
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>This won&#8217;t compile because we need to link to the Alchemy-compiled C code. Create a <em>bin</em> directory at the root of the project and copy <em>stringecho.swf</em>, compiled before, here. Go into the project <em>Properties</em> menu item, select <em>ActionScript Build Path</em>, go to the <em>Library Path</em> tab and select <em>Add SWC&#8230;</em>. Browse to the <em>bin</em> directory and select <em>stringecho.swf</em>. Now when you click on <em>OK</em> you should find that the project compiles.</p>
<p>To see anything happen you need to run in debug mode&#8230; even then its not very exciting: you&#8217;ll just see <em>foo</em> written in the Console.</p>
<p>The main objective (for me at least) is to set up an environment where we can compile the C/C++ code with Alchemy within the Flex environment. For this I&#8217;m going to be combining some <em>automake</em> files with shell scripts and link them to Eclipse with an <em>ant</em> build file.</p>
<p>Lets first of all copy the alchemy source in the project. Create a directory called <em>alchemy</em> at the root of the project. Into this, copy the C file from the Alchemy samples (ALCHEMY_HOME/samples/stringecho/stringecho.c).</p>
<p>For automake we need a <em>configure.in</em> file and (depending on the project) several <em>Makefile.am</em> files.</p>
<p>At the project root, copy the following into <em>configure.in</em> :</p>
<div id="codeSnippet">
<pre>
<blockquote>

dnl Process this file with autoconf to produce a configure script.
AC_INIT(alchemyTest, 0.0.1)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(alchemy/stringecho.c)

AM_INIT_AUTOMAKE

dnl Compiler
AC_PROG_CXX
AC_PROG_CC
AC_LANG(C++)
AC_LANG(C)

CFLAGS=""
AM_CFLAGS="-Wall -O3 -swc "
AC_SUBST(AM_CFLAGS)
CXXFLAGS=""
AM_CXXFLAGS="-Wall -O3 -swc "
AC_SUBST(AM_CXXFLAGS)

dnl Initialise top_srcdir
top_srcdir=.

AC_OUTPUT([
Makefile
alchemy/Makefile
])
</blockquote>
</pre>
</div>
<p>Create a <em>Makefile.am</em> file at the project root as well containing the following line (indicating simply which is the main alchemy source directory):</p>
<div id="codeSnippet">
<pre>
<blockquote>

SUBDIRS = alchemy
</blockquote>
</pre>
</div>
<p>Finally in the <em>alchemy</em> directory, copy the following also into a <em>Makefile.am</em> file :</p>
<div id="codeSnippet">
<pre>
<blockquote>

INCLUDES = -I$(top_srcdir)/alchemy

bin_PROGRAMS = stringecho.swc

stringecho_swc_SOURCES = \
&nbsp; stringecho.c
</blockquote>
</pre>
</div>
<p>That&#8217;s all that&#8217;s needed for the automake part. Now we need a couple of shell scripts to be called from <em>ant</em> and that take into account the environment variables necessary for the Alchemy tools.</p>
<p>At the root, create a file called init and copy the following:</p>
<div id="codeSnippet">
<pre>
<blockquote>

#!/bin/sh

if [ ! -d config ]
then
&nbsp; mkdir config;
fi

if [ ! -x AUTHORS ]
then
&nbsp; touch AUTHORS;
&nbsp; touch README;
&nbsp; touch NEWS;
&nbsp; touch ChangeLog;
fi

aclocal -I config
autoconf
automake --gnu --add-missing

if [ ! -d obj ]
then
&nbsp; mkdir obj;
fi

path=`pwd`

cd obj
../configure --prefix=`pwd`/..

cd $path
</blockquote>
</pre>
</div>
<p>Once it is created, make sure it is executable by changing the file permissions (<em>chmod +x init</em>). This will essentially create any necessary directories and files (for automake) and launch the configuration process. This will then create all the necessary Makefiles.</p>
<p>In the same directory (the root) create a file called build (that should also be executable) and copy this:</p>
<div id="codeSnippet">
<pre>
<blockquote>

#!/bin/bash

ALCHEMY_HOME=$HOME/Applications/Alchemy
source $ALCHEMY_HOME/alchemy-setup

PATH=$ALCHEMY_HOME/achacks:$PATH
export PATH

cd obj
make -e install
</blockquote>
</pre>
</div>
<p>Here we specify the home of Alchemy (so, obviously, change the directories accordingly) and we then launch the compilation, passing the environment variables at the same time (with the <em>-e</em> flag).</p>
<p>Finally, we come to the <em>ant</em> build file. The following should be copied into <em>build.xml</em> at the project root.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&lt;project name="EchoTest" basedir="."&gt;

&nbsp; &lt;property name="builddir" value="."/&gt;

&nbsp; &lt;target name="compile alchemy"&gt;
&nbsp; &nbsp; &lt;exec executable="${builddir}/build"/&gt;
&nbsp; &lt;/target&gt;

&nbsp; &lt;target name="init alchemy"&gt;
&nbsp; &nbsp; &lt;exec executable="${builddir}/init"&gt;
&nbsp; &nbsp; &lt;/exec&gt;
&nbsp; &lt;/target&gt;

&nbsp; &lt;target name="remove obj"&gt;
&nbsp; &nbsp; &lt;exec executable="rm"&gt;
&nbsp; &nbsp; &nbsp; &lt;arg line="-fr"/&gt;
&nbsp; &nbsp; &nbsp; &lt;arg line="obj"/&gt;
&nbsp; &nbsp; &lt;/exec&gt;
&nbsp; &lt;/target&gt;

&nbsp;
&lt;/project&gt;
</blockquote>
</pre>
</div>
<p>This includes a couple of targets to initialise the compilation (create the Makefiles) and compile the C source. A final target just removes the compiles object files.</p>
<p>in the end you should have a project structure that looks something like this:</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/12/alchemy-devel.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/12/alchemy-devel.png" alt="" title="" width="331" height="646" class="aligncenter size-full wp-image-272" /></a></p>
<p>So let&#8217;s test this. Open the <em>Ant</em> view in eclipse by selection the menu <em>Window</em>, <em>Show View</em>, <em>Other&#8230;</em> and then searching for the <em>Ant</em> view. Drag and drop <em>build.xml</em> into this view and you should find the targets <em>compile alchemy</em> and <em>init alchemy</em> available.</p>
<p><strong>NOTE !!!</strong> For this to work you need to lauch eclipse from the command line using the command <em>tcsh -e ./eclipse</em> from the installed eclipse directory. I don&#8217;t know why, but ant behaves differently - I presume because environment variables are passed to it! If you could tell me why, or how to avoid this, I&#8217;d be very happy to hear from you!</p>
<p>So, back again, assuming that eclipse is launched as <em>tcsh -c ./eclipse</em>, double click on the <em>init alchemy</em> target. You should hopefully see the configuration process in the console terminated with <em>BUILD SUCCESS</em>! This means that the Makefiles are ready. You can now double click on <em>build alchemy</em> to compile the C code. If it works you should see output that resembles that shown of the compilation on the <a href="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Getting_Started"><em>Getting Started</em></a> page.</p>
<p>The <em>init</em> process is typically necessary only once. From now on when modifying the C code just launch the <em>build</em> target.</p>
<p>This has now compiled <em>stringecho.swc</em> in the <em>bin</em> directory. Refresh the workspace (fn_key + F5 on a Mac) if it doesn&#8217;t refresh automatically which then recompiles the ActionScript if a change has occurred. In this case, I&#8217;m simply showing a build process so there&#8217;s no difference to the result. However, in future projects, you&#8217;ll find that every time you recompile using the Alchemy tools you&#8217;ll need to refresh the workspace otherwise the ActionScript project isn&#8217;t updated.</p>
<p>Also to note, when editing the C or C++ files, I&#8217;d recommend using the <a href="http://www.eclipse.org/cdt/">CDT plugin for eclipse</a> rather than an external editor - again it avoids switching application for compiling the same project!</p>
<p>Anyway, hope this is of some use to people getting started with Alchemy (like me!). If you find any problems then please let me know&#8230; same if you have any comments. Next I&#8217;ll be looking at testing some of what Alchemy is supposed to be capable of!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/g8ScrZvv8I8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/setting-up-an-alchemy-development-environment-in-flex-builder-3/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 6 - Normal mapping and environment mapping</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/6XGgxZ9E718/</link>
		<comments>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-6-normal-mapping-and-environment-mapping/#comments</comments>
		<pubDate>Sun, 07 Dec 2008 18:32:55 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<category><![CDATA[bump mapping]]></category>

		<category><![CDATA[environment mapping]]></category>

		<category><![CDATA[lighting]]></category>

		<category><![CDATA[normal mapping]]></category>

		<category><![CDATA[texture mapping]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=257</guid>
		<description><![CDATA[r]]></description>
			<content:encoded><![CDATA[<p>Back again after a break longer than predicted! In this tutorial I&#8217;ll show how we can add more stunning visual effects to objects by applying normal maps (to give the impression that an object is composed of many more triangles from the rendered shading) and environment maps (for objects to appear shiny and reflecting the surrounding environment). An equivalent tutorial for Papervision3D can be found at my post on <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7-texture-mapping-with-lighting-bump-mapping-and-environment-mapping/">texture mapping with lighting, bump mapping and environment mapping</a>.</p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - Animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">First steps in Away3D : Part 3 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/">First steps in Away3D : Part 4 - Scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/">First steps in Away3D : Part 5 - Lighting and shading</a><br />
A light source is added to the scene and the materials are changed to illustrate how Away3D renders objects with different shading characteristics.
</li>
</ul>
<p>Normal maps - or Dot3 bump maps - can be seen as something of an evolution from standard bump maps. Bump maps, as used in Papervision3D, contain a single value describing a displacement perpendicular to a surface. Normal maps, however, are more detailed because they contain three axis elements, effectively describing the normal to a specific point on a surface, replacing the triangle normal entirely. Whereas a bump map would be rendered the same for any point of view, a normal map is rendered differently depending on the viewer&#8217;s position: hence giving a much better impression of realism.</p>
<p>Normal maps are mapped in much the same way as a texture map, using the same <em>uv</em> values as for a texture. The bitmap data used in a normal map is split into the three components red, green and blue, each one giving a representation of the normal vector components in <em>x</em>, <em>y</em> and <em>z</em> respectively. So, normal values between -1 and 1 are discretised to an integer value between 0 and 255.</p>
<p>Normal maps greatly increase the performance of rendering a 3D object since the normals are given directly rather than requiring a calculation from triangles. So, a complex model requiring thousands of triangles can be reduced to, say, a few hundred (a low-poly model) with a normal map being derived from the original model. You can check out wikipedia for more information on <a href="http://en.wikipedia.org/wiki/Normal_mapping">normal mapping</a>. For an example of a low-poly model using a normal map generated from a more complex one, check out this <a href="http://away3d.com/away3d-normal-mapped-bust">demo of normal mapping</a> at Away3D.</p>
<p>Environment mapping, or reflection mapping, is a technique used to map a surrounding environment onto an object giving the impression that the object has a mirrored surface. The technique is much more efficient than ray tracing and, even though it is not exact, still produces realistic effects. Again, wikipedia contains some useful <a href="http://en.wikipedia.org/wiki/Environment_mapping">information on environment mapping</a>. </p>
<p>In this tutorial I&#8217;m going to show normal mapping on a cube and a sphere and environment mapping on a sphere. Following from the last post on <a href="http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/">Lighting and Shading</a>, we&#8217;re going to be using another couple of <em>CompositeMaterials</em>: namely the <em>Dot3BitmapMaterial</em> and the <em>EnviroBitmapMaterial</em>.</p>
<p>It should be noted that while normal mapping can produce a more realistic effect than bump mapping, it can be more complex to implement. Since a normal map replaces the normal to a surface we cannot use the same map on an object that has many faces (unless the normal map has been created specifically for example as shown in the Away3D demo above). This is a problem for example for Primitives. A <em>Cube</em> for example has six faces with six discrete <em>principal</em> normals - if we use the same normal map for each surface then each face will have the same normal data and hence be rendered identically, rather than each face being independent. Currently we therefore have to provide six independent normal maps.</p>
<p>My method for this example however is to create a cube using six individual planes using the same normal map and rotating and translating them: the normal map data is then rendered correctly for each face.</p>
<p>I also had a problem retrieving normal maps from the web for use in this tutorial. To help me I created a small utility that takes bump (displacement) map data and converts this into normal map data for either a plane or a sphere. You can try this out yourselves by checking out my article on <a href="http://blog.tartiflop.com/2008/12/displacement-map-to-normal-map-converter/">displacement map to normal map conversion</a>. With this utility you are able to specify the direction of the displacement (for a plane) or the direction against which the angle <em>phi</em> is calculated for a sphere.</p>
<p>So, lets get on with the code! Below you&#8217;ll see the next example in this series, producing three rotating texture-mapped objects each one rendered with either an environment map or normal map.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.HoverCamera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.render.Renderer;
&nbsp; import away3d.core.utils.Cast;
&nbsp; import away3d.lights.DirectionalLight3D;
&nbsp; import away3d.materials.Dot3BitmapMaterial;
&nbsp; import away3d.materials.EnviroBitmapMaterial;
&nbsp; import away3d.primitives.Plane;
&nbsp; import away3d.primitives.Sphere;
&nbsp;
&nbsp; import flash.display.Bitmap;
&nbsp; import flash.display.BitmapData;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example006 extends Sprite {

&nbsp; &nbsp; [Embed(source="/../assets/away3D.png")] private var Away3DImage:Class;
&nbsp; &nbsp; private var away3DBitmap:Bitmap = new Away3DImage();

&nbsp; &nbsp; [Embed(source="/../assets/normalMap.png")] private var NormalImage:Class;
&nbsp; &nbsp; private var normalBitmap:Bitmap = new NormalImage();

&nbsp; &nbsp; [Embed(source="/../assets/asteroidNormal.png")] private var SphereNormalImage:Class;
&nbsp; &nbsp; private var sphereNormalBitmap:Bitmap = new SphereNormalImage();

&nbsp; &nbsp; [Embed(source="/../assets/checker.jpg")] private var CheckerImage:Class;
&nbsp; &nbsp; private var checkerBitmap:Bitmap = new CheckerImage();

&nbsp; &nbsp; [Embed(source="/../assets/envMap.png")] private var EnvironmentImage:Class;
&nbsp; &nbsp; private var envBitmap:Bitmap = new EnvironmentImage();

&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 150;
&nbsp; &nbsp; private static const CAMERA_ORBIT:Number = 600;

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:HoverCamera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp; &nbsp; private var planeGroup:ObjectContainer3D;
&nbsp; &nbsp; private var normalSphere:Sphere;
&nbsp; &nbsp; private var envSphere:Sphere;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var lastPanAngle:Number = 60;
&nbsp; &nbsp; private var lastTiltAngle:Number = -60;

&nbsp; &nbsp;
&nbsp; &nbsp; public function Example006() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Initialise Away3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Initialise all 3D components.
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new HoverCamera3D({zoom:25, focus:30, distance:600});
&nbsp; &nbsp; &nbsp; camera.targetpanangle = camera.panangle = -10;
&nbsp; &nbsp; &nbsp; camera.targettiltangle = camera.tiltangle = 20;
&nbsp; &nbsp; &nbsp; camera.yfactor = 1;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the view to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // ensure that the z-order is calculated correctly
&nbsp; &nbsp; &nbsp; view.renderer = Renderer.CORRECT_Z_ORDER;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Create the objects and lighting of the scene
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create 3 different materials: two normal mapped ones (planar and spherical) and an
&nbsp; &nbsp; &nbsp; // environment mapped one.
&nbsp; &nbsp; &nbsp; var normalMapMaterial:Dot3BitmapMaterial = new Dot3BitmapMaterial(Cast.bitmap(away3DBitmap), Cast.bitmap(normalBitmap), {smooth:true, precision:5});
&nbsp; &nbsp; &nbsp; var envMapMaterial:EnviroBitmapMaterial = new EnviroBitmapMaterial(Cast.bitmap(checkerBitmap), Cast.bitmap(envBitmap), {smooth:true, precision:5});
&nbsp; &nbsp; &nbsp; var sphereNormalMapMaterial:Dot3BitmapMaterial = new Dot3BitmapMaterial(new BitmapData(1, 1, false, 0x666666), Cast.bitmap(sphereNormalBitmap), {smooth:true, precision:5});

&nbsp; &nbsp; &nbsp; // create a new directional white light source with specific ambient, diffuse and specular parameters
&nbsp; &nbsp; &nbsp; var light:DirectionalLight3D = new DirectionalLight3D({color:0xFFFFFF, ambient:0.25, diffuse:0.75, specular:0.9});
&nbsp; &nbsp; &nbsp; light.x = 10000;
&nbsp; &nbsp; &nbsp; light.z = 50000;
&nbsp; &nbsp; &nbsp; light.y = 50000;
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // Create six with the same (normal mapped) material and position them them to create a cube
&nbsp; &nbsp; &nbsp; var topPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; topPlane.y = 50;
&nbsp; &nbsp; &nbsp; var leftPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; leftPlane.rotationZ = 90;
&nbsp; &nbsp; &nbsp; leftPlane.x = -50;
&nbsp; &nbsp; &nbsp; var frontPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; frontPlane.rotationX = 90;
&nbsp; &nbsp; &nbsp; frontPlane.z = -50;
&nbsp; &nbsp; &nbsp; var bottomPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; bottomPlane.rotationX = 180;
&nbsp; &nbsp; &nbsp; bottomPlane.y = -50;
&nbsp; &nbsp; &nbsp; var rightPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; rightPlane.rotationZ = -90;
&nbsp; &nbsp; &nbsp; rightPlane.x = 50;
&nbsp; &nbsp; &nbsp; var backPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; backPlane.rotationX = -90;
&nbsp; &nbsp; &nbsp; backPlane.z = 50;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create an object container to group the sides of the cube
&nbsp; &nbsp; &nbsp; planeGroup = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(planeGroup);

&nbsp; &nbsp; &nbsp; planeGroup.addChild(topPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(leftPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(frontPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(bottomPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(rightPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(backPlane);
&nbsp; &nbsp; &nbsp; planeGroup.x = -100;
&nbsp; &nbsp; &nbsp; planeGroup.z = 100;

&nbsp; &nbsp; &nbsp; // Create a sphere with normal-mapped material
&nbsp; &nbsp; &nbsp; normalSphere = new Sphere({material:sphereNormalMapMaterial, radius:65, segmentsW:10, segmentsH:10, ownCanvas:true});
&nbsp; &nbsp; &nbsp; normalSphere.x = 100;
&nbsp; &nbsp; &nbsp; normalSphere.z = 100;
&nbsp; &nbsp; &nbsp; scene.addChild(normalSphere);

&nbsp; &nbsp; &nbsp; // Create a sphere with environment-mapped material
&nbsp; &nbsp; &nbsp; envSphere = new Sphere({material:envMapMaterial, radius:65, segmentsW:10, segmentsH:10, ownCanvas:true});
&nbsp; &nbsp; &nbsp; envSphere.z = -90;
&nbsp; &nbsp; &nbsp; scene.addChild(envSphere);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Frame-enter event handler
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; planeGroup.rotationY += 2;
&nbsp; &nbsp; &nbsp; normalSphere.rotationY += 2;
&nbsp; &nbsp; &nbsp; envSphere.rotationY += 2;

&nbsp; &nbsp; &nbsp; // update camera position
&nbsp; &nbsp; &nbsp; updateCamera();
&nbsp; &nbsp; &nbsp; camera.hover();  

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Update the camera position from mouse movements
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp; camera.targetpanangle = 0.5 * (stage.mouseX - lastMouseX) + lastPanAngle;
&nbsp; &nbsp; &nbsp; &nbsp; camera.targettiltangle = 0.5 * (stage.mouseY - lastMouseY) + lastTiltAngle;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Mouse down listener for camera rotation
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; lastPanAngle = camera.targetpanangle;
&nbsp; &nbsp; &nbsp; lastTiltAngle = camera.targettiltangle;
&nbsp; &nbsp; &nbsp; lastMouseX = stage.mouseX;
&nbsp; &nbsp; &nbsp; lastMouseY = stage.mouseY;
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Mouse up listener for camera rotation
&nbsp; &nbsp;  */
&nbsp; &nbsp;  private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; &nbsp; stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
&nbsp; &nbsp; }

&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Mouse stage leave listener for camera rotation
&nbsp; &nbsp;  */
&nbsp; &nbsp; private function onStageMouseLeave(event:Event):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; &nbsp; stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; /**
&nbsp; &nbsp;  * Resize the scene when the stage resizes
&nbsp; &nbsp;  */&nbsp;
&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }

&nbsp; }
&nbsp;
&nbsp;
}
</blockquote>
</pre>
</div>
<p>If you want to use the same images as in this example then away3D.png and checker.jpg you&#8217;ll find in the previous post on <a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">texture mapping in Away3D</a>. The new images are shown below.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/12/normalmap.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/12/normalmap-150x150.png" alt="" title="" margin="10" width="150" height="150" class="alignnone size-thumbnail wp-image-261" /></a> <a href="http://blog.tartiflop.com/wp-content/uploads/2008/12/asteroidnormal.jpg"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/12/asteroidnormal-150x150.jpg" alt="" title="" margin="10" width="150" height="150" class="alignnone size-thumbnail wp-image-262" /></a> <a href="http://blog.tartiflop.com/wp-content/uploads/2008/12/envmap.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/12/envmap-150x150.png" alt="" title="" margin="10" width="150" height="150" class="alignnone size-thumbnail wp-image-263" /></a></p>
<p>The first two images (the normal maps) were created using the utility described above. The first one from a bump map I used for a <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7-texture-mapping-with-lighting-bump-mapping-and-environment-mapping/">Papervision3D tutorial on bump mapping</a>, the second one comes from a bump map I found on the internet at <a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=263350">gamedev.net</a>. The environment map comes from and old OpenGL example I discovered on my hard disk&#8230; if you search for &#8220;opengl sphere map&#8221; in Google you&#8217;ll find plenty of instances!</p>
<p>Once its all compiled you should see three rotating objects with either normal and environment mapped data. Click on the image below to see the Flash movie. You can click anywhere and move the mouse to rotate the scene.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example006.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/12/example006.png" border="0" /></a></p>
<p>So, lets go into more detail on each part of the code. There&#8217;s nothing too complicated here but a few changes from the last time&#8230;</p>
<p>The first change comes from the initialisation of the 3D basics of the scene, specifically with the camera.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new HoverCamera3D({zoom:25, focus:30, distance:600});
&nbsp; &nbsp; &nbsp; camera.targetpanangle = camera.panangle = -10;
&nbsp; &nbsp; &nbsp; camera.targettiltangle = camera.tiltangle = 20;
&nbsp; &nbsp; &nbsp; camera.yfactor = 1;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the view to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // ensure that the z-order is calculated correctly
&nbsp; &nbsp; &nbsp; view.renderer = Renderer.CORRECT_Z_ORDER;
&nbsp; &nbsp; &nbsp;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>I&#8217;ve now chosen to use a <em>HoverCamera3D</em>. This simplifies the movement and positioning of the camera. You&#8217;ll remember that previously I used the basic <em>Camera3D</em> class and had to calculate specific values of <em>x</em>, <em>y</em> and <em>z</em> as well as redirect the camera towards the origin. Much of this is included in the <em>HoverCamera3D</em> class. By specifying <em>targettiltangle</em> and <em>targetpanangle</em> the camera will calculate a trajectory necessary to move the camera to a new position and keep it focused on a particular target. To maintain the orbital radius of the camera we set the <em>yfactor</em> to 1 otherwise a more elliptical orbit is calculated.</p>
<p>You&#8217;ll see towards the end of the code how we perform an interaction with the camera. If we look at the <em>loop</em> function, called on every frame-enter event we can see how the camera position is updated.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; planeGroup.rotationY += 2;
&nbsp; &nbsp; &nbsp; normalSphere.rotationY += 2;
&nbsp; &nbsp; &nbsp; envSphere.rotationY += 2;

&nbsp; &nbsp; &nbsp; // update camera position
&nbsp; &nbsp; &nbsp; updateCamera();
&nbsp; &nbsp; &nbsp; camera.hover();  

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>The object rotation is self evident so we&#8217;ll ignore that. The <em>updateCamera</em> function recalculates the camera position from mouse position. More importantly the <em>camera.hover()</em> call makes the camera move gradually towards the <em>target</em> tilt and pan angles giving a smoother animation of the camera than in previous examples.</p>
<p>For completeness, the <em>updateCamera</em> function and the <em>mouseDown</em> event listener are shown below.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp; camera.targetpanangle = 0.5 * (stage.mouseX - lastMouseX) + lastPanAngle;
&nbsp; &nbsp; &nbsp; &nbsp; camera.targettiltangle = 0.5 * (stage.mouseY - lastMouseY) + lastTiltAngle;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; lastPanAngle = camera.targetpanangle;
&nbsp; &nbsp; &nbsp; lastTiltAngle = camera.targettiltangle;
&nbsp; &nbsp; &nbsp; lastMouseX = stage.mouseX;
&nbsp; &nbsp; &nbsp; lastMouseY = stage.mouseY;
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see, the target angles are updated in the <em>updateCamera</em> function, taking into account the current mouse position. The <em>onMouseDown</em> function performs the necessary initialisation of pan and tilt angles. It also adds an event listener to detect when the mouse leaves the stage: this is useful because if the mouse button is released outside the stage, the <em>onMouseUp</em> listener is not called and we can obtain a state in which the scene is continuously rotated even if the mouse button is up. </p>
<p>So, on to more interesting elements of the code: normal mapped and environment mapped materials!</p>
<p>All the interesting stuff happens in <em>createScene</em> where the materials and objects are created.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create 3 different materials: two normal mapped ones (planar and spherical) and an
&nbsp; &nbsp; &nbsp; // environment mapped one.
&nbsp; &nbsp; &nbsp; var normalMapMaterial:Dot3BitmapMaterial = new Dot3BitmapMaterial(Cast.bitmap(away3DBitmap), Cast.bitmap(normalBitmap), {smooth:true, precision:5});
&nbsp; &nbsp; &nbsp; var envMapMaterial:EnviroBitmapMaterial = new EnviroBitmapMaterial(Cast.bitmap(checkerBitmap), Cast.bitmap(envBitmap), {smooth:true, precision:5});
&nbsp; &nbsp; &nbsp; var sphereNormalMapMaterial:Dot3BitmapMaterial = new Dot3BitmapMaterial(new BitmapData(1, 1, false, 0x666666), Cast.bitmap(sphereNormalBitmap), {smooth:true, precision:5});

&nbsp; &nbsp; &nbsp; // create a new directional white light source with specific ambient, diffuse and specular parameters
&nbsp; &nbsp; &nbsp; var light:DirectionalLight3D = new DirectionalLight3D({color:0xFFFFFF, ambient:0.25, diffuse:0.75, specular:0.9});
&nbsp; &nbsp; &nbsp; light.x = 10000;
&nbsp; &nbsp; &nbsp; light.z = 50000;
&nbsp; &nbsp; &nbsp; light.y = 50000;
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // Create six with the same (normal mapped) material and position them them to create a cube
&nbsp; &nbsp; &nbsp; var topPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; topPlane.y = 50;
&nbsp; &nbsp; &nbsp; var leftPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; leftPlane.rotationZ = 90;
&nbsp; &nbsp; &nbsp; leftPlane.x = -50;
&nbsp; &nbsp; &nbsp; var frontPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; frontPlane.rotationX = 90;
&nbsp; &nbsp; &nbsp; frontPlane.z = -50;
&nbsp; &nbsp; &nbsp; var bottomPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; bottomPlane.rotationX = 180;
&nbsp; &nbsp; &nbsp; bottomPlane.y = -50;
&nbsp; &nbsp; &nbsp; var rightPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; rightPlane.rotationZ = -90;
&nbsp; &nbsp; &nbsp; rightPlane.x = 50;
&nbsp; &nbsp; &nbsp; var backPlane:Plane = new Plane({material:normalMapMaterial, width:100, height:100, segmentsW:2, segmentsH:2, ownCanvas:true});
&nbsp; &nbsp; &nbsp; backPlane.rotationX = -90;
&nbsp; &nbsp; &nbsp; backPlane.z = 50;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create an object container to group the sides of the cube
&nbsp; &nbsp; &nbsp; planeGroup = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(planeGroup);

&nbsp; &nbsp; &nbsp; planeGroup.addChild(topPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(leftPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(frontPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(bottomPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(rightPlane);
&nbsp; &nbsp; &nbsp; planeGroup.addChild(backPlane);
&nbsp; &nbsp; &nbsp; planeGroup.x = -100;
&nbsp; &nbsp; &nbsp; planeGroup.z = 100;

&nbsp; &nbsp; &nbsp; // Create a sphere with normal-mapped material
&nbsp; &nbsp; &nbsp; normalSphere = new Sphere({material:sphereNormalMapMaterial, radius:65, segmentsW:10, segmentsH:10, ownCanvas:true});
&nbsp; &nbsp; &nbsp; normalSphere.x = 100;
&nbsp; &nbsp; &nbsp; normalSphere.z = 100;
&nbsp; &nbsp; &nbsp; scene.addChild(normalSphere);

&nbsp; &nbsp; &nbsp; // Create a sphere with environment-mapped material
&nbsp; &nbsp; &nbsp; envSphere = new Sphere({material:envMapMaterial, radius:65, segmentsW:10, segmentsH:10, ownCanvas:true});
&nbsp; &nbsp; &nbsp; envSphere.z = -90;
&nbsp; &nbsp; &nbsp; scene.addChild(envSphere);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>To start off with the three different materials are created. Firstly a <em>Dot3BitmapMaterial</em> taking the Away3D texture and a random normal map. I&#8217;ve chosen to smooth the material and have increased the precision of rendering to 5 pixels. The second material uses the <em>EnviroBitmapMaterial</em> using the checkered texture and the OpenGl sphere-map for the environment data, again smoothed as before. Incidentally, the shininess of the material can be modified by specifying the <em>reflectiveness</em> parameter in the initialisation parameters, taking a value between 0 and 1 (for most reflective). The final <em>Dot3BitmapMaterial</em> material, rather than using a bitmap file, creates a plain grey bitmap. The normal map comes from the asteroid spherical normal map.</p>
<p>We add a <em>DirectionalLight3D</em> to the scene to provide uniform lighting, independent of light distance. It should be noted that the <em>Dot3BitmapMaterial</em> will not currently work with a <em>PointLight3D</em>. Also, the <em>EnviroBitmapMaterial</em> is independent of the source: the environment map provides the equivalent shading.</p>
<p>For the <em>cube</em> we create six <em>Plane</em>s, each using the same material. These are then rotated and translated to form a cube. They are finally added to a <em>ObjectContainer3D</em> so that we can rotate all of them together in the <em>loop</em> function. Note as well that, as before, each object needs to have its own canvas which is specified within the initialisation parameters.</p>
<p>The two spheres are then created: one using an environment map, the other with normal mapped data. These are then positioned and added to the scene, again with independent canvases. </p>
<p>And that&#8217;s all there is to it! As you&#8217;ll see, the normal map produces fantastic results and really adds a feeling of depth to the object surface. The environment map really gives the impression that the object is very shiny. These effects are very simple to produce in Away3D but be aware too that added realism comes at a cost - the frame rate is bound to be slower than without these effects - so be warned!</p>
<p>Anyway, I hope this has been a useful addition to basic lighting and shading. As always, let me know if you have any comments or questions!</p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-7-movie-and-video-materials/">First steps in Away3D : Part 7 - Movie and video materials</a>Add depth to website by displaying interactive movies or videos as materials on 3D surfaces.
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/6XGgxZ9E718" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-6-normal-mapping-and-environment-mapping/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-6-normal-mapping-and-environment-mapping/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Cold War Kids</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/CVlMU8s86wE/</link>
		<comments>http://blog.tartiflop.com/2008/12/musical-interlude-cold-war-kids-2/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 19:15:49 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=250</guid>
		<description><![CDATA[Discover Cold War Kids!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2160487&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2160487&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/cold-war-kids.html'>Cold War Kids</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/CVlMU8s86wE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/musical-interlude-cold-war-kids-2/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/musical-interlude-cold-war-kids-2/</feedburner:origLink></item>
		<item>
		<title>Displacement map to normal map converter</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/3Jf_uy6SrLo/</link>
		<comments>http://blog.tartiflop.com/2008/12/displacement-map-to-normal-map-converter/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 18:39:06 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Papervision3D]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<category><![CDATA[bump mapping]]></category>

		<category><![CDATA[displacement mapping]]></category>

		<category><![CDATA[Flash Player 10]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[normal mapping]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=247</guid>
		<description><![CDATA[I&#8217;m currently looking at the normal mapping materials that are available in Away3D and became aware that to do a decent test it&#8217;d be nice to be able create normal maps myself. Previously, when looking at lighting effects in Papervision3D, I created my own bump map from random data very easily. I&#8217;ve tried doing the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently looking at the normal mapping materials that are available in Away3D and became aware that to do a decent test it&#8217;d be nice to be able create normal maps myself. Previously, when looking at <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7-texture-mapping-with-lighting-bump-mapping-and-environment-mapping/">lighting effects in Papervision3D</a>, I created my own bump map from random data very easily. I&#8217;ve tried doing the same for a normal map but haven&#8217;t found a decent utility to help me do that&#8230; so, I decided to write one myself.</p>
<p>Assuming that the displacement map image is applied to a single surface, the normal to the surface can be calculated quite easily by taking the gradients in the <em>x</em> and <em>y</em> directions and calculating the cross product of the two (see this <a href="http://mathworld.wolfram.com/NormalVector.html">description from Wolfram MathWorld on surface normals</a> for example).</p>
<p>Using the bitmap data (assuming it is greyscale), we can calculate the gradients using finite difference calculations using the pixel data as a height (displacement) and the pixel position as the <em>x</em> and <em>y</em> coordinates (again, <a href="http://mathworld.wolfram.com/FiniteDifference.html">Wolfram MathWorld on finite differences</a> provides a useful source of information). The normals can then be calculated at each individual pixel and converted into red, green and blue data.</p>
<p>The Flex application shown below reads displacement map data, calculates the normals, and creates normal map data. You can check it out by clicking on the image below or visiting <a href="http://www.tartiflop.com/disp2norm/">http://www.tartiflop.com/disp2norm/</a>.</p>
<p><a href="http://www.tartiflop.com/disp2norm/" class="lightwindow" params="lightwindow_width=720,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/12/disp2norm1.png" border="0" width="500" /></a></p>
<p>Note that this requires Flash Player 10 because it uses some of the new features available: namely reading and writing to the local file system and the use of the <em>Vector3D</em> class.</p>
<p>If you&#8217;re interested you can check out the <a href="http://www.tartiflop.com/disp2norm/srcview/index.html">source</a> as well.</p>
<p>Two additional features are available:</p>
<ul>
<li>Selection of the displacement direction. For example if you have a displacement on a <em>xz</em> surface, for the lighting to be correct you need to specify that the displacement is in the <em>y</em> direction.</li>
<li>Amplitude selection. You can modify the coarseness of the displacements by adjusting the amplitude factor - low is a smooth surface, high is a very rough surface.</li>
</ul>
<p><strong>Update !</strong></p>
<p>The converter can now create normal maps for spherical objects too! </p>
<p>Simply select the <em>Spherical</em> radio button and the normal map will be produced for a sphere. It assumes that the displacement map data has also been created for a sphere. The axis from which <em>phi</em> is calculated can be chosen using the combo. For example, in Away3D, this is the <em>y</em> axis for the <em>Sphere</em> primitive.</p>
<p>For info, the normal is calculated differently (and more simply): from the pixel indices, equivalent to spherical positions, we can calculate Cartesian positions. These can be converted into vectors and hence the cross product of vectors running across the pixel (in latitude and longitude directions), taking into account the displacement map data, gives us directly the normal to the sphere&#8230; hope that makes some kind of sense!</p>
<p>If you have any comments or questions then please let me know!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/3Jf_uy6SrLo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/12/displacement-map-to-normal-map-converter/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/12/displacement-map-to-normal-map-converter/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Clap Your Hands Say Yeah</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/vQL6M2iA46k/</link>
		<comments>http://blog.tartiflop.com/2008/11/musical-interlude-clap-your-hands-say-yeah/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 20:39:51 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=230</guid>
		<description><![CDATA[Discover Clap Your Hands Say Yeah!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=3427&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=3427&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/clap-your-hands-say-yeah.html'>Clap Your Hands Say Yeah</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/vQL6M2iA46k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/musical-interlude-clap-your-hands-say-yeah/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/musical-interlude-clap-your-hands-say-yeah/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 5 - Lighting and shading</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/P0dSKABsF3A/</link>
		<comments>http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 20:28:00 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Actionscript 3]]></category>

		<category><![CDATA[animation]]></category>

		<category><![CDATA[lighting]]></category>

		<category><![CDATA[texture mapping]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=223</guid>
		<description><![CDATA[Having obtained an interactive, texture mapped scene I&#8217;d now like to a bit more realism into it by adding a light source and shading the objects. The price of course for having a more realistic scene is at the cost of reduced performance as you&#8217;ll find many more calculations are necessary to render the scene. [...]]]></description>
			<content:encoded><![CDATA[<p>Having obtained an interactive, texture mapped scene I&#8217;d now like to a bit more realism into it by adding a light source and shading the objects. The price of course for having a more realistic scene is at the cost of reduced performance as you&#8217;ll find many more calculations are necessary to render the scene. You can find the equivalent article for Papervision3D in my post on <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-4-lighting-and-shading/"><em>First steps in Papervision3D : Part 4 - lighting and shading</em></a>, however I find that there is quite a difference for Away3D, at least compared to the other tutorials in this series.</p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - Animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">First steps in Away3D : Part 3 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/">First steps in Away3D : Part 4 - Scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.
</li>
</ul>
<p>Lighting in Away3D can be split into three basic components:</p>
<ul>
<li>the <strong>light source(s)</strong> defining the properties of the light(s)</li>
<li><strong>shaders</strong> providing algorithms that determine how a light source  interacts with a material</li>
<li>a <strong>material type</strong> combining different shaders along with base colours or bitmaps</li>
</ul>
<p>The first difference I notice compared to Papervision3D is that we can specify more than one light source. This of course increases the cpu load but in certain cases may produce a more realistic rendering of a scene.</p>
<p>There are three main types of light sources:</p>
<ul>
<li><em><strong>AmbientLight3D</strong></em> which has no position and provides a uniform ambient light to all objects</li>
<li><em><strong>DirectionalLight3D</strong></em> which provides light from a specified position but with a strength that does not diminish with distance</li>
<li><em><strong>PointLight3D</strong></em> providing light from a specified position that weakens in intensity with distance</li>
</ul>
<p>In terms of shaders we have the following posibilities:</p>
<ul>
<li><em><strong>AmbientShader</strong></em> which provides ambient shading to a triangle face</li>
<li><em><strong>DiffusePhongShader</strong></em> which, depending on the angle between the light source and a triangle face, produces a diffuse shading pattern</li>
<li><em><strong>SpecularPhongShader</strong></em> which produces specular shading on triangles to imitate a surface that is reflecting light, depending on the observer&#8217;s position and the light position</li>
<li><em><strong>EnviroShader</strong></em> allowing for environment mapping, producing a reflection from a surrounding <em>environment</em> on an object, independent of a light source. Requires bitmap data for the environment</li>
<li><em><strong>DiffuseDot3Shader</strong></em> to increase scene reality by adding more small scale structure through the use of <em>normal mapping</em> to an object. Requires bitmap data for the normal map</li>
</ul>
<p>The above shaders, with the exception of the <em>EnviroShader</em> assume that the light source is a <em>DirectionalLight3D</em>. </p>
<p>We then have a choice of <em>CompositeMaterials</em> that uses a combination of different shaders and <em>base</em> materials as shown in the following list:</p>
<ul>
<li><em><strong>PhongBitmapMaterial</strong></em> used to create ambient, diffuse and specular lighting on a texture-mapped material<br />
Base material : <em>BitmapMaterial</em><br />
Shaders : <em>AmbientShader</em>, <em>DiffusePhongShader</em> and <em>SpecularPhongShader</em></li>
<li><em><strong>PhongMovieMaterial</strong></em> used to create ambient, diffuse and specular lighting on a material based on another Flash movie<br />
Base material : <em>MovieMaterial</em><br />
Shaders : <em>AmbientShader</em>, <em>DiffusePhongShader</em> and <em>SpecularPhongShader</em></li>
<li><em><strong>PhongColorMaterial</strong></em> used to create ambient, diffuse and specular lighting on a simple coloured material<br />
Base material : <em>ColorMaterial</em><br />
Shaders : <em>AmbientShader</em>, <em>DiffusePhongShader</em> and <em>SpecularPhongShader</em></li>
<li><em><strong>EnviroBitmapMaterial</strong></em> used to create environmental lighting on a texture-mapped material<br />
Base material : <em>BitmapMaterial</em><br />
Shaders : <em>EnviroShader</em></li>
<li><em><strong>Dot3BitmapMaterial</strong></em> used to create ambient and normal-mapped lighting on a texture-mapped material<br />
Base material : <em>BitmapMaterial</em><br />
Shaders : <em>AmbientShader</em> and <em>DiffuseDot3Shader</em>,</li>
<li><em><strong>Dot3MovieMaterial</strong></em> used to create ambient and normal-mapped lighting on a material based on another Flash movie<br />
Base material : <em>MovieMaterial</em><br />
Shaders : <em>AmbientShader</em> and <em>DiffuseDot3Shader</em></li>
</ul>
<p>The above materials all produce smoothly shaded objects which naturally has a price in terms of performance. If we want to have objects that are more simply shaded then we can use a <em>CenterLightingMaterial</em>. This type of material produces the equivalent of flat-shaded materials in Papervision3D. We have in this category two choices:</p>
<ul>
<li><strong><em>ShadingColorMaterial</em></strong> for simple flat shading of a <em>ColorMaterial</em></li>
<li><strong><em>WhiteShadingBitmapMaterial</em></strong> for simple flat shading of a <em>BitmapMaterial</em>, but assuming that the light source is always white (independent of colour given to light source).</li>
</ul>
<p>In the example code for this article I&#8217;m going to look at two of these materials: the <em>PhongBitmapMaterial</em> and the <em>WhiteShadingBitmapMaterial</em>. These two materials are very simple to use and provide a lot of control over the lighting effects on the material. One advantage here, personally speaking, over Papervision3D is the ability to mix ambient, diffuse and specular lighting all together which is necessary to produce <em>real</em> <a href="http://en.wikipedia.org/wiki/Phong_shading">Phong reflection</a>. Papervision3D provides materials for ambient plus diffuse and ambient plus specular but not all three together. This obviously is quicker to render but is less realistic when drawing <em>shiny</em> materials for example. Mixing all three is still possible but requires more effort as I showed in my post on <a href="http://blog.tartiflop.com/2008/10/nice-and-shiny-phong-reflection-in-papervision3d/">phong reflection with Papervision3D</a>. </p>
<p>For the light source I&#8217;m simply going to use a <em>DirectionalLight3D</em> which, as I mentioned before, correctly renders these materials. Another aspect that I like with Away3D is that the light source itself can be given a number of characteristics. Specifically we can give it a colour and define relative strengths of ambient, diffuse and specular shading, none of which are possible with Papervision3D. Being able to specify a light colour allows us to create new effects with materials of different colours. Specifying the ambient level directly with the light source, for example, also eliminates the need to specify the ambient light with every material created, as is the case with Papervision3D. </p>
<p>Away3D also allows us to create more than one light source and have a material rendered appropriately, which is not possible in Papervision3D. This, again, is obviously a drain on computational resources, but, in certain cases, this can open up new possibilities for rendering a more realistic scene.</p>
<p>I guess what I like most is that, conceptually, Away3D allows us to disassociate the light source from the material meaning that we can create a specific material without thinking about the environment and lighting in which it will be placed. </p>
<p>Anyway, enough of the theory and personal opinions, lets move onto the code. I&#8217;m using exactly the same scene as for the previous example only this time adding a <em>DirectionalLight3D</em> and replacing the <em>BitmapMaterial</em> with <em>PhongBitmapMaterial</em> and <em>WhiteShadingBitmapMaterial</em>.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.Camera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.base.Object3D;
&nbsp; import away3d.core.math.Number3D;
&nbsp; import away3d.core.render.Renderer;
&nbsp; import away3d.core.utils.Cast;
&nbsp; import away3d.events.MouseEvent3D;
&nbsp; import away3d.lights.DirectionalLight3D;
&nbsp; import away3d.materials.PhongBitmapMaterial;
&nbsp; import away3d.materials.WhiteShadingBitmapMaterial;
&nbsp; import away3d.primitives.Cube;
&nbsp; import away3d.primitives.Cylinder;
&nbsp; import away3d.primitives.Sphere;
&nbsp; import away3d.primitives.Torus;
&nbsp;
&nbsp; import caurina.transitions.Tweener;
&nbsp;
&nbsp; import flash.display.Bitmap;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example005 extends Sprite {

&nbsp; &nbsp; [Embed(source="/../assets/earth.jpg")] private var EarthImage:Class;
&nbsp; &nbsp; private var earthBitmap:Bitmap = new EarthImage();

&nbsp; &nbsp; [Embed(source="/../assets/away3D.png")] private var Away3DImage:Class;
&nbsp; &nbsp; private var away3DBitmap:Bitmap = new Away3DImage();

&nbsp; &nbsp; [Embed(source="/../assets/checker.jpg")] private var CheckerImage:Class;
&nbsp; &nbsp; private var checkerBitmap:Bitmap = new CheckerImage();

&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 150;
&nbsp; &nbsp; private static const CAMERA_ORBIT:Number = 600;

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:Camera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp; &nbsp; private var group:ObjectContainer3D;
&nbsp; &nbsp; private var sphere:Sphere;
&nbsp; &nbsp; private var cube:Cube;
&nbsp; &nbsp; private var centerCube:Cube;
&nbsp; &nbsp; private var cylinder:Cylinder;
&nbsp; &nbsp; private var torus:Torus;
&nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;
&nbsp; &nbsp; private var cameraYaw:Number = -60;

&nbsp; &nbsp;
&nbsp; &nbsp; public function Example005() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:25, focus:30});
&nbsp; &nbsp; &nbsp; setCameraPosition();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera, renderer:Renderer.CORRECT_Z_ORDER});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; //view.renderer = Renderer.CORRECT_Z_ORDER;
&nbsp; &nbsp; &nbsp;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // create a new directional white light source with specific ambient, diffuse and specular parameters
&nbsp; &nbsp; &nbsp; var light:DirectionalLight3D = new DirectionalLight3D({color:0xFFFFFF, ambient:0.25, diffuse:0.75, specular:0.9});
&nbsp; &nbsp; &nbsp; light.x = 100;
&nbsp; &nbsp; &nbsp; light.z = 500;
&nbsp; &nbsp; &nbsp; light.y = 500;
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new sphere object using a very shiny phong-shaded bitmap material representing the earth
&nbsp; &nbsp; &nbsp; var earthMaterial:PhongBitmapMaterial = new PhongBitmapMaterial(Cast.bitmap(earthBitmap));
&nbsp; &nbsp; &nbsp; earthMaterial.shininess = 100;
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:earthMaterial, radius:50, segmentsW:10, segmentsH:10});
&nbsp; &nbsp; &nbsp; sphere.x = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; sphere.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);

&nbsp; &nbsp; &nbsp; // Create a new cube object using a tiled, phong-shaded bitmap material
&nbsp; &nbsp; &nbsp; var tiledAway3DMaterial:PhongBitmapMaterial = new PhongBitmapMaterial(Cast.bitmap(away3DBitmap), {repeat:true, scaleX:.5, scaleY:.5});
&nbsp; &nbsp; &nbsp; cube = new Cube({material:tiledAway3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; cube.z = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; cube.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(cube);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a cylinder mapping the earth data again
&nbsp; &nbsp; &nbsp; cylinder = new Cylinder({material:earthMaterial, radius:25, height:100, segmentsW:16});
&nbsp; &nbsp; &nbsp; cylinder.x = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; cylinder.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(cylinder);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a torus object and use a checkered, flat-shaded (from white light) bitmap material
&nbsp; &nbsp; &nbsp; var checkerBitmapMaterial:WhiteShadingBitmapMaterial = new WhiteShadingBitmapMaterial(Cast.bitmap(checkerBitmap));
&nbsp; &nbsp; &nbsp; torus = new Torus({material:checkerBitmapMaterial, radius:40, tube:10, segmentsT:8, segmentsR:16});
&nbsp; &nbsp; &nbsp; torus.z = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; torus.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(torus);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a new cube object using a smoothed, precise, phong-shaded, mat (not shiny) bitmap material
&nbsp; &nbsp; &nbsp; var away3DMaterial:PhongBitmapMaterial = new PhongBitmapMaterial(Cast.bitmap(away3DBitmap), {smooth:true, precision:2});
&nbsp; &nbsp; &nbsp; away3DMaterial.shininess = 0;
&nbsp; &nbsp; &nbsp; centerCube = new Cube({material:away3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; centerCube.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(centerCube);

&nbsp; &nbsp; &nbsp; // add mouse listeners to all the 3D objects
&nbsp; &nbsp; &nbsp; sphere.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cube.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cylinder.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; torus.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; centerCube.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; sphere.yaw(-4);
&nbsp; &nbsp; &nbsp; cube.yaw(-4);
&nbsp; &nbsp; &nbsp; cylinder.yaw(-4);
&nbsp; &nbsp; &nbsp; torus.yaw(-4);

&nbsp; &nbsp; &nbsp; // update the camera position
&nbsp; &nbsp; &nbsp; updateCamera();

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; // updates the camera position
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch &gt;= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; setCameraPosition();
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; // sets the camera position given pitch and yaw angles
&nbsp; &nbsp; private function setCameraPosition():void {
&nbsp; &nbsp; &nbsp; camera.y = CAMERA_ORBIT * Math.cos(cameraPitch * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.x = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.cos(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.z = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.sin(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // keep the camera looking at the origin
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp;
&nbsp; &nbsp; // called when mouse down on a 3D object
&nbsp; &nbsp; private function onMouseDownOnObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:200, time:1, transition:"easeOutSine", onComplete:function():void {goBack(object);} });
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when a tween created in onMouseDownOnObject has terminated
&nbsp; &nbsp; private function goBack(object:Object3D):void {
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:0, time:2, transition:"easeOutBounce"});
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when the window is resized
&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }

&nbsp; }
&nbsp;
&nbsp; 

}
</blockquote>
</pre>
</div>
<p>When compiled you should get the same result as below (click on the image). As before, the scene is interactive so you can click on the background and move the mouse to move the camera and click on an object to make it bounce.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example005.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/example005.png" border="0" /></a></p>
<p>Since the code is so similar to the previous example I&#8217;m going to concentrate solely on the function <em>createScene</em> - this is the only function that has been modified.</p>
<p>In this example we use a simple white light source and see four different types of materials rendered: one that is very shiny, another that has a mat texture, one that takes default lighting parameters (being quite shiny) and another that is flat shaded.</p>
<p>Starting with the light source, we use a <em>DirectionLight3D</em> for which we specify its position and lighting properties.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // create a new directional white light source with specific ambient, diffuse and specular parameters
&nbsp; &nbsp; &nbsp; var light:DirectionalLight3D = new DirectionalLight3D({color:0xFFFFFF, ambient:0.25, diffuse:0.75, specular:0.9});
&nbsp; &nbsp; &nbsp; light.x = 100;
&nbsp; &nbsp; &nbsp; light.z = 500;
&nbsp; &nbsp; &nbsp; light.y = 500;
&nbsp; &nbsp; &nbsp; scene.addChild(light);
</blockquote>
</pre>
</div>
<p>As you can see the constructor takes an array of initialisation parameters in which we set the colour to white and give it ambient, diffuse and specular factors (being between 0 and 1).</p>
<p>The first object that we create is the rotating globe. Here I wanted the object to appear to be very shiny so modify its shininess.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create a new sphere object using a very shiny phong-shaded bitmap material representing the earth
&nbsp; &nbsp; &nbsp; var earthMaterial:PhongBitmapMaterial = new PhongBitmapMaterial(Cast.bitmap(earthBitmap));
&nbsp; &nbsp; &nbsp; earthMaterial.shininess = 100;
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:earthMaterial, radius:50, segmentsW:10, segmentsH:10});
&nbsp; &nbsp; &nbsp; sphere.x = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; sphere.ownCanvas = true;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);
</blockquote>
</pre>
</div>
<p>First of all, the <em>PhongBitmapMaterial</em> takes bitmap data for the texture mapping, as is the case for an ordinary, unshaded <em>BitmapMaterial</em>. Next we modify the shininess property (by default this is set at 20). This property, on the rendered scene, in effect modifies the extent of the specular lighting. The bright white dot that we see on the globe is reduced by increasing this property as if the light source is reflected off a more concentrated region of the material.</p>
<p>An important point to note is the line</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; sphere.ownCanvas = true;
</blockquote>
</pre>
</div>
<p>Without this line the scene is not correctly rendered as objects remain partially visible when they pass behind others. </p>
<p>Moving on to the tiled material object, I wanted to show that the initialisation parameters that we send to a material are still taken into account for the <em>base</em> material. The <em>PhongBitmapMaterial</em> is composed of a <em>TransformBitmapMaterial</em> (as well as the shaders) as we discussed in the previous example. The initialisation parameters <em>{repeat:true, scaleX:.5, scaleY:.5}</em> are passed directly to this element when it is constructed and therefore the texture map is still tiled. This object uses the default shading parameters of the <em>PhongBitmapMaterial</em> and is therefore appears less shiny than the globe.</p>
<p>The cylinder uses the same material as the globe just to illustrate that we can use the same material more than once.</p>
<p>Next, for the torus, we implement flat shading by using a <em>WhiteShadingBitmapMaterial</em>. As its name indicates this assumes a white light source. You can test this by experimenting with the light source colour. You&#8217;ll notice that all the other objects correctly reflect the change in light colour but this object remains white and red.  This material is obviously less complex in terms of necessary calculations and therefore provides better rendering performance. However, we see that smoothly shaded materials, as with the other objects, allow us to reduce the number of rendered triangles to produce more <em>rounded</em> objects.</p>
<p>Finally, the cube in the center is rendered with shininess set to zero. Only diffuse and ambient lighting remain in this case. This is useful for rendering mat materials but unfortunately has no performance benefits. We can see however that there is a difference in the visible result for the two cubes.</p>
<p>So thats it for this tutorial! I hope this has given a useful overview of lighting and shading in Away3D. Of course I&#8217;ve not gone into detail for all the different types of lights and shaders - you&#8217;ll discover a lot by experimenting with this example, for example by changing the materials, the type of lighting, its properties and its position. I&#8217;ve purposely ignored the <em>Dot3BitmapMaterial</em> and <em>EnviroBitmapMaterial</em> for this post because I felt that it was important to look at simple lighting and shading first - they should appear in the next article. But for now, at least, I hope this provides a useful starting point - comments and suggestions, as always, are very welcome! </p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/12/first-steps-in-away3d-part-6-normal-mapping-and-environment-mapping/">First steps in Away3D : Part 6 - Normal mapping and environment mapping</a><br />
Additional realism is added to the scene by applying normal maps (to give a higher level of shading characteristics) and environment maps (as an alternative to simple lighting models).
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/P0dSKABsF3A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 4 - Scene interaction</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/GwfHPqOEXC0/</link>
		<comments>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 18:06:19 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[animation]]></category>

		<category><![CDATA[Tweener]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=217</guid>
		<description><![CDATA[Having created a scene last time with texture mapped objects, I&#8217;d now like to add some interaction so that we can rotate the camera around the scene and make the 3D objects react to mouse events. As you&#8217;ll see this is very straightforward with Away3D as each triangle drawn on the screen individually detects mouse [...]]]></description>
			<content:encoded><![CDATA[<p>Having created a scene last time with texture mapped objects, I&#8217;d now like to add some interaction so that we can rotate the camera around the scene and make the 3D objects react to mouse events. As you&#8217;ll see this is very straightforward with Away3D as each triangle drawn on the screen individually detects mouse events. For an equivalent tutorial in Papervision3D, check out <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-5-scene-interaction/"><em>First steps in Papervision3D : Part 5</em></a>. </p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - Animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">First steps in Away3D : Part 3 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
</ul>
<p>For the scene interaction we&#8217;ll be looking at two different types of events. Firstly, the standard flash <em>MouseEvent</em> that we&#8217;ll use to rotate the camera when the user clicks on the stage and moves the mouse. Secondly we&#8217;ll look at the Away3D-specific event: the <em>MouseEvent3D</em>. This event is created for similar mouse actions on 3D objects but more importantly it contains the associated 3D object. To add <em>MouseEvent3D</em> listeners, all <em>Object3D</em> objects have the following functions for different mouse interactions:</p>
<ul>
<li><strong>onMouseDown</strong> : called when the mouse button is pressed over the object</li>
<li><strong>onMouseUp</strong> : called when the mouse button is released over the object</li>
<li><strong>onMouseMove</strong> : called when the mouse moves over the object</li>
<li><strong>onMouseOver</strong> : called when the mouse enters the object</li>
<li><strong>onMouseOut</strong> : called when the mouse leaves the object</li>
</ul>
<p>Another new feature for this tutorial is to add object animation using an external library: <a href="http://code.google.com/p/tweener/"><em>Tweener</em></a>. </p>
<p>Without having to calculate and specify the change in positions (for example) of objects within the code, a <em>tween</em> does all the hard work for us. A tween works on a particular property of an object and at each frame of an animation modifies this property in a particular manner. You&#8217;ll find more information on tweens on the web, for example at <a href="http://en.wikipedia.org/wiki/Tweening">wikipedia</a>. </p>
<p>Tweener is an opensource library, compatible with Actionscript2 and Actionscript3 as well as JavaScript and HaXE. To install it in your Eclipse/Flex Builder 3 environment simply create a new Flex Library Project, download the sources from the Tweener homepage and extract them into the <em>src</em> directory. The source should be automatically compiled and you can either link your own ActionScript projects to this project or directly used the compiled library. If you need help on compiling new flex library projects in eclipse then you should find useful information on my post for <a href="http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/">installing and compiling Away3D in eclipse</a>.</p>
<p>Lets take a look at the code. I&#8217;m following directly from the example in the last post but am simply adding the new mouse listeners.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.Camera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.base.Object3D;
&nbsp; import away3d.core.math.Number3D;
&nbsp; import away3d.core.utils.Cast;
&nbsp; import away3d.events.MouseEvent3D;
&nbsp; import away3d.materials.BitmapMaterial;
&nbsp; import away3d.materials.TransformBitmapMaterial;
&nbsp; import away3d.primitives.Cube;
&nbsp; import away3d.primitives.Cylinder;
&nbsp; import away3d.primitives.Sphere;
&nbsp; import away3d.primitives.Torus;
&nbsp;
&nbsp; import caurina.transitions.Tweener;
&nbsp;
&nbsp; import flash.display.Bitmap;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example004 extends Sprite {

&nbsp; &nbsp; [Embed(source="/../assets/earth.jpg")] private var EarthImage:Class;
&nbsp; &nbsp; private var earthBitmap:Bitmap = new EarthImage();

&nbsp; &nbsp; [Embed(source="/../assets/away3D.png")] private var Away3DImage:Class;
&nbsp; &nbsp; private var away3DBitmap:Bitmap = new Away3DImage();

&nbsp; &nbsp; [Embed(source="/../assets/checker.jpg")] private var CheckerImage:Class;
&nbsp; &nbsp; private var checkerBitmap:Bitmap = new CheckerImage();

&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 150;
&nbsp; &nbsp; private static const CAMERA_ORBIT:Number = 600;

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:Camera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp; &nbsp; private var group:ObjectContainer3D;
&nbsp; &nbsp; private var sphere:Sphere;
&nbsp; &nbsp; private var cube:Cube;
&nbsp; &nbsp; private var centerCube:Cube;
&nbsp; &nbsp; private var cylinder:Cylinder;
&nbsp; &nbsp; private var torus:Torus;
&nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;
&nbsp; &nbsp; private var cameraYaw:Number = -60;

&nbsp; &nbsp;
&nbsp; &nbsp; public function Example004() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:25, focus:30});
&nbsp; &nbsp; &nbsp; setCameraPosition();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new sphere object using a bitmap material representing the earth
&nbsp; &nbsp; &nbsp; var earthMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(earthBitmap));
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:earthMaterial, radius:50, segmentsW:10, segmentsH:10});
&nbsp; &nbsp; &nbsp; sphere.x = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);

&nbsp; &nbsp; &nbsp; // Create a new cube object using a tiled bitmap material
&nbsp; &nbsp; &nbsp; var tiledAway3DMaterial:TransformBitmapMaterial = new TransformBitmapMaterial(Cast.bitmap(away3DBitmap), {repeat:true, scaleX:.5, scaleY:.5});
&nbsp; &nbsp; &nbsp; cube = new Cube({material:tiledAway3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; cube.z = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cube);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a cylinder mapping the earth data again
&nbsp; &nbsp; &nbsp; cylinder = new Cylinder({material:earthMaterial, radius:25, height:100, segmentsW:16});
&nbsp; &nbsp; &nbsp; cylinder.x = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cylinder);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a torus object and use a checkered bitmap material
&nbsp; &nbsp; &nbsp; var checkerBitmapMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(checkerBitmap));
&nbsp; &nbsp; &nbsp; torus = new Torus({material:checkerBitmapMaterial, radius:40, tube:10, segmentsT:8, segmentsR:16});
&nbsp; &nbsp; &nbsp; torus.z = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(torus);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a new cube object using a smoothed, precise bitmap material
&nbsp; &nbsp; &nbsp; var away3DMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(away3DBitmap), {smooth:true, precision:2});
&nbsp; &nbsp; &nbsp; centerCube = new Cube({material:away3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; group.addChild(centerCube);

&nbsp; &nbsp; &nbsp; // add mouse listeners to all the 3D objects
&nbsp; &nbsp; &nbsp; sphere.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cube.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cylinder.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; torus.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; centerCube.addOnMouseDown(onMouseDownOnObject);

&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; sphere.yaw(-4);
&nbsp; &nbsp; &nbsp; cube.yaw(-4);
&nbsp; &nbsp; &nbsp; cylinder.yaw(-4);
&nbsp; &nbsp; &nbsp; torus.yaw(-4);

&nbsp; &nbsp; &nbsp; // update the camera position
&nbsp; &nbsp; &nbsp; updateCamera();

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; // updates the camera position
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch &gt;= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; setCameraPosition();
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; // sets the camera position given pitch and yaw angles
&nbsp; &nbsp; private function setCameraPosition():void {
&nbsp; &nbsp; &nbsp; camera.y = CAMERA_ORBIT * Math.cos(cameraPitch * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.x = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.cos(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.z = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.sin(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // keep the camera looking at the origin
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp;
&nbsp; &nbsp; // called when mouse down on a 3D object
&nbsp; &nbsp; private function onMouseDownOnObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:200, time:1, transition:"easeOutSine", onComplete:function():void {goBack(object);} });
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when a tween created in onMouseDownOnObject has terminated
&nbsp; &nbsp; private function goBack(object:Object3D):void {
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:0, time:2, transition:"easeOutBounce"});
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when the window is resized
&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }

&nbsp; }
&nbsp;
&nbsp;
}
</blockquote>
</pre>
</div>
<p>The example embeds the same images as the last time so if you need them you can find them in my last post. Don&#8217;t forget that you&#8217;ll need to link to the Tweener library for this to compile correctly. The resulting Flash movie should be as below - click on the image below to load it. Now when you click on the background and move the mouse you should be able to rotate the scene (effectively moving the camera) and clicking on each object should make them bounce.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example004.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/example004.png" border="0" /></a></p>
<p>First of all, lets have a look how the we add the standard Flash <em>MouseEvent</em> to rotate the camera. </p>
<p>Starting with the constructor we add two listeners.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
</blockquote>
</pre>
</div>
<p>When a mouse click is detected on the stage the function <em>onMouseDown</em> is called. When the button is released <em>onMouseUp</em> is called. These functions indicate when the camera movement should start and stop.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>To start the camera movement we set the boolean <em>doRotation</em> to true and to stop it we set it to false. The amount of rotation depends on how far the mouse moves during a single frame so we store the position of the mouse at every frame as well. The camera is then updated during the <em>loop</em> function</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; sphere.yaw(-4);
&nbsp; &nbsp; &nbsp; cube.yaw(-4);
&nbsp; &nbsp; &nbsp; cylinder.yaw(-4);
&nbsp; &nbsp; &nbsp; torus.yaw(-4);

&nbsp; &nbsp; &nbsp; // update the camera position
&nbsp; &nbsp; &nbsp; updateCamera();

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Other than the call to <em>updateCamera</em> the rendering remains identical to the last example. The camera position is then calculated as follows.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; // updates the camera position
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch &gt;= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; setCameraPosition();
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>From the change in mouse position we calculate (arbitrarily) a change in angle <em>from</em> the y axis (pitch) and similarly <em>around</em> the y axis (yaw). The pitch is kept within limits to avoid the camera from going over the poles and hence changing the <em>up</em> direction of the camera. Once we&#8217;ve calculated the new values of pitch and yaw for the camera position we can convert these angles into x, y and z positions. This is done in <em>setCameraPosition</em>.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; // sets the camera position given pitch and yaw angles
&nbsp; &nbsp; private function setCameraPosition():void {
&nbsp; &nbsp; &nbsp; camera.y = CAMERA_ORBIT * Math.cos(cameraPitch * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.x = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.cos(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp; camera.z = CAMERA_ORBIT * Math.sin(cameraPitch * Math.PI / 180) * Math.sin(cameraYaw * Math.PI / 180);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // keep the camera looking at the origin
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Note that we keep the camera at all times looking at the origin.</p>
<p>Moving on to the interaction with the 3D objects using the <em>MouseEvent3D</em> event, for this example I&#8217;m just going to look at the events when the mouse is clicked over an object. You&#8217;ll see that adding the listeners is very simple: at the end of the <em>createScene</em> a listener is added to each object.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // add mouse listeners to all the 3D objects
&nbsp; &nbsp; &nbsp; sphere.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cube.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; cylinder.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; torus.addOnMouseDown(onMouseDownOnObject);
&nbsp; &nbsp; &nbsp; centerCube.addOnMouseDown(onMouseDownOnObject);
</blockquote>
</pre>
</div>
<p>The rest of <em>createScene</em> is identical to the previous example. Now, whenever a user clicks on these objects, the function <em>onMouseDownOnObject</em> is called.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; // called when mouse down on a 3D object
&nbsp; &nbsp; private function onMouseDownOnObject(event:MouseEvent3D):void {
&nbsp; &nbsp; &nbsp; var object:Object3D = event.object;
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:200, time:1, transition:"easeOutSine", onComplete:function():void {goBack(object);} });
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>The listener is called with the <em>MouseEvent3D</em> passed as an argument. From this we can easily obtain the <em>Object3D</em> for which the event occurred. We then invoke <em>Tweener</em> to perform an animation on the object.</p>
<p>Tweener contains static methods that allow us to modify object properties. In this case we simply modify the y position of the object so that it goes to a value of 200 in 1 second using the <em>easeOutSine</em> transition function. I&#8217;d recommend looking at the Tweener documentation on the different <a href="http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html">transition functions</a>. The <em>onComplete</em> argument allows us to put the sphere back to its original position when the tween has completed.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; // called when a tween created in onMouseDownOnObject has terminated
&nbsp; &nbsp; private function goBack(object:Object3D):void {
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:0, time:2, transition:"easeOutBounce"});
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>This then uses another tween with an <em>easeOutBounce</em> transition to move the sphere back to the x-z plane.</p>
<p>And that&#8217;s all there is to it! With Tweener you can modify a number of different properties in parallel. For example you can change y and scale the object at the same time. The interface provided by Away3D is in any case very easy to use. Making a comparison to Papervision3D I find it a bit easier: with Papervision3D we need to say that the say that each individual material is interactive, as well as the <em>View</em> itself. This is surely to produce some performance optimisation. Other than this the interaction with objects is very similar for both engines and, I hope you&#8217;ll find, is straightforward to implement!</p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away-3d-part-5-lighting-and-shading/">First steps in Away3D : Part 5 - Lighting and shading</a><br />
A light source is added to the scene and the materials are changed to illustrate how Away3D renders objects with different shading characteristics.
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/GwfHPqOEXC0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Editors</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/X0j7nAEbg0c/</link>
		<comments>http://blog.tartiflop.com/2008/11/musical-interlude-editors/#comments</comments>
		<pubDate>Sun, 16 Nov 2008 18:35:29 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=212</guid>
		<description><![CDATA[Discover Editors!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2507605&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=2507605&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/editors.html'>Editors</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/X0j7nAEbg0c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/musical-interlude-editors/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/musical-interlude-editors/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 3 - Texture mapping</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/sVzzyiV_fyA/</link>
		<comments>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/#comments</comments>
		<pubDate>Sun, 16 Nov 2008 17:02:03 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[texture mapping]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=202</guid>
		<description><![CDATA[In this post I&#8217;d like to show how to add textures to 3D objects rather than using plain colours which provides much more realistic (or at least interesting) rendering. You&#8217;ll find that with Away3D the concepts are very similar to those used in other 3D engines - for a comparison and some texture mapping references [...]]]></description>
			<content:encoded><![CDATA[<p>In this post I&#8217;d like to show how to add textures to 3D objects rather than using plain colours which provides much more realistic (or at least interesting) rendering. You&#8217;ll find that with Away3D the concepts are very similar to those used in other 3D engines - for a comparison and some texture mapping references check out my equivalent tutorial for <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6-texture-mapping/">texture mapping in Papervision3D</a>. I&#8217;m going to discuss texture mapping rather early on in this series of articles (earlier than for the Papervision3D series) simply because you&#8217;ll find that when come on to adding lighting and shading it opens up a much richer set of possibilities. But, I&#8217;m sure you&#8217;ll find that adding textures is a very simple process - at least, I hope so!</p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - Animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
</ul>
<p>Adding textures to objects in Away3D (as with most, if not all, 3D engines) is done by mapping coordinates on bitmap data to triangle vertices, known as <em><a href="http://en.wikipedia.org/wiki/Texture_mapping">texture mapping</a></em>. More specifically, a technique known as <em><a href="http://en.wikipedia.org/wiki/UV_mapping">uv mapping</a></em> is used where <em>u</em> and <em>v</em> are the coordinates of the bitmap data which are then passed to the renderer for every triangle vertex. The following diagram tries to explain this for a pyramid. The <em>uv</em> coordinates are totally invented but you can see that for a single triangle the <em>uv</em> coordinates for every vertex are mapped onto the bitmap data (having a maximum <em>u</em> being equal to 1, and similarly for the maximum <em>v</em>) and the resulting triangle from the bitmap used to render the pyramid face.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/texturemapping.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/texturemapping.png" alt="" title="" width="500" height="374" class="aligncenter size-full wp-image-203" /></a></p>
<p>In this example you&#8217;ll see that a number of different primitives are used (a cube, sphere, torus and cylinder). Each triangle used to produce these 3D objects has the <em>uv</em> coordinates for each vertex calculated. You can see in the link above for <em>uv</em> mapping the calculation necessary for a sphere. As you&#8217;ll see below, the image used to give texture to the sphere has been pre-calculated so that once mapped it produces a realistic image of the earth.</p>
<p>Ok, so on with the example code. As usual this is built on the previous example and there are not too many differences. We&#8217;ll go into more detail on what&#8217;s changed later. The code produces five primitives, all rotating about the origin and each one rotating about its individual y-axis.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.Camera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.math.Number3D;
&nbsp; import away3d.core.utils.Cast;
&nbsp; import away3d.materials.BitmapMaterial;
&nbsp; import away3d.materials.TransformBitmapMaterial;
&nbsp; import away3d.primitives.Cube;
&nbsp; import away3d.primitives.Cylinder;
&nbsp; import away3d.primitives.Sphere;
&nbsp; import away3d.primitives.Torus;
&nbsp;
&nbsp; import flash.display.Bitmap;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example003 extends Sprite {

&nbsp; &nbsp; [Embed(source="/../assets/earth.jpg")] private var EarthImage:Class;
&nbsp; &nbsp; private var earthBitmap:Bitmap = new EarthImage();

&nbsp; &nbsp; [Embed(source="/../assets/away3D.png")] private var Away3DImage:Class;
&nbsp; &nbsp; private var away3DBitmap:Bitmap = new Away3DImage();

&nbsp; &nbsp; [Embed(source="/../assets/checker.jpg")] private var CheckerImage:Class;
&nbsp; &nbsp; private var checkerBitmap:Bitmap = new CheckerImage();

&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 150;

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:Camera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp; &nbsp; private var group:ObjectContainer3D;
&nbsp; &nbsp; private var sphere:Sphere;
&nbsp; &nbsp; private var cube:Cube;
&nbsp; &nbsp; private var centerCube:Cube;
&nbsp; &nbsp; private var cylinder:Cylinder;
&nbsp; &nbsp; private var torus:Torus;
&nbsp; &nbsp;
&nbsp; &nbsp; public function Example003() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:25, focus:30, x:-200, y:400, z:-400});
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new sphere object using a bitmap material representing the earth
&nbsp; &nbsp; &nbsp; var earthMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(earthBitmap));
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:earthMaterial, radius:50, segmentsW:10, segmentsH:10});
&nbsp; &nbsp; &nbsp; sphere.x = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);

&nbsp; &nbsp; &nbsp; // Create a new cube object using a tiled bitmap material
&nbsp; &nbsp; &nbsp; var tiledAway3DMaterial:TransformBitmapMaterial = new TransformBitmapMaterial(Cast.bitmap(away3DBitmap), {repeat:true, scaleX:.5, scaleY:.5});
&nbsp; &nbsp; &nbsp; cube = new Cube({material:tiledAway3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; cube.z = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cube);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a cylinder mapping the earth data again
&nbsp; &nbsp; &nbsp; cylinder = new Cylinder({material:earthMaterial, radius:25, height:100, segmentsW:16});
&nbsp; &nbsp; &nbsp; cylinder.x = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cylinder);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a torus object and use a checkered bitmap material
&nbsp; &nbsp; &nbsp; var checkerBitmapMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(checkerBitmap));
&nbsp; &nbsp; &nbsp; torus = new Torus({material:checkerBitmapMaterial, radius:40, tube:10, segmentsT:8, segmentsR:16});
&nbsp; &nbsp; &nbsp; torus.z = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(torus);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a new cube object using a smoothed, precise bitmap material
&nbsp; &nbsp; &nbsp; var away3DMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(away3DBitmap), {smooth:true, precision:2});
&nbsp; &nbsp; &nbsp; centerCube = new Cube({material:away3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; group.addChild(centerCube);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; sphere.yaw(-4);
&nbsp; &nbsp; &nbsp; cube.yaw(-4);
&nbsp; &nbsp; &nbsp; cylinder.yaw(-4);
&nbsp; &nbsp; &nbsp; torus.yaw(-4);

&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>Copy the code above and compile it within Flex Builder 3 or Eclipse. The images I used are shown below - click on them and save them if you want to use the same ones.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/away3d.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/away3d-150x150.png" alt="" title="" margin="10" width="150" height="150" class="alignnone size-thumbnail wp-image-205" /></a> <a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/checker.jpg"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/checker-150x150.jpg" alt="" title="" width="150" height="150" class="alignnone size-thumbnail wp-image-206" /></a> <a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/earth.jpg"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/earth-150x150.jpg" alt="" title="" width="150" height="150" class="alignnone size-thumbnail wp-image-207" /></a></p>
<p>Click on the image below to see the resulting flash movie. The images are embedded in the movie making it larger than the previous examples so it could take a couple of seconds to load.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example003.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/example003.png" border="0" /></a></p>
<p>The code follows the same style as the previous examples: initialisation of 3D elements, creation of scene and rendering loop. As usual I&#8217;ll just concentrate on what&#8217;s new.</p>
<p>Not really related to Away3D but important for projects (in Flex) using images is the ability to embed images in the compiled movie. As you can see the images are embedded in the class definition.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; [Embed(source="/../assets/earth.jpg")] private var EarthImage:Class;
&nbsp; &nbsp; private var earthBitmap:Bitmap = new EarthImage();

&nbsp; &nbsp; [Embed(source="/../assets/away3D.png")] private var Away3DImage:Class;
&nbsp; &nbsp; private var away3DBitmap:Bitmap = new Away3DImage();

&nbsp; &nbsp; [Embed(source="/../assets/checker.jpg")] private var CheckerImage:Class;
&nbsp; &nbsp; private var checkerBitmap:Bitmap = new CheckerImage();
</blockquote>
</pre>
</div>
<p>Using the <em>Embed</em> meta-tag we can add binary object to the compiled movie. These can then be converted into usable graphic elements, as shown above for a <em>Bitmap</em>. As with the <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6-texture-mapping/">same example in Papervision3D</a>, I&#8217;m not going to go into detail of embedding objects here, rather I&#8217;ll leave you with these couple of references that are very useful. The first one is at at <a href="http://www.asserttrue.com/articles/2006/04/18/library-type-assets-in-actionscript-3-0-using-the-embed-metatdata-tag">assertTrue</a> and the second is from the <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=embed_4.html">Flex livedocs</a>. </p>
<p>You&#8217;ll note that the source is <em>&#8220;../assets&#8221;</em>. This is because I have my <em>assets</em> folder at the same level as the <em>src</em> folder - when the Actionscript is compiled, the root folder is the <em>src</em> folder. If you want to compile the above source then simply create an <em>assets</em> folder and put the image files in it.</p>
<p>Now that we have embedded the images and obtained bitmap data we can start to create texture mapped materials. This is done in <em>createScene</em> where some different methods of creating different textures is examined.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new sphere object using a bitmap material representing the earth
&nbsp; &nbsp; &nbsp; var earthMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(earthBitmap));
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:earthMaterial, radius:50, segmentsW:10, segmentsH:10});
&nbsp; &nbsp; &nbsp; sphere.x = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);

&nbsp; &nbsp; &nbsp; // Create a new cube object using a tiled bitmap material
&nbsp; &nbsp; &nbsp; var tiledAway3DMaterial:TransformBitmapMaterial = new TransformBitmapMaterial(Cast.bitmap(away3DBitmap), {repeat:true, scaleX:.5, scaleY:.5});
&nbsp; &nbsp; &nbsp; cube = new Cube({material:tiledAway3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; cube.z = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cube);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a cylinder mapping the earth data again
&nbsp; &nbsp; &nbsp; cylinder = new Cylinder({material:earthMaterial, radius:25, height:100, segmentsW:16});
&nbsp; &nbsp; &nbsp; cylinder.x = -ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(cylinder);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a torus object and use a checkered bitmap material
&nbsp; &nbsp; &nbsp; var checkerBitmapMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(checkerBitmap));
&nbsp; &nbsp; &nbsp; torus = new Torus({material:checkerBitmapMaterial, radius:40, tube:10, segmentsT:8, segmentsR:16});
&nbsp; &nbsp; &nbsp; torus.z = ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; group.addChild(torus);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a new cube object using a smoothed, precise bitmap material
&nbsp; &nbsp; &nbsp; var away3DMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(away3DBitmap), {smooth:true, precision:2});
&nbsp; &nbsp; &nbsp; centerCube = new Cube({material:away3DMaterial, width:75, height:75, depth:75});
&nbsp; &nbsp; &nbsp; group.addChild(centerCube);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see, the creation of the 3D objects is very simple: just create a new primitive, pass it some initialisation arguments and create a new material for it. Of course, compared the previous example, the materials are now texture mapped. Two different materials are used in this example: the <em>BitmapMaterial</em> for simple texture mapping and <em>TransformBitmapMaterial</em> which gives us more options.</p>
<p>Starting with the <em>Sphere</em>, we use a simple <em>BitmapMaterial</em> and pass it bitmap data. The class <em>Cast</em> in Away3D provides useful transformation routines - in this case to return the <em>BitmapData</em> of the <em>Bitmap</em> object.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; var earthMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(earthBitmap));
</blockquote>
</pre>
</div>
<p>The <em>Sphere</em> is then created using this material. All <em>uv</em> mapping is handled by the <em>Sphere</em> itself to render the image over the sphere triangles.</p>
<p>The next object is a <em>Cube</em>. Here I want to illustrate how to <em>tile</em> images over an object. Tiling allows us to repeat an image over a surface, for example imagine a scene with a grassy plain with the same grass image repeated a number of times. This allows us to keep the image size reasonable and have a texture mapped object that isn&#8217;t too pixelated. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; var tiledAway3DMaterial:TransformBitmapMaterial = new TransformBitmapMaterial(Cast.bitmap(away3DBitmap), {repeat:true, scaleX:.5, scaleY:.5});
</blockquote>
</pre>
</div>
<p>To tile bitmap we need to use the <em>TransformBitmapMaterial</em> class. With this we can manipulate the image data, for example, here we scale it to half its size and indicate that it should be repeated. Scaling here implies that the maximum <em>u</em> and <em>v</em> coordinates of the texture become 0.5 rather than 1 hence we should see a two-by-two image drawn on each face of the cube. If the <em>repeat:true</em> initialisation parameter is skipped then the image is drawn only once&#8230; try recompiling without this to see the result.</p>
<p>The <em>Cylinder</em> and <em>Torus</em> objects use simple <em>BitmapMaterial</em>s again just to show how the bitmaps are mapped to these primitives.</p>
<p>Finally the cube in the center shows an example of a texture map using a smoothed image and uses more precise perspective calculations when rendered. This link for <a href="http://en.wikipedia.org/wiki/Texture_mapping">texture mapping</a> shows what happens for <em>affine</em> texture mapping: Away3D (as for Papervision3D) tries to optimise the calculation for rendering textures and this can result in a distorted image. You can see this in the above example for the tiled cube where the black lines appear to be wavy. The distortion can, however, be corrected but of course this produces a more cpu-intensive calculation.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; var away3DMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap(away3DBitmap), {smooth:true, precision:2});
</blockquote>
</pre>
</div>
<p>For the central cube we set <em>smooth:true</em> to have a less pixelated texture and we set <em>precision:2</em> to indicate that the texture should be correctly rendered to within 2 pixels. A value of 0 turns off the precision calculation.</p>
<p>As an alternative to using more precise rendering of a texture we can also increase the number of triangles used so that the distortion becomes less evident. You can check out this <a href="http://www.papervision3d.org/demos/LinearMapping/">example for Papervision3D</a> that illustrates the result. Of course, increasing the number of triangles increases the render time but within limits it can produce a visually acceptable rendering quicker than a single precise texture mapping.</p>
<p>So that&#8217;s it for texture mapping at its simplest! As you can see there&#8217;s nothing too complicated in adding bitmaps to 3D objects but bear in mind that it is obviously more cpu-intensive that simple coloured objects. As with the previous articles I&#8217;d recommend having a look at the Away3D source - you&#8217;ll see that there are a lot of different types of materials in the <em>away3D.materials</em> package including the <em>BitmapFileMaterial</em> which loads an image from a URL, rather than embedding it in the movie. Anyway, hope this has been of use. As always, questions and comments are welcome! </p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-4-scene-interaction/">First steps in Away3D : Part 4 - Scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/sVzzyiV_fyA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 2 - Animation</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/67wDI0Vea84/</link>
		<comments>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 13:10:57 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[animation]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=196</guid>
		<description><![CDATA[Following from my previous post, I&#8217;d like to make the scene a bit more interesting by adding some animation. As you&#8217;ll see, not many modifications to the code are necessary. As with Part 1, I&#8217;m basing this example on a previous Papervision3D example that you can find in First steps in Papervision3D : Part 3.
Previous [...]]]></description>
			<content:encoded><![CDATA[<p>Following from my previous post, I&#8217;d like to make the scene a bit more interesting by adding some animation. As you&#8217;ll see, not many modifications to the code are necessary. As with Part 1, I&#8217;m basing this example on a previous Papervision3D example that you can find in <a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-3-animation/">First steps in Papervision3D : Part 3</a>.</p>
<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/">First steps in Away3D : Part 1 - Getting started</a><br />
Creation of a new Away3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Away3D classes.</li>
</ul>
<p>Using the same objects as before (a <em>Sphere</em> and <em>LineSegments</em> displaying the x, y and z axes), my objective is to rotate all of them about the origin and individually rotate the sphere. Rotation in Away3D is very easy to achieve. These objects inherit from a base class called <em>Object3D</em> as do all 3D object displayed in a <em>Scene</em> in Away3D. This class provides a number of useful functions to rotate, translate and scale an object. The simplest way to rotate an object is to use the <em>pitch</em>, <em>yaw</em> and <em>roll</em> functions which rotate an object about its local x, y and z axes respectively.</p>
<p>So, lets dive right in and take a look at the code. As I mentioned before, this is based on the previous example and very little modifications have been made. As before I&#8217;m using eclipse with the Flex Builder 3 plugin to compile the examples: take a look at my previous post if you&#8217;re new to eclipse and want to see how to set up the projects. Otherwise, create a new ActionScript class, call it <em>Example002</em> and cut and paste the following code.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.Camera3D;
&nbsp; import away3d.containers.ObjectContainer3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.base.Vertex;
&nbsp; import away3d.core.math.Number3D;
&nbsp; import away3d.materials.WireColorMaterial;
&nbsp; import away3d.materials.WireframeMaterial;
&nbsp; import away3d.primitives.LineSegment;
&nbsp; import away3d.primitives.Sphere;
&nbsp;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example002 extends Sprite {

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:Camera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp; &nbsp; private var group:ObjectContainer3D;
&nbsp; &nbsp; private var sphere:Sphere;
&nbsp; &nbsp;
&nbsp; &nbsp; public function Example002() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;

&nbsp; &nbsp; &nbsp; // Add resize event listener
&nbsp; &nbsp; &nbsp; stage.addEventListener(Event.RESIZE, onResize);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise frame-enter loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:15, focus:30, x:100, y:300, z:-200});
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new sphere object using a wirecolor material
&nbsp; &nbsp; &nbsp; var sphereMaterial:WireColorMaterial = new WireColorMaterial(0x5500FF, {wirecolor:0xFF9900});
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:sphereMaterial, radius:50, segmentsW:10, segmentsH:10});

&nbsp; &nbsp; &nbsp; // Position the sphere and add it to the group
&nbsp; &nbsp; &nbsp; sphere.x = -100;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a origin vertex
&nbsp; &nbsp; &nbsp; var origin:Vertex = new Vertex(0, 0, 0);

&nbsp; &nbsp; &nbsp; // Create the red-coloured x-axis with a width of 2 and add it to the group
&nbsp; &nbsp; &nbsp; var xAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0xFF0000, {width:2})});
&nbsp; &nbsp; &nbsp; xAxis.start = origin;
&nbsp; &nbsp; &nbsp; xAxis.end = new Vertex(100, 0, 0);
&nbsp; &nbsp; &nbsp; group.addChild(xAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the green-coloured y-axis with a width of 2 and add it to the group
&nbsp; &nbsp; &nbsp; var yAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x00FF00, {width:2})});
&nbsp; &nbsp; &nbsp; yAxis.start = origin;
&nbsp; &nbsp; &nbsp; yAxis.end = new Vertex(0, 100, 0);
&nbsp; &nbsp; &nbsp; group.addChild(yAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the blue-coloured z-axis with a width of 2 and add it to the group
&nbsp; &nbsp; &nbsp; var zAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x0000FF, {width:2})});
&nbsp; &nbsp; &nbsp; zAxis.start = origin;
&nbsp; &nbsp; &nbsp; zAxis.end = new Vertex(0, 0, 100);
&nbsp; &nbsp; &nbsp; group.addChild(zAxis);
&nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(5);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the sphere
&nbsp; &nbsp; &nbsp; sphere.yaw(-10);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>This should produce a scene that is rotated about the y-axis with a sphere that rotates in the opposite direction, also about its y-axis. Click on the image below to see the final result.</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example002.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/example002.png" border="0" /></a></p>
<p>As always, lets take a look at the code in more detail. Since there are so many similarities with the previous example I won&#8217;t go into detail for everything, just what is new.</p>
<p>Starting with the constructor, you&#8217;ll notice that I&#8217;ve added a resize listener that calls the method <em>onResize</em>. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function onResize(event:Event):void {
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
&nbsp; &nbsp; }
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>This is used to ensure that if a user resizes the browser or flash player that the <em>View</em> is automatically resized to take up the full stage area. Its not really much of a 3D element of the scene but its important not to forget it!</p>
<p>The rest of the code takes the same form as before: initialise the 3D elements, create the scene and re-render the scene at every new frame. As you&#8217;ll see in <em>init3D</em> I&#8217;ve modified the camera slightly.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:15, focus:30, x:100, y:300, z:-200});
&nbsp; &nbsp; &nbsp; camera.lookAt(new Number3D(0, 0, 0));
</blockquote>
</pre>
</div>
<p>The camera is now in a different position, but more importantly I&#8217;ve added a call to <em>camera.lookAt</em>. Previously the camera was looking directly along the z-axis: now I&#8217;ve told it to look at the origin. You can similarly call the functions <em>tilt</em> and <em>pan</em> which (as it says in the code comments for the <em>Camera3D</em> class) is like someone nodding and shaking their head.</p>
<p>Moving on to the scene creation in <em>createScene</em>, I&#8217;ve introduced a new element used to group the objects: an <em>ObjectContainer3D</em>. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create an object container to group the objects on the scene
&nbsp; &nbsp; &nbsp; group = new ObjectContainer3D();
&nbsp; &nbsp; &nbsp; scene.addChild(group);
</blockquote>
</pre>
</div>
<p>This object is not itself visible on the scene but allows us to add children to it and translate, rotate and scale these children all together. So, rather than adding each individual object to the <em>scene</em>, they are now added to the <em>group</em> as is, for example, the sphere.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // Create a new sphere object using a wirecolor material
&nbsp; &nbsp; &nbsp; var sphereMaterial:WireColorMaterial = new WireColorMaterial(0x5500FF, {wirecolor:0xFF9900});
&nbsp; &nbsp; &nbsp; sphere = new Sphere({material:sphereMaterial, radius:50, segmentsW:10, segmentsH:10});

&nbsp; &nbsp; &nbsp; // Position the sphere and add it to the group
&nbsp; &nbsp; &nbsp; sphere.x = -100;
&nbsp; &nbsp; &nbsp; group.addChild(sphere);
&nbsp;
</blockquote>
</pre>
</div>
<p>The lines are similarly added to the <em>group</em>. So that&#8217;s the only difference to the scene creation itself (other than the sphere now being a different colour). Now we come to adding the animation.</p>
<p>To add animation we simply need to modify object parameters at each frame and then re-render the scene. As I mentioned before I simple rotate the <em>ObjectContainer3D</em> and the <em>Sphere</em> itself and this is done in the <em>loop</em> function that is called at the start of every new frame.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; group.yaw(5);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the sphere
&nbsp; &nbsp; &nbsp; sphere.yaw(-10);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see there&#8217;s really not much to it: simple rotate the group about its y axis, and the same for the sphere itself. The call the <em>view.render</em> then updates what we see on the screen.</p>
<p>And that&#8217;s it! To get a feel for the animation, try changing the yaw method to roll or pitch, or try adding some translation. I&#8217;d recommend having a look at the Away3D code to see what else is available - you&#8217;ll find that there are a lot of possibilities! Anyway, I hope this has been a useful step in making more interesting 3D scenes in Away3D!</p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-3-texture-mapping/">First steps in Away3D : Part 3 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/67wDI0Vea84" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - dEUS</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/49oV49KYj_w/</link>
		<comments>http://blog.tartiflop.com/2008/11/musical-interlude-deus/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 21:02:20 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=189</guid>
		<description><![CDATA[Discover dEUS!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1088047&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1088047&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/deus.html'>dEUS</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/49oV49KYj_w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/musical-interlude-deus/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/musical-interlude-deus/</feedburner:origLink></item>
		<item>
		<title>First steps in Away3D : Part 1 - Getting started</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/ZVafVwYqo5E/</link>
		<comments>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 19:53:53 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[eclipse]]></category>

		<category><![CDATA[Flex Builder 3]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=177</guid>
		<description><![CDATA[In the same spirit as the First steps in Papervision3D series of articles, I&#8217;m documenting my own progress in learning about this 3D engine for Flash. I hope as well that this provides a useful tutorial for others getting started with Away3D. I guess what I&#8217;m trying to say is that this is by no [...]]]></description>
			<content:encoded><![CDATA[<p>In the same spirit as the <a href="http://blog.tartiflop.com/first-steps-in-papervision3d/"><em>First steps in Papervision3D</em></a> series of articles, I&#8217;m documenting my own progress in learning about this 3D engine for Flash. I hope as well that this provides a useful tutorial for others getting started with Away3D. I guess what I&#8217;m trying to say is that this is by no means a definitive guide to Away3D! This is my first day as well so if you find mistakes or have suggestions then please let me know!</p>
<p>Before starting I&#8217;d like to post a couple of links to a series of articles that I found very interesting and useful for beginners learning the basics of 3D programming. The first one one, <a href="http://www.flashmagazine.com/Tutorials/detail/flash_3d_basics/">Flash 3D Basics</a>, provides a very good overview of the important elements for any 3D development. The second one is aimed directly at Away3D, but is relevant also to Papervision3D, and discusses the two main classes for any Away3D flash movie: <a href="http://www.flashmagazine.com/Tutorials/detail/away3d_basics_the_view_and_the_scene/">The View and The Scene</a>. You&#8217;ll see both of these being used below. Anyway, I&#8217;d really recommend taking a look at them.</p>
<p>For this post I&#8217;m really starting at the very beginning. My aim is simply to draw 3D shapes on the screen, exactly as I did for <a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-1/"><em>First steps in Papervision3D : Part 1</em></a>. For this I&#8217;m assuming that you are using Flex Builder 3, or the Flex Builder 3 plugin for eclipse, as I am. I&#8217;m also assuming that you have Away3D built and ready to link to. My previous article on <a href="http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/">downloading and installing Away3D in eclipse</a> might help if this isn&#8217;t the case.</p>
<p>For those of you who are new to using Flex Builder 3, we need to first of all create a new project and then set it&#8217;s build path to that of the Away3D source.</p>
<p>In eclipse (or Flex Builder 3), from the <em>File</em> menu, select <em>New</em> and then <em>ActionScript project</em>. You&#8217;ll see a <em>New ActionScript Project</em> window appear.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-13.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-13-300x287.png" alt="" title="" width="300" height="287" class="aligncenter size-medium wp-image-178" /></a></p>
<p>Type in a project name (for example I named it <em>Tartiflop</em>) and click on <em>Finish</em>. We then need to configure the project to use either the <em>Away3D.swf</em> library that I showed how to create before, or we link directly to the Away3D source. I prefer the second method simply because it gives me a more convenient access to the library source by navigating within eclipse. To do this, select the new project and right-click. Select <em>Properties</em> from the drop-down menu. Select the <em>ActionScript Build Path</em> on the left.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-14.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-14-292x300.png" alt="" title="" width="292" height="300" class="aligncenter size-medium wp-image-179" /></a></p>
<p>Select the <em>Library path</em> tab and click on <em>Add Project&#8230;</em>.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-15.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-15-300x274.png" alt="" title="" width="300" height="274" class="aligncenter size-medium wp-image-180" /></a></p>
<p>Select the <em>Away3D</em> Flex Library project and click on OK. You&#8217;ll see that the library has now been added into the list of build path libraries.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-13.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-13-300x287.png" alt="" title="" width="300" height="287" class="aligncenter size-medium wp-image-178" /></a></p>
<p>We&#8217;re now ready to start creating our first Away3D flash movie! You&#8217;ll notice that the new project wizard of eclipse has automatically created an ActionScript class called <em>Tartiflop.as</em>. We don&#8217;t need this so you can delete it. For this post the class is called <em>Example001.as</em> so you&#8217;ll need to create a new ActionScript. Right-click on <em>src</em> in the <em>Tartiflop</em> project in the <em>Flex Navigator</em> tree. Select <em>New</em> and then <em>ActionScript Class</em>. Name the new class <em>Example001</em> and click <em>Finish</em>.</p>
<p>The following code draws a sphere and three lines showing the <em>x</em>, <em>y</em> and <em>z</em> axes. Cut and paste the code below (we&#8217;ll go into the details of how it works later), save and it should hopefully compile without any errors! </p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp; import away3d.cameras.Camera3D;
&nbsp; import away3d.containers.Scene3D;
&nbsp; import away3d.containers.View3D;
&nbsp; import away3d.core.base.Vertex;
&nbsp; import away3d.materials.WireColorMaterial;
&nbsp; import away3d.materials.WireframeMaterial;
&nbsp; import away3d.primitives.LineSegment;
&nbsp; import away3d.primitives.Sphere;
&nbsp;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.display.StageAlign;
&nbsp; import flash.display.StageScaleMode;
&nbsp; import flash.events.Event;
&nbsp;
&nbsp; [SWF(backgroundColor="#000000")]
&nbsp;
&nbsp; public class Example001 extends Sprite {

&nbsp; &nbsp; private var scene:Scene3D;
&nbsp; &nbsp; private var camera:Camera3D;
&nbsp; &nbsp; private var view:View3D;
&nbsp;
&nbsp;
&nbsp; &nbsp; public function Example001() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Event loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);&nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:20, focus:30, x:-100, y:-100, z:-500});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // First object : a sphere
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new material for the sphere : simple white wireframe
&nbsp; &nbsp; &nbsp; var sphereMaterial:WireColorMaterial = new WireColorMaterial(0x000000, {wirecolor:0xFFFFFF});

&nbsp; &nbsp; &nbsp; // Create a new sphere object using wireframe material, radius 50 with
&nbsp; &nbsp; &nbsp; //   10 horizontal and vertical segments
&nbsp; &nbsp; &nbsp; var sphere:Sphere = new Sphere({material:sphereMaterial, radius:50, segmentsW:10, segmentsH:10});

&nbsp; &nbsp; &nbsp; // Position the sphere (default = [0, 0, 0])
&nbsp; &nbsp; &nbsp; sphere.x = -100;
&nbsp; &nbsp; &nbsp; scene.addChild(sphere);
&nbsp;
&nbsp; &nbsp; &nbsp; // Second object : x-, y- and z-axis
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a origin vertex
&nbsp; &nbsp; &nbsp; var origin:Vertex = new Vertex(0, 0, 0);

&nbsp; &nbsp; &nbsp; // Create the red-coloured x-axis with a width of 2
&nbsp; &nbsp; &nbsp; var xAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0xFF0000, {width:2})});
&nbsp; &nbsp; &nbsp; xAxis.start = origin;
&nbsp; &nbsp; &nbsp; xAxis.end = new Vertex(100, 0, 0);
&nbsp; &nbsp; &nbsp; scene.addChild(xAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the green-coloured y-axis with a width of 2
&nbsp; &nbsp; &nbsp; var yAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x00FF00, {width:2})});
&nbsp; &nbsp; &nbsp; yAxis.start = origin;
&nbsp; &nbsp; &nbsp; yAxis.end = new Vertex(0, 100, 0);
&nbsp; &nbsp; &nbsp; scene.addChild(yAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the blue-coloured z-axis with a width of 2
&nbsp; &nbsp; &nbsp; var zAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x0000FF, {width:2})});
&nbsp; &nbsp; &nbsp; zAxis.start = origin;
&nbsp; &nbsp; &nbsp; zAxis.end = new Vertex(0, 0, 100);
&nbsp; &nbsp; &nbsp; scene.addChild(zAxis);
&nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }

&nbsp; }
}
</blockquote>
</pre>
</div>
<p>To see the final result, right-click again on the <em>Tartiflop</em> project and select <em>Run As</em> and <em>Flex Application</em>. What you should see is the following: click on the image below to see the real flash movie (its not much more interesting than the image though!).</p>
<p><a href="http://www.tartiflop.com/away3d/FirstSteps/Example001.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-17.png" border="0" /></a></p>
<p>Let&#8217;s go into more detail with the code. I&#8217;m taking a look at this with the point of view of someone who has been using Papervision3D and its interesting to look at the similarities and differences between the two libraries. If you compare the code to the <a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-1/">equivalent in Papervision3D</a>, you can see that the codes resemble a lot.</p>
<p>The constructor of <em>Example001</em> is identical to that of the equivalent example in Paperivision3D: the stage parameters are set so that the scene is scaled correctly, the 3D elements are initialised, the scene is created and then we add a <em>frame-enter</em> event listener. </p>
<p><em>Example001</em> inherits from the <em>Sprite</em> class as is indeed possible with Papervision3D. Papervision3D however provides a <em>BasicView</em> class where the scene, camera, view and renderer are all encapsulated (see <a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-2/">part 2 of the Papervision3D series</a> for example). Also the stage scaling is automatically encapsulated in the <em>BasicView</em> class.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; public function Example001() {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up the stage
&nbsp; &nbsp; &nbsp; stage.align = StageAlign.TOP_LEFT;
&nbsp; &nbsp; &nbsp; stage.scaleMode = StageScaleMode.NO_SCALE;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Event loop
&nbsp; &nbsp; &nbsp; this.addEventListener(Event.ENTER_FRAME, loop);&nbsp; &nbsp;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>However, as we can see, its not very complicated to initialise all the 3D elements individually - as we do in the <em>init3D()</em> function. </p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function init3D():void {

&nbsp; &nbsp; &nbsp; // Create a new scene where all the 3D object will be rendered
&nbsp; &nbsp; &nbsp; scene = new Scene3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new camera, passing some initialisation parameters
&nbsp; &nbsp; &nbsp; camera = new Camera3D({zoom:20, focus:30, x:-100, y:-100, z:-500});
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new view that encapsulates the scene and the camera
&nbsp; &nbsp; &nbsp; view = new View3D({scene:scene, camera:camera});

&nbsp; &nbsp; &nbsp; // center the viewport to the middle of the stage
&nbsp; &nbsp; &nbsp; view.x = stage.stageWidth / 2;
&nbsp; &nbsp; &nbsp; view.y = stage.stageHeight / 2;
   &nbsp; &nbsp; &nbsp; addChild(view);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>We first of all create a <em>Scene3D</em> object which is used later to contain all of our rendered 3D elements. Secondly we create a <em>Camera3D</em> which sets up all our viewing parameters and finally we create a <em>View3D</em> object which provides us with our <em>window</em> through which we observe the scene.</p>
<p>Interesting to note is the way we can create Away3D objects. Unlike Papervsion3D which has <em>well defined</em> constructors taking specific arguments, Away3D allows us to pass an array of initialisation parameters. One good point is that this makes the code more concise, however, personally, I feel that it is less intuitive: with Papervision3D I felt I could determine relatively quickly what was needed to construct an object but here you need to search more within a class to obtain useful information. Having said that I have to admit that I haven&#8217;t yet looked at the Away3D documentation! I&#8217;m someone who is too excited to get his hands dirty before reading the manual!</p>
<p>With respect to the camera, unlike Papervision3D it is not possible to modify the <em>field of view</em> (or <em>fov</em>) directly and instead we need to manipulate the <em>zoom</em> and <em>focus</em> of the camera (see my post on the <a href="http://blog.tartiflop.com/2008/08/understanding-zoom-focus-and-field-of-view-in-papervision3d/">relationship between all three</a> and also this really good article explaining the <a href="http://www.flashmagazine.com/tutorials/detail/away3d_basics_the_cameras/">Away3D camera</a>). Having an OpenGL background I find the field of view more intuitive however this is just a personal opinion.</p>
<p>After the 3D base elements have been created we can move on to creating the scene. This, as is fairly obvious, is done in the <em>createScene()</em> function.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // First object : a sphere
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new material for the sphere : simple white wireframe
&nbsp; &nbsp; &nbsp; var sphereMaterial:WireColorMaterial = new WireColorMaterial(0x000000, {wirecolor:0xFFFFFF});

&nbsp; &nbsp; &nbsp; // Create a new sphere object using wireframe material, radius 50 with
&nbsp; &nbsp; &nbsp; //   10 horizontal and vertical segments
&nbsp; &nbsp; &nbsp; var sphere:Sphere = new Sphere({material:sphereMaterial, radius:50, segmentsW:10, segmentsH:10});

&nbsp; &nbsp; &nbsp; // Position the sphere (default = [0, 0, 0])
&nbsp; &nbsp; &nbsp; sphere.x = -100;
&nbsp; &nbsp; &nbsp; scene.addChild(sphere);
&nbsp;
&nbsp; &nbsp; &nbsp; // Second object : x-, y- and z-axis
&nbsp;
&nbsp; &nbsp; &nbsp; // Create a origin vertex
&nbsp; &nbsp; &nbsp; var origin:Vertex = new Vertex(0, 0, 0);

&nbsp; &nbsp; &nbsp; // Create the red-coloured x-axis with a width of 2
&nbsp; &nbsp; &nbsp; var xAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0xFF0000, {width:2})});
&nbsp; &nbsp; &nbsp; xAxis.start = origin;
&nbsp; &nbsp; &nbsp; xAxis.end = new Vertex(100, 0, 0);
&nbsp; &nbsp; &nbsp; scene.addChild(xAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the green-coloured y-axis with a width of 2
&nbsp; &nbsp; &nbsp; var yAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x00FF00, {width:2})});
&nbsp; &nbsp; &nbsp; yAxis.start = origin;
&nbsp; &nbsp; &nbsp; yAxis.end = new Vertex(0, 100, 0);
&nbsp; &nbsp; &nbsp; scene.addChild(yAxis);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the blue-coloured z-axis with a width of 2
&nbsp; &nbsp; &nbsp; var zAxis:LineSegment = new LineSegment({material:new WireframeMaterial(0x0000FF, {width:2})});
&nbsp; &nbsp; &nbsp; zAxis.start = origin;
&nbsp; &nbsp; &nbsp; zAxis.end = new Vertex(0, 0, 100);
&nbsp; &nbsp; &nbsp; scene.addChild(zAxis);
&nbsp;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>The scene is very simple: no lighting and just two stationary types of objects. As with Papervision3D, most objects provide only the vertices of a given shape: the rendering (what we see on the screen) is done through the <em>material</em>.</p>
<p>In this example we use two types of materials for two different types of shapes. This is different to Papervision3D where any material seems to be usable with any object. Here, the two shapes belong to two different families: an <em>AbstractPrimitive</em> and an <em>AbstractWirePrimitive</em>. Each one uses a material also belonging to a different family: an <em>ITriangleMaterial</em> and an <em>ISegmentMaterial</em> respectively. If we give the wrong type of material to a particular primitive then it is not rendered.</p>
<p>The two shapes used are a <em>Sphere</em> (an <em>AbstractPrimitive</em>) and a <em>LineSegment</em> (an <em>AbstractWirePrimitive</em>). We therefore give them two different types of materials. In this example I&#8217;ve used a <em>WireColorMaterial</em> and a <em>WireframeMaterial</em> respectively. The <em>WireColorMaterial</em> is created with a face color (black in this case) and a wire color is passed in the list of initialisation arguments (being white). The wireframe material is simply white but I&#8217;ve passed a width of 2 in the initialisation parameters.</p>
<p>The sphere is created first, taking a list of initialisation parameters including the sphere material. It should be noted that these parameters can be set afterwards, not necessarily in the constructor. I then create 3 lines for each axis, each one with a different color wireframe material. The lines are then given two vertices to define their start and end positions. Each 3D object is added to the <em>scene</em> so that they are rendered.</p>
<p>As a first impression of Away3D, I actually find that the construction of these primitive objects is more concise than for Papervision3D. Looking through the source directory of Away3D I also get the impression that there is more choice of primitives compared to Papervision3D.</p>
<p>Finally for this example, a small function is used to render the scene. We added in the constructor a frame-enter event listener called <em>loop</em>.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; private function loop(event:Event):void {
&nbsp; &nbsp; &nbsp; // Render the 3D scene
&nbsp; &nbsp; &nbsp; view.render();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Very simply, we call the function <em>render</em> of view to redraw the scene. This is another difference to Papervision3D: Papervision3D has a specific <em>Renderer</em> class used to draw the scene.</p>
<p>And that&#8217;s it! A very simple example of rendering a 3D scene in Away3D. Compared to Papervision3D, for something this simple, there really isn&#8217;t a huge difference. Overall I feel that Away3D is more concise but maybe loses degree of simplicity using the parameters array rather than having explicit constructor arguments&#8230; but that&#8217;s just a personal point of view though.</p>
<p>One surprise is the difference in file sizes between Papervision3D and Away3D. In Away3D the flash animation come to 136KB whereas in Papervision3D its at only 82KB. Okay, so neither are huge and maybe Away3D is a bigger library&#8230; but I&#8217;m interested to see how this compares for more complex examples.</p>
<p>Anyway, that&#8217;s it for this example. For me too its a <em>first step</em> - I just wanted to see what the Away3D library was like and how easy it was to convert from a Papervision3D source to an Away3D one. I hope to continue along the same theme to produce more complex examples over the coming weeks. As always, comments and suggestions as are always welcome so please don&#8217;t hesitate!</p>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-2-animation/">First steps in Away3D : Part 2 - animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/ZVafVwYqo5E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/first-steps-in-away3d-part-1-getting-started/</feedburner:origLink></item>
		<item>
		<title>Downloading and compiling Away3D sources with SVN in Eclipse</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/suwEISQQ-AY/</link>
		<comments>http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 14:29:42 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Flex]]></category>

		<category><![CDATA[eclipse]]></category>

		<category><![CDATA[Flex Builder 3]]></category>

		<category><![CDATA[SVN]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=157</guid>
		<description><![CDATA[Away3D can be installed either from the latest releases on the Away3D downloads page or from the SVN repository located on the googlecode site.
I&#8217;ve chosen the second method so that I can easily and regularly update the source to be up to date with the latest fixes and enhancements. I&#8217;m using the same technique that [...]]]></description>
			<content:encoded><![CDATA[<p>Away3D can be installed either from the latest releases on the <a href="http://away3d.com/downloads">Away3D downloads page</a> or from the SVN repository located on the <a href="http://code.google.com/p/away3d/">googlecode</a> site.</p>
<p>I&#8217;ve chosen the second method so that I can easily and regularly update the source to be up to date with the latest fixes and enhancements. I&#8217;m using the same technique that I showed <a href="http://blog.tartiflop.com/2008/07/downloading-and-compiling-papervision3d-v20-great-white-sources-with-svn-in-eclipse/">downloading and compiling Papervision3D using SVN in eclipse</a>. Since I use eclipse as my development environment (with the Flex Builder 3 plugin), I like to keep all my sources together in the same environment and the <a href="http://blog.tartiflop.com/2008/07/installing-subversion-svn-plugin-for-eclipse/">SVN plugin for eclipse</a> works very well.</p>
<p>In eclipse select <em>Import&#8230;</em> from the <em>File</em> menu. You&#8217;ll see the following window appear.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-1.png"><img class="aligncenter size-medium wp-image-158" src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-1-255x300.png" alt="" width="255" height="300" /></a></p>
<p>Under the <em>SVN</em> item, select <em>Projects from SVN</em> and click <em>Next</em>. You&#8217;ll then be requested to enter details for the SVN repository.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-2.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-2-255x300.png" alt="" title="" width="255" height="300" class="aligncenter size-medium wp-image-159" /></a></p>
<p>For the <em>URL</em> enter http://away3d.googlecode.com/svn. Leave the user details empty - we&#8217;ll use anonymous access to obtain the source. Click <em>Next</em> to continue. Eclipse will examine the SVN repository and show the repository structure.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-5.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-5-255x300.png" alt="" title="" width="255" height="300" class="aligncenter size-medium wp-image-160" /></a></p>
<p>We&#8217;ll download everything from the <em>trunk</em> (which includes the source, docs and examples), so select <em>trunk</em> and click on <em>Finish</em>. You&#8217;ll then be asked how you want to check out the source.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-7.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-7-300x246.png" alt="" title="" width="300" height="246" class="aligncenter size-medium wp-image-161" /></a></p>
<p>We want to create a Flex Library project so select <em>Check out as a project configured using the New Project Wizard</em>.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-8.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-8-300x287.png" alt="" title="" width="300" height="287" class="aligncenter size-medium wp-image-162" /></a></p>
<p>Under <em>Flex Builder</em>, choose <em>Flex Library Project</em> and click <em>Next</em>. </p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-9.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-9-300x287.png" alt="" title="" width="300" height="287" class="aligncenter size-medium wp-image-163" /></a></p>
<p>Enter <em>Away3D</em> as the <em>Project name</em> (or any other name you&#8217;d like&#8230;) then select <em>Next</em> to configure the source directory.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-10.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-10-234x300.png" alt="" title="" width="234" height="300" class="aligncenter size-medium wp-image-164" /></a></p>
<p>Click next to <em>src</em> under <em>Classes to include in the library</em>. The <em>Main source folder</em> should show <em>src</em>, and the <em>Output folder</em> should show <em>bin</em>. Sometimes selecting the source folder here doesn&#8217;t always work and we&#8217;ll have to explicitly give the source folder again after the project has been created, as shown below.</p>
<p>You should now see in the <em>Flex Navigator</em> in eclipse a new project called <em>Away3D</em> with the latest revision number next to it. If you have the error <em>nothing was specified to be included in the library</em> shown in the <em>Problems</em> view, then you need to re-specify the source directory as I mentioned above. Simply right-click on the <em>Away3D</em> project and select <em>Properties</em>.</p>
<p><a href="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-11.png"><img src="http://blog.tartiflop.com/wp-content/uploads/2008/11/picture-11-300x251.png" alt="" title="" width="300" height="251" class="aligncenter size-medium wp-image-165" /></a></p>
<p>Under <em>Flex Library Build Path</em>, once again click next to <em>src</em> in the <em>Classes to include in library</em> box. After clicking <em>OK</em> you should see that eclipse is compiling the sources.</p>
<p>The final result is the <em>Away3D.swc</em> Flex library, located in the <em>bin</em> directory, that can be used with other Away3D projects that you create afterwards. Similarly, with eclipse, you can compile Away3D projects by linking directly to this project. Personally I prefer the second method simply because it makes developing and debugging easier as you can directly look at the source for a particular Away3D class.</p>
<p>Hope this is of some use. I&#8217;ll be taking a look, as I did with Papervision3D, at producing a few simple examples just to get a feel of the library&#8230; more soon I hope!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/suwEISQQ-AY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/downloading-and-compiling-away3d-sources-with-svn-in-eclipse/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Foals</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/23EUOcYtMic/</link>
		<comments>http://blog.tartiflop.com/2008/11/musical-interlude-foals/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 11:42:07 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=145</guid>
		<description><![CDATA[Discover Foals!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=797959&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=797959&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/foals.html'>Foals</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/23EUOcYtMic" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/musical-interlude-foals/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/musical-interlude-foals/</feedburner:origLink></item>
		<item>
		<title>3D flash curious</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/fnbp1yOBzSU/</link>
		<comments>http://blog.tartiflop.com/2008/11/3d-flash-curious/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 11:36:29 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Away3D]]></category>

		<category><![CDATA[Papervision3D]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=143</guid>
		<description><![CDATA[So, big pause since my last post&#8230; unfortunately sometimes real-world work gets the better of us and consumes most of our time! Not good&#8230; so time to get back into the swing of more interesting things!
I&#8217;m going to take a little break from Papervision3D for a while and check out another library - Away3D. Its [...]]]></description>
			<content:encoded><![CDATA[<p>So, big pause since my last post&#8230; unfortunately sometimes real-world work gets the better of us and consumes most of our time! Not good&#8230; so time to get back into the swing of more interesting things!</p>
<p>I&#8217;m going to take a little break from Papervision3D for a while and check out another library - Away3D. Its not that I&#8217;m turning my back on pv3d but since its not the only 3D motor out there for flash I thought I&#8217;d see what its like to work with&#8230; I&#8217;m simply curious!</p>
<p>Finding recent comparisons between different 3D motors is not so obvious. Here&#8217;s <a href="http://mrdoob.com/blog/?postid=393">one from Mr.Doob</a> dating from July 2007 for example but since both Away3D and Papervision3D have advanced enormously over the last 12 months its difficult to know if its still valid. </p>
<p>However, I did come across this blog by <a href="http://www.tsoin.com/asblog/2008/09/26/moteurs-3d-alternativa3d-away3d-papervision3d-sandy3d/">Vincent Helwig</a> which is work in progress but aims to compare Alterniva3D, Papervision3D, Away3D and Sandy3D. Each one is briefly presented and simple examples for all four are given. The impression I get from this is that Sandy3D is lagging behind the others in terms of being actively developed (no easy task of course), Alternativa3D is not open source which leaves (speaking personally) Papervision3D and Away3D as the two main players. </p>
<p>What&#8217;s interesting to note as well is that <a href="http://labs.adobe.com/technologies/flashplayer10/">Flash Player 10</a> includes some 3D capabilities (z-sorting for example is not included) which for some circumstances greatly improves performance (see this <a href="http://www.airtightinteractive.com/news/?p=114">comparison between Away3D and FP10</a> for example). These new embedded capabilities will surely be integrated by both pv3d and Away3D over the coming months - interesting times ahead for sure!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/fnbp1yOBzSU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/11/3d-flash-curious/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/11/3d-flash-curious/</feedburner:origLink></item>
		<item>
		<title>Nice and shiny! Phong reflection in Papervision3D</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/z2vj-Um8g_c/</link>
		<comments>http://blog.tartiflop.com/2008/10/nice-and-shiny-phong-reflection-in-papervision3d/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 14:52:43 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Papervision3D]]></category>

		<category><![CDATA[lighting]]></category>

		<category><![CDATA[phong reflection]]></category>

		<category><![CDATA[viewport layers]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=131</guid>
		<description><![CDATA[In my post First steps in Papervision3D : Part 4 - lighting and shading, I mentioned that the materials provided by Papervision3D do not allow us to include ambient, diffuse and specular lighting all together at the same time. The two principal shaded materials provided by Papervision3D are

GouraudMaterial: includes ambient and diffuse lighting
PhongMaterial: includes ambient [...]]]></description>
			<content:encoded><![CDATA[<p>In my post <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-4-lighting-and-shading/"><em>First steps in Papervision3D : Part 4 - lighting and shading</em></a>, I mentioned that the materials provided by Papervision3D do not allow us to include ambient, diffuse <em>and</em> specular lighting all together at the same time. The two principal shaded materials provided by Papervision3D are</p>
<ul>
<li><em>GouraudMaterial</em>:<em> </em>includes ambient and diffuse lighting</li>
<li><em>PhongMaterial</em>: includes ambient and specular lighting</li>
</ul>
<p>The <a href="http://en.wikipedia.org/wiki/Phong_shading">Phong reflection model</a> however is a combination of all three and allows us to model surfaces that have both a rough (diffusive) characteristic and a shiny (specular) one. This is particularly good, for example, in modeling plastic-type materials.</p>
<p>Even though there is not a specific material for which we can specify ambient, diffuse and specular lighting all together, using the <a href="http://blog.zupko.info/?p=129"><em>viewport layers</em></a> interface of Papervision3D we can create different lighting effects on an object and combine them together on the screen.</p>
<p>In <a href="http://books.google.fr/books?id=1hwR5gIq0I8C&amp;pg=PA523&amp;lpg=PA523&amp;dq=specular+light+additive&amp;source=web&amp;ots=nmBhP5uHy7&amp;sig=04hP3J0UbdehkvSF06OEH5Zsa_4&amp;hl=fr&amp;sa=X&amp;oi=book_result&amp;resnum=5&amp;ct=result">theory</a>, diffusive lighting is added to a scene in a <em>multiplicative</em> fashion. The resulting colour seen on the screen is the product of the colour of the material and the quantity of the diffused light. For example we can have a material that is blue (0&#215;0000FF) with a diffusive light pattern that varies from bright white (0xFFFFFF) to grey (ambient) (0&#215;222222). The resulting colours seen on the screen therefore vary from bright blue (0&#215;0000FF) to dark blue (0&#215;000022).</p>
<p>Specular light is added to the scene in an <em>additive</em> way: light is reflected off an object towards an observer thereby brightening the object. Therefore even parts of a black material can be <em>seen</em> with specular light.</p>
<p>Phong reflection is the combination of these two lighting techniques: a material darkened with a diffusive and abient light and enhanced by a specular one.</p>
<p>The demo shown here tries to implement these characteristics. Using <em>ViewportLayers</em> a surface is rendered three times: once with a simple material colour, once with a diffuse light pattern (using a <em>GouraudMaterial</em> to create both diffusive and ambient effects) and finally with a specular one (using a modified <em>PhongMaterial</em> for which the ambient light is turned off, hence producing only specular light).</p>
<p>Each layer is added to the scene with a different <em>BlendMode</em>: <em>MULTIPLY</em> for the diffusive light pattern and <em>ADD</em> for the specular one. The order of each layers is important hence the coloured material is rendered first, followed by the diffusive light and finally the specular light added to the end.</p>
<p>You can take a look at the demo by clicking on the image below. To rotate the scene click and move the mouse. Clicking on the surface separates it into the different components for five seconds so you can see what each individual layer looks like.</p>
<p style="text-align: center;"><a href="http://www.tartiflop.com/pv3d/PhongReflection/"><img class="size-medium wp-image-134 aligncenter" style="border: 1px solid white;" title="Phong Reflection" src="http://blog.tartiflop.com/wp-content/uploads/2008/10/phongreflection-300x192.png" alt="Surface showing phong reflection" width="400" height="256" /></a></p>
<p>You can take a look at the source at <a href="http://www.tartiflop.com/pv3d/PhongReflection/srcview/">http://www.tartiflop.com/pv3d/PhongReflection/srcview/</a>.</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/z2vj-Um8g_c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/10/nice-and-shiny-phong-reflection-in-papervision3d/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/10/nice-and-shiny-phong-reflection-in-papervision3d/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - Interpol</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/mEzMn3fKCDA/</link>
		<comments>http://blog.tartiflop.com/2008/09/musical-interlude-interpol/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 22:29:24 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=121</guid>
		<description><![CDATA[Discover Interpol!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=948563&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=948563&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/interpol.html'>Interpol</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/mEzMn3fKCDA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/09/musical-interlude-interpol/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/09/musical-interlude-interpol/</feedburner:origLink></item>
		<item>
		<title>First steps in Papervision3D : Part 9 - Importing and working with 3D objects</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/soSWjx4Hr_g/</link>
		<comments>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-9-importing-and-working-with-3d-objects/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 20:14:51 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Papervision3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[animation]]></category>

		<category><![CDATA[Collada]]></category>

		<category><![CDATA[DAE]]></category>

		<category><![CDATA[lighting]]></category>

		<category><![CDATA[texture mapping]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=108</guid>
		<description><![CDATA[Previous articles summary :

First steps in Papervision3D : Part 1
Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes.
First steps in Papervision3D : Part 2
Illustration of use of new Papervision3D v2.0 class BasicView that encapsulates essential elements to rapidly start [...]]]></description>
			<content:encoded><![CDATA[<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-1">First steps in Papervision3D : Part 1</a><br />
Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-2">First steps in Papervision3D : Part 2</a><br />
Illustration of use of new Papervision3D v2.0 class <span style="font-style: italic;">BasicView</span> that encapsulates essential elements to rapidly start developing new 3D scenes.</li>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-3">First steps in Papervision3D : Part 3 - animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-4">First steps in Papervision3D : Part 4 - lighting and shading</a><br />
A point light source is added to the scene. Fours materials with different characteristics are added to spheres to illustrate how Papervision3D performs shading.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-5">First steps in Papervision3D : Part 5 - scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6">First steps in Papervision3D : Part 6 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7">First steps in Papervision3D : Part 7 - Texture mapping with lighting, bump mapping and environment mapping</a><br />
Advanced materials using specific shaders to enhance texture mapped materials with bump mapping and environment mapping.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-8">First steps in Papervision3D : Part 8 - Movie materials</a><br />
Displaying animated and interactive movies as materials on 3D surfaces.</li>
</ul>
<p>Back again for another article in the <em>First Steps</em> series&#8230; its been a while since the last one mainly because I&#8217;ve moved from Blogger to Wordpress and that&#8217;s been quite a hassle. But, hopefully, now that its up and running it won&#8217;t be so long before the next one&#8230; fingers crossed!</p>
<p>In this article (which again is probably going to be quite a long one) I&#8217;m looking at how to import 3D objects that have been created using specialised applications such as <em>3DS Max</em>, <em>Maya</em>, <em>Blender</em> and <em>Google Sketchup</em> to name a few.</p>
<p>To improve the exchange of digital assets between these different applications, various file formats exists that allow 3D objects from one application to be used in another. One particular format that is readable by Papervision3D, is the Collaborative Design Activity format or <a href="http://en.wikipedia.org/wiki/COLLADA">COLLADA</a> which saves the information of a 3D scene as XML.</p>
<p>The Collada format specifications are maintained by the <a href="http://www.khronos.org/collada/">Khronos Group</a> and embedded within the file are details on geometry, shaders and effects, physics, animation and kinematics. The specifications are supported by a number of companies including <em>3DS Max</em>, <em>Maya</em> and <em>Blender</em>. The files themselves have the <em>.dae</em> extension, standing for Digital Asset Exchange.</p>
<p>Papervision3D contains a extensive package to parse and import Collada files yet has a simple interface making it easy to use complex 3D models created in specialised applications. Worth noting are a couple of sites that contain Collada files created by different communities that can be downloaded and used fairly freely. These are</p>
<ul>
<li><a href="http://www.3dvia.com">3DVIA</a> that has a large collection of models in a number of different formats, including Collada, supported by a community of 3D artists</li>
<li>The test model bank at <a href="http://www.collada.org/owl">Khronos</a> which has a limited number of models available to the public</li>
</ul>
<p>As I&#8217;ve mentioned from the beginning of this series, these posts represent also what I&#8217;ve learned over the last few weeks and are by no means expert tutorials. I&#8217;ve therefore made use of a number of sites in understanding how to import objects into Papervision3D and I&#8217;m sure you&#8217;ll find useful information on them as well.</p>
<ul>
<li><a href="http://www.flexhacks.org/wordpress/?p=52">Mikes blog</a> has a number of links and source code on how to create Collada objects.</li>
<li><a href="http://modern-carpentry.com/talk/?p=30">Modern Carpentry</a> shows how to instantiate a DAE object.</li>
<li><a href="http://papervision2.com/loading-complex-models/">Papervision2</a> has a very good tutorial on creating Collada objects that I&#8217;d really recommend&#8230; especially since the <em>cow</em> Collada object comes from them :)</li>
<li><a href="http://blog.emmanuelbonnet.com/2007/06/02/papervision-tuto-import-de-collada/">Emmanuel Bonnet</a> also has a nice little demo with source for a Collada object.</li>
</ul>
<p>Since there are a number of points to look at I decided it was best to split this post into two parts. In the first part of this post I&#8217;ll illustrate a selection of different ways of importing objects into Papervision3D based on the above examples and also from exploring the source code of Paperivison3D itself. In the second part I&#8217;m going to look at how to add interactivity and shading with Collada objects. I&#8217;ll also present some problems that exist with shading in the current version of Papervision3D - well, it is <em>beta</em> after all!</p>
<p>Lets have a look at the source for the first example. Here, my objective is simply to import 3D objects into a scene using a number of different sources. These include</p>
<ul>
<li>An embedded Collada file and bitmap</li>
<li>A URL for an external Collada</li>
<li>An animated Collada object from an external URL</li>
<li>A Google Earth object file, exported from Google Sketchup</li>
</ul>
<p>The last one is making use of a special class within Papervision3D dedicated to file with the <em>.kmz</em> file extension (Google Earth). These files are actually <em>.zip</em> files that contain texture maps and Collada data.</p>
<p>Papervision3D also has (as far as I can tell) two main ways of importing Collada data: one is using the <em>Collada</em> class, the other is using the <em>DAE</em> class, both of which are in the <em>org.papervision3d.objects.parsers</em> package. Again, as far as I can tell, the <em>DAE</em> class appears to be more <em>mature</em> making extensive use of the <em>org.ascollada</em> package and I&#8217;ve had more success over the last few days using this rather than the <em>Collada</em> class<em>.</em></p>
<p>So here&#8217;s the source code, importing four objects using different sources and different importing methods.</p>
<div id="codeSnippet">
<pre>
<blockquote>

package {
&nbsp;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp;
&nbsp; import org.papervision3d.events.FileLoadEvent;
&nbsp; import org.papervision3d.lights.PointLight3D;
&nbsp; import org.papervision3d.materials.BitmapMaterial;
&nbsp; import org.papervision3d.materials.MovieMaterial;
&nbsp; import org.papervision3d.materials.utils.MaterialsList;
&nbsp; import org.papervision3d.objects.DisplayObject3D;
&nbsp; import org.papervision3d.objects.parsers.Collada;
&nbsp; import org.papervision3d.objects.parsers.DAE;
&nbsp; import org.papervision3d.objects.parsers.KMZ;
&nbsp; import org.papervision3d.view.BasicView;

&nbsp; public class Example009a extends BasicView {
&nbsp;
&nbsp; &nbsp; [Embed(source="/../assets/cow.dae", mimeType="application/octet-stream")] private var CowDAE:Class;
&nbsp; &nbsp; [Embed(source="/../assets/Cow.png")] private var CowBitmapImage:Class;

&nbsp; &nbsp; private var light:PointLight3D;

&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;
&nbsp; &nbsp; private var cameraYaw:Number = -60;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; public function Example009a() {
&nbsp; &nbsp; &nbsp; super(0, 0, true, true);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();

&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Start rendering the scene
&nbsp; &nbsp; &nbsp; startRendering();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function init3D():void {
&nbsp; &nbsp; &nbsp; // position the camera
&nbsp; &nbsp; &nbsp; camera.z = -700;
&nbsp; &nbsp; &nbsp; camera.fov = 60;
&nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; }

&nbsp; &nbsp;
&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // create new Collada from URL, using original materials and scaled to 50%
&nbsp; &nbsp; &nbsp; var cow:Collada = new Collada("http://www.tartiflop.com/pv3d/FirstSteps/collada/cow.dae", null, 0.5);
&nbsp; &nbsp; &nbsp; cow.moveDown(100);
&nbsp; &nbsp; &nbsp; cow.moveBackward(200);
&nbsp; &nbsp; &nbsp; cow.yaw(90);
&nbsp; &nbsp; &nbsp; scene.addChild(cow);

&nbsp; &nbsp; &nbsp; // create a texture mapped material from embedded png
&nbsp; &nbsp; &nbsp; var cowMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the texture map to a material list corresponding to the material symbols in the dae
&nbsp; &nbsp; &nbsp; var cowMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; cowMaterials.addMaterial(cowMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new Collada, specifying the materials we want to use
&nbsp; &nbsp; &nbsp; var cow2:Collada = new Collada(new XML(new CowDAE()), cowMaterials);
&nbsp; &nbsp; &nbsp; cow2.moveRight(300);
&nbsp; &nbsp; &nbsp; cow2.moveDown(100);
&nbsp; &nbsp; &nbsp; scene.addChild(cow2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a new DAE that is animated and perform actions once it is loaded
&nbsp; &nbsp; &nbsp; var seymour:DAE = new DAE(true);
&nbsp; &nbsp; &nbsp; seymour.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; seymour.scale = 20;
&nbsp; &nbsp; &nbsp; &nbsp; seymour.moveForward(200);
&nbsp; &nbsp; &nbsp; &nbsp; seymour.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; scene.addChild(seymour);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the DAE from a specific URL
&nbsp; &nbsp; &nbsp; seymour.load("http://www.tartiflop.com/pv3d/FirstSteps/collada/Seymour.dae");
&nbsp; &nbsp; &nbsp; 

&nbsp; &nbsp; &nbsp; // create a new 3D object from a 3D google earth object file and perform actions when loaded
&nbsp; &nbsp; &nbsp; var kmz:KMZ = new KMZ();
&nbsp; &nbsp; &nbsp; kmz.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; kmz.scale = 20;
&nbsp; &nbsp; &nbsp; &nbsp; kmz.moveLeft(300);
&nbsp; &nbsp; &nbsp; &nbsp; kmz.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; scene.addChild(kmz);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load kmz from a specific URL
&nbsp; &nbsp; &nbsp; kmz.load("http://www.tartiflop.com/pv3d/FirstSteps/collada/thing.kmz");
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; override protected function onRenderTick(event:Event=null):void {

&nbsp; &nbsp; &nbsp; // update camera position
&nbsp; &nbsp; &nbsp; updateCamera();
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // call the renderer
&nbsp; &nbsp; &nbsp; super.onRenderTick(event);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch >= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>This produces the following flash animation (click on the image below). Note that it can take some time for the models to be loaded into flash, but in the end you should see four models including two cows, an animated <em>Space Boy</em> (coming from the public directory of the <a href="http://www.collada.org/owl">Collada test model bank at Khronos</a>) and a rather crappy <em>thing</em> I made in Google Sketchup! You can rotate the scene by clicking and moving the mouse at the same time.</p>
<p><a href="http://www.tartiflop.com/pv3d/FirstSteps/Example009a.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/09/imports.png" border="0" /></a></p>
<p>So, lets take a closer look at the code&#8230; As with other examples I&#8217;m using the same standard <em>BasicView</em> derived class - the main difference from previous ones coming in the <em>createScene</em> function.</p>
<p>The first cow object is created by obtaining all the data for the Collada object from an external URL. Contained in the <em>.dae</em> file is information on the texture maps so we don&#8217;t need to specify anything other than the location of the Collada file itself to create a fully rendered object.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // create new Collada from URL, using original materials and scaled to 50%
&nbsp; &nbsp; &nbsp; var cow:Collada = new Collada("http://www.tartiflop.com/pv3d/FirstSteps/collada/cow.dae", null, 0.5);
&nbsp; &nbsp; &nbsp; cow.moveDown(100);
&nbsp; &nbsp; &nbsp; cow.moveBackward(200);
&nbsp; &nbsp; &nbsp; cow.yaw(90);
&nbsp; &nbsp; &nbsp; scene.addChild(cow);
</blockquote>
</pre>
</div>
<p>Here I&#8217;m using the <em>Collada</em> class which provides a very simple interface to import Collada data. The first argument is of course the location of the <em>.dae</em> file (you can just as easily use a file on the local file system). The second argument is to specify a different material for the object: in this case I&#8217;ll use the file referenced by the Collada file itself. The third parameter relates to the scaling: in this case 50%. The resulting object is then translated, rotated and added to the scene.</p>
<p>We can similarly import Collada data by embedding the data in the Flash animation (as we&#8217;ve seen in previous examples in this series). We have to, however, embed both the Collada data <em>and</em> the texture map data for it to be correctly rendered. You&#8217;ll find the embedded files at the beginning of the class definition.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; [Embed(source="/../assets/cow.dae", mimeType="application/octet-stream")] private var CowDAE:Class;
&nbsp; &nbsp; [Embed(source="/../assets/Cow.png")] private var CowBitmapImage:Class;
</blockquote>
</pre>
</div>
<p>The <em>.dae</em> file format is not recognised by Flash which is why we need to explicitly give the <em>mimeType</em>. As you&#8217;ll see below we can use the DAE data directly as an XML document. The Collada object is then created as follows.</p>
<div id="codeSnippet">
<pre>
<blockquote>

&nbsp; &nbsp; &nbsp; // create a texture mapped material from embedded png
&nbsp; &nbsp; &nbsp; var cowMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the texture map to a material list corresponding to the material symbols in the dae
&nbsp; &nbsp; &nbsp; var cowMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; cowMaterials.addMaterial(cowMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new Collada, specifying the materials we want to use
&nbsp; &nbsp; &nbsp; var cow2:Collada = new Collada(new XML(new CowDAE()), cowMaterials);
&nbsp; &nbsp; &nbsp; cow2.moveRight(300);
&nbsp; &nbsp; &nbsp; cow2.moveDown(100);
&nbsp; &nbsp; &nbsp; scene.addChild(cow2);
</blockquote>
</pre>
</div>
<p>We specifically create a material for the 3D object: I&#8217;m using a <em>MovieMaterial</em> which in this case is created with a simple bitmap image. Since a Collada object can have a number of different textured materials we need to provide it with a <em>MaterialList</em>. The names associated with the materials have to relate to details within the Collada file&#8230; after some investigation I found that the material was referenced by the name <em>mat0</em>. The <em>Collada</em> object is then created by passing data encapsulated in an <em>XML</em> format and this time specifying the material list used in association with the data. As with the first object, we then translate it and add it to the scene.</p>
<p>The third object is an animated Collada object. This time I&#8217;m using the <em>DAE</em> class which has more success in importing the data. The interface remains very similar to the <em>Collada</em> class however we need to specifically <em>load</em> the data.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; &nbsp; // create a new DAE that is animated and perform actions once it is loaded
&nbsp; &nbsp; &nbsp; var seymour:DAE = new DAE(true);
&nbsp; &nbsp; &nbsp; seymour.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; seymour.scale = 20;
&nbsp; &nbsp; &nbsp; &nbsp; seymour.moveForward(200);
&nbsp; &nbsp; &nbsp; &nbsp; seymour.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; scene.addChild(seymour);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the DAE from a specific URL
&nbsp; &nbsp; &nbsp; seymour.load("http://www.tartiflop.com/pv3d/FirstSteps/collada/Seymour.dae");
</blockquote>
</pre>
</div>
<p>The first argument to the <em>DAE</em> constructor specifies whether we want the DAE to be animated or not: in this case we do. We then add a listener which is triggered when the data is fully loaded. This allows us to add it to the scene and modify its size and position when we are sure that the data is coherent. The data is loaded by specifying a URL to the Collada file.</p>
<p>Finally to show how to import data from a different source, I&#8217;ve included an example that I made using Google Sketchup and exported as a Google Earth object (<em>.kmz</em> file extension). And yes, I know, its not very pretty&#8230; </p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; &nbsp; // create a new 3D object from a 3D google earth object file and perform actions when loaded
&nbsp; &nbsp; &nbsp; var kmz:KMZ = new KMZ();
&nbsp; &nbsp; &nbsp; kmz.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; kmz.scale = 20;
&nbsp; &nbsp; &nbsp; &nbsp; kmz.moveLeft(300);
&nbsp; &nbsp; &nbsp; &nbsp; kmz.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; scene.addChild(kmz);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load kmz from a specific URL
&nbsp; &nbsp; &nbsp; kmz.load("http://www.tartiflop.com/pv3d/FirstSteps/collada/thing.kmz");
</blockquote>
</pre>
</div>
<p>Papervision3D provides us with a class <em>KMZ</em> specifically to import this type of data. In fact, embedded in this file is a <em>.dae</em> Collada file (and the class has a reference to a <em>DAE</em> object as well) so the import mechanism remains the same&#8230; it is however another handy tool. As you can see we use the same technique as with the DAE import.</p>
<p>So, there we are: four different methods of importing Collada data. Now for the more advanced part of this post: adding shading to the objects.</p>
<p>In principal this should follow from the previous post on <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7-texture-mapping-with-lighting-bump-mapping-and-environment-mapping/">texture mapping with lighting</a> where a <em>ShadedMaterial</em> is used to <em>skin</em> an object (as we did above with <em>cow2</em> when we specified a list of materials for the DAE). However, at the time of writing this article, this is not working correctly: the main problem being black lines appearing on face edges. As you can see from the <a href="http://code.google.com/p/papervision3d/issues/list">list of bugs at the home of Papervision3D</a>, an <a href="http://code.google.com/p/papervision3d/issues/detail?id=107">issue has been raised explaining the problem</a>. You can also see on the Papervision3D mailing list that this is a recurring problem (<a href="http://www.nabble.com/BitmapMaterial-%2B-PhongShader-%2B-DAE.--Why-black-lines-on-the-material--td18491117.html">here</a> and <a href="http://www.nabble.com/DAE-ShadedMaterial-update-issue-td18483570.html#a18527428">here</a> for example).</p>
<p>This said, all is not lost! Thanks to those talented people involved in the Papervision3D project, specifically in this case to <a href="http://blog.zupko.info/">Andy Zupko</a>, a work-around does exist! Also, I&#8217;d like to give a thanks to the <a href="http://www.nabble.com/Papervision3D-f22855.html">Papervision3D newsgroup</a> because the list is very active and you can find a lot of very good information on it&#8230; like this fix.</p>
<p>So, here&#8217;s the second example source code for this post. Here I&#8217;m showing the two different methods for rendering a shaded Collada object: the first (not fully working in the current release of Papervision3D) using a ShadedMaterial and the second using Andy&#8217;s work-around which involves <em>blending</em> two identical models: one with a simple shaded material, the other with a texture-mapped material.</p>
<div id="codeSnippet">
<pre>
<blockquote>
package {
&nbsp;
&nbsp; import flash.display.BlendMode;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp; import flash.text.TextField;
&nbsp; import flash.text.TextFieldAutoSize;
&nbsp; import flash.text.TextFormat;
&nbsp; import flash.utils.getTimer;
&nbsp;
&nbsp; import org.papervision3d.events.FileLoadEvent;
&nbsp; import org.papervision3d.events.InteractiveScene3DEvent;
&nbsp; import org.papervision3d.lights.PointLight3D;
&nbsp; import org.papervision3d.materials.BitmapMaterial;
&nbsp; import org.papervision3d.materials.MovieMaterial;
&nbsp; import org.papervision3d.materials.shadematerials.GouraudMaterial;
&nbsp; import org.papervision3d.materials.shaders.GouraudShader;
&nbsp; import org.papervision3d.materials.shaders.ShadedMaterial;
&nbsp; import org.papervision3d.materials.utils.MaterialsList;
&nbsp; import org.papervision3d.objects.DisplayObject3D;
&nbsp; import org.papervision3d.objects.parsers.DAE;
&nbsp; import org.papervision3d.view.BasicView;

&nbsp; public class Example009b extends BasicView {
&nbsp;
&nbsp; &nbsp; [Embed(source="/../assets/cow.dae", mimeType="application/octet-stream")] private var CowDAE:Class;
&nbsp; &nbsp; [Embed(source="/../assets/Cow.png")] private var CowBitmapImage:Class;

&nbsp; &nbsp; private var light:PointLight3D;
&nbsp; &nbsp;
&nbsp; &nbsp; private var shadedMaterialCow:DAE;
&nbsp; &nbsp; private var gouraudCow:DAE;
&nbsp; &nbsp; private var texturedCow:DAE;
&nbsp; &nbsp; private var allCows:DisplayObject3D;
&nbsp; &nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;

&nbsp; &nbsp; private var cameraYaw:Number = -60;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; private var fpsText:TextField;
&nbsp; &nbsp; private var textFormat:TextFormat;
&nbsp;
&nbsp; &nbsp; private var frames:Number = 0;
&nbsp; &nbsp; private var lastTimeMS:Number = 0;
&nbsp;
&nbsp; &nbsp; private var doSimple:Boolean = false;
&nbsp;
&nbsp; &nbsp; public function Example009b() {
&nbsp; &nbsp; &nbsp; super(0, 0, true, true);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();

&nbsp; &nbsp; &nbsp; // create the frame rate counter label
&nbsp; &nbsp; &nbsp; createFPSLabel();

&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Start rendering the scene
&nbsp; &nbsp; &nbsp; startRendering();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function init3D():void {
&nbsp; &nbsp; &nbsp; // position the camera
&nbsp; &nbsp; &nbsp; camera.z = -500;
&nbsp; &nbsp; &nbsp; camera.fov = 60;
&nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function createFPSLabel():void {
&nbsp; &nbsp; &nbsp; // create text and format to display current fps
&nbsp; &nbsp; &nbsp; textFormat = new TextFormat();
&nbsp; &nbsp; &nbsp; textFormat.size = 20;
&nbsp; &nbsp; &nbsp; textFormat.font = "Arial";
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; fpsText = new TextField();
&nbsp; &nbsp; &nbsp; fpsText.x = 50;
&nbsp; &nbsp; &nbsp; fpsText.y = 50;
&nbsp; &nbsp; &nbsp; fpsText.textColor = 0xFFFFFF;
&nbsp; &nbsp; &nbsp; fpsText.text = "";
&nbsp; &nbsp; &nbsp; fpsText.setTextFormat(textFormat);
&nbsp; &nbsp; &nbsp; fpsText.autoSize = TextFieldAutoSize.LEFT;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; stage.addChild(fpsText);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // Specify a point light source and its location
&nbsp; &nbsp; &nbsp; light = new PointLight3D(true);
&nbsp; &nbsp; &nbsp; light.x = 500;
&nbsp; &nbsp; &nbsp; light.y = 300;
&nbsp; &nbsp; &nbsp; light.z = -500;
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // create a display object to group all created cows
&nbsp; &nbsp; &nbsp; allCows = new DisplayObject3D();
&nbsp; &nbsp; &nbsp; scene.addChild(allCows);

&nbsp; &nbsp; &nbsp; // create a cow with a shaded material
&nbsp; &nbsp; &nbsp; createSimpleShadedDAE();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a shaded cow by blending two different rendered objects
&nbsp; &nbsp; &nbsp; createNiceShadedDAE();
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createSimpleShadedDAE():void {

&nbsp; &nbsp; &nbsp; // create BitmapMaterial from texture map
&nbsp; &nbsp; &nbsp; var cowBitmapMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp;
&nbsp; &nbsp; &nbsp; // create a ShadedMaterial using a Gouraud shader
&nbsp; &nbsp; &nbsp; var shader:GouraudShader = new GouraudShader(light, 0xFFFFFF, 0x333333);
&nbsp; &nbsp; &nbsp; var shadedMaterial:ShadedMaterial = new ShadedMaterial(cowBitmapMaterial, shader);
&nbsp; &nbsp; &nbsp; shadedMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Material list linked to material symbol name in dae
&nbsp; &nbsp; &nbsp; var mainMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; mainMaterials.addMaterial(shadedMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; shadedMaterialCow = new DAE(false);
&nbsp; &nbsp; &nbsp; shadedMaterialCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; shadedMaterialCow.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; shadedMaterialCow.scale = 100;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add cow to scene when loaded
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(shadedMaterialCow);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // recursively add event listeners to dae and all children
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(shadedMaterialCow, InteractiveScene3DEvent.OBJECT_CLICK, toggleRendering);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; shadedMaterialCow.load(new XML(new CowDAE()), mainMaterials);

&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function createNiceShadedDAE():void {

&nbsp; &nbsp; &nbsp; // create a simple texture mapped material for the embedded png
&nbsp; &nbsp; &nbsp; var cowBitmapMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp; &nbsp; &nbsp; cowBitmapMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the material to a material list corresponding to the dae
&nbsp; &nbsp; &nbsp; var bitmapMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; bitmapMaterials.addMaterial(cowBitmapMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; texturedCow = new DAE(false);
&nbsp; &nbsp; &nbsp; texturedCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.scale = 100;

&nbsp; &nbsp; &nbsp; &nbsp; // set the dae to initially not be visible
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.visible = false;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add to the scene
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(texturedCow);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // listen to events (applies to all children of dae as well)
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(texturedCow, InteractiveScene3DEvent.OBJECT_CLICK, toggleRendering);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; });

&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; texturedCow.load(new XML(new CowDAE()), bitmapMaterials);

&nbsp; &nbsp; &nbsp; // create a simple Gouraud shaded material and add to list corresponding to dae
&nbsp; &nbsp; &nbsp; var gouraudMaterial:GouraudMaterial = new GouraudMaterial(light, 0xFFFFFF, 0x333333);
&nbsp; &nbsp; &nbsp; var shadedMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; shadedMaterials.addMaterial(gouraudMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; gouraudCow = new DAE(false);
&nbsp; &nbsp; &nbsp; gouraudCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.scale = 100;
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.moveDown(100);

&nbsp; &nbsp; &nbsp; &nbsp; // set the dae to initially not be visible
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.visible = false;
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add to the scene
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(gouraudCow);

&nbsp; &nbsp; &nbsp; &nbsp; // change the rendering so that it is blended with other rendered objects
&nbsp; &nbsp; &nbsp; &nbsp; viewport.getChildLayer(gouraudCow).blendMode = BlendMode.MULTIPLY;&nbsp;
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; gouraudCow.load(new XML(new CowDAE()), shadedMaterials);

&nbsp; &nbsp; }

&nbsp; &nbsp; // used to ensure that all children in a dae listen to events
&nbsp; &nbsp; private function addEventListeners(displayObject:DisplayObject3D, eventType:String, listener:Function):void {
&nbsp; &nbsp; &nbsp; // add listener to DisplayObect
&nbsp; &nbsp; &nbsp; displayObject.addEventListener(eventType, listener);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add listener to all contained childred
&nbsp; &nbsp; &nbsp; for each(var child:DisplayObject3D in displayObject.children) {
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(child, eventType, listener);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // toggles between the two rendering techniques
&nbsp; &nbsp; private function toggleRendering(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; texturedCow.visible = !texturedCow.visible;
&nbsp; &nbsp; &nbsp; gouraudCow.visible = !gouraudCow.visible;
&nbsp; &nbsp; &nbsp; shadedMaterialCow.visible = !shadedMaterialCow.visible;
&nbsp; &nbsp; }

&nbsp; &nbsp; override protected function onRenderTick(event:Event=null):void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the scene
&nbsp; &nbsp; &nbsp; allCows.yaw(-1);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // calculate the frame rate
&nbsp; &nbsp; &nbsp; calculateFrameRate();

&nbsp; &nbsp; &nbsp; // update the camera position
&nbsp; &nbsp; &nbsp; updateCamera();
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // call the renderer
&nbsp; &nbsp; &nbsp; super.onRenderTick(event);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function calculateFrameRate():void {

&nbsp; &nbsp; &nbsp; // calculate the time elapsed since the last calculation&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var currentTimeMS:Number = getTimer();
&nbsp; &nbsp; &nbsp; var elapsedTimeMS:Number = currentTimeMS - lastTimeMS;

&nbsp; &nbsp; &nbsp; // if a second has elapsed then calculate the fps
&nbsp; &nbsp; &nbsp; if (elapsedTimeMS >= 1000) {
&nbsp; &nbsp; &nbsp; &nbsp; fpsText.text = frames.toString() + " fps";
&nbsp; &nbsp; &nbsp; &nbsp; fpsText.setTextFormat(textFormat);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the counter
&nbsp; &nbsp; &nbsp; &nbsp; lastTimeMS = currentTimeMS;
&nbsp; &nbsp; &nbsp; &nbsp; frames = 0;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; // increment the counter
&nbsp; &nbsp; &nbsp; &nbsp; frames++;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function updateCamera():void {
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch >= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>The resulting Flash animation can be seen below by clicking on the image. You can rotate the scene by clicking and moving the mouse. You can also switch between the two rendering techniques by clicking on the cow. To show that there is not a huge difference in performance between the two techniques, a frame-rate meter is shown in the top-left hand corner. </p>
<p><a href="http://www.tartiflop.com/pv3d/FirstSteps/Example009b.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://blog.tartiflop.com/wp-content/uploads/2008/09/nice-shaded.png" border="0" /></a></p>
<p>So again, lets take a closer look at the code. Starting with the <em>ShadedMaterial</em> version that produces the problems. This is created in the <em>createSimpleShadedDAE</em> function.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function createSimpleShadedDAE():void {

&nbsp; &nbsp; &nbsp; // create BitmapMaterial from texture map
&nbsp; &nbsp; &nbsp; var cowBitmapMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp;
&nbsp; &nbsp; &nbsp; // create a ShadedMaterial using a Gouraud shader
&nbsp; &nbsp; &nbsp; var shader:GouraudShader = new GouraudShader(light, 0xFFFFFF, 0x333333);
&nbsp; &nbsp; &nbsp; var shadedMaterial:ShadedMaterial = new ShadedMaterial(cowBitmapMaterial, shader);
&nbsp; &nbsp; &nbsp; shadedMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Material list linked to material symbol name in dae
&nbsp; &nbsp; &nbsp; var mainMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; mainMaterials.addMaterial(shadedMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; shadedMaterialCow = new DAE(false);
&nbsp; &nbsp; &nbsp; shadedMaterialCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; shadedMaterialCow.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; shadedMaterialCow.scale = 100;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add cow to scene when loaded
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(shadedMaterialCow);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // recursively add event listeners to dae and all children
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(shadedMaterialCow, InteractiveScene3DEvent.OBJECT_CLICK, toggleRendering);
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; shadedMaterialCow.load(new XML(new CowDAE()), mainMaterials);

&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As we&#8217;ve seen in previous posts, to create a shaded bitmap material we combine a <em>BitmapMaterial</em> with a <em>Shader</em>. Here we use the embedded bitmap data of the texture map combined with a simple Gouraud shader. These are combined in a <em>ShadedMaterial</em> which is then added to the material list as we did above for the first part of this post. I&#8217;m using a <em>DAE</em> object to load the Collada data which is then combined with material data.</p>
<p>What you&#8217;ll notice however is that the interactivity is added in a different manner from previous posts. For Collada objects we need to add the event listener to all of the children of the <em>DAE</em> as well as the <em>DAE</em> itself - see this <a href="http://www.nabble.com/Collada-InteractiveScene3DEvent-td18760172.html">post on the Papervision3D newsgroup</a> for details. To perform this, I&#8217;ve added (as mentioned in the post) a small routine to recursively add the listener to all children.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; // used to ensure that all children in a dae listen to events
&nbsp; &nbsp; private function addEventListeners(displayObject:DisplayObject3D, eventType:String, listener:Function):void {
&nbsp; &nbsp; &nbsp; // add listener to DisplayObect
&nbsp; &nbsp; &nbsp; displayObject.addEventListener(eventType, listener);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add listener to all contained childred
&nbsp; &nbsp; &nbsp; for each(var child:DisplayObject3D in displayObject.children) {
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(child, eventType, listener);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>So, as you can see from the Flash animation, this method doesn&#8217;t work - yet! So, now for the <em>fix</em> provided by Andy Zupko. You&#8217;ll find his <a href="http://blog.zupko.info/?p=146">original post</a> on shadow casting very interesting. The idea is that we take advantage of the Flash architecture to blend 2D objects together. To do this we render the DAE twice: once with a texture map but no shading and another time with no texture map and simple shading. Each render produces a 2D image (what is seen on the screen). These images can be superimposed and blended so that the resulting image is a shaded texture map. </p>
<p>The overhead of drawing the same 3D object twice seems to be fairly small (as you can see from the fps counter in the demo). This is not really surprising since the <em>ShadedMaterial</em> method also does two passes: each triangle is initially rendered with a texture map and then again with a shader. </p>
<p>Lets look at the code in <em>createNiceShadedDAE</em>&#8230;</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function createNiceShadedDAE():void {

&nbsp; &nbsp; &nbsp; // create a simple texture mapped material for the embedded png
&nbsp; &nbsp; &nbsp; var cowBitmapMaterial:BitmapMaterial = new MovieMaterial(new CowBitmapImage(), true);
&nbsp; &nbsp; &nbsp; cowBitmapMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the material to a material list corresponding to the dae
&nbsp; &nbsp; &nbsp; var bitmapMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; bitmapMaterials.addMaterial(cowBitmapMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; texturedCow = new DAE(false);
&nbsp; &nbsp; &nbsp; texturedCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.moveDown(100);
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.scale = 100;

&nbsp; &nbsp; &nbsp; &nbsp; // set the dae to initially not be visible
&nbsp; &nbsp; &nbsp; &nbsp; texturedCow.visible = false;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add to the scene
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(texturedCow);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // listen to events (applies to all children of dae as well)
&nbsp; &nbsp; &nbsp; &nbsp; addEventListeners(texturedCow, InteractiveScene3DEvent.OBJECT_CLICK, toggleRendering);
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; });

&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; texturedCow.load(new XML(new CowDAE()), bitmapMaterials);

&nbsp; &nbsp; &nbsp; // create a simple Gouraud shaded material and add to list corresponding to dae
&nbsp; &nbsp; &nbsp; var gouraudMaterial:GouraudMaterial = new GouraudMaterial(light, 0xFFFFFF, 0x333333);
&nbsp; &nbsp; &nbsp; var shadedMaterials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; shadedMaterials.addMaterial(gouraudMaterial, "mat0");

&nbsp; &nbsp; &nbsp; // create a new dae and perform actions when loaded
&nbsp; &nbsp; &nbsp; gouraudCow = new DAE(false);
&nbsp; &nbsp; &nbsp; gouraudCow.addEventListener(FileLoadEvent.LOAD_COMPLETE, function onLoad(event:Event):void {
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.scale = 100;
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.moveDown(100);

&nbsp; &nbsp; &nbsp; &nbsp; // set the dae to initially not be visible
&nbsp; &nbsp; &nbsp; &nbsp; gouraudCow.visible = false;
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // add to the scene
&nbsp; &nbsp; &nbsp; &nbsp; allCows.addChild(gouraudCow);

&nbsp; &nbsp; &nbsp; &nbsp; // change the rendering so that it is blended with other rendered objects
&nbsp; &nbsp; &nbsp; &nbsp; viewport.getChildLayer(gouraudCow).blendMode = BlendMode.MULTIPLY;&nbsp;
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // load the dae from the embedded structure and replace the materials
&nbsp; &nbsp; &nbsp; gouraudCow.load(new XML(new CowDAE()), shadedMaterials);

&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see two <em>DAE</em>s are created: one as before with the embedded texture map data and another using a <em>Gouraud</em> shaded material. They are both initially set with <em>visible = false</em>. This means that they are not visible on screen and no rendering of them occurs. The Papervision3D event listeners are added to the first one (recursively for all DAE children too). </p>
<p>To ensure that the two are blended we just need to add the line <em>viewport.getChildLayer(gouraudCow).blendMode = BlendMode.MULTIPLY</em> to the Gouraud shaded <em>DAE</em>. The <em>layer</em> contains the 2D end result (or <em>Sprite</em>) of the render process for the <em>DisplayObject3D</em> (as it is seen on the screen) so by specifying <em>BlendMode.MULTIPLY</em> we are directly modifying the Flash characteristics of the <em>Sprite</em>. As you can see from the example this works very well which little, or no, change to the fps. As a little bit of further reading, I&#8217;d recommend <a href="http://blog.zupko.info/?p=129">another post by Andy Zupko</a> where he gives more details on what can be achieved by modifying the layer characteristics and how this can create some greate effects.</p>
<p>Finally just to illustrate how the two models are switched, lets have a look at the event handler</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; // toggles between the two rendering techniques
&nbsp; &nbsp; private function toggleRendering(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; texturedCow.visible = !texturedCow.visible;
&nbsp; &nbsp; &nbsp; gouraudCow.visible = !gouraudCow.visible;
&nbsp; &nbsp; &nbsp; shadedMaterialCow.visible = !shadedMaterialCow.visible;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Very simply, we set the different <em>DAE</em> models to <em>visible = true</em> or <em>visible = false</em> depending on which rendering technique we want to use. This is a very efficient way of adding and removing objects from a scene.</p>
<p>So just before ending this post, a couple of points about this technique. Firstly, this works fine for simple Gouraud, Flat, Cell or Phong shading, however how can bump mapping be included? Bump mapping requires a <em>ShadedMaterial</em> (see <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7-texture-mapping-with-lighting-bump-mapping-and-environment-mapping/">Part 7</a>) but as we&#8217;ve seen this type of material doesn&#8217;t fully work yet for Collada objects. Secondly, if the Collada object is animated there needs to be synchronisation between the two rendered models: each frame has to be matched identically but the animation starts as soon as the model is loaded and each model can load in a different time. How can this synchronisation be achieved?</p>
<p>If you have comments or suggestions on these last couple of points, or indeed on any part of this post, then please don&#8217;t hesitate to add to the discussion below - I&#8217;d be very happy to hear of solutions and experiences! </p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/soSWjx4Hr_g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-9-importing-and-working-with-3d-objects/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-9-importing-and-working-with-3d-objects/</feedburner:origLink></item>
		<item>
		<title>new blog.tartiflop!</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/AW8QROAI7RY/</link>
		<comments>http://blog.tartiflop.com/2008/09/new-blogtartiflop/#comments</comments>
		<pubDate>Mon, 22 Sep 2008 15:46:47 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/?p=95</guid>
		<description><![CDATA[So, after a few problems with my old blogger account I&#8217;ve finally moved to this new address : blog.tartiflop.com!
Its not been as straight-forward as I was hoping for so sorry for the delay since my last First Steps post&#8230; but promise, the next one shouldn&#8217;t be too far away! Thanks for all the encouragement I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>So, after a few problems with my old blogger account I&#8217;ve finally moved to this new address : <a href="http://blog.tartiflop.com/">blog.tartiflop.com</a>!</p>
<p>Its not been as straight-forward as I was hoping for so sorry for the delay since my last <em>First Steps</em> post&#8230; but promise, the next one shouldn&#8217;t be too far away! Thanks for all the encouragement I&#8217;ve been getting over the last few weeks&#8230; its been a real surprise and I&#8217;m really happy that people have found these posts useful&#8230;</p>
<p>Anyway, hope there&#8217;s no problems with the change in address&#8230; but of course there&#8217;s been quite a bit of work necessary to get all the links altered correctly so if you do find anything wrong just drop me a line.</p>
<p>As I mentioned before, the next <em>First Steps</em> post should be along soon&#8230; see you hopefully before the end of the month!</p>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/AW8QROAI7RY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/09/new-blogtartiflop/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/09/new-blogtartiflop/</feedburner:origLink></item>
		<item>
		<title>Musical Interlude - PJ Harvey</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/VZbg5s_VPHc/</link>
		<comments>http://blog.tartiflop.com/2008/09/musical-interlude-pj-harvey/#comments</comments>
		<pubDate>Sun, 07 Sep 2008 09:56:00 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/2008/09/musical-interlude-pj-harvey/</guid>
		<description><![CDATA[Discover PJ Harvey!
]]></description>
			<content:encoded><![CDATA[<div style="width:220px;height:55px;"><object width="220" height="55"><param name="movie" value="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1172877&#038;colorBackground=0x555552&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0"></param><embed src="http://www.deezer.com/embedded/small-widget-v2.swf?idSong=1172877&#038;colorBackground=0x525252&#038;textColor1=0xFFFFFF&#038;colorVolume=0x39D1FD&#038;autoplay=0" type="application/x-shockwave-flash" width="220" height="55"></embed></object><br /><font size='1' color ='#000000'>Discover <a href='http://www.deezer.com/en/pj-harvey.html'>PJ Harvey</a>!</font></div>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/VZbg5s_VPHc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/09/musical-interlude-pj-harvey/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/09/musical-interlude-pj-harvey/</feedburner:origLink></item>
		<item>
		<title>First steps in Papervision3D : Part 8 - Movie materials</title>
		<link>http://feedproxy.google.com/~r/tartiflop/~3/uW9RB8VwQS4/</link>
		<comments>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-8-movie-materials/#comments</comments>
		<pubDate>Sat, 06 Sep 2008 21:32:00 +0000</pubDate>
		<dc:creator>tartiflop</dc:creator>
		
		<category><![CDATA[Papervision3D]]></category>

		<category><![CDATA[ActionScript 3]]></category>

		<category><![CDATA[animation]]></category>

		<category><![CDATA[Flex Builder 3]]></category>

		<category><![CDATA[movie material]]></category>

		<category><![CDATA[Tweener]]></category>

		<category><![CDATA[video stream]]></category>

		<guid isPermaLink="false">http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-8-movie-materials/</guid>
		<description><![CDATA[Previous articles summary :

First steps in Papervision3D : Part 1
Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes.
First steps in Papervision3D : Part 2
Illustration of use of new Papervision3D v2.0 class BasicView that encapsulates essential elements to rapidly start [...]]]></description>
			<content:encoded><![CDATA[<p>Previous articles summary :</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-1">First steps in Papervision3D : Part 1</a><br />
Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes.</li>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-2">First steps in Papervision3D : Part 2</a><br />
Illustration of use of new Papervision3D v2.0 class <span style="font-style: italic;">BasicView</span> that encapsulates essential elements to rapidly start developing new 3D scenes.
</li>
<li><a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-3">First steps in Papervision3D : Part 3 - animation</a><br />
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame.</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-4">First steps in Papervision3D : Part 4 - lighting and shading</a><br />
A point light source is added to the scene. Fours materials with different characteristics are added to spheres to illustrate how Papervision3D performs shading.
</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-5">First steps in Papervision3D : Part 5 - scene interaction</a><br />
Listen to mouse events to interact with the scene and with individual rendered objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6">First steps in Papervision3D : Part 6 - Texture mapping</a><br />
Create materials using bitmap data with the aim of having more detailed or realistic objects.
</li>
<li><a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-7">First steps in Papervision3D : Part 7 - Texture mapping with lighting, bump mapping and environment mapping</a><br />
Advanced materials using specific shaders to enhance texture mapped materials with bump mapping and environment mapping.
</li>
</ul>
<p>This article continues investigating the wide range of materials available in Papervision3D and probably represents the last one of this theme. Whereas the previous examples tried to improve the realism of a 3D scene, this article takes a look at the more dynamic materials available with Papervision3D.</p>
<p>First, apologies for the length of this entry : actually, the more you look at what is available in Papervision3D the more you realise how much it offers! The aim here is to look at <span style="font-style:italic;">MovieMaterials</span>. These offer the ability of having interactive and dynamic surfaces on 3D objects either with Flash movies or Flash video streams. Summarizing this to a few lines probably wouldn&#8217;t do it justice so I&#8217;ve tried to illustrate here some of the more exciting features offered&#8230; and even in doing so am probably still missing a lot!</p>
<p>Anyway, this article introduces two new kinds of materials: <span style="font-style:italic;">MovieMaterial</span> and <span style="font-style:italic;">VideoStreamMaterial</span> (which inherits from the former). </p>
<p>The <span style="font-style:italic;">MovieMaterial</span> allows us to create a material using a pre-existing Flash movie (embedded in a Papervision3D movie) or simply from any <span style="font-style:italic;">MovieClip</span> / <span style="font-style:italic;">Sprite</span> inheriting class instance. Papervision3D provides mapping functions that allow us to interact with these Flash movies with mouse clicks and movements even in a 3D environment. </p>
<p>The <span style="font-style:italic;">VideoStreamMaterial</span>, as its name implies, allows us to stream flash video streams (<span style="font-style:italic;">flv</span> files) onto a 3D object.</p>
<p>The example shown in this article includes these three possibilities including: a flash video stream from a given URL, an embedded standard (non-3D) Flash movie and an example showing a Papervision3D scene being animated as a material in another Papervision3D scene&#8230; did I mention before that this article might be quite long?!</p>
<p>So, what we essentially have here are three Actionscript classes: the main 3D scene, a non-3D Sprite-inheriting class and another, secondary Papervision3D scene. I&#8217;m only going to discuss the first one here but I&#8217;ll include the source for the others at the end.</p>
<p>The main source code is shown below. The example shows the three movie materials projected onto a specific face of three projectors (<span style="font-style:italic;">Cube</span> instances), all rotating about the y-axis. The projectors can be double-clicked to enlarge them, stop them from rotating and provide a more simple means of interacting with them. Double-clicking again puts them back with the others. The whole scene can be rotated by clicking on the background and moving the mouse. The code, as warned, is a little longer than hoped for, but we&#8217;ll look at each part in more details afterwards and really there&#8217;s nothing very complicated there. I&#8217;m using the Tweener library again to provide smoother visual effects (see <a href="http://blog.tartiflop.com/2008/07/first-steps-in-papervision3d-part-3">Part 3 - animation</a> - for more details).</p>
<div id="codeSnippet">
<pre>
<blockquote>
package {
&nbsp;
&nbsp; import caurina.transitions.Tweener;
&nbsp;
&nbsp; import flash.display.MovieClip;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp; import flash.media.Video;
&nbsp; import flash.net.NetConnection;
&nbsp; import flash.net.NetStream;
&nbsp;
&nbsp; import org.papervision3d.core.proto.MaterialObject3D;
&nbsp; import org.papervision3d.events.InteractiveScene3DEvent;
&nbsp; import org.papervision3d.lights.PointLight3D;
&nbsp; import org.papervision3d.materials.MovieMaterial;
&nbsp; import org.papervision3d.materials.VideoStreamMaterial;
&nbsp; import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
&nbsp; import org.papervision3d.materials.utils.MaterialsList;
&nbsp; import org.papervision3d.objects.DisplayObject3D;
&nbsp; import org.papervision3d.objects.primitives.Cube;
&nbsp; import org.papervision3d.view.BasicView;

&nbsp; [SWF(backgroundColor="#222222")]

&nbsp; public class Example008 extends BasicView {
&nbsp;
&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 400;

&nbsp; &nbsp; [Embed(source="/../assets/DrawTool.swf")]
&nbsp; &nbsp; private var DrawTool:Class;

&nbsp; &nbsp; private var exampleMovie:MovieClip;

 &nbsp; &nbsp; private var videoURL:String = "http://www.tartiflop.com/pv3d/FirstSteps/Radiohead_HOC.flv";

&nbsp; &nbsp; private var video:Video;
&nbsp; &nbsp; private var stream:NetStream;
&nbsp; &nbsp; private var connection:NetConnection;

&nbsp; &nbsp; private var objectGroup:DisplayObject3D;
&nbsp; &nbsp; private var light:PointLight3D;
&nbsp; &nbsp; private var currentActiveObject:DisplayObject3D = null;
&nbsp; &nbsp;
&nbsp; &nbsp; private var projectors:Array = new Array();
&nbsp; &nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var canRotate:Boolean = true;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;
&nbsp; &nbsp; private var cameraYaw:Number = -60;
&nbsp; &nbsp;
&nbsp; &nbsp; public function Example008() {
&nbsp; &nbsp; &nbsp; super(0, 0, true, true);

&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();

&nbsp; &nbsp; &nbsp; // create video stream for VideoStreamMaterial
&nbsp; &nbsp; &nbsp; createVideoStream();

&nbsp; &nbsp; &nbsp; // create the 3D Objects
&nbsp; &nbsp; &nbsp; createScene();

&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Start rendering the scene
&nbsp; &nbsp; &nbsp; startRendering();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function init3D():void {
&nbsp; &nbsp; &nbsp; // position the camera
&nbsp; &nbsp; &nbsp; camera.z = -1000;
&nbsp; &nbsp; &nbsp; camera.fov = 60;
&nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createVideoStream():void {
&nbsp; &nbsp; &nbsp; // Create a NetConnection. 2-way connection not necessary: connect to null
&nbsp; &nbsp; &nbsp; connection = new NetConnection();
&nbsp; &nbsp; &nbsp; connection.connect(null);

&nbsp; &nbsp; &nbsp; // Create a new NetStream to obtain the flv stream. Ignore client messages so use a simple Object
&nbsp; &nbsp; &nbsp; stream = new NetStream(connection);
&nbsp; &nbsp; &nbsp; stream.client = new Object();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a new video player
&nbsp; &nbsp; &nbsp; video = new Video();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // start streaming the video from the given URL and play it on the video player
&nbsp; &nbsp; &nbsp; stream.play(videoURL);
&nbsp; &nbsp; &nbsp; video.attachNetStream(stream);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {
&nbsp; &nbsp; &nbsp; // Specify a point light source and its location
&nbsp; &nbsp; &nbsp; light = new PointLight3D();
&nbsp; &nbsp; &nbsp; light.x = 400;
&nbsp; &nbsp; &nbsp; light.y = 1000;
&nbsp; &nbsp; &nbsp; light.z = -400;

&nbsp; &nbsp; &nbsp; // Create a 3D object to group the projectors
&nbsp; &nbsp; &nbsp; objectGroup = new DisplayObject3D();

&nbsp; &nbsp; &nbsp; // Create a new video stream material with precise rendering.
&nbsp; &nbsp; &nbsp; var videoMaterial:VideoStreamMaterial = new VideoStreamMaterial(video, stream, true);
&nbsp; &nbsp; &nbsp; addProjector(videoMaterial);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new flash movie material from an actionscript class (not transparent, animated and precise rendering)
&nbsp; &nbsp; &nbsp; var movieMaterial1:MovieMaterial = new MovieMaterial(new Example006b(), false, true, true);
&nbsp; &nbsp; &nbsp; addProjector(movieMaterial1);

&nbsp; &nbsp; &nbsp; // Create a new flash movie material from an embedded flash movie (not transparent, animated and precise rendering)
&nbsp; &nbsp; &nbsp; var movieMaterial2:MovieMaterial = new MovieMaterial(new DrawTool(), false, true, true);
&nbsp; &nbsp; &nbsp; addProjector(movieMaterial2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the object group and light
&nbsp; &nbsp; &nbsp; scene.addChild(objectGroup);
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // set up the projector positions in the scene
&nbsp; &nbsp; &nbsp; organiseProjectors();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function addProjector(material:MovieMaterial):void {
&nbsp; &nbsp; &nbsp; // materials are smooth rendred, interactive and resize to the 3D object.
&nbsp; &nbsp; &nbsp; material.smooth = true;
&nbsp; &nbsp; &nbsp; material.interactive = true;
&nbsp; &nbsp; &nbsp; material.allowAutoResize = true;

&nbsp; &nbsp; &nbsp; // simple flat shaded material as default for the projector
&nbsp; &nbsp; &nbsp; var flatShadedMaterial:MaterialObject3D = new FlatShadeMaterial(light, 0x554D33, 0x1A120C);
&nbsp; &nbsp; &nbsp; flatShadedMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Material list with MovieMaterial used on the front, the rest being flat shaded
&nbsp; &nbsp; &nbsp; var materialList:MaterialsList = new MaterialsList({"all":flatShadedMaterial, "front":material});

&nbsp; &nbsp; &nbsp; // create a new interactive projector
&nbsp; &nbsp; &nbsp; var projector:Cube = new Cube(materialList, 320, 10, 240);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_DOUBLE_CLICK, onMouseDoubleClickOnObject);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, onMouseOverObject);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, onMouseOutObject);

&nbsp; &nbsp; &nbsp; // add the projector to the scene, being part of the object group
&nbsp; &nbsp; &nbsp; objectGroup.addChild(projector);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // store projector in an array
&nbsp; &nbsp; &nbsp; projectors.push(projector);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function organiseProjectors():void {
&nbsp; &nbsp; &nbsp; // calculate angle between projectors
&nbsp; &nbsp; &nbsp; var theta:Number = 360 / projectors.length;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up each projector so that they are distributed in a circle and facing outwards
&nbsp; &nbsp; &nbsp; for (var i:int = 0; i < projectors.length; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; var projector:Cube = projectors[i];
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // specifc angle for projector
&nbsp; &nbsp; &nbsp; &nbsp; var angle:Number = i * theta - 180;
&nbsp; &nbsp; &nbsp; &nbsp; var angleRadians:Number = angle * 2 * Math.PI / 360.;

&nbsp; &nbsp; &nbsp; &nbsp; // position of projector
&nbsp; &nbsp; &nbsp; &nbsp; var x:Number = Math.sin(angleRadians) * ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; &nbsp; var z:Number = Math.cos(angleRadians) * ORBITAL_RADIUS;

&nbsp; &nbsp; &nbsp; &nbsp; // create tween to position, rotate and scale projector smoothly over 1 second
&nbsp; &nbsp; &nbsp; &nbsp; Tweener.addTween(projector, {x:x, y:-150, z:z, rotationY:angle, scale:0.8, time:1, transition:"linear" });
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; override protected function onRenderTick(event:Event=null):void {
&nbsp; &nbsp; &nbsp; // rotate the object group: angle kept between 0 and 360 degrees
&nbsp; &nbsp; &nbsp; objectGroup.rotationY += 1;
&nbsp; &nbsp; &nbsp; if (objectGroup.rotationY > 360) {
&nbsp; &nbsp; &nbsp; &nbsp; objectGroup.rotationY -= 360;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // if an object is active (double clicked) rotate it in the opposite direction
&nbsp; &nbsp; &nbsp; // to the group so that it is stationary
&nbsp; &nbsp; &nbsp; if (currentActiveObject != null) {
&nbsp; &nbsp; &nbsp; &nbsp; currentActiveObject.rotationY -=1;
&nbsp; &nbsp; &nbsp; &nbsp; if (currentActiveObject.rotationY < 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentActiveObject.rotationY += 360;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation &#038;&#038; canRotate) {
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch >= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // call the renderer
&nbsp; &nbsp; &nbsp; super.onRenderTick(event);
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when mouse double clicked on a projector
&nbsp; &nbsp; private function onMouseDoubleClickOnObject(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; var object:DisplayObject3D = event.displayObject3D;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // determine if the object is to be activated (placed in center) or deactivated
&nbsp; &nbsp; &nbsp; if (object == currentActiveObject) {
&nbsp; &nbsp; &nbsp; &nbsp; deactivate(object);
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; activate(object);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // disable camera rotation when mouse is over a projector
&nbsp; &nbsp; private function onMouseOverObject(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; canRotate = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // re-enable camera rotation when mouse is out of a projector
&nbsp; &nbsp; private function onMouseOutObject(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; canRotate = true;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // places a projector in the center
&nbsp; &nbsp; private function activate(object:DisplayObject3D):void {
&nbsp; &nbsp; &nbsp; // remove projector from rotating projectors array
&nbsp; &nbsp; &nbsp; projectors.splice(projectors.indexOf(object), 1);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // if a projector is active already, put it back in the array of rotating projectors
&nbsp; &nbsp; &nbsp; if (currentActiveObject != null) {
&nbsp; &nbsp; &nbsp; &nbsp; projectors.push(currentActiveObject);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a tween to place selected projector in the center
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:100, x:0, z:0, rotationY:-objectGroup.rotationY, scale:2, time:1, transition:"linear" });
&nbsp; &nbsp; &nbsp; currentActiveObject = object;

&nbsp; &nbsp; &nbsp; // re-organise the other projectors
&nbsp; &nbsp; &nbsp; organiseProjectors();&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // puts an activated projector back into the main pack of rotating projectors
&nbsp; &nbsp; private function deactivate(object:DisplayObject3D):void {
&nbsp; &nbsp; &nbsp; // put the projector back into the rotating projectors array
&nbsp; &nbsp; &nbsp; projectors.push(currentActiveObject);
&nbsp; &nbsp; &nbsp; currentActiveObject = null;&nbsp;
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // re-organise all projectors
&nbsp; &nbsp; &nbsp; organiseProjectors();&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>All of this provides the following Flash movie. As mentioned above, double-click on an object to activate it (this actually just means that the object is magnified and stops spinning - it doesn&#8217;t change any of the object characteristics). Double-click on an activated one to deactivate it (put it back with the others). Two projectors allow for user interactions at any point in time: you can draw on one and rotate the 3D scene on the other. The final projector streams <span style="font-style:italic;">House Of Cards</span> by <span style="font-style:italic;">Radiohead</span> (<a href="http://blog.papervision3d.org/2008/07/15/radiohead%E2%80%99s-house-of-cards/">another Paperivision3D example</a>?!). The whole scene can be rotated by clicking on the background and moving the mouse. Click on the image below to see it all in action.</p>
<p><a href="http://www.tartiflop.com/pv3d/FirstSteps/Example008.swf" class="lightwindow" params="lightwindow_width=640,lightwindow_height=480" title=""><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_gOqHtPCk6xw/SMMBz4syALI/AAAAAAAAAGk/Ml4kQyIjqes/s400/Example008.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5243036382094557362" /></a></p>
<p>So, as with the other articles in this series lets take a look at how the scene is constructed step-by-step. As usual, the code is organised in more of less the same way as previous examples. The main difference comes from creating and attaching a video stream and modifying the animation and object interaction. </p>
<p>Let&#8217;s start with the constructor. The only difference here is the initialisation of the video stream. If you take a look at the source code for the <span style="font-style:italic;">VideoStreamMaterial</span> you&#8217;ll see that it takes two objects: a <span style="font-style:italic;">Video</span> and a <span style="font-style:italic;">NetStream</span>. These are pure Actionscript objects necessary for streaming the data and displaying it. The <a href="http://livedocs.adobe.com/flex/3/langref/flash/net/NetConnection.html">Flex language reference for <span style="font-style:italic;">NetConnection</span></a> came in handy here to see what these objects do and how to create them. A slightly cut-down method is used here but it remains in principal the same.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function createVideoStream():void {
&nbsp; &nbsp; &nbsp; // Create a NetConnection. 2-way connection not necessary: connect to null
&nbsp; &nbsp; &nbsp; connection = new NetConnection();
&nbsp; &nbsp; &nbsp; connection.connect(null);

&nbsp; &nbsp; &nbsp; // Create a new NetStream to obtain the flv stream. Ignore client messages so use a simple Object
&nbsp; &nbsp; &nbsp; stream = new NetStream(connection);
&nbsp; &nbsp; &nbsp; stream.client = new Object();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a new video player
&nbsp; &nbsp; &nbsp; video = new Video();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // start streaming the video from the given URL and play it on the video player
&nbsp; &nbsp; &nbsp; stream.play(localVideoURL);
&nbsp; &nbsp; &nbsp; video.attachNetStream(stream);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see in the <a href="http://livedocs.adobe.com/flex/3/langref/flash/net/NetConnection.html#includeExamplesSummary">example shown in the Flex livedocs</a>, there are ways to listen to events occurring during the streaming but for this example I&#8217;ve just done a minimum to restrict the length of the code a bit.</p>
<p>Next we come to the scene creation. This again is based on previous examples so we have a light source, an object group to simplify the rotation of a number of objects and then the individual 3D objects, each one with a different <span style="font-style:italic;">MovieMaterial</span>. </p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function createScene():void {
&nbsp; &nbsp; &nbsp; // Specify a point light source and its location
&nbsp; &nbsp; &nbsp; light = new PointLight3D();
&nbsp; &nbsp; &nbsp; light.x = 400;
&nbsp; &nbsp; &nbsp; light.y = 1000;
&nbsp; &nbsp; &nbsp; light.z = -400;

&nbsp; &nbsp; &nbsp; // Create a 3D object to group the projectors
&nbsp; &nbsp; &nbsp; objectGroup = new DisplayObject3D();

&nbsp; &nbsp; &nbsp; // Create a new video stream material with precise rendering.
&nbsp; &nbsp; &nbsp; var videoMaterial:VideoStreamMaterial = new VideoStreamMaterial(video, stream, true);
&nbsp; &nbsp; &nbsp; addProjector(videoMaterial);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create a new flash movie material from an actionscript class (not transparent, animated and precise rendering)
&nbsp; &nbsp; &nbsp; var movieMaterial1:MovieMaterial = new MovieMaterial(new Example006b(), false, true, true);
&nbsp; &nbsp; &nbsp; addProjector(movieMaterial1);

&nbsp; &nbsp; &nbsp; // Create a new flash movie material from an embedded flash movie (not transparent, animated and precise rendering)
&nbsp; &nbsp; &nbsp; var movieMaterial2:MovieMaterial = new MovieMaterial(new DrawTool(), false, true, true);
&nbsp; &nbsp; &nbsp; addProjector(movieMaterial2);
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // add the object group and light
&nbsp; &nbsp; &nbsp; scene.addChild(objectGroup);
&nbsp; &nbsp; &nbsp; scene.addChild(light);

&nbsp; &nbsp; &nbsp; // set up the projector positions in the scene
&nbsp; &nbsp; &nbsp; organiseProjectors();
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>As you can see the three <span style="font-style:italic;">MovieMaterials</span> (<span style="font-style:italic;">VideoStreamMaterial</span> inherits from this) are simple to create. Firstly the <span style="font-style:italic;">VideoStreamMaterial</span> takes the <span style="font-style:italic;">Video</span> and <span style="font-style:italic;">NetStream</span> we created just before and I&#8217;ve chosen precise rendering to minimise perspective distortions. The other two <span style="font-style:italic;">MovieMaterials</span> take in one case a Actionscript object and an embedded Flash movie in the other (see the start of the class definition to see the embedding, which is identical to how we embedded images in previous examples). The three boolean values are associated with <span style="font-style:italic;">transparent</span>, <span style="font-style:italic;">animated</span> and <span style="font-style:italic;">precise rendering</span> arguments. So since the Flash movie objects are animated we need to specify <span style="font-style:italic;">true</span> for the animated argument to ensure that the scenes are updated.</p>
<p>The scene is then populated with the object group (containing the 3D objects) and the light. The positioning of the 3D objects is delegated to the <span style="font-style:italic;">organiseProjectors</span> function which we&#8217;ll come to shortly.</p>
<p>In this example I&#8217;m using the <span style="font-style:italic;">Cube</span> primitive. Each one has a specific face (the &#8220;front&#8221;) showing the <span style="font-style:italic;">MovieMaterial</span> and since each one has essentially the same characteristics I&#8217;ve factorised the code to initialise each one identically.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function addProjector(material:MovieMaterial):void {
&nbsp; &nbsp; &nbsp; // materials are smooth rendred, interactive and resize to the 3D object.
&nbsp; &nbsp; &nbsp; material.smooth = true;
&nbsp; &nbsp; &nbsp; material.interactive = true;
&nbsp; &nbsp; &nbsp; material.allowAutoResize = true;

&nbsp; &nbsp; &nbsp; // simple flat shaded material as default for the projector
&nbsp; &nbsp; &nbsp; var flatShadedMaterial:MaterialObject3D = new FlatShadeMaterial(light, 0x554D33, 0x1A120C);
&nbsp; &nbsp; &nbsp; flatShadedMaterial.interactive = true;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Material list with MovieMaterial used on the front, the rest being flat shaded
&nbsp; &nbsp; &nbsp; var materialList:MaterialsList = new MaterialsList({"all":flatShadedMaterial, "front":material});

&nbsp; &nbsp; &nbsp; // create a new interactive projector
&nbsp; &nbsp; &nbsp; var projector:Cube = new Cube(materialList, 320, 10, 240);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_DOUBLE_CLICK, onMouseDoubleClickOnObject);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, onMouseOverObject);
&nbsp; &nbsp; &nbsp; projector.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, onMouseOutObject);

&nbsp; &nbsp; &nbsp; // add the projector to the scene, being part of the object group
&nbsp; &nbsp; &nbsp; objectGroup.addChild(projector);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // store projector in an array
&nbsp; &nbsp; &nbsp; projectors.push(projector);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Each <span style="font-style:italic;">MovieMaterial</span> is smoothed (to appear less pixelated), made interactive (so that the 3D object responds to mouse events) and auto-resized so that they resize automatically to the cube dimensions. The other five faces of the cube are covered in a simple flat-shaded material (as seen in <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-4">Part 4</a>) which is also interactive. The cube is then constructed with a <span style="font-style:italic;">MaterialList</span> containing these two different materials. Event listeners are then added to the cube so that it responds to double-click events (to <span style="font-style:italic;">activate</span> and <span style="font-style:italic;">deactivate</span> it) and mouse over and out events which, as we&#8217;ll see later, are used to restrict the stage mouse listeners for rotating the scene (essentially they stop the scene from rotating when a user is interacting with one of the 3D objets).</p>
<p>The new cube is then added to the object group (so that it is rendered) and stored in an <span style="font-style:italic;">Array</span> to allow us to access it later.</p>
<p>As you see in the example, the non-activated <span style="font-style:italic;">projectors</span> are spaced evenly in a circle, facing outwards (the rotation comes simply from a rotation of the object group, handled separately). The function <span style="font-style:italic;">organiseProjectors</span> performs the necessary calculations and animation.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; private function organiseProjectors():void {
&nbsp; &nbsp; &nbsp; // calculate angle between projectors
&nbsp; &nbsp; &nbsp; var theta:Number = 360 / projectors.length;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // set up each projector so that they are distributed in a circle and facing outwards
&nbsp; &nbsp; &nbsp; for (var i:int = 0; i < projectors.length; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; var projector:Cube = projectors[i];
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // specifc angle for projector
&nbsp; &nbsp; &nbsp; &nbsp; var angle:Number = i * theta - 180;
&nbsp; &nbsp; &nbsp; &nbsp; var angleRadians:Number = angle * 2 * Math.PI / 360.;

&nbsp; &nbsp; &nbsp; &nbsp; // position of projector
&nbsp; &nbsp; &nbsp; &nbsp; var x:Number = Math.sin(angleRadians) * ORBITAL_RADIUS;
&nbsp; &nbsp; &nbsp; &nbsp; var z:Number = Math.cos(angleRadians) * ORBITAL_RADIUS;

&nbsp; &nbsp; &nbsp; &nbsp; // create tween to position, rotate and scale projector smoothly over 1 second
&nbsp; &nbsp; &nbsp; &nbsp; Tweener.addTween(projector, {x:x, y:-150, z:z, rotationY:angle, scale:0.8, time:1, transition:"linear" });
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
</blockquote>
</blockquote>
</pre>
</div>
<p>This function quite simply calculates the angle between each projector (<span style="font-style:italic;">Cube</span> instance) and positions them in the x-z plane accordingly. To smoothly position each of them I&#8217;ve used a linear <span style="font-style:italic;">tween</span> to modify the x, y, z, rotationY and scale properties of each of them, taking one second to animate. Thanks to Tweener this is very simple to perform!</p>
<p>Next we come to the <span style="font-style:italic;">onRenderTick</span> function which updates the scene at every movie frame. This is essentially the same as for previous examples in the series</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; override protected function onRenderTick(event:Event=null):void {
&nbsp; &nbsp; &nbsp; // rotate the object group: angle kept between 0 and 360 degrees
&nbsp; &nbsp; &nbsp; objectGroup.rotationY += 1;
&nbsp; &nbsp; &nbsp; if (objectGroup.rotationY > 360) {
&nbsp; &nbsp; &nbsp; &nbsp; objectGroup.rotationY -= 360;
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // if an object is active (double clicked) rotate it in the opposite direction
&nbsp; &nbsp; &nbsp; // to the group so that it is stationary
&nbsp; &nbsp; &nbsp; if (currentActiveObject != null) {
&nbsp; &nbsp; &nbsp; &nbsp; currentActiveObject.rotationY -=1;
&nbsp; &nbsp; &nbsp; &nbsp; if (currentActiveObject.rotationY < 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentActiveObject.rotationY += 360;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation &#038;&#038; canRotate) {
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (mouseY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (mouseX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch >= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = mouseX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = mouseY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // call the renderer
&nbsp; &nbsp; &nbsp; super.onRenderTick(event);
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>The object group is rotated as in previous examples. This time I&#8217;m using the <span style="font-style:italic;">rotationY</span> property rather than the function <span style="font-style:italic;">yaw</span> to have a better control of the angle of rotation. The activated object is spun in the opposite direction at the same time so that it is effectively stationary. </p>
<p>The camera rotation is essentially the same as before except that we use the <span style="font-style:italic;">canRotate</span> boolean value to restrict the rotation when the mouse is over a 3D object.</p>
<p>The rest of the code is essentially to handle the mouse events. The <span style="font-style:italic;">onMouseDown</span>, <span style="font-style:italic;">onMouseUp</span> are the same as before to initiate and stop the scene rotation. <span style="font-style:italic;">onMouseOverObject</span> and <span style="font-style:italic;">onMouseOutObject</span> add to this by limiting the rotation when the user is interacting with a 3D object.</p>
<p>To activate and deactivate a projector the double-click event on a 3D object is used.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; // called when mouse double clicked on a projector
&nbsp; &nbsp; private function onMouseDoubleClickOnObject(event:InteractiveScene3DEvent):void {
&nbsp; &nbsp; &nbsp; var object:DisplayObject3D = event.displayObject3D;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // determine if the object is to be activated (placed in center) or deactivated
&nbsp; &nbsp; &nbsp; if (object == currentActiveObject) {
&nbsp; &nbsp; &nbsp; &nbsp; deactivate(object);
&nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; activate(object);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>Simply, if the object clicked is the current active object then we deactivate it. If not we activate it. </p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; // places a projector in the center
&nbsp; &nbsp; private function activate(object:DisplayObject3D):void {
&nbsp; &nbsp; &nbsp; // remove projector from rotating projectors array
&nbsp; &nbsp; &nbsp; projectors.splice(projectors.indexOf(object), 1);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // if a projector is active already, put it back in the array of rotating projectors
&nbsp; &nbsp; &nbsp; if (currentActiveObject != null) {
&nbsp; &nbsp; &nbsp; &nbsp; projectors.push(currentActiveObject);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create a tween to place selected projector in the center
&nbsp; &nbsp; &nbsp; Tweener.addTween(object, {y:100, x:0, z:0, rotationY:-objectGroup.rotationY, scale:2, time:1, transition:"linear" });
&nbsp; &nbsp; &nbsp; currentActiveObject = object;

&nbsp; &nbsp; &nbsp; // re-organise the other projectors
&nbsp; &nbsp; &nbsp; organiseProjectors();&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>When activating a projector, it is removed from the <span style="font-style:italic;">Array</span> of spinning projectors. If another projector is already activated then we put it back into this group. A simple linear tween is then used to reposition the newly activated projector in the center and to rescale it so that it is bigger than the others. We then recall <span style="font-style:italic;">organiseProjectors</span> to reposition the remaining projectors around a circle.</p>
<p>Deactivating a projector simply involves putting it back into the <span style="font-style:italic;">Array</span> and repositioning all of them around a circle.</p>
<div id="codeSnippet">
<pre>
<blockquote>
&nbsp; &nbsp; // puts an activated projector back into the main pack of rotating projectors
&nbsp; &nbsp; private function deactivate(object:DisplayObject3D):void {
&nbsp; &nbsp; &nbsp; // put the projector back into the rotating projectors array
&nbsp; &nbsp; &nbsp; projectors.push(currentActiveObject);
&nbsp; &nbsp; &nbsp; currentActiveObject = null;&nbsp;
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // re-organise all projectors
&nbsp; &nbsp; &nbsp; organiseProjectors();&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
</blockquote>
</pre>
</div>
<p>So that&#8217;s all there is to it! Really Papervision3D and Tweener do all the complicated work to display and animated the 3D scene: all that&#8217;s new here is the creation of the movie materials. Once again I hope this shows that Papervision3D is really very simple to use. Looking at the Papervision3D source code really helps a lot to understand how the materials are created and you&#8217;ll see that I haven&#8217;t covered everything but hopefully this gives a good starting point in creating your own 3D scenes with movie materials!</p>
<p>Just for completeness I&#8217;ve included below the source code for the animated movies used for the <span style="font-style:italic;">MovieMaterials</span>. One is a simple 2D, standard Flash animation that reacts to mouse events. The other is based on a previous Papervision3D example shown in this series (from <a href="http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6">Part 6</a>) but without the <span style="font-style:italic;">InteractiveScene3DEvent</span> handlers. I found it really amazing that one 3D scene can be used as a material in another 3D scene - good work Papervision3D!</p>
<p>Here&#8217;s drawTool.as&#8230;</p>
<div id="codeSnippet">
<pre>
<blockquote>
package {
&nbsp; import flash.display.Sprite;
&nbsp; import flash.events.MouseEvent;
&nbsp; import flash.text.TextField;
&nbsp; import flash.text.TextFieldAutoSize;
&nbsp; import flash.text.TextFormat;
&nbsp; 

&nbsp; public class DrawTool extends Sprite {

&nbsp; &nbsp; private var isDrawing:Boolean = false;

&nbsp; &nbsp; public function DrawTool() {

&nbsp; &nbsp; &nbsp; // create a drawing surface
&nbsp; &nbsp; &nbsp; graphics.beginFill(0xEEEEEE);
&nbsp; &nbsp; &nbsp; graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; graphics.lineTo(320, 0);
&nbsp; &nbsp; &nbsp; graphics.lineTo(320, 240);
&nbsp; &nbsp; &nbsp; graphics.lineTo(0, 240);
&nbsp; &nbsp; &nbsp; graphics.endFill();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create text and format
&nbsp; &nbsp; &nbsp; var textFormat:TextFormat = new TextFormat();
&nbsp; &nbsp; &nbsp; textFormat.size = 30;
&nbsp; &nbsp; &nbsp; textFormat.font = "Arial";
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; var text:TextField = new TextField();
&nbsp; &nbsp; &nbsp; text.x = 50;
&nbsp; &nbsp; &nbsp; text.y = 100;
&nbsp; &nbsp; &nbsp; text.textColor = 0x222222;
&nbsp; &nbsp; &nbsp; text.text = "click to draw!";
&nbsp; &nbsp; &nbsp; text.setTextFormat(textFormat);
&nbsp; &nbsp; &nbsp; text.autoSize = TextFieldAutoSize.LEFT;
&nbsp; &nbsp; &nbsp; text.selectable = false;
&nbsp; &nbsp; &nbsp; addChild(text);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // listen to mouse events
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
&nbsp; &nbsp; &nbsp; this.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // start drawing circles
&nbsp; &nbsp; private function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; isDrawing = true;
&nbsp; &nbsp; &nbsp; drawCircle(event.stageX, event.stageY);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // stop drawing circles
&nbsp; &nbsp; private function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; isDrawing = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // draw a circle
&nbsp; &nbsp; private function onMouseMove(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; if (isDrawing) {
&nbsp; &nbsp; &nbsp; &nbsp; drawCircle(event.stageX, event.stageY);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; // circle drawing function
&nbsp; &nbsp; private function drawCircle(x:int, y:int):void {
&nbsp; &nbsp; &nbsp; graphics.beginFill(Math.random() * 0xFFFFFF, 0.5);
&nbsp; &nbsp; &nbsp; graphics.drawCircle(x, y, 5);
&nbsp; &nbsp; &nbsp; graphics.endFill();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>&#8230; and finally Example006b.as :</p>
<div id="codeSnippet">
<pre>
<blockquote>
package {
&nbsp;
&nbsp; import flash.display.Bitmap;
&nbsp; import flash.display.Sprite;
&nbsp; import flash.events.Event;
&nbsp; import flash.events.MouseEvent;
&nbsp;
&nbsp; import org.papervision3d.materials.BitmapMaterial;
&nbsp; import org.papervision3d.materials.utils.MaterialsList;
&nbsp; import org.papervision3d.objects.DisplayObject3D;
&nbsp; import org.papervision3d.objects.primitives.Cube;
&nbsp; import org.papervision3d.objects.primitives.Sphere;
&nbsp; import org.papervision3d.view.BasicView;

&nbsp; [SWF(backgroundColor="#FFFFFF")]

&nbsp; public class Example006b extends BasicView {
&nbsp;
&nbsp; &nbsp; [Embed(source="/../assets/pv3d.png")] private var PV3D:Class;

&nbsp; &nbsp; private static const ORBITAL_RADIUS:Number = 100;
&nbsp;
&nbsp; &nbsp; private var bitmap:Bitmap = new PV3D();

&nbsp; &nbsp; private var cube1:Cube;
&nbsp; &nbsp; private var cube2:Cube;
&nbsp; &nbsp; private var sphere1:Sphere;
&nbsp; &nbsp; private var sphere2:Sphere;
&nbsp; &nbsp; private var objectGroup:DisplayObject3D;
&nbsp; &nbsp;
&nbsp; &nbsp; private var doRotation:Boolean = false;
&nbsp; &nbsp; private var lastMouseX:int;
&nbsp; &nbsp; private var lastMouseY:int;
&nbsp; &nbsp; private var cameraPitch:Number = 60;
&nbsp; &nbsp; private var cameraYaw:Number = -60;
&nbsp; &nbsp;
&nbsp; &nbsp; public function Example006b() {
&nbsp; &nbsp; &nbsp; var background:Sprite = new Sprite();
&nbsp; &nbsp; &nbsp; background.graphics.beginFill(0x000000);
&nbsp; &nbsp; &nbsp; background.graphics.moveTo(0, 0);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(320, 0);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(320, 240);
&nbsp; &nbsp; &nbsp; background.graphics.lineTo(0, 240);
&nbsp; &nbsp; &nbsp; background.graphics.endFill();
&nbsp; &nbsp; &nbsp; addChild(background);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; super(320, 240, true, false);

&nbsp; &nbsp; &nbsp; // Initialise Papervision3D
&nbsp; &nbsp; &nbsp; init3D();
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // Create the 3D objects
&nbsp; &nbsp; &nbsp; createScene();

&nbsp; &nbsp; &nbsp; // Listen to mouse up and down events on the stage
&nbsp; &nbsp; &nbsp; background.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
&nbsp; &nbsp; &nbsp; background.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
&nbsp; &nbsp; &nbsp; background.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

&nbsp; &nbsp; &nbsp; // Start rendering the scene
&nbsp; &nbsp; &nbsp; startRendering();
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function init3D():void {
&nbsp; &nbsp; &nbsp; // position the camera
&nbsp; &nbsp; &nbsp; camera.z = -500;
&nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; }

&nbsp; &nbsp; private function createScene():void {

&nbsp; &nbsp; &nbsp; // create interactive bitmap material
&nbsp; &nbsp; &nbsp; var bitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false);

&nbsp; &nbsp; &nbsp; // create an interactive tiled bitmap material (bitmap tiled as 2 x 2)
&nbsp; &nbsp; &nbsp; var tiledBitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false);
&nbsp; &nbsp; &nbsp; tiledBitmapMaterial.tiled = true;
&nbsp; &nbsp; &nbsp; tiledBitmapMaterial.maxU = 2;
&nbsp; &nbsp; &nbsp; tiledBitmapMaterial.maxV = 2;
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // create cube with simple bitmap material
&nbsp; &nbsp; &nbsp; cube1 = new Cube(getBitmapMaterials(bitmapMaterial), 50, 50, 50);
&nbsp; &nbsp; &nbsp; cube1.x =  ORBITAL_RADIUS;

&nbsp; &nbsp; &nbsp; // create cube with tiled bitmap material
&nbsp; &nbsp; &nbsp; cube2 = new Cube(getBitmapMaterials(tiledBitmapMaterial), 50, 50, 50);
&nbsp; &nbsp; &nbsp; cube2.x = -ORBITAL_RADIUS;
&nbsp;
&nbsp; &nbsp; &nbsp; // create sphere with simple bitmap material
&nbsp; &nbsp; &nbsp; sphere1 = new Sphere(bitmapMaterial, 25, 10, 10);
&nbsp; &nbsp; &nbsp; sphere1.z =  ORBITAL_RADIUS;

&nbsp; &nbsp; &nbsp; // create sphere with tiled bitmap material
&nbsp; &nbsp; &nbsp; sphere2 = new Sphere(tiledBitmapMaterial, 25, 10, 10);
&nbsp; &nbsp; &nbsp; sphere2.z = -ORBITAL_RADIUS;

&nbsp; &nbsp; &nbsp; // Create a 3D object to group the spheres
&nbsp; &nbsp; &nbsp; objectGroup = new DisplayObject3D();
&nbsp; &nbsp; &nbsp; objectGroup.addChild(cube1);
&nbsp; &nbsp; &nbsp; objectGroup.addChild(cube2);
&nbsp; &nbsp; &nbsp; objectGroup.addChild(sphere1);
&nbsp; &nbsp; &nbsp; objectGroup.addChild(sphere2);

&nbsp; &nbsp; &nbsp; // Add the light and spheres to the scene
&nbsp; &nbsp; &nbsp; scene.addChild(objectGroup);
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; private function getBitmapMaterials(bitmapMaterial:BitmapMaterial):MaterialsList {
&nbsp; &nbsp; &nbsp; // create list of materials for all faces of the cube,
&nbsp; &nbsp; &nbsp; //    all with the same bitmap material
&nbsp; &nbsp; &nbsp; var materials:MaterialsList = new MaterialsList();
&nbsp; &nbsp; &nbsp; materials.addMaterial(bitmapMaterial, "all");
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; return materials;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; override protected function onRenderTick(event:Event=null):void {

&nbsp; &nbsp; &nbsp; // rotate the objects
&nbsp; &nbsp; &nbsp; cube1.yaw(-3);
&nbsp; &nbsp; &nbsp; cube2.yaw(-3);
&nbsp; &nbsp; &nbsp; sphere1.yaw(-3);
&nbsp; &nbsp; &nbsp; sphere2.yaw(-3);
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; // rotate the group of objects
&nbsp; &nbsp; &nbsp; objectGroup.yaw(1);

&nbsp; &nbsp; &nbsp; // call the renderer
&nbsp; &nbsp; &nbsp; super.onRenderTick(event);
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse down on stage
&nbsp; &nbsp; public function onMouseDown(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = true;
&nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; }

&nbsp; &nbsp; // called when mouse up on stage
&nbsp; &nbsp; public function onMouseUp(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; doRotation = false;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; &nbsp; // called when the mouse moves over the stage
&nbsp; &nbsp; public function onMouseMove(event:MouseEvent):void {
&nbsp; &nbsp; &nbsp; // If the mouse button has been clicked then update the camera position&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; if (doRotation) {
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // convert the change in mouse position into a change in camera angle
&nbsp; &nbsp; &nbsp; &nbsp; var dPitch:Number = (event.stageY - lastMouseY) / 2;
&nbsp; &nbsp; &nbsp; &nbsp; var dYaw:Number = (event.stageX - lastMouseX) / 2;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // update the camera angles
&nbsp; &nbsp; &nbsp; &nbsp; cameraPitch -= dPitch;
&nbsp; &nbsp; &nbsp; &nbsp; cameraYaw -= dYaw;
&nbsp; &nbsp; &nbsp; &nbsp; // limit the pitch of the camera
&nbsp; &nbsp; &nbsp; &nbsp; if (cameraPitch &lt;= 0) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 0.1;
&nbsp; &nbsp; &nbsp; &nbsp; } else if (cameraPitch >= 180) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cameraPitch = 179.9;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reset the last mouse position
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseX = event.stageX;
&nbsp; &nbsp; &nbsp; &nbsp; lastMouseY = event.stageY;
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; // reposition the camera
&nbsp; &nbsp; &nbsp; &nbsp; camera.orbit(cameraPitch, cameraYaw);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; }
&nbsp; &nbsp;
&nbsp; }
}
</blockquote>
</pre>
</div>
<p>Next article:</p>
<ul>
<li><a href="http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-9-importing-and-working-with-3d-objects/">First steps in Papervision3D : Part 9 - Importing and working with 3D objects</a><br />
Import Collada data to render 3D objects created by 3DSMax, Maya, Blender and other 3D modeling applications and use them in Papervision3D scenes.
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/tartiflop/~4/uW9RB8VwQS4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-8-movie-materials/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.tartiflop.com/2008/09/first-steps-in-papervision3d-part-8-movie-materials/</feedburner:origLink></item>
	</channel>
</rss>

