<?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>Benny's Blog &#187; Papervision3D</title>
	<atom:link href="http://blog.projectnibble.org/category/papervision3d/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.projectnibble.org</link>
	<description>House Of Code</description>
	<lastBuildDate>Fri, 13 Aug 2010 15:06:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>Papervision3D star (sun) tutorial and source</title>
		<link>http://blog.projectnibble.org/2010/02/11/papervision3d-star-sun-tutorial-and-source/</link>
		<comments>http://blog.projectnibble.org/2010/02/11/papervision3d-star-sun-tutorial-and-source/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 22:33:04 +0000</pubDate>
		<dc:creator>Benny Bottema</dc:creator>
				<category><![CDATA[Papervision3D]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[star]]></category>
		<category><![CDATA[sun]]></category>

		<guid isPermaLink="false">http://blog.projectnibble.org/?p=423</guid>
		<description><![CDATA[Read how by combing Perlin noise and a trick using two planes, you can make a real-time animated glaring sun corona in Papervision3D.]]></description>
			<content:encoded><![CDATA[<p>If you are looking for a cool sun effect (no pun intended) with flaring corona, you&#8217;re in the right place. This post isn&#8217;t about some practical sun in some shooter though: it would require some tweaking to make it useful in such context, as the animation is rather cpu heavy due to its massive corona noise textures.</p>
<p>No, this post is about combining cool PV3D features in order to achieve a nice looking animated sun. I’ve used the trunk of the papervision code repository, revision 851 (it works up to r910, after that <a href="http://code.google.com/p/papervision3d/issues/detail?id=250">a bug was introduced</a>). Note that I&#8217;m no PV3D guru; I&#8217;m just sharing what I&#8217;ve learned so far.</p>
<div style="text-align:center">
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_sun/suntutorial.rar">download sun source</a></li>
</ul>
<p>
<object width="400" height="400">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_sun/Suntutorial.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="400" height="400" src="http://projectnibble.org/dump/blog/papervision3d_sun/Suntutorial.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:999999">(note: this sun uses the skybox from the <a href="http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/">skybox tutorial</a>)</span>
</div>
<p>Closely watch that corona for a while!</p>
<p><span id="more-423"></span></p>
<h2>How it works</h2>
<ul>In short: the sun exist entirely of planes, controlled by alpha ratios and always facing the camera:</p>
<li>one plane with a gradient texture white to red with glow</li>
<li>two planes with a perlin texture, that resize and tag eachother as to provide a continuous outwards motion</li>
<li>one plane that acts as a mask for the other planes to provide a perfect circle giving the illusion of a round star</li>
</ul>
<h3>The star&#8217;s gradient</h3>
<p>Actually, it took quite some tweaking to get a nice gradient of white in the middle and yellow to red on the edge. It&#8217;s a basic <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/Graphics.html#beginGradientFill()">Sprite gradient fill</a>, using three colors, alpha layering and a specific color ratio array to get the last two colors (yellow and red) on the edge. Then I&#8217;m applying this gradient <em>twice</em> on the same canvas to get the result I want when the flaring corona&#8217;s are added. I couldn&#8217;t get it the way I wanted with the alpha array alone (let me know if you got a better way), but this worked and the gradients are only calculated and drawn once.</p>
<p>Drawing it twice means less transparency and that means more dense flares as we&#8217;ll see later on when we&#8217;re combining the star glow layer and corona layer using <a href="http://www.bukisa.com/articles/38637_papervision-3d-programming-tutorial-blend-modes">BlendMode.ADD</a> (which is also the reason why we need MovieMaterial here: otherwise they won&#8217;t interact on layer-level).</p>
<div style="text-align:center">
<img src="http://projectnibble.org/dump/blog/papervision3d_sun/sunglow.png" alt="sunglow" />
</div>
<pre  name="code" class="java">
// pseudo code
var sunColors:Array = [0xfefefe, 0xFAEB61, 0xff0000]; // white, orange/yellow, red
var sunAlphas:Array = [1, .8, 0]; // white part opaque, 20% from the edge out fading out
var sunRatios:Array = [0x85, 0xAA, 0xDD]; // all white except for the edges

var size:Number = 1000;
var sunglowMaterial:MovieMaterial = createSunglowMaterial(size, sunColors, sunAlphas, sunRatios);
var sun:Plane = new Plane(sunglowMaterial, size, size, null, null);

/**
 * Creates a disc texture using radial alpha. Draw twice for extra intensity of the colors.
 */
private function createSunglowMaterial(size:Number, colors:Array, alphas:Array, ratios:Array):MovieMaterial {
	var mat:Matrix = new Matrix();
	mat.createGradientBox(size, size);
	var sunTexture:Sprite = new Sprite();
	for (var i:Number = 0; i < 2; i++) {
		sunTexture.graphics.beginGradientFill(GradientType.RADIAL, colors, alphas, ratios, mat);
		sunTexture.graphics.drawRect(0, 0, size, size);
		sunTexture.graphics.endFill();
	}
	return new MovieMaterial(sunTexture, true);
}
</pre>
<h3>The star's flaring corona</h3>
<p>The corona was tricky. I needed to find some way to create a seamless and continuous outward motion of a Perlin noise map that would function as a flare animation. In the end I settled for a two plane solution where one slowly grows and finally fades out at which point the second fades in, rotated randomly and grows until it fades out again. Rinse and repeat. When calibrated carefully, the resizing, rotating and fading is imperceptible to the eye, due to the naturally distributed Perlin noise:</p>
<div style="text-align:center">

<object width="300" height="300">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_sun/imperceptible%20corona.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="300" height="300" src="http://projectnibble.org/dump/blog/papervision3d_sun/imperceptible%20corona.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:999999">(imperceptible version)</span><br />
<br />

<object width="300" height="300">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_sun/perceptible%20corona.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="300" height="300" src="http://projectnibble.org/dump/blog/papervision3d_sun/perceptible%20corona.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:999999">(perceptible version)</span><br />
<br />

<object width="200" height="200">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_sun/sun%20final%20corner.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="200" height="200" src="http://projectnibble.org/dump/blog/papervision3d_sun/sun%20final%20corner.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:999999">(result)</span>
</div>
<p>The Perlin noise is added with a simple Perlin noise command as follows:</p>
<pre  name="code" class="java">
var coronaMaterial1:BitmapMaterial = createCoronaMaterial(size / 1.25, size / 100, SEGMENTS);
var coronaMaterial2:BitmapMaterial = createCoronaMaterial(size / 1.25, size / 100, SEGMENTS);
var corona1:Plane = new Plane(coronaMaterial1);
var corona2:Plane = new Plane(coronaMaterial2);

/**
 * Creates a perlin noise texture to simulate the flaring flames on the sun's outer glow.
 */
private function createCoronaMaterial(textureSize:Number, noiseSize:Number, segments:Number):BitmapMaterial {
	var coronaBitmap:BitmapData = new BitmapData(textureSize, textureSize);
	coronaBitmap.perlinNoise(noiseSize, noiseSize, 4, 61, true, true, 1, false);
	return new BitmapMaterial(coronaBitmap, true);
}
</pre>
<p>The algorithm to animate the two planes is included in the attached sources.</p>
<h3>The corona and star glow combined and masked by a perfect circle</h3>
<p>The planes are all on the same depth and level. This works because we're using alpha ratios to determine where one plane's visibility starts and the other disappears. The star glow textures stands on its own, it is inherently radial and as such doesn't need a circle mask. This leaves the Perlin noise textures which need masking. To do this, I've put them in separate layers, which are then both masked by a third layer.</p>
<pre  name="code" class="java">
/*
 * use root corona layer so we can perform an alpha mask to both child layers at once
 *     - contains child corona layers so we can control individual alpha properties
 *         - contains child corona planes so we can apply a perlin noise texture to it for 'flaring' effect
 */
var coronaLayer:ViewportLayer = new ViewportLayer(viewport, null);
coronaChildLayer1 = new ViewportLayer(viewport, null);
coronaChildLayer2 = new ViewportLayer(viewport, null);
coronaLayer.addLayer(coronaChildLayer1);
coronaLayer.addLayer(coronaChildLayer2);
coronaChildLayer1.addDisplayObject3D(corona1);
coronaChildLayer2.addDisplayObject3D(corona2);
viewport.containerSprite.addLayer(coronaLayer);
// give the corona of the sun a 'flaring' effect
coronaLayer.blendMode = BlendMode.ADD;

// only show the corona part of the flaring perlin noise planes
var coronaMaskLayer:ViewportLayer = viewport.getChildLayer(coronaMask);
coronaLayer.cacheAsBitmap = true;
coronaMaskLayer.cacheAsBitmap = true;
coronaLayer.mask = coronaMaskLayer;
</pre>
<p>On a final note, I'm using the skybox from the <a href="http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/">skybox tutorial</a> and also the <a href="http://blog.projectnibble.org/2009/06/15/papervision3d-displayobject3d-helper-baseclass-for-realtime-updates/">RealtimeDisplayObject3D helper baseclass</a> for the sun's scene updates (which is why the coronas keep animating smoothly even at low FPS).</p>
<p><a href="http://blog.projectnibble.org/2010/02/01/papervision3d-star-sun-tutorial-and-source/trackback/">trackback</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.projectnibble.org/2010/02/11/papervision3d-star-sun-tutorial-and-source/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Papervision3D clouded planet Earth tutorial and source</title>
		<link>http://blog.projectnibble.org/2009/06/19/papervision3d-clouded-planet-earth-tutorial-and-source/</link>
		<comments>http://blog.projectnibble.org/2009/06/19/papervision3d-clouded-planet-earth-tutorial-and-source/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 17:00:17 +0000</pubDate>
		<dc:creator>Benny Bottema</dc:creator>
				<category><![CDATA[Papervision3D]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[clouds]]></category>
		<category><![CDATA[earth]]></category>
		<category><![CDATA[game design]]></category>
		<category><![CDATA[perlin noise]]></category>
		<category><![CDATA[planet]]></category>

		<guid isPermaLink="false">http://blog.projectnibble.org/?p=209</guid>
		<description><![CDATA[Here's a simulated Earth in Papervision3D, using realtime maintained clouds and a nice Earth glow.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a tutorial about a possible way to create planets and indeed Earth. I&#8217;ll briefly explain the main textures used and from then on go through the code step-by-step to explain what I did and why.</p>
<p>I had to tone down the size and fps, and leave out the bumpmap for this demo because my Opera browser was halting when I added the other images and clouds swf demo :P</p>
<p>
<object width="500" height="250">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_earth/Planettutorial.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="500" height="250" src="http://projectnibble.org/dump/blog/papervision3d_earth/Planettutorial.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:#999999">(notice the dynamic clouds and the glow around the globe)</span></p>
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_earth/earthtutorial.rar">Download Clouded planet Earth source</a></li>
</ul>
<p>On my core 2 duo laptop I get about 20-25 fps whith a slightly larger stage size and the movie set to 30 fps. Although the planet looks very nice to me, I also realize it isn&#8217;t very practical for games or other realtime simulations. To get better fps, you can remove the bumpmap texture, replace the realtime clouds with a fixed texture, user fewer segments in the spheres, zoom out more, or use lower resolution textures for land- and cloud materials. A combination of two or more of these suggestions should easily get you above 35 fps.</p>
<p><span id="more-209"></span></p>
<h2>Used Ingredients</h2>
<p>I&#8217;ll get into the explanations later, but here are the ingredients used in this example:</p>
<p>- A sphere for geological data (land texture)<br />
- Another sphere for clouds<br />
- two planes that mask a perfect circle for the spheres<br />
- a plane that contains the fresnell glow on top</p>
<p>On the spheres I&#8217;ve used two phongshaded materials of which one has the land texture with a bumpmap for mountains and stuff, and the other contains the clouds texture with a runtime maintained perlin noise map applied to the alpha channel.</p>
<p>On the masking planes I&#8217;ve used a simple gradient circle shaped fill on the alpha channel.</p>
<p>On the glow plane I&#8217;ve used a gradient circle fill with a blue color and alpha channel for nice fading.</p>
<p>There&#8217;s also a pointlight in there that represents the sun (hits earth top-right).</p>
<h2>Main textures</h2>
<h3>Earth surface</h3>
<p>I took the public Earth surface texture (<a href="http://visibleearth.nasa.gov/view_set.php?categoryID=2364">Blue Marble</a>) from NASA, which I used on the sphere. On the rightside you can see it applied to the sphere with phongshader.</p>
<div style="width: 600px;">
<img src="http://projectnibble.org/dump/blog/papervision3d_earth/earth.jpg" alt="NASA's Earth surface texture" style="float:left;"/><img src="http://projectnibble.org/dump/blog/papervision3d_earth/phongshaded_geological_texture.png" alt="Phong shaded earth texture" style="height:188px; float:right"/>
</div>
<div style="clear:both"> </div>
<p>The shown image is about the half of the size I used for the used texture. One thing I&#8217;ve noticed is how large the texture needs to be to get some decent quality when applied to a sphere. Maybe there&#8217;s some room for optimization there&#8230;</p>
<h3>Clouds surface</h3>
<p><img src="http://projectnibble.org/dump/blog/papervision3d_earth/clouds.jpg" alt="NASA's cloud coverage texture"/></p>
<p>For the clouds I initially started with the public clouds texture from NASA, but when I applied the dynamic visibility map it turned out I didn&#8217;t get enough cloud coverage, because in effect now two visibly maps were applied: nature&#8217;s own, hardcoded in the texture, and my own applied in runtime.</p>
<p>So I ended up mirroring the original clouds texture in both dimensions to get much more cloud coverage, so that when I apply my own runtime visibility map I get about as much cloud coverage as in the original image. When applied to the sphere, it is also subject to the Phong shader I&#8217;ve used.</p>
<div style="background-image: url('http://projectnibble.org/dump/blog/papervision3d_earth/earth.jpg'); width: 600px; height: 188px; background-repeat: no-repeat; line-height: 0px;"> <br />
<img src="http://projectnibble.org/dump/blog/papervision3d_earth/clouds2.png" alt="Expanded cloud coverage with alpha channel" style="float:left"/><img src="http://projectnibble.org/dump/blog/papervision3d_earth/phongshaded_clouds_texture.png" alt="Phong shaded cloud coverage" style="height:188px; float:right"/>
</div>
<div style="clear:both"> </div>
<p>I&#8217;ve increased overall brightness to get more out of the less dense clouds, but I&#8217;ve also increased contrast to get the clear shapes of the clouds. Then I&#8217;ve applied the image itself as its own alpha channel and played around with its visibility until it became what you see above.</p>
<p>For the runtime visibility map I&#8217;ve used the ever amazing <a href="http://polygeek.com/1780_flex_explorer-bitmapdata-perlin-noise">perlin noise effect</a>. Since perlin noise works with a phase, I can use that to animate perlin noise and apply the results to the alpha channel of the clouds texture. On a straight texture, it looks like the following example:</p>
<p><a href="http://projectnibble.org/dump/blog/papervision3d_earth/realtimeclouds.html" target="_blank"><img src="http://projectnibble.org/dump/blog/papervision3d_earth/realtime_clouds.png" alt="Realtime clouds texture demo" /></a><br />
<span style="color:#999999">(click to see in action)</span></p>
<p>You can probably imagine how hard this must be to render each frame: a large clouds texture with alpha channel modified each frame by a new perlin noise map, with a phong shader applied. I see how this won&#8217;t work in a game, so I&#8217;ll probably use a fixed clouds texture in the future, but right now I&#8217;m satisfied with the effect.</p>
<h2>Code walkthrough</h2>
<p>Aside from the actual structuring of the code and Papervision3D usage, there are some interesting aspects to this demo. For example, there&#8217;s the Earth&#8217;s light glow, and the use of masking discs to disguise the low quality of the spheres. I&#8217;ve explained everything in details on this on the following page:</p>
<ul>
<li><a href="/papervision3d-clouded-planet-earth-tutorial-and-source-code-walkthrough/">Read the Earth code walkthrough</a></li>
</ul>
<p>If anyone has suggestion on how to improve performance, please let me know!</p>
<p><a href="http://blog.projectnibble.org/2009/06/19/papervision3d-clouded-planet-earth-tutorial-and-source/trackback/">trackback</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.projectnibble.org/2009/06/19/papervision3d-clouded-planet-earth-tutorial-and-source/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Papervision3D DisplayObject3D helper baseclass for realtime updates</title>
		<link>http://blog.projectnibble.org/2009/06/15/papervision3d-displayobject3d-helper-baseclass-for-realtime-updates/</link>
		<comments>http://blog.projectnibble.org/2009/06/15/papervision3d-displayobject3d-helper-baseclass-for-realtime-updates/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 14:36:34 +0000</pubDate>
		<dc:creator>Benny Bottema</dc:creator>
				<category><![CDATA[Papervision3D]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[real time updates]]></category>

		<guid isPermaLink="false">http://blog.projectnibble.org/?p=281</guid>
		<description><![CDATA[Here's a small class I made for adding realtime updates to DisplayObject3D objects. This class allows for easy time-based updates instead of the traditional frame-based updates.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a small class I made for adding realtime updates to DisplayObject3D objects. This class allows for easy time-based updates instead of the traditional frame-based updates.</p>
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_realtime/RealtimeDisplayObject3D.as">RealtimeDisplayObject3D.as</a></li>
</ul>
<p>I use the convention of adding update methods to all (my own) DisplayObject3D objects, which then update themselves according to preconfigured settings (eg. passed in the constructor). I pass in a Camera3D and that&#8217;s it, let the objects do their own thing. I&#8217;m making use of this convention by extracting this update method to a baseclass which then can do time-based updates instead.</p>
<p><span id="more-281"></span></p>
<p>It only works for new classes you create that normally would extend DisplayObject3D, such as a composite parent DisplayObject3D. For example, if you were to create an <a href="http://blog.projectnibble.org/2009/06/19/papervision3d-clouded-planet-earth-tutorial-and-source/">Earth object in PV3D</a>, you could create a new DisplayObject3D container class which adds a planet, clouds and a glow to itself as child objects. This Earth object could then extend our special class, RealtimeDisplayObject3D, for controlling time-based updates.</p>
<pre  name="code" class="java">
public class Planet extends RealtimeDisplayObject3D {

	private var earth:DisplayObject3D;

	// define: 1 update every 200ms (5 updates per second) and process 1 value per second
	public function Planet() {
		super(200, 1);
		// add planet, clouds and glow etc.
	}

	// rotates Earth 5 times per second, with a stepsize of 0.2 (1 second / updates per second)
	protected override function realtimeUpdate(camera:Camera3D, stepsize:Number):void {
		earth.rotate(stepsize);
	}
}
</pre>
<p>With the planet now extending our RealtimeDisplayObject3D class instead of DisplayObject3D, you can provide realistic rotation speed that is not influenced by the FPS the movie is pulling. Instead, it works by applying a set value-per-second (phase speed) and a required update frequency per second; the phase speed is spread out over the number of updates per second.</p>
<p>There is one requirement though: <strong>the fps the movie is pulling cannot go below the updates per second specified</strong>, or the updates per second is capped by the frames per second. If you specify 200ms for each update, this means 5 updates per second (1000 / 200). This won&#8217;t be a problem. If however you define 50ms for each update, this means 20 updates per second (1000 / 50). You must ensure that your movie is running on 20 frames per second or more.</p>
<h2>Combining time-based updates with frame-based updates</h2>
<p>You can still update normally on frame-based timetable by overriding the <i>update(camera)</i> method of the baseclass. Or, you can combine both type of updates by overriding <i>update(camera)</i>, do a frame-based update, call <i>super.update(camera)</i> and override the <i>realtimeUpdate(camera)</i> method as we did before. Here&#8217;s an example of that:</p>
<pre  name="code" class="java">
public class Planet extends RealtimeDisplayObject3D {

	private var earth:DisplayObject3D;

	// define: 1 update every 200ms (5 updates per second) and process 1 value per second
	public function Planet() {
		super(200, 1);
		// add planet, clouds and glow etc.
	}

	// makes the planet face the camera each and every frame
	protected override function update(camera:Camera3D, stepsize:Number):void {
		earth.lookAt(camera);
		super.update(camera);
	}

	// rotates Earth 5 times per second, with a stepsize of 0.2 (1 second / updates per second)
	protected override function realtimeUpdate(camera:Camera3D, stepsize:Number):void {
		earth.rotate(stepsize);
	}
}
</pre>
<p><a href="http://blog.projectnibble.org/2009/06/15/papervision3d-displayobject3d-helper-baseclass-for-realtime-updates/trackback/">trackback</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.projectnibble.org/2009/06/15/papervision3d-displayobject3d-helper-baseclass-for-realtime-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Easy Papervision3D space dust tutorial and source</title>
		<link>http://blog.projectnibble.org/2009/05/29/easy-papervision3d-space-dust-tutorial-and-source/</link>
		<comments>http://blog.projectnibble.org/2009/05/29/easy-papervision3d-space-dust-tutorial-and-source/#comments</comments>
		<pubDate>Fri, 29 May 2009 17:43:53 +0000</pubDate>
		<dc:creator>Benny Bottema</dc:creator>
				<category><![CDATA[Papervision3D]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[game design]]></category>
		<category><![CDATA[space dust]]></category>

		<guid isPermaLink="false">http://blog.projectnibble.org/?p=161</guid>
		<description><![CDATA[Many space shooters use this concept where you are the pilot that looks out from the front window, lasering down enemies for bounty, right. Ever noticed spacedust? It&#8217;s very subtle when it is used, but it adds to the realism of outer space, making the space feel less empty, less static. Here&#8217;s how you can [...]]]></description>
			<content:encoded><![CDATA[<p>Many space shooters use this concept where you are the pilot that looks out from the front window, lasering down enemies for bounty, right. Ever noticed spacedust? It&#8217;s very subtle when it is used, but it adds to the realism of outer space, making the space feel less empty, less static.</p>
<p>Here&#8217;s how you can do that in Papervision3D, using ParticleFields. I’ve used the trunk of the papervision code repository, revision 851, but it should work with the last release without to much hassle. Note that I&#8217;m no PV3D guru; I just started to learn this stuff and I&#8217;m just sharing what I&#8217;ve learned so far.</p>
<div style="text-align:center">
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_spacedust/spacedusttutorial.rar">download spacedust source</a> </li>
</ul>
<p>
<object width="600" height="300">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_spacedust/Spacedusttutorial.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="600" height="300" src="http://projectnibble.org/dump/blog/papervision3d_spacedust/Spacedusttutorial.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>
<br />
<span style="color:999999">(note: space dust uses the skybox from the <a href="http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/">skybox tutorial</a>)</span>
</div>
<ul>Here&#8217;s how it works: </p>
<li>divide space into a 3d grid and parts of the spacedust cloud on 8 gridpoints directly around the camera (the ship), we&#8217;ll call these dustpockets</li>
<li>when the camera moves, dustpockets are removed and created to keep only the 8 gridpoints around the ship occupied</li>
</ul>
<p><span id="more-161"></span></p>
<h3>Divide space into a 3d grid and snap dust pockets on it</h3>
<p>We&#8217;re not actually creating a grid, but we&#8217;re going to say things like: &#8220;Give me the closest 3d point behind the ship in the upper left corner on the invisible grid&#8221;, so that we can create a dust pocket in that position. Sounds complicated? Luckily, the math is easy:</p>
<p>Let&#8217;s say there&#8217;s only the x-axis. Now from 0 to 100, I want the gridpoint on the left of 32 on grid with size 5. Here is how it would look:</p>
<div style="text-align:center">
<img src="http://projectnibble.org/dump/blog/papervision3d_spacedust/grid_x_example.png" alt="gridpoint 30 lies left of x-value 32 on a grid of size 5" />
</div>
<p>As you can see, the x-value 30 is the value to the left of 32 on a grid with size 5. Here&#8217;s the equation to get to that answer:</p>
<p><code>gridpoint left: Xgrid = Xvalue - (Xvalue % gridsize)<br />
gridpoint right: Xgrid = Xvalue - (Xvalue % gridsize) + gridsize</code></p>
<p>Example gridpoint left for value 32 and grid size 5:<br />
<code>gridpoint left: Xgrid = 32 - (32 % 5)<br />
gridpoint left: Xgrid = 32 - (2)<br />
gridpoint left: Xgrid = 30</code></p>
<p>Example gridpoint right for value 32 and grid size 5:<br />
<code>gridpoint left: Xgrid = 32 - (32 % 5) + 5<br />
gridpoint left: Xgrid = 32 - (2) + 5<br />
gridpoint left: Xgrid = 35</code></p>
<p>We&#8217;re going to apply this kind of math to find all 8 gridpoints around the camera. So not just the x-axis, but y and z-axis as well.</p>
<p>The reason we need these 8 gridpoints is because we can&#8217;t just create a single cloud. Since the ship can move in any direction and look in any direction, but we can&#8217;t fill all of space with dust particles due to memory restrictions, we need to dynamically &#8216;move&#8217; the cloud with the ship, while keeping the dust particles on the same place. The only way to do this is by dividing the single dust cloud into several small ones and create them as the ship goes. At the same time we need to keep the number of particles down, so we need the minimum dust pockets and still cover all sides by create 8 small clouds that together form a big cloud and can grow in any direction without draining too much memory and cpu power.</p>
<p>Here&#8217;s how we&#8217;re going to place the clouds:</p>
<p><img src="http://projectnibble.org/dump/blog/papervision3d_spacedust/3d%20spacedust%20grid.png" alt="space dust pockets around the ship on a grid" /></p>
<p>Here&#8217;s the code to do this:</p>
<pre  name="code" class="java">
public function update(fieldsize:Number = 2500):void {
	// calculate segment (dustpocket) size
	const FIELDSIZE_POCKET:Number = fieldsize / 5;

	// determine the 8 gridpositions around the ship (eg. 1: front bottom left, 2: behind top right)
	const pocketPositions:Array = new Array();
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, false, false));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, false, false));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, true, false));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, false, true));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, true, false));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, false, true));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, true, true));
	pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, true, true));
}

