<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>InnerDriveStudios.com</title>
	<atom:link href="http://www.innerdrivestudios.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.innerdrivestudios.com/blog</link>
	<description>Multimedia development</description>
	<lastBuildDate>Tue, 17 Apr 2012 19:36:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>100% freelance and now&#8230;</title>
		<link>http://www.innerdrivestudios.com/blog/uncategorized/100-freelance-and-now</link>
		<comments>http://www.innerdrivestudios.com/blog/uncategorized/100-freelance-and-now#comments</comments>
		<pubDate>Tue, 17 Apr 2012 19:36:08 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=436</guid>
		<description><![CDATA[&#8230;I need a new website   But first there is a lot of other things to be taken care of, such as finishing up some client projects. 
So after 13 years I&#8217;ve left TriMM and Enschede behind to focus more on games and mobile apps. Even more specific, if possible, educational software, aimed at [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230;I need a new website <img src='http://www.innerdrivestudios.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  But first there is a lot of other things to be taken care of, such as finishing up some client projects. </p>
<p>So after 13 years I&#8217;ve left TriMM and Enschede behind to focus more on games and mobile apps. Even more specific, if possible, educational software, aimed at kids. But I&#8217;m not that picky tbh. Although I&#8217;ve been working for NeuroFlasher and Inner Drive since 2006, it still feels kinda weird, but I&#8217;m sure the dust will settle soon.</p>
<p>My big plan was to have the new site up and running before starting, but then the client work started coming in and&#8230; there you are still staring at my old blog&#8230; <img src='http://www.innerdrivestudios.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/uncategorized/100-freelance-and-now/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FC Twente Game finished!</title>
		<link>http://www.innerdrivestudios.com/blog/miscellaneous/fc-twente-game-finished</link>
		<comments>http://www.innerdrivestudios.com/blog/miscellaneous/fc-twente-game-finished#comments</comments>
		<pubDate>Wed, 21 Dec 2011 11:27:43 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS3 GFX]]></category>
		<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=433</guid>
		<description><![CDATA[I recently finished a game for FC Twente, and although there are some improvements to be made to the gameplay &#038; flow, I&#8217;m nonetheless pretty happy with the way it turned out. Give it a swing and let me know what you think!

]]></description>
			<content:encoded><![CDATA[<p>I recently finished a game for FC Twente, and although there are some improvements to be made to the gameplay &#038; flow, I&#8217;m nonetheless pretty happy with the way it turned out. Give it a swing and let me know what you think!</p>
<p><a href="http://www.fctwente.nl/pdb/"><img src="http://www.innerdrivestudios.com/blog/wp-content/uploads/fctwente.jpg" alt="" title="fctwente" width="641" height="481" class="aligncenter size-full wp-image-434" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/miscellaneous/fc-twente-game-finished/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Scrollrect, drawing api, textfield bug</title>
		<link>http://www.innerdrivestudios.com/blog/as2-bugs-other-weird-stuff/scrollrect-drawing-api-textfield-bug</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-bugs-other-weird-stuff/scrollrect-drawing-api-textfield-bug#comments</comments>
		<pubDate>Wed, 14 Jul 2010 15:17:52 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 Bugs & other weird stuff]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=429</guid>
		<description><![CDATA[So I&#8217;ve been developing these actionscript 2 panorama&#8217;s, but had not tested them in player 8. *wrong*.
Apparently some version of the player 8 crash as soon as debug information is printed.
Some further research indicated that it is caused by a bug, through a combination of a dynamically created textfield on top of a clip with [...]]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been developing these actionscript 2 panorama&#8217;s, but had not tested them in player 8. *wrong*.<br />
Apparently some version of the player 8 crash as soon as debug information is printed.</p>
<p>Some further research indicated that it is caused by a bug, through a combination of a dynamically created textfield on top of a clip with a scrollrect set, on which I draw using the drawing API.</p>
<p>The solution is in the CubeView class, instead of setting the scrollrect on the _canvas, set it on the _canvas._parent. I&#8217;m not going to update all downloads, but now you know how to fix it <img src='http://www.innerdrivestudios.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-bugs-other-weird-stuff/scrollrect-drawing-api-textfield-bug/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>General ActionScript 2 Matrix Multiplication code</title>
		<link>http://www.innerdrivestudios.com/blog/miscellaneous/general-actionscript-2-matrix-multiplication-code</link>
		<comments>http://www.innerdrivestudios.com/blog/miscellaneous/general-actionscript-2-matrix-multiplication-code#comments</comments>
		<pubDate>Fri, 25 Jun 2010 18:59:53 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=428</guid>
		<description><![CDATA[Just a tidbit of code, for a general matrix multiplication:

var result:Array = new Array ();
for (var y:Number = 0; y < mAHeight; y++) {
	for (var x:Number = 0; x < mBWidth; x++) {
	 result[x+mAHeight*y] = 0;
	 for (var e:Number = 0; e < mAWidth; e++) {
	  result[x+mAHeight*y] += mA[(y * mAWidth) + e]*mB[x + [...]]]></description>
			<content:encoded><![CDATA[<p>Just a tidbit of code, for a general matrix multiplication:</p>
<div class="codewrapper">
var result:Array = new Array ();</p>
<p>for (var y:Number = 0; y < mAHeight; y++) {<br />
	for (var x:Number = 0; x < mBWidth; x++) {<br />
	 result[x+mAHeight*y] = 0;<br />
	 for (var e:Number = 0; e < mAWidth; e++) {<br />
	  result[x+mAHeight*y] += mA[(y * mAWidth) + e]*mB[x + (e * mBWidth)];<br />
	 }<br />
	}<br />
}
</div>
<p>Although if you need real performance you will probably unroll the 3 loops.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/miscellaneous/general-actionscript-2-matrix-multiplication-code/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part VII &#8211; Panorama hotspot interaction, light up on mouse over</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vii-panorama-hotspot-interaction-light-up-on-mouse-over</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vii-panorama-hotspot-interaction-light-up-on-mouse-over#comments</comments>
		<pubDate>Sat, 05 Jun 2010 20:15:36 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=426</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_422679193"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_7/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_7/PanoramaDemo.swf"
			name="fm_PanoramaDemo_422679193"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Please give the panorama a moment to load)
Download the sources here: 
With respect to the last post/implementation, only a few minor changes were required to the demo we had so far. Basically making the hotspot light up is implemented by drawing on the plane&#8217;s material. That&#8217;s all there [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_1663660403"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_7/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_7/PanoramaDemo.swf"
			name="fm_PanoramaDemo_1663660403"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Please give the panorama a moment to load)</em></p>
<p>Download the sources here: <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=63">3d Panorama v0.7 (287)</a></p>
<p>With respect to the last post/implementation, only a few minor changes were required to the demo we had so far. Basically making the hotspot light up is implemented by drawing on the plane&#8217;s material. That&#8217;s all there is to it. I&#8217;ve implemented this idea in the interactive material class.<br />
<span id="more-426"></span><br />
Lots of room for optimization, but the basic principle remains the same. </p>
<p>Although the goal has never been to deliver a set of reusable classes/components, the basics are all there, and the possibilities are legion. And although the architecture of the code samples can be improved, and they are far from being a complete application, most of the principles and a lot of the sources can be reused and applied to your own panorama implementations. Also note that you might need to clean the code a bit (I saw some left over parameters sneaking around that are no longer used, hunt them down!)</p>
<p>So this concludes my panorama series, hope you enjoyed it. Onto the next project! </p>
<p>Below is a screenshot of the final version with real images and hotspots implemented. The image is a 3d image and was rendered by my colleague at <a href="http://www.trimm.nl">TriMM</a>, <a href="http://www.qstudios.nl/">Sebastiaan Dorgelo</a>.</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/final.jpg" alt="Final" class="postimage"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vii-panorama-hotspot-interaction-light-up-on-mouse-over/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part VI &#8211; Panorama hotspot interaction</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vi-panorama-hotspot-interaction</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vi-panorama-hotspot-interaction#comments</comments>
		<pubDate>Wed, 02 Jun 2010 20:40:43 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=425</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_1262194572"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_6/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_6/PanoramaDemo.swf"
			name="fm_PanoramaDemo_1262194572"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Please give the panorama a moment to load)
Download the sources here: 
How you define your hotspots is up to you. For example you could write a tool which allows you to edit and generate a CubicPanorama. For a project for the dutch police academy I&#8217;m currently working on [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_652761048"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_6/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_6/PanoramaDemo.swf"
			name="fm_PanoramaDemo_652761048"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Please give the panorama a moment to load)</em></p>
<p>Download the sources here: <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=62">3d Panorama v0.6 (225)</a></p>
<p>How you define your hotspots is up to you. For example you could write a tool which allows you to edit and generate a CubicPanorama. For a project for the dutch police academy I&#8217;m currently working on at <a href="http://www.trimm.nl">TriMM</a>, I am writing such an editor in Flex. Here is a screenshot of the work in progress:</p>
<p><span id="more-425"></span></p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/tool_screenshot.jpg" alt="Flex tool" /></p>
<p>Basically it allows you to select a cube side, import a picture for it and draw hotspots on it. The complete definition/model for the cube is then saved to xml, the polygon information with it. </p>
<p>In this demo I&#8217;m simply generating rectangular hotspots on the fly randomly as you can see when you reload the page. No matter whether you are using irregular shapes through xml or random rectangles the principle stays the same.</p>
<p><strong>One important note though </strong> before I continue, <strong>the hotspots do not have to be visible and not rectangular either</strong>. The only reason they are here, is to keep it simple and to provide some visual clue of where you should point and click. In addition whether you show a handcursor or not is all up to your implementation.</p>
<p>But like I said the principle stays the same. In the last post we showed how to derive an x,y coordinate within a plane&#8217;s texture. But we do not have to use the plane&#8217;s texture, we can use any x,y lookup system. For example an array as a look up table. But wait, there is a better way, we simply use another bitmap as a lookup table.</p>
<p>So the basic idea is: for each cubeside, create another bitmap called lookupbitmap with the same size as the texture, and draw the hotspots for each plane onto the lookupbitmap with the hotspot&#8217;s ids as colorvalue.</p>
<p>From an architectural standpoint there are again multiple approaches of course. I introduced the CubicPanoramaModel a couple of examples ago, so if you do define your hotspots in xml, that would be a good place to store them. I decided to leave that as an exercise to the reader (you) however, and keep it simple.<br />
We could implement a bitmap manager, material manager, hotspot manager or whatever. I decided to implement this feature in a subclass of a plane&#8217;s material and call it InteractiveMaterial. In this case, since it&#8217;s a bit hacked together and unoptimized, it&#8217;s called MockupInteractiveMaterial, since it is just there to demonstrate the principles.</p>
<p>The MockupInteractiveMaterial generates 5 random hotspots with an id of 1-5 for plane 0, 11-15 for plane 1, 21-25 for plane 2 etc. It paints these hotspots into it&#8217;s lookup table and onto it&#8217;s own material so you have a visual clue of where to point your mouse. You might even want to be able to toggle this hotspot visibility in which case you would have to retain a copy of the original material, before you ruin it with random rectangles.</p>
<p>There are a couple of things to keep in mind though:</p>
<ul>
<li>you will have to deal with overlapping hotspots. In this example I simply drew the hotspots into the lookup table using the lighten blend mode, which will give the hotspot with the highest id precedence.</li>
<li>by default flash will draw everything anti-aliased, which cannot be switched off except by setting quality to low. Drawing a hotspot with an id of 10 will result in some pixels around the edges of the hotspot having id 9 which ruins the idea. The &#8216;trick&#8217; is to draw your hotspot into an inbetween bitmap and threshold that bitmap on the id/pixel value that you want.</li>
</ul>
<p>Checking which hotspot is under the mouse is now as simple as extending the interactive material with the following method:</p>
<div class="codewrapper">
public function getHotspotId (pX:Number, pY:Number):Number {<br />
	return _lookupTable.getPixel (pX, pY);<br />
}
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-vi-panorama-hotspot-interaction/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part V &#8211; Mouse to Plane coordinates, second step to implementing panorama hotspots</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-v-mouse-to-plane-coordinates-second-step-to-implementing-panorama-hotspots</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-v-mouse-to-plane-coordinates-second-step-to-implementing-panorama-hotspots#comments</comments>
		<pubDate>Tue, 01 Jun 2010 20:03:32 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=424</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_563534504"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_5/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_5/PanoramaDemo.swf"
			name="fm_PanoramaDemo_563534504"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Please give the panorama a moment to load)
Download the source here: 
In the previous post, we implemented a vector pointing at the cube plane under your mouse. In this post we will look at deriving the local x,y coordinate within that plane, and with it the local x,y [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_1274650496"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_5/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_5/PanoramaDemo.swf"
			name="fm_PanoramaDemo_1274650496"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Please give the panorama a moment to load)</em></p>
<p>Download the source here: <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=61">3d Panorama v0.5 (191)</a></p>
<p>In the previous post, we implemented a vector pointing at the cube plane under your mouse. In this post we will look at deriving the local x,y coordinate within that plane, and with it the local x,y coordinate of the pixel within the plane&#8217;s texture under your mouse. (Although for hotspots, any local coordinate system will do).</p>
<p>In order to do so, we need to project the vector at the plane it is pointing at. This results in a coordinate that lies within the plane. The coordinate comes from a set of coordinates that all lie within that plane, and this set can be mapped to a range representing the texture coordinates (or hotspot coordinates as we will see later). Although this might sound complicated, it is not so bad as it sounds.</p>
<p><span id="more-424"></span></p>
<p>Let&#8217;s review projection first.</p>
<p>The formula for projection was:</p>
<p>px = &#8211; (projectionplanedistance / original_z) * original_x<br />
py = &#8211; (projectionplanedistance / original_z) * original_y</p>
<p>It doesn&#8217;t matter whether the original z lies in front or behind the projection plane.</p>
<p>My next two crappy sketches demonstrate this point, first behind the plane (I have left the y coordinate out of the images for clarity, so it is as if we are viewing the 3d scene from the top):</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_e_after.jpg" alt="Projection of a point behind the projectionplane" class="postimage" /></p>
<p>Our original point lies at an (x,z) of (1.5,-6) (in other words x,y,z = 1.5,0,-6).<br />
Our projectionplane lies at a distance of 4 from the origin:</p>
<p>px = &#8211; ( 4 / -6 ) * 1.5) =><br />
px = 2/3 * 1.5<br />
px = 1</p>
<p>Our projected point has an x of 1, at a z of -e.</p>
<p>A point in front of the projectionplane is handled the same way:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_e_before.jpg" alt="Projection of a point in front of the projectionplane" class="postimage" /></p>
<p>Our original point lies at an (x,z) of (1,-2) (in other words x,y,z = 1,0,-2).<br />
Our projectionplane lies at a distance of 4 from the origin.</p>
<p>px = &#8211; ( 4 / -2 ) * 1) =><br />
px = 2 </p>
<p>Our projected point has an x of 1, at a z of -e.</p>
<p>In a cube we can do the same, by projecting each vector at the plane it is pointing at no matter what the length of the original vector was:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_e_cube.jpg" alt="Projection of a point onto the cube planes" class="postimage" /></p>
<p>The distance e we choose is arbitrary, it merely influences the range of the resulting projected values which have to be normalized/mapped to the texture coordinates anyway. However if we choose 1, it simplifies our projection formulas:</p>
<p>px = &#8211; (1 / original_z) * original_x<br />
py = &#8211; (1 / original_z) * original_y</p>
<p>which is</p>
<p>px = -(original_x / original_z)<br />
py = -(original_y / original_z)</p>
<p>Which will result in a mapping of the vector to a projected px and py within the range -1 to 1.</p>
<p>BUT which coordinate values we should use as x, y and z&#8217;s for our projection formulas depends on the orientation of the plane we are projecting our vector at, take a look at the following image:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_point_mapping.jpg" alt="The local coordinates used for planes" class="postimage" /></p>
<p>The projection formulas are based on the projection of coordinates having a negative z with respect to the plane we are projection points on. So for plane 0 we get what you would expect:</p>
<p>px = -(original_x / original_z)<br />
py = -(original_y / original_z)</p>
<p>And in plane 0, z is negative, so this is the same as:</p>
<p>px = (original_x / Math.abs(original_z))<br />
py = (original_y / Math.abs(original_z))</p>
<p>The only reason I&#8217;m writing it that way is that we already calculated the maximum absolute values of x,y,z to determine which plane we were pointing at. We see the original upperleft corner in plane 0 has an x,y value of -1,-1 to a lowerright x,y value of 1,1, so there is nothing extra we have to do to map these coordinates from topleft to lowerright to a range of -1 to 1.</p>
<p>For plane 1, we see that the negative z value we need for our projection formulas is actually a positive x value, and that the local x,y is represented by a pair of y,z coordinates. So we negate our x value and fill in the rest:</p>
<p>px = -(original_y / -original_x)<br />
py = -(original_z / -original_x)</p>
<p>which is</p>
<p>px = (original_y / original_x)<br />
py = (original_z / original_x)</p>
<p>Since the topleft y,z = -1,-1 to bottomright y,z 1,1 is already mapped correctly no further action is required.</p>
<p>(If you are confused about the planes and their corner coordinates, check out the previous post which displays the cube with all it&#8217;s coordinates per plane.)</p>
<p>For plane 2, we see the negative required z value is actually a positive z value, and the local x,y pair is actually a local x,y pair, so we get:</p>
<p>px = -(original_x / -original_z)<br />
py = -(original_y / -original_z)</p>
<p>which is</p>
<p>px = (original_x / original_z)<br />
py = (original_y / original_z)</p>
<p>BUT WAIT! We see that the upperleft coordinate of the plane is not -1,-1. It&#8217;s 1,-1. And the lowerright is not 1,1 but it is -1,1. In other words the x range has been flipped. To correct this we need to negate the px:</p>
<p>px = -(original_x / original_z)<br />
py = (original_y / original_z)</p>
<p>We can do this for each plane, but I will spare you the pain, since I already did that in the source code. </p>
<p>Now we have the calculations that map our mouse position within a plane to a local x,y coordinate with x and y both in the range -1, 1. We can map this to a texture pixel coordinate. Assuming our projected local x and y are represented by planeX and planeY we get:</p>
<p>texture_x = (plane_x/2) * texture_size + (texture_size/2);</p>
<p>which is the same as:</p>
<p>texture_x = ((plane_x+1) * texture_size) /2;</p>
<p>and ofcourse for y:</p>
<p>texture_y = ((plane_y+1) * texture_size) /2;</p>
<p>The example at the top of the page demonstrates these principles. Check out the updated checkPlane method. Note that the texture size is 400 x 400 pixels.</p>
<p>Finally in our next post we will implement the hotspot detection and then we have only one post to go I think which demonstrates hotspots in a 3d panorama that light up as you mouse over them and are correctly transformed in perspective along with the rest of the cube.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-v-mouse-to-plane-coordinates-second-step-to-implementing-panorama-hotspots/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part IV &#8211; Plane detection, a first step to implementing panorama hotspots</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iv-plane-detection-a-first-step-to-implementing-panorama-hotspots</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iv-plane-detection-a-first-step-to-implementing-panorama-hotspots#comments</comments>
		<pubDate>Tue, 01 Jun 2010 11:38:10 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=423</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_719288020"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_4/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_4/PanoramaDemo.swf"
			name="fm_PanoramaDemo_719288020"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Please give the panorama a moment to load)
Download the source here: 
In order to be able to detect hotspots under the mouse, the first thing we need to do is find some way to detect which plane the mouse is currently over and what the local x,y coordinates [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_2084498004"
			class="kml_flashembed"
			width="600"
			height="400">
	<param name="movie" value="/content/flash_examples/3d_panorama_4/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_4/PanoramaDemo.swf"
			name="fm_PanoramaDemo_2084498004"
			width="600"
			height="400">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Please give the panorama a moment to load)</em></p>
<p>Download the source here: <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=60">3d Panorama v0.4 (118)</a></p>
<p>In order to be able to detect hotspots under the mouse, the first thing we need to do is find some way to detect which plane the mouse is currently over and what the local x,y coordinates of the mousecursor are in the local space of that plane.</p>
<p>Instead of providing all the theoretical background I want to try and make it conceptually clear how we can do this. So let go of the mouse coordinates for a moment and take a look at our untransformed starting cube we discussed in a previous post:</p>
<p><span id="more-423"></span></p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/pano_cube.jpg" alt="The Cube" class="postimage" /></p>
<p>We can see that a cube is nothing more than a space enclosed by 6 planes. We can even specify the equations for these planes:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/pano_cube_planes.jpg" alt="The Cube Planes" class="postimage"  /></p>
<p>The plane numbers correspond to how we have defined our planes in the panoramas these past examples. Contained within this cube is the set of all (x,y,z) coordinates with an absolute value for x, y and z less or equal to 1. In addition for the coordinates that lie exactly within a plane of the cube, &#8217;special&#8217; equations hold. For example for plane 0 we could say that Math.abs(x) <= 1 AND Math.abs (y) <= 1, which is the same as saying that for all points in plane 0, Math.abs(x) <= Math.abs(z) AND Math.abs (y) <= Math.abs(z).</p>
<p>But this is true for plane 2 as well, so how do we differentiate between these two planes? Simple, check the sign of z. If z < 0 and Math.abs(x) <= Math.abs(z) and Math.abs (y) <= Math.abs (z), or even shorter, if z < 0 and Math.abs(x) >= z and Math.abs (y) >= z, we are dealing with points in plane 0.</p>
<p>It gets even better, if the planes are closer or further away from the origin (0,0,0) and in effect the cube is smaller or larger, this will still hold. In order words seeing the z instead of -1 and 1 in the example equations above means that these equations hold for planes parallel to our planes as well. And we can write these kind of equations for each plane. So given any point you can tell in which plane (or rather quadrant) the point lies by looking at &#8220;the sign of the coordinate having the largest absolute value&#8221; (from page 142 from Mathematics for 3d Game Programming and Computer Graphics).</p>
<p>Visually this means that given any point contained in the cube you cannot only tell in which plane it lies, but in which quadrant as well. In other words if you view a cube as 6 pyramids put together, you know in which &#8216;pyramid&#8217; a point lies by looking at &#8220;the sign of the coordinate having the largest absolute value&#8221;.</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/cube.jpg" alt="The Cube Pyramids" class="postimage"  /><br />
<em>(A cube&#8217;s content split into 6 pyramids)</em></p>
<p>So the next problem presents itself: when we are pointing at a certain pixel in our cube, what is it&#8217;s coordinate? We can calculate the coordinate by pointing a vector in the direction of our mouse pointer and see where it intersects one of the 6 planes. But how do we calculate the direction of the vector based on the position of the mouse pointer?</p>
<p>Remember the information we discussed in an earlier post about relating the field of view, wall size and wall distance (projection plane distance)?:</p>
<p>projectionplane_distance = (wallsize/2) / tan (fov_in_radians * 0.5)</p>
<p>Visually:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_1.jpg" alt="Calculating the field of view" class="postimage"  /></p>
<p>The area within the rectangle on the wall, is the area of our 3d space actually visible on the screen.</p>
<p>(Note that we are using the same field of vision horizontally as we are vertically, like it has been in our panorama&#8217;s all this time)</p>
<p>What this did in effect, was given a wall size (stage size in pixels), and a field of vision, calculate the projection plane distance. </p>
<p>Once we have a projection plane distance, we could pick a point in the visible area of our 3d space, in other words a point on our stage, in other words at a certain distance in pixels from the center of the wall/stage, and calculate what the angle of a vector towards that point on the wall would be:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_2.jpg" class="postimage"  /></p>
<p>First for the angle alpha which represents the angle between a vector pointing straight at the screen and the mouse x position:</p>
<p>projectionplane_distance = x_offset_from_center / tan (alpha) =><br />
projectionplane_distance * tan (alpha) = x_offset_from_center   =><br />
tan (alpha) = x_offset_from_center / projectionplane_distance =><br />
alpha  = atan (x_offset_from_center / projectionplane_distance)</p>
<p>The x_offset_from_center is the difference between the center of the stage and the mouse x in pixels. </p>
<p>Of course the mouse position does not only present an offset across the x axis but across the y axis as well:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_3.jpg" class="postimage"  /></p>
<p>We can see the same formula applies, however instead of the projectionplane_distance we need to use pythagoras on the plane distance and the mouse y offset from the center, to calculate the length of our adjacent, which gives us the following y angle:</p>
<p>beta = atan (y_offset_from_center / sqrt (projectionplane_distance^2 + x_offset_from_center^2))</p>
<p>So now, given any vector that goes through our camera and points at the center of the screen, we can create a vector that points at the pixel under our mouse by rotating it by the calculated angles. </p>
<p>rotatedvector = [0 0 z].rotateY (alpha).rotateX(beta)</p>
<p>Visually:</p>
<p><img src="http://www.innerdrivestudios.com/content/articles/panoramas/projection_4.jpg" class="postimage"  /></p>
<p>Pick whatever you want for z for example [0 0 -1] or [0 0 -10] or whatever. As long as x and y are zero and we are pointing away from the camera.</p>
<p>So now we have rotated vector, what can we do with it? </p>
<p>If we view our rotated vector as a point, we can determine in what quadrant of the cube we are. However we are faced with another problem. The principle that &#8220;the sign of the coordinate having the largest absolute value&#8221; determines that quadrant only works for an unrotated cube. And we are constantly rotating our cube as we are looking around in our panorama. So we have to &#8216;undo&#8217; the rotation of the cube on our rotated vector, which gives us the vector we would have had if we were able to point at the same spot in the unrotated cube and use that one to determine in which quadrant (is quadrant actually the right term or should it be pyramid?) our vector lies:</p>
<div class="codewrapper">
_lastX = _canvas._xmouse;<br />
_lastY = _canvas._ymouse;</p>
<p>var lDeltaXFromCenter:Number = _lastX &#8211; _viewportWidthDiv2;<br />
var lDetaYFromCenter:Number = _lastY &#8211; _viewportHeightDiv2;</p>
<p>//tan (alpha) = opposite/adjacent<br />
var lXAngleFromCameraToMouseX:Number = Math.atan(lDeltaXFromCenter / _projectionPlaneDistance);<br />
var lYAngleFromCameraToMouseY:Number = Math.atan(lDetaYFromCenter / Math.sqrt((lDeltaXFromCenter * lDeltaXFromCenter) + (_projectionPlaneDistance * _projectionPlaneDistance)));</p>
<p>StageUtil.printScreen (&#8220;Mouse angles:&#8221; + lXAngleFromCameraToMouseX + &#8220;|&#8221; + lYAngleFromCameraToMouseY);<br />
StageUtil.printScreen (&#8220;Pan/tilt angles:&#8221; + _pan + &#8220;|&#8221; + _tilt);</p>
<p>//now create a center point vector which points at the mouse coordinates by rotating it by our deduced angles<br />
var lCenterPointVector:Point3D = new Point3D(0, 0, -1);<br />
var lMatrix:IdentityMatrix3D = new IdentityMatrix3D();<br />
lMatrix.rotateX (lYAngleFromCameraToMouseY); //is in radians<br />
lMatrix.multiplyVector (lCenterPointVector);<br />
lMatrix.rotateY (lXAngleFromCameraToMouseX); //is in radians<br />
lMatrix.multiplyVector (lCenterPointVector);<br />
//undo cube rotation<br />
lMatrix.rotateX ( -_tilt * _toRadians);<br />
lMatrix.multiplyVector (lCenterPointVector);<br />
lMatrix.rotateY ( -_pan * _toRadians);<br />
lMatrix.multiplyVector (lCenterPointVector);</p>
<p>var x:Number = Math.abs (lCenterPointVector.x);<br />
var y:Number = Math.abs (lCenterPointVector.y);<br />
var z:Number = Math.abs (lCenterPointVector.z);</p>
<p>var lPlane:Number = null;</p>
<p>if (z >= x &#038;&#038; z >= y) {<br />
	if (lCenterPointVector.z < 0) {<br />
		lPlane = 0;<br />
	} else {<br />
		lPlane = 2;<br />
	}<br />
} else if (x >= y &#038;&#038; x >= z) {<br />
	if (lCenterPointVector.x < 0) {<br />
		lPlane = 3;<br />
	} else {<br />
		lPlane = 1;<br />
	}<br />
} else if (y >= x &#038;&#038; y >= z) {<br />
	if (lCenterPointVector.y < 0) {<br />
		lPlane = 4;<br />
	} else {<br />
		lPlane = 5;<br />
	}<br />
}
</div>
<p>The example in this post demonstrates that principle. You can look around in our cube, in which I have replaced the shrine images by images containing the plane number, and while you are doing that a textfield displays in which plane the calculations think you are currently moving your mouse.</p>
<p>Next time we will see how we can process this info to find the x and y coordinate local to that plane&#8217;s texture, which brings us one step closer to our hotspot implementation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iv-plane-detection-a-first-step-to-implementing-panorama-hotspots/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part III &#8211; Externalizing the panorama assets</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iii-externalizing-the-panorama-assets</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iii-externalizing-the-panorama-assets#comments</comments>
		<pubDate>Thu, 27 May 2010 12:00:44 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=422</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_637422458"
			class="kml_flashembed"
			width="576"
			height="432">
	<param name="movie" value="/content/flash_examples/3d_panorama_3/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_3/PanoramaDemo.swf"
			name="fm_PanoramaDemo_637422458"
			width="576"
			height="432">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Please give the panorama a moment to load)
Download the source here: 
There is an issue with distributing source code for your demo&#8217;s. Besides demonstrating what you want to demonstrate, you give people a look at how you program. But the focus is not how I program, it&#8217;s demonstrating [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_1531959454"
			class="kml_flashembed"
			width="576"
			height="432">
	<param name="movie" value="/content/flash_examples/3d_panorama_3/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_3/PanoramaDemo.swf"
			name="fm_PanoramaDemo_1531959454"
			width="576"
			height="432">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Please give the panorama a moment to load)</em></p>
<p>Download the source here: <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=59">3d panorama v0.3 (142)</a></p>
<p>There is an issue with distributing source code for your demo&#8217;s. Besides demonstrating what you want to demonstrate, you give people a look at how you program. But the focus is not how I program, it&#8217;s demonstrating the concepts of creating interactive panorama&#8217;s with hotspots that light up. This means I have to find some middle ground in which the code is kept to the bare minimum without hardly any framework classes or complex program structures, while keeping the example readable and extensible.</p>
<p>Therefore I decided to open this post with a little information on application structures. Probably one of the hardest parts of programming is rising to/with the correct level of complexity. You want to be prepared for anything, but not over complicate things (KISS). </p>
<p><span id="more-422"></span></p>
<p>So what do you choose for your application structure? You can choose one of the many frameworks, or you can roll with your own. And after that, do you apply that framework to any application you write? </p>
<p>Personally I love to use a setup which allows me to refactor fast, so I can keep the application as simple as possible and then go more complex when needed. This might not always be preferable when working with larger teams, but for these tutorials, for me it is a nice way to work.</p>
<p>For example:<br />
super simple concept demonstration => some quick &#038; dirty code on a timeline<br />
simple concept demonstration => single class demo without any clear division of responsibilities<br />
concept demonstration => couple classes, mainapplication and subparts start to take shape<br />
more formal simple single view application => mainapplication, mainmodel, mainview (with possibly other names like we have in this example)<br />
large scale multiview application => mainapplication, startup tasks, mainmodel, mainview, submodels, subviews etc. I could write a book about this but I won&#8217;t anytime soon.</p>
<p>In the more simpler variants, models might initialize themselves and they might use simple callbacks (like in this example). In more complex variants, models might be deserialized from xml, but queueloaders and services might take care of loading other required data, and everything might communicate through events instead of callbacks, maintaining some sense of progress and reporting errors when necessary.</p>
<p>If the application gets really complex, I usually employ a main application model, through which all the application parts are accessible. For people familiar with PureMVC&#8217;s ApplicationFacade, it shares similarities (although the way I build stuff everything is strongly type-checked and I almost never employ singletons. What I am doing in these examples with arrays without accessor functions is something that would be a nono in large applications). If the application gets even more complex, the application gets divided into sub applications / modules / application cores etc and the process repeats itself.</p>
<p>All in all there is a pretty seamless way to scale up when required, and when you know ahead of time that you will be building a monstrosity there is always the option of scaling up from the very beginning. The main thing is that the complexity of the architecture is usually matched by the complexity of what you want to achieve (warranted by).</p>
<p>So back to these tutorials, I&#8217;m trying to find a middle ground between demonstrating the principles, keeping a decent structure which can be extended, not over complicating things, not adding a bunch of library classes to bulk load content etc etc. And some days I succeed better at that than other days <img src='http://www.innerdrivestudios.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Just remember the focus is on concepts, not on application structure nor holy code conventions wars. And that most of this is written after 9:30 PM when the gremlins have gone to bed <img src='http://www.innerdrivestudios.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>All that said, since we will be adding hotspots and light up features in the coming examples, this example prepares the way to add those things later. I&#8217;ve scaled up the example&#8217;s complexity a bit and replaced the DistortedPlane class by a less general CubicPanoramaPlane class.</p>
<p>All images are now loaded externally, and the example can no longer be run from the Flash IDE since there is no longer a fla required (although it is very simple to create one yourself). Instead you should <a href="http://www.flashdevelop.org/community/viewforum.php?f=11">download the latest FlashDevelop</a> version.</p>
<p>As mentioned before, there is no errorhandling, no progress display and probably lots of other stuff missing. Feel free to add it, but it is not part of what I am trying to demonstrate here.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-iii-externalizing-the-panorama-assets/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Part II &#8211; Improved Panorama</title>
		<link>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-ii-improved-panorama</link>
		<comments>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-ii-improved-panorama#comments</comments>
		<pubDate>Wed, 26 May 2010 14:42:24 +0000</pubDate>
		<dc:creator>Hans Wichman</dc:creator>
				<category><![CDATA[AS2 3D Panorama creation]]></category>

		<guid isPermaLink="false">http://www.innerdrivestudios.com/blog/?p=421</guid>
		<description><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_1430774528"
			class="kml_flashembed"
			width="576"
			height="432">
	<param name="movie" value="/content/flash_examples/3d_panorama_2/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_2/PanoramaDemo.swf"
			name="fm_PanoramaDemo_1430774528"
			width="576"
			height="432">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
(Click and drag, mousewheel or keys)
Download the sources for this panorama (fully documented): 
In the previous panorama post I mentioned a number of issues that would have to be fixed. For this demo I used another image from http://www.flickr.com/photos/heiwa4126/, who has a set of amazing images, so it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_PanoramaDemo_833874399"
			class="kml_flashembed"
			width="576"
			height="432">
	<param name="movie" value="/content/flash_examples/3d_panorama_2/PanoramaDemo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/content/flash_examples/3d_panorama_2/PanoramaDemo.swf"
			name="fm_PanoramaDemo_833874399"
			width="576"
			height="432">
	<!--<![endif]-->
		
	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object><br />
<em>(Click and drag, mousewheel or keys)</em></p>
<p>Download the sources for this panorama (fully documented): <a href="http://www.innerdrivestudios.com/blog/wp-content/plugins/download-monitor/download.php?id=58">3d Panorama v0.2 (148)</a></p>
<p>In the previous panorama post I mentioned a number of issues that would have to be fixed. For this demo I used another image from <a href="http://www.flickr.com/photos/heiwa4126/2507985087/">http://www.flickr.com/photos/heiwa4126/</a>, who has a set of amazing images, so it&#8217;s really worth to go there and take a look (the other images in the flickr equirectangular group are very good as well btw).</p>
<p>So in no particular order, what did we add/fix in this version?</p>
<p><span id="more-421"></span></p>
<p><strong>Clipping</strong><br />
The clipping issue was described in the <a href="http://www.innerdrivestudios.com/blog/as2-3d-principles/3d-in-actionscript-2-part-vb-intermezzo-improved-quad-clipping">previous post</a>.</p>
<p><strong>Seams</strong><br />
The seams were a surprise to me. I thought the render process caused the seams, and that I would have to fix it by making the planes slightly overlap. I even implemented it first, so if you ever need it, here it is:</p>
<div class="codewrapper">
  //overlay factor (how much to overlay the tiles to prevent tearing.<br />
  //enter 0.9 to see a clean separation<br />
  var lOverlayFactor:Number = 1.0005;<br />
  _points = [];<br />
  _transformedPoints = [];<br />
  var l90DegreesInRadians:Number = 90 * _toRadians;<br />
  var lTransformedPoint:Point3D = null;<br />
  //for each side<br />
  for (var lSide:Number = 0; lSide < 6; lSide++) {<br />
   //store side as if we are looking at it<br />
   var lSidePoints:Array = [<br />
    new Point3D (-lOverlayFactor, -lOverlayFactor, -1),<br />
    new Point3D (lOverlayFactor, -lOverlayFactor, -1),<br />
    new Point3D ( -lOverlayFactor, lOverlayFactor, -1),<br />
    new Point3D ( lOverlayFactor, lOverlayFactor, -1)<br />
   ];</p>
<p>   //now rotate these points based on on which side they should represent<br />
   switch (lSide) {<br />
    //case 0: leave as is; break;<br />
    //side right, back, left<br />
    case 1: case 2: case 3:<br />
     _rotationMatrix.rotateY(-l90DegreesInRadians * lSide);<br />
     break;<br />
    //side up<br />
    case 4:<br />
     _rotationMatrix.rotateX(-l90DegreesInRadians);<br />
     break;<br />
    //side down<br />
    case 5:<br />
     _rotationMatrix.rotateX(l90DegreesInRadians);<br />
     break;<br />
   }</p>
<p>   for (var lPoint:Number = 0; lPoint < 4; lPoint++) {<br />
    _rotationMatrix.multiplyVector (lSidePoints[lPoint]);<br />
    lTransformedPoint = new Point3D();<br />
    lTransformedPoint.copyFrom (lSidePoints[lPoint]);<br />
    _transformedPoints.push (lTransformedPoint);<br />
   }</p>
<p>   _points = _points.concat (lSidePoints);</p>
<p>   var lOffset:Number = lSide * 4;<br />
   DistortedPlane (_planes[lSide]).setTransform (<br />
    _transformedPoints[lOffset+0], _transformedPoints[lOffset+1], _transformedPoints[lOffset+2], _transformedPoints[lOffset+3]<br />
   );</p>
<p>  }
</p></div>
<p>however, that didn&#8217;t fix it, it only made things worse. Then I discovered that the seams were caused by the bitmapfill repeat parameter which was set to true, when smoothing was turned on for the planes. If you remember, this setting was switched on to prevent drawing lag when points crossed the diagonal of drawn triangle. Since that will never happen when rendering the inside of a cube with our field of view setting, we can safely turn it off. And poof ! No more seams.</p>
<p><strong>(Fluid) motion</strong><br />
I updated the mouse and key movement and added mass. The slight delay after you press a key is now gone as well. See the render function for more info on this.</p>
<p><strong>Correct rotation</strong><br />
The rotation is correct. In order to implement that, we needed to keep the original points untransformed, and store a transformed copy of those points as well. Using two rotation matrices, one for x and one for the y direction, we can correctly transform these points each render pass (but only if we have moved).</p>
<p><strong>Field of vision</strong></p>
<p>I implemented a somewhat more scientific way of calculating the projection plane distance based on a field of view parameter. Please refer to the sources for more info.</p>
<p><strong>What&#8217;s next?</strong></p>
<p>We fixed a number of minor other stuff as well and cleaned the code a bit, so we are slowly getting to where we want to be. In the next version I will refactor the DistortedPlane class into a more specific custom PanoCubeSide class to make the performance even better, although I think that for actionscript 2 it is pretty solid already.</p>
<p>In addition we will look at externalizing the images and the implementation of hotspots in the next version!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.innerdrivestudios.com/blog/as2-3d-panorama-creation/part-ii-improved-panorama/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