/**
 * Calculates a gridpoint around the ship.
 */
private function calcGridPosition(position:Number3D, gridSize:Number, xMin:Boolean, yMin:Boolean, zMin:Boolean):Number3D {
	const gridPosition:Number3D = new Number3D();
	gridPosition.x = (position.x - (position.x % gridSize)) + ((xMin) ? 0 : gridSize);
	gridPosition.y = (position.y - (position.y % gridSize)) + ((yMin) ? 0 : gridSize);
	gridPosition.z = (position.z - (position.z % gridSize)) + ((zMin) ? 0 : gridSize);
	return gridPosition;
}
</pre>
<p>This is really all there is to it. The only thing we need to do now is create new dust pockets for gridpoints without one and remove dust pockets for points that are not within range anymore. Over and over again. Here&#8217;s the entire Spacedust class:</p>
<pre  name="code" class="java">
package org.codemonkey.spacedusttutorial.papervision3d {
	import flash.utils.Dictionary;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.core.math.Number3D;
	import org.papervision3d.materials.special.ParticleMaterial;
	import org.papervision3d.objects.special.ParticleField;
	import org.papervision3d.scenes.Scene3D;

	/**
	 * Spacedust simulator. Creates 8 segments of the dustcloud around the given camera at any point in space.
	 * When the camera moves, new dustpockets are generated and old ones (out of sight) are removed.
	 *
	 * @author Benny Bottema
	 */
	public class Spacedust {

		private static const DEFAULT_PARTICLEMATERIAL:ParticleMaterial = new ParticleMaterial(0xffffff, .5, ParticleMaterial.SHAPE_CIRCLE);

		private var basic3DSetup:Basic3DSetup;
		private var camera:Camera3D;
		private var spacedustCloud:Dictionary;

		private var fieldsize:Number;
		private var particleCount:Number;
		private var dustMaterial:ParticleMaterial = new ParticleMaterial(0xffffff, .5, ParticleMaterial.SHAPE_CIRCLE);

		public function Spacedust(basic3DSetup:Basic3DSetup, camera:Camera3D = null, fieldsize:Number = 2500, particleCount:Number = 400, dustMaterial:ParticleMaterial = null) {
			spacedustCloud = new Dictionary();
			this.basic3DSetup = basic3DSetup;
			this.camera = (camera != null) ? camera : basic3DSetup.camera;
			this.fieldsize = fieldsize;
			this.particleCount = particleCount;
			this.dustMaterial = (dustMaterial != null) ? dustMaterial : DEFAULT_PARTICLEMATERIAL;
		}

		public function update():void {
			// calculate segment (dustpocket) size
			const FIELDSIZE_POCKET:Number = fieldsize / 5;

			// determine the 8 gridpositions around the ship (eg. 1: front bottom left, 2: behind top right)
			var pocketPositions:Array = new Array();
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, false, false));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, false, false));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, true, false));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, false, true));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, true, false));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, false, true));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, false, true, true));
			pocketPositions.push(calcGridPosition(camera.position, FIELDSIZE_POCKET, true, true, true));

			var newSpacedustCloud:Dictionary = new Dictionary();

			// create new dustfields or transfer existing ones (and remove existing ones the scene)
			const particlesPerPocket:Number = particleCount / pocketPositions.length;
			for each (var pocketPosition:Number3D in pocketPositions) {
				var pocketKey:String = pocketPosition.toString();
				var reusableDustPocket:ParticleField = spacedustCloud[pocketKey];
				// remove so we can delete the particles from the remaining particlefields (which means they are out of sight)
				delete spacedustCloud[pocketKey];
				// add the removed particlefield to the new dustcloud or create one if dustpocket is new for te current gridposition around the ship
				if (reusableDustPocket != null) {
					basic3DSetup.removeFromScene(reusableDustPocket);
					newSpacedustCloud[pocketKey] = reusableDustPocket;
				} else {
					newSpacedustCloud[pocketKey] = new ParticleField(dustMaterial, particlesPerPocket, 2, fieldsize, fieldsize, fieldsize);
					newSpacedustCloud[pocketKey].x = pocketPosition.x;
					newSpacedustCloud[pocketKey].y = pocketPosition.y;
					newSpacedustCloud[pocketKey].z = pocketPosition.z;
				}
			}

			// manually remove all the remaining obsolete particles from the old cloud (they are out of sight)
			for each (var oldDustPocket:ParticleField in spacedustCloud) {
				oldDustPocket.removeAllParticles();
			}

			// now add the old dustpockets which are still within sight, plus the new dustpockets to the scene
			for each (var newDustPocket:ParticleField in newSpacedustCloud) {
				basic3DSetup.addToScene(newDustPocket);
			}

			// replace the old cloud with the new cloud
			spacedustCloud = newSpacedustCloud;
		}

		/**
		 * Calculates a gridpoint around the ship.
		 */
		private function calcGridPosition(position:Number3D, gridSize:Number, xMin:Boolean, yMin:Boolean, zMin:Boolean):Number3D {
			const gridPosition:Number3D = new Number3D();
			gridPosition.x = (position.x - (position.x % gridSize)) + ((xMin) ? 0 : gridSize);
			gridPosition.y = (position.y - (position.y % gridSize)) + ((yMin) ? 0 : gridSize);
			gridPosition.z = (position.z - (position.z % gridSize)) + ((zMin) ? 0 : gridSize);
			return gridPosition;
		}
	}
}
</pre>
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_spacedust/Spacedust.as">Download Spacedust.as</a></li>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_spacedust/spacedusttutorial.rar">download entire spacedust source</a> </li>
</ul>
<p>Notice the particel fields we&#8217;re using to create the eight dust pockets with.</p>
<p><code>new ParticleField(dustMaterial, particlesPerPocket, 2, fieldsize, fieldsize, fieldsize);</code></p>
<p>Also, the <i>Basic3DSetup</i> class I&#8217;ve used is simply a convenience class with default camera, scene, viewport etc. It&#8217;s much like Papervision&#8217;s own <a href="http://pv3d.org/2008/12/06/what-is-basicview/">BasicView</a> -which I didn&#8217;t know about at the time- except even cleaner.</p>
<p>The Spacedust class accepts an optional camera to position the dust cloud around. Since this approach is meant to create the illusion of infinite space dust, it doesn&#8217;t make sense to create clouds on non-camera&#8217;s. Also, you can specify your own particle count and dust material in the constructor of the Spacedust class. The example at the top of the page uses only the defaults.</p>
<p><a href="http://blog.projectnibble.org/2009/05/29/easy-papervision3d-space-dust-tutorial-and-source/trackback/">trackback</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.projectnibble.org/2009/05/29/easy-papervision3d-space-dust-tutorial-and-source/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Easy Papervision3D skybox tutorial and source</title>
		<link>http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/</link>
		<comments>http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/#comments</comments>
		<pubDate>Fri, 22 May 2009 08:06:23 +0000</pubDate>
		<dc:creator>Benny Bottema</dc:creator>
				<category><![CDATA[Papervision3D]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[game design]]></category>
		<category><![CDATA[skybox]]></category>

		<guid isPermaLink="false">http://blog.projectnibble.org/?p=112</guid>
		<description><![CDATA[Adding a skybox in Papervision3D is easy. I've made a small class that nicely encapsulates what you need.]]></description>
			<content:encoded><![CDATA[<div style="float:left; margin: 1em">

<object width="300" height="300">
<param name="movie" value="http://projectnibble.org/dump/blog/papervision3d_skybox/Skyboxtutorial.swf"></param>
<param name="quality" value="high"></param>
<param name="wmode" value="window"></param>
<param name="menu" value="false"></param>
<param name="bgcolor" value="#000000"></param>
<embed type="application/x-shockwave-flash" width="300" height="300" src="http://projectnibble.org/dump/blog/papervision3d_skybox/Skyboxtutorial.swf" quality="high" bgcolor="#000000" wmode="window" menu="false" ></embed>
</object>

</div>
<div style="padding-top:.5em">
<p>Adding a skybox in Papervision3D is extremely easy. I couldn&#8217;t find a whole lot of examples/tutorials about skyboxes in Papervision3D, but I managed to find a <a href="http://professionalpapervision.wordpress.com/2008/10/20/putting-stars-and-more-into-a-skybox-source/">skybox tutorial source</a> and learned how to do it. The tutorial I got the initial source from is actually about adding stars using particle fields, but I just used the skybox part of it (and used the textures).</p>
<p>I decided to clean it up and make a nice class out of it. I&#8217;ve used the trunk of the papervision code repository, revision 851, but since it&#8217;s very basic stuff I doubt it&#8217;ll break with future versions.</p>
<ul style="text-indent:1cm">
<li><a href="http://projectnibble.org/dump/blog/papervision3d_skybox/skyboxtutorial.rar">download skybox source</a></li>
</ul>
</div>
<div style="clear:both">&nbsp;</div>
<p><span id="more-112"></span></p>
<pre  name="code" class="java">
package org.codemonkey.papervision3d {
	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.primitives.Cube;

	public class Skybox extends Cube {

		public static const QUALITY_LOW:Number = 4;
		public static const QUALITY_MEDIUM:Number = 6;
		public static const QUALITY_HIGH:Number = 8;

		public function Skybox(bf:Class, bl:Class, bb:Class, bu:Class, br:Class, bd:Class, skysize:Number, quality:Number):void {
			super(generateMaterials(bf, bl, bb, bu, br, bd), skysize, skysize, skysize, quality, quality, quality);
		}

		protected function generateMaterials(bf:Class, bl:Class, bb:Class, bu:Class, br:Class, bd:Class):MaterialsList {
			var materials:MaterialsList = new MaterialsList();
			materials.addMaterial(new BitmapMaterial(new bf().bitmapData), "front");
			materials.addMaterial(new BitmapMaterial(new bl().bitmapData), "left");
			materials.addMaterial(new BitmapMaterial(new bb().bitmapData), "back");
			materials.addMaterial(new BitmapMaterial(new bu().bitmapData), "top");
			materials.addMaterial(new BitmapMaterial(new br().bitmapData), "right");
			materials.addMaterial(new BitmapMaterial(new bd().bitmapData), "bottom");

			for each (var material:BitmapMaterial in materials.materialsByName) {
				material.doubleSided = true;
			}

			return materials;
		}
	}
}
</pre>
<ul>
<li><a href="http://projectnibble.org/dump/blog/papervision3d_skybox/Skybox.as">download Skybox.as</a></li>
</ul>
<p>See the line <i>material.doubleSided = true;</i>? That&#8217;s needed since we&#8217;re inside the cube that is the skybox. Since normally you can only see objects from the outside we&#8217;re setting the double-sidedness of the skybox. Perhaps a better solution is to flip the faces of the skybox and leave out the double-sidedness all together:</p>
<pre  name="code" class="java">
		public function Skybox(bf:Class, bl:Class, bb:Class, bu:Class, br:Class, bd:Class, skysize:Number, quality:Number):void {
			super(generateMaterials(bf, bl, bb, bu, br, bd), skysize, skysize, skysize, quality, quality, quality);
			geometry.flipFaces(); // now you can only see the box from the inside...
		}
</pre>
<p>To use the Skybox class, here&#8217;s an example:</p>
<pre  name="code" class="java">
public class SkyboxTest {

		// skybox images
		[Embed (source="assets/hot_nebula_0.jpg")]
		private var BitmapFront:Class;
		[Embed (source="assets/hot_nebula_270.jpg")]
		private var BitmapRight:Class;
		[Embed (source="assets/hot_nebula_180.jpg")]
		private var BitmapBack:Class;
		[Embed (source="assets/hot_nebula_90.jpg")]
		private var BitmapLeft:Class;
		[Embed (source="assets/hot_nebula_bottom.jpg")]
		private var BitmapDown:Class;
		[Embed (source="assets/hot_nebula_top.jpg")]
		private var BitmapUp:Class;

		public static const SKYSIZE:Number = Number.MAX_VALUE;

		public function loadSkyBox(scene:Scene3D) {
			var skybox:Skybox = new Skybox(BitmapFront, BitmapLeft, BitmapBack, BitmapUp, BitmapRight, BitmapDown, SKYSIZE, Skybox.QUALITY_HIGH);
			scene.addChild(skybox);
		}
}
</pre>
<p>Here are the steps you need:</p>
<ul>
<li>define a bunch of textures in the top of your classes by embedding them and pass these classes to the Skybox constructor.</li>
<li>pass in a size for your skybox: I&#8217;ve used <i>Number.MAX_VALUE</i> so the skybox won&#8217;t move or pixelate while I move through it with the camera.</li>
<li>pass in a quality value: this can be any number actually, I just found 4, 6 and 8 to work nicely. These numbers determine how many segments are used in each of the faces of the skybox to avoid texture distortion and awkward transitions from one texture into another.</li>
</ul>
<p>For my own convenience I&#8217;ve made a NebulaSkybox which simply encapsulates all the embedded images for the nebula sky:</p>
<pre  name="code" class="java">
	public class NebulaSkybox extends Skybox {

		// nebula skybox images
		[Embed (source="../../../assets/hot_nebula_0_lowquality.jpg")]
		private var BitmapFront:Class;
		[Embed (source="../../../assets/hot_nebula_270_lowquality.jpg")]
		private var BitmapRight:Class;
		[Embed (source="../../../assets/hot_nebula_180_lowquality.jpg")]
		private var BitmapBack:Class;
		[Embed (source="../../../assets/hot_nebula_90_lowquality.jpg")]
		private var BitmapLeft:Class;
		[Embed (source="../../../assets/hot_nebula_bottom_lowquality.jpg")]
		private var BitmapDown:Class;
		[Embed (source="../../../assets/hot_nebula_top_lowquality.jpg")]
		private var BitmapUp:Class;

		public function NebulaSkybox(skysize:Number, quality:Number) {
			super(BitmapFront, BitmapLeft, BitmapBack, BitmapUp, BitmapRight, BitmapDown, skysize, quality);
		}
	}

	public class SkyboxTest {

		public static const SKYSIZE:Number = Number.MAX_VALUE;

		public function loadSkyBox(scene:Scene3D) {
			var skybox:Skybox = new NebulaSkybox(SKYSIZE, Skybox.QUALITY_HIGH);
			scene.addChild(skybox);
		}
	}
</pre>
<p><a href="http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/trackback/">trackback</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.projectnibble.org/2009/05/22/easy-papervision3d-skybox-tutorial-and-source/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
