<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Miles Macklin&#039;s blog</title>
	<atom:link href="http://mmack.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://mmack.wordpress.com</link>
	<description>Graphics, code and cups of tea</description>
	<lastBuildDate>Fri, 25 Nov 2011 09:37:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='mmack.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Miles Macklin&#039;s blog</title>
		<link>http://mmack.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://mmack.wordpress.com/osd.xml" title="Miles Macklin&#039;s blog" />
	<atom:link rel='hub' href='http://mmack.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Blackbody Rendering</title>
		<link>http://mmack.wordpress.com/2010/12/29/blackbody-rendering/</link>
		<comments>http://mmack.wordpress.com/2010/12/29/blackbody-rendering/#comments</comments>
		<pubDate>Wed, 29 Dec 2010 08:21:08 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Fluid Simulation]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Volume Rendering]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=1265</guid>
		<description><![CDATA[In between bouts of festive over-eating I added support for blackbody emission to my fluid simulator and thought I&#8217;d describe what was involved. Briefly, a blackbody is an idealised substance that gives off light when heated. Planck&#8217;s formula describes the intensity of light per-wavelength with units W·sr-1·m-2·m-1. Radiance has units W·sr-1·m-2 so we need a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1265&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In between bouts of festive over-eating I added support for blackbody emission to my fluid simulator and thought I&#8217;d describe what was involved.</p>
<p>Briefly, a <a href="http://en.wikipedia.org/wiki/Black_body">blackbody</a> is an idealised substance that gives off light when heated. <a href="http://en.wikipedia.org/wiki/Planck's_law">Planck&#8217;s formula</a> describes the intensity of light per-wavelength with units <strong>W·sr<sup>-1</sup>·m<sup>-2</sup>·m<sup>-1</sup></strong>.</p>
<p>Radiance has units <strong>W·sr<sup>-1</sup>·m<sup>-2</sup></strong> so we need a way to convert the wavelength dependent power distribution given by Planck&#8217;s formula to a radiance value in RGB that we can use in our shader / ray-tracer.</p>
<p>The typical way to do this is as follows:</p>
<ol>
<li>Integrate Planck&#8217;s formula against the CIE XYZ colour matching functions (available as part of <a href="https://github.com/mmp/pbrt-v2/blob/master/src/core/spectrum.cpp">PBRT</a> in 1nm increments)</li>
<li>Convert from <a href="http://en.wikipedia.org/wiki/CIE_1931_color_space">XYZ</a> to linear <a href="http://en.wikipedia.org/wiki/SRGB">sRGB</a> (do not perform gamma correction yet)</li>
<li>Render as normal</li>
<li>Perform tone-mapping / gamma correction</li>
</ol>
<p>We are throwing away spectral information by projecting into XYZ but a quick dimensional analysis shows that now we at least have the correct units (because the integration is with respect to <em>dλ</em> measured in meters the extra  <strong>m<sup>-1</sup></strong> is removed).</p>
<p>I was going to write more about the colour conversion process, but I didn&#8217;t want to add to the confusion out there by accidentally misusing terminology. Instead here are a couple of papers describing the conversion from Spectrum-&gt;RGB and RGB-&gt;Spectrum, questions about these come up all the time on various forums and I think these two papers do a good job of providing background and clarifying the process:</p>
<ul>
<li><a href="http://www.anyhere.com/gward/papers/egwr02/index.html">Picture Perfect RGB Rendering Using Spectral Prefiltering and Sharp Color Primaries</a></li>
<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.40.9608">An RGB to Spectrum Conversion for Reflectances</a></li>
</ul>
<p>And some more general colour space links:</p>
<ul>
<li><a href="http://graphics.stanford.edu/courses/cs148-10-summer/docs/2010--kerr--cie_xyz.pdf">The CIE XYZ and xyY Color Spaces by Douglas Kerr</a> (particularly good)</li>
<li><a href="http://renderwonk.com/publications/s2010-color-course/">SIGGRAPH 2010: Color Enhancement and Rendering in Film and Game Production</a></li>
<li><a href="ftp://rtfm.mit.edu/pub/usenet/news.answers/graphics/colorspace-faq">Color Space FAQ</a></li>
</ul>
<p>Here is a small sample of linear sRGB radiance values for different Blackbody temperatures:<br />
<code><br />
1000K: 1.81e-02, 1.56e-04, 1.56e-04<br />
2000K: 1.71e+03, 4.39e+02, 4.39e+02<br />
4000K: 5.23e+05, 3.42e+05, 3.42e+05<br />
8000K: 9.22e+06, 9.65e+06, 9.65e+06<br />
</code></p>
<p>It&#8217;s clear from the range of values that we need some sort of exposure control and tone-mapping. I simply picked a temperature in the upper end of my range (around 3000K) and scaled intensities around it before applying Reinhard tone mapping and gamma correction.  You can also perform more advanced mapping by taking into account the human visual system adaptation as described in <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.84.3511&amp;rep=rep1&amp;type=pdf">Physically Based Modeling and Animation of Fire</a>.</p>
<p>Again the hardest part was setting up the simulation parameters to get the look you want, here&#8217;s one I spent at least 4 days tweaking:</p>
<p><iframe src="http://player.vimeo.com/video/18232573" width="480" height="360" frameborder="0"></iframe></p>
<p>Simulation time is ~30s a frame (10 substeps) on a 128^3 grid tracking temperature, fuel, smoke and velocity. Most of that time is spent in the tri-cubic interpolation during advection, I&#8217;ve been meaning to try MacCormack advection to see if it&#8217;s a net win.</p>
<p>There are some pretty obvious artifacts due to the tri-linear interpolation on the GPU, that would be helped by a higher resolution grid or manually performing tri-cubic in the shader.</p>
<p>Inspired by Kevin Beason&#8217;s work in progress videos I put together a collection of my own failed tests which I think are quite amusing:</p>
<p><iframe src="http://player.vimeo.com/video/18232467" width="480" height="360" frameborder="0"></iframe></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/1265/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1265&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/12/29/blackbody-rendering/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>
	</item>
		<item>
		<title>Adventures in Fluid Simulation</title>
		<link>http://mmack.wordpress.com/2010/11/01/adventures-in-fluid-simulation/</link>
		<comments>http://mmack.wordpress.com/2010/11/01/adventures-in-fluid-simulation/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 01:34:27 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Fluid Simulation]]></category>
		<category><![CDATA[GPU]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Interactive Frame Rates]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=1152</guid>
		<description><![CDATA[I have to admit to being simultaneously fascinated and slightly intimidated by the fluid simulation crowd. I&#8217;ve been watching the videos on Ron Fedkiw&#8217;s page for years and am still in awe of his results, which sometimes seem little short of magic. Recently I resolved to write my first fluid simulator and purchased a copy [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1152&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I have to admit to being simultaneously fascinated and slightly intimidated by the fluid simulation crowd. I&#8217;ve been watching the videos on <a href="http://physbam.stanford.edu/~fedkiw/">Ron Fedkiw&#8217;s page</a> for years and am still in awe of his results, which sometimes seem little short of magic.</p>
<p>Recently I resolved to write my first fluid simulator and purchased a copy of <a href="http://www.cs.ubc.ca/~rbridson/fluidbook/">Fluid Simulation for Computer Graphics</a> by Robert Bridson.</p>
<p><img src="http://mmack.files.wordpress.com/2010/11/fluidbook.jpg?w=125&#038;h=185" alt="" title="fluidbook" width="125" height="185" class="alignright size-full wp-image-1461" /> Like a lot of developers my first exposure to the subject was <a href="http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/ns.pdf">Jos Stam&#8217;s stable fluids paper</a> and his more accessible <a href="http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf">Fluid Dynamics for Games</a> presentation, while the ideas are undeniable great I never came away feeling like I truly understood the concepts or the mathematics behind it.</p>
<p>I&#8217;m happy to report that Bridson&#8217;s book has helped change that. It includes a review of vector calculus in the appendix that is given in a wonderfully straight-foward and concise manner, Bridson takes almost nothing for granted and gives lots of real-world examples which helps for some of the less intuitive concepts.</p>
<p>I&#8217;m planning a bigger post on the subject but I thought I&#8217;d write a quick update with my progress so far.</p>
<p>I started out with a 2D simulation similar to Stam&#8217;s demos, having a 2D implementation that you&#8217;re confident in is really useful when you want to quickly try out different techniques and to sanity check results when things go wrong in 3D (and they will).</p>
<p>Before you write the 3D sim though, you need a way of visualising the data. I spent quite a while on this and implemented a single-scattering model using brute force ray-marching on the GPU.</p>
<p>I did some tests with a procedural pyroclastic cloud model which you can see below, this runs at around 25ms on my MacBook Pro (NVIDIA 320M) but you can dial the sample counts up and down to suit:</p>
<div class='embed-vimeo' style='text-align:center;'><iframe src='http://player.vimeo.com/video/16159247' width='500' height='281' frameborder='0'></iframe></div>
<p>(videos don&#8217;t show in RSS feeds)</p>
<p>Here&#8217;s a simplified GLSL snippet of the volume rendering shader, it&#8217;s not at all optimised apart from some branches to skip over empty space and an assumption that absorption varies linearly with density:</p>
<p><pre class="brush: cpp; wrap-lines: false;">
uniform sampler3D g_densityTex;
uniform vec3 g_lightPos;
uniform vec3 g_lightIntensity;
uniform vec3 g_eyePos;
uniform float g_absorption;

void main()
{
	// diagonal of the cube
	const float maxDist = sqrt(3.0);

	const int numSamples = 128;
	const float scale = maxDist/float(numSamples);

	const int numLightSamples = 32;
	const float lscale = maxDist / float(numLightSamples);

	// assume all coordinates are in texture space
	vec3 pos = gl_TexCoord[0].xyz;
	vec3 eyeDir = normalize(pos-g_eyePos)*scale;

	// transmittance
	float T = 1.0;
	// in-scattered radiance
	vec3 Lo = vec3(0.0);

	for (int i=0; i &lt; numSamples; ++i)
	{
		// sample density
		float density = texture3D(g_densityTex, pos).x;

		// skip empty space
		if (density &gt; 0.0)
		{
			// attenuate ray-throughput
			T *= 1.0-density*scale*g_absorption;
			if (T &lt;= 0.01)
				break;

			// point light dir in texture space
			vec3 lightDir = normalize(g_lightPos-pos)*lscale;

			// sample light
			float Tl = 1.0;	// transmittance along light ray
			vec3 lpos = pos + lightDir;

			for (int s=0; s &lt; numLightSamples; ++s)
			{
				float ld = texture3D(g_densityTex, lpos).x;
				Tl *= 1.0-g_absorption*lscale*ld;

				if (Tl &lt;= 0.01)
					break;

				lpos += lightDir;
			}

			vec3 Li = g_lightIntensity*Tl;

			Lo += Li*T*density*scale;
		}

		pos += eyeDir;
	}

	gl_FragColor.xyz = Lo;
	gl_FragColor.w = 1.0-T;
}
</pre></p>
<p>I&#8217;m pretty sure there&#8217;s a whole post on the ways this could be optimised but I&#8217;ll save that for next time.  Also this example shader doesn&#8217;t have any wavelength dependent variation.  Making your absorption coefficient different for each channel looks much more interesting and having a different coefficient for your primary and shadow rays also helps, you can see this effect in the videos.</p>
<p>To create the cloud like volume texture in OpenGL I use a displaced distance field like this (see the SIGGRAPH course for more details):</p>
<p><pre class="brush: cpp; wrap-lines: false;">
// create a volume texture with n^3 texels and base radius r
GLuint CreatePyroclasticVolume(int n, float r)
{
	GLuint texid;
	glGenTextures(1, &amp;texid);

	GLenum target = GL_TEXTURE_3D;
	GLenum filter = GL_LINEAR;
	GLenum address = GL_CLAMP_TO_BORDER;

	glBindTexture(target, texid);

	glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
	glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);

	glTexParameteri(target, GL_TEXTURE_WRAP_S, address);
	glTexParameteri(target, GL_TEXTURE_WRAP_T, address);
	glTexParameteri(target, GL_TEXTURE_WRAP_R, address);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	byte *data = new byte[n*n*n];
	byte *ptr = data;

	float frequency = 3.0f / n;
	float center = n / 2.0f + 0.5f;

	for(int x=0; x &lt; n; x++)
	{
		for (int y=0; y &lt; n; ++y)
		{
			for (int z=0; z &lt; n; ++z)
			{
				float dx = center-x;
				float dy = center-y;
				float dz = center-z;

				float off = fabsf(Perlin3D(x*frequency,
										   y*frequency,
										   z*frequency,
										   5,
										   0.5f));

				float d = sqrtf(dx*dx+dy*dy+dz*dz)/(n);

				*ptr++ = ((d-off) &lt; r)?255:0;
			}
		}
	}

	// upload
	glTexImage3D(target,
				 0,
				 GL_LUMINANCE,
				 n,
				 n,
				 n,
				 0,
				 GL_LUMINANCE,
				 GL_UNSIGNED_BYTE,
				 data);

	delete[] data;

	return texid;
}
</pre></p>
<p>An excellent introduction to volume rendering is the SIGGRAPH 2010 course, <a href="http://magnuswrenninge.com/volumetricmethods">Volumetric Methods in Visual Effects</a> and Kyle Hayward&#8217;s <a href="http://graphicsrunner.blogspot.com/2009/01/volume-rendering-101.html">Volume Rendering 101</a> for some GPU specifics.</p>
<p>Once I had the visualisation in place, porting the fluid simulation to 3D was actually not too difficult. I spent most of my time tweaking the initial conditions to get the smoke to behave in a way that looks interesting, you can see one of my more successful simulations below:</p>
<div class='embed-vimeo' style='text-align:center;'><iframe src='http://player.vimeo.com/video/16357651' width='400' height='600' frameborder='0'></iframe></div>
<p>Currently the simulation runs entirely on the CPU using a 128^3 grid with monotonic tri-cubic interpolation and vorticity confinement as described in <a href="http://graphics.ucsd.edu/~henrik/papers/smoke/smoke.pdf">Visual Simulation of Smoke</a> by Fedkiw.  I&#8217;m fairly happy with the result but perhaps I have the vorticity confinement cranked a little high.</p>
<p>Nothing is optimised so its running at about 1.2s a frame on my 2.66ghz Core 2 MacBook.</p>
<p>Future work is to port the simulation to OpenCL and implement some more advanced features.  Specifically I&#8217;m interested in <a href="http://physbam.stanford.edu/~fedkiw/papers/stanford2005-01.pdf">A Vortex Particle Method for Smoke, Water and Explosions</a> which <a href="http://www.kevinbeason.com/">Kevin Beason</a> describes on his <a href="http://www.kevinbeason.com/scs/fluid/">fluid page</a> (with some great videos).</p>
<p>On a personal note, I resigned from LucasArts a couple of weeks ago and am looking forward to some time off back in New Zealand with my family and friends.  Just in time for the Kiwi summer!</p>
<h2>Links</h2>
<p><a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch38.html">GPU Gems &#8211; Fluid Simulation on the GPU</a><br />
<a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch30.html">GPU Gems 3 &#8211; Real-Time Rendering and Simulation of 3D Fluids</a><br />
<a href="http://www.colinbraley.com/Pubs/FluidSimColinBraley.pdf">Fluid Simulation For Computer Graphics: A Tutorial in Grid Based and Particle Based Methods</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/1152/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/1152/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/1152/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1152&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/11/01/adventures-in-fluid-simulation/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/11/fluidbook.jpg" medium="image">
			<media:title type="html">fluidbook</media:title>
		</media:content>
	</item>
		<item>
		<title>Tracing</title>
		<link>http://mmack.wordpress.com/2010/10/03/tracing/</link>
		<comments>http://mmack.wordpress.com/2010/10/03/tracing/#comments</comments>
		<pubDate>Sun, 03 Oct 2010 23:37:47 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Offline]]></category>
		<category><![CDATA[Ray tracing]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=1033</guid>
		<description><![CDATA[Gregory Pakosz reminded me to write a follow up on my path tracing efforts since my last post on the subject. It&#8217;s good timing because the friendly work-place competition between Tom and me has been in full swing. For about two weeks each of us would arrive in the morning and announce our supremacy in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1033&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Gregory Pakosz reminded me to write a follow up on my path tracing efforts since my <a href="http://mmack.wordpress.com/2009/12/02/path-tracing/">last post</a> on the subject. </p>
<p>It&#8217;s good timing because the friendly work-place competition between <a href="http://imdoingitwrong.wordpress.com/">Tom</a> and me has been in full swing.  For about two weeks each of us would arrive in the morning and announce our supremacy in the speed race, only to be dethroned the next day (or a few hours later).</p>
<p>The great thing about ray tracing is that there are many opportunities for optimisation at all levels of computation.  This keeps you &#8220;hooked&#8221; by constantly offering decent speed increases for relatively little effort.</p>
<p>My competitor had an existing BIH (<a href="http://en.wikipedia.org/wiki/Bounding_interval_hierarchy">bounding interval hierarchy</a>) implementation that was doing a pretty good job, so I had some catching up to do.  Previously I had a positive experience using a BVH (<a href="http://en.wikipedia.org/wiki/Bounding_volume_hierarchy">AABB tree</a>) in a games context so decided to go that route.</p>
<p>Our benchmark scene was <a href="http://www.crytek.com/cryengine/cryengine3/downloads">Crytek&#8217;s Sponza</a> with the camera positioned in the center of the model looking down the z-axis.  This might not be the most representative case but was good enough for comparing primary ray speeds.</p>
<p><a href="http://mmack.files.wordpress.com/2010/10/sponza_bench.png"><img class="aligncenter size-full wp-image-1070" title="sponza_bench" src="http://mmack.files.wordpress.com/2010/10/sponza_bench.png?w=480&#038;h=267" alt="" width="480" height="267" /></a></p>
<p>Here&#8217;s a rough timeline of the performance progress (all timings were taken from my 2.6ghz i7 running 8 worker threads):</p>
<table style="text-align:left;" border="1">
<tbody>
<tr>
<th>Optimisation</th>
<th>Rays/second</th>
</tr>
<tr>
<td>Baseline (median split)</td>
<td>91246</td>
</tr>
<tr>
<td>Tweak compiler settings (/fp:fast /sse2 /Ot)</td>
<td>137486</td>
</tr>
<tr>
<td>Non-recursive traversal</td>
<td>145847</td>
</tr>
<tr>
<td>Traverse closest branch first</td>
<td>146822</td>
</tr>
<tr>
<td>Surface area heuristic</td>
<td>1.27589e+006</td>
</tr>
<tr>
<td>Surface area heuristic (exhaustive)</td>
<td>1.9375e+006</td>
</tr>
<tr>
<td>Optimized ray-AABB</td>
<td>2.14232e+006</td>
</tr>
<tr>
<td>VS2008 to VS2010</td>
<td>2.47746e+006</td>
</tr>
</tbody>
</table>
<p>You can see the massive difference tree quality has on performance.  What I found surprising though was the effect switching to VS2010 had, 15% faster is impressive for a single compiler revision.</p>
<p>I played around with a quantized BVH which reduced node size from 32 bytes to 11 but I couldn&#8217;t get the decrease in cache traffic to outweigh the cost in decoding the nodes.  If anyone has had success with this I&#8217;d be interested in the details.</p>
<p>Algorithmically it is a uni-directional path tracer with multiple importance sampling.  Of course importance sampling doesn&#8217;t make individual samples faster but allows you to take less total samples than you would have to otherwise.</p>
<p>So, time for some pictures:</p>
<p><a href="http://mmack.files.wordpress.com/2010/10/sponza_plus.png"><img class="aligncenter size-full wp-image-1042" title="Sponza" src="http://mmack.files.wordpress.com/2010/10/sponza_plus.png?w=480&#038;h=283" alt="" width="480" height="283" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2010/10/classroom_neon.png"><img class="aligncenter size-full wp-image-1036" title="Classroom (from LuxRender distibution)" src="http://mmack.files.wordpress.com/2010/10/classroom_neon.png?w=480&#038;h=282" alt="" width="480" height="282" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2010/10/matte_lucy_big.png"><img class="aligncenter size-full wp-image-1040" title="Lucy" src="http://mmack.files.wordpress.com/2010/10/matte_lucy_big.png?w=480&#038;h=282" alt="" width="480" height="282" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2010/10/gold_statuette_exp.png"><img class="aligncenter size-full wp-image-1039" title="Thai Statuette" src="http://mmack.files.wordpress.com/2010/10/gold_statuette_exp.png?w=480&#038;h=783" alt="" width="480" height="783" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2010/10/gold_dragon.png"><img class="aligncenter size-full wp-image-1038" title="Dragon" src="http://mmack.files.wordpress.com/2010/10/gold_dragon.png?w=480&#038;h=268" alt="" width="480" height="268" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2010/10/bunny_fresnel.png"><img class="aligncenter size-full wp-image-1035" title="Bunny" src="http://mmack.files.wordpress.com/2010/10/bunny_fresnel.png?w=480&#038;h=267" alt="" width="480" height="267" /></a></p>
<p>Despite being the lowest poly models, Sponza (200k triangles) and the classroom (250k triangles) were by far the most difficult for the renderer; they both took 10+ hours and still have visible noise.  In contrast the gold statuette (10 million triangles) took only 20 mins to converge!</p>
<p>This is mainly because the architectural models have a mixture of very large and very small polygons which creates deep trees with large nodes near the root.  I think a kd-tree which splits or duplicates primitives might be more effective in this case.</p>
<p>A fun way to break your spatial hierarchy is simply to add a ground plane.  Until I performed an exhaustive split search adding a large two triangle ground plane could slow down tracing by as much as 50%.</p>
<p>Of course these numbers are peanuts compared to what people are getting with GPU or SIMD packet tracers, <a href="http://www.tml.tkk.fi/~timo/">Timo Aila</a> reports speeds of 142 million rays/second on similar scenes using a GPU tracer in <a href="http://www.tml.tkk.fi/~timo/publications/aila2009hpg_paper.pdf">this paper</a>.</p>
<p>Writing a path tracer has been a great education for me and I would encourage anyone interested in getting a better grasp on computer graphics to get a copy of PBRT and have a go at it.  It&#8217;s easy to get started and seeing the finished product is hugely rewarding.</p>
<h3 style="text-align:left;">Links:</h3>
<p>John Carmack <a href="http://twitter.com/id_aa_carmack">tweeting</a> about his experience optimising the offline global illumination calculations in <a href="http://www.rockpapershotgun.com/2009/08/11/carmack-talks-rage-other-stuff/">RAGE</a>.</p>
<p>I was surprised to learn at SIGGRAPH that Arnold (as used by Sony Pictures Imageworks) is at it&#8217;s core a uni-directional path tracer.  Marcos Fajardo described some details in the <a href="http://www.graphics.cornell.edu/~jaroslav/gicourse2010/">Global Illumination Across Industries</a> talk.</p>
<p>Mental Images <a href="http://www.youtube.com/watch?v=nhXBx8l0iso">iRay</a> (their GPU based cloud renderer) looks impressive and apparently uses a single BSSRDF on all their surfaces which I guess helps simplify their GPU implementation.</p>
<p><a href="http://ompf.org/forum/">Ompf.org</a></p>
<h3 style="text-align:left;">Model credits:</h3>
<p>Sponza &#8211; <a href="http://www.crytek.com/cryengine/cryengine3/downloads">Crytek</a><br />
Classroom &#8211; <a href="http://src.luxrender.net/luxrays/">LuxRender</a><br />
Thai Statuette, Dragon, Bunny, Lucy &#8211; <a href="http://graphics.stanford.edu/data/3Dscanrep/">Stanford scanning repository</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/1033/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/1033/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/1033/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=1033&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/10/03/tracing/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/sponza_bench.png" medium="image">
			<media:title type="html">sponza_bench</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/sponza_plus.png" medium="image">
			<media:title type="html">Sponza</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/classroom_neon.png" medium="image">
			<media:title type="html">Classroom (from LuxRender distibution)</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/matte_lucy_big.png" medium="image">
			<media:title type="html">Lucy</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/gold_statuette_exp.png" medium="image">
			<media:title type="html">Thai Statuette</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/gold_dragon.png" medium="image">
			<media:title type="html">Dragon</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/10/bunny_fresnel.png" medium="image">
			<media:title type="html">Bunny</media:title>
		</media:content>
	</item>
		<item>
		<title>Faster Fog</title>
		<link>http://mmack.wordpress.com/2010/06/10/faster-fog/</link>
		<comments>http://mmack.wordpress.com/2010/06/10/faster-fog/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 03:24:11 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Fog Volumes]]></category>
		<category><![CDATA[Graphics]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=856</guid>
		<description><![CDATA[Cedrick at Lucas suggested some nice optimisations for the in-scattering equation I posted last time. I had left off at: But we can remove one of the two inverse trigonometric functions by using the following identity: Giving us: With: , So the updated GLSL snippet looks like: Of course it&#8217;s always good to verify your [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=856&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://ccollomb.free.fr/blog/">Cedrick</a> at Lucas suggested some nice optimisations for the in-scattering equation I posted <a href="http://mmack.wordpress.com/2010/05/29/in-scattering-demo/">last time</a>.</p>
<p>I had left off at:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Cfrac%7B%5Csigma_%7Bs%7DI%7D%7Bv%7D%28+%5Ctan%5E%7B-1%7D%5Cfrac%7Bd%2Bb%7D%7Bv%7D+-+%5Ctan%5E%7B-1%7D%5Cfrac%7Bb%7D%7Bv%7D+%29+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( &#92;tan^{-1}&#92;frac{d+b}{v} - &#92;tan^{-1}&#92;frac{b}{v} ) &#92;nonumber ' title='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( &#92;tan^{-1}&#92;frac{d+b}{v} - &#92;tan^{-1}&#92;frac{b}{v} ) &#92;nonumber ' class='latex' /></p>
<p>But we can remove one of the two inverse trigonometric functions by using the following identity:</p>
<p><img src='http://s0.wp.com/latex.php?latex=%5Ctan%5E%7B-1%7Dx+-%5Ctan%5E%7B-1%7Dy+%3D+%5Ctan%5E%7B-1%7D%5Cfrac%7Bx-y%7D%7B1%2Bxy%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;tan^{-1}x -&#92;tan^{-1}y = &#92;tan^{-1}&#92;frac{x-y}{1+xy} &#92;nonumber ' title='&#92;tan^{-1}x -&#92;tan^{-1}y = &#92;tan^{-1}&#92;frac{x-y}{1+xy} &#92;nonumber ' class='latex' /></p>
<p>Giving us:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Cfrac%7B%5Csigma_%7Bs%7DI%7D%7Bv%7D%28+%5Ctan%5E%7B-1%7D%5Cfrac%7Bx-y%7D%7B1%2Bxy%7D+%29+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( &#92;tan^{-1}&#92;frac{x-y}{1+xy} ) &#92;nonumber ' title='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( &#92;tan^{-1}&#92;frac{x-y}{1+xy} ) &#92;nonumber ' class='latex' /></p>
<p>With:</p>
<p><img src='http://s0.wp.com/latex.php?latex=x+%3D+%5Cfrac%7Bd%2Bb%7D%7Bv%7D&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='x = &#92;frac{d+b}{v}' title='x = &#92;frac{d+b}{v}' class='latex' />, <img src='http://s0.wp.com/latex.php?latex=y+%3D+%5Cfrac%7Bb%7D%7Bv%7D&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='y = &#92;frac{b}{v}' title='y = &#92;frac{b}{v}' class='latex' /></p>
<p>So the updated GLSL snippet looks like:</p>
<p><pre class="brush: cpp;">
float InScatter(vec3 start, vec3 dir, vec3 lightPos, float d)
{
   vec3 q = start - lightPos;

   // calculate coefficients
   float b = dot(dir, q);
   float c = dot(q, q);
   float s = 1.0f / sqrt(c - b*b);

   // after a little algebraic re-arrangement
   float x = d*s;
   float y = b*s;
   float l = s * atan( (x) / (1.0+(x+y)*y));

   return l;
}
</pre></p>
<p>Of course it&#8217;s always good to verify your &#8216;optimisations&#8217;, ideally I would take GPU timings but next best is to run it through NVShaderPerf and check the cycle counts:</p>
<p><pre class="brush: plain;">
Original (2x atan()):

Fragment Performance Setup: Driver 174.74, GPU G80, Flags 0x1000
Results 76 cycles, 10 r regs, 2,488,320,064 pixels/s

Updated (1x atan())

Fragment Performance Setup: Driver 174.74, GPU G80, Flags 0x1000
Results 55 cycles, 8 r regs, 3,251,200,103 pixels/s
</pre></p>
<p>A tasty 25% reduction in cycle count!</p>
<p>Another idea is to use an approximation of atan(), Robin Green has some great articles about <a href="http://www.research.scea.com/gdc2003/fast-math-functions.html">faster math functions</a> where he discusses how you can range reduce to 0-1 and approximate using <a href="http://mathworld.wolfram.com/MinimaxPolynomial.html">minimax polynomials</a>.</p>
<p>My first attempt was much simpler, looking at it&#8217;s graph we can see that atan() is almost linear near 0 and asymptotically approaches <img src='http://s0.wp.com/latex.php?latex=%5Cfrac%7B%5Cpi%7D%7B2%7D+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;frac{&#92;pi}{2} ' title='&#92;frac{&#92;pi}{2} ' class='latex' />.</p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/06/atan.png"><img class="aligncenter size-full wp-image-878" title="atan" src="http://mmack.files.wordpress.com/2010/06/atan.png?w=496&#038;h=421" alt="" width="496" height="421" /></a></p>
<p>Perhaps the simplest approximation we could try would be something like:</p>
<p><img src='http://s0.wp.com/latex.php?latex=%5Ctan%5E%7B-1%7D%28x%29+%5Capprox+%5Cmin%28x%2C+%5Cfrac%7B%5Cpi%7D%7B2%7D%29&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;tan^{-1}(x) &#92;approx &#92;min(x, &#92;frac{&#92;pi}{2})' title='&#92;tan^{-1}(x) &#92;approx &#92;min(x, &#92;frac{&#92;pi}{2})' class='latex' /></p>
<p>Which looks like:</p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/06/atan_approx.png"><img class="aligncenter size-full wp-image-879" title="atan_approx" src="http://mmack.files.wordpress.com/2010/06/atan_approx.png?w=496&#038;h=419" alt="" width="496" height="419" /></a></p>
<p><pre class="brush: cpp;">
float atanLinear(float x)
{
   return clamp(x, -0.5*kPi, 0.5*kPi);
}

Fragment Performance Setup: Driver 174.74, GPU G80, Flags 0x1000
Results 34 cycles, 8 r regs, 4,991,999,816 pixels/s
</pre></p>
<p>Pretty ugly, but even though the maximum error here is huge (~0.43 relative), visually the difference is <a href="http://mmack.files.wordpress.com/2010/06/linear.png">surprisingly small</a>.</p>
<p>Still I thought I&#8217;d try for something more accurate, I used a 3rd degree minimax polynomial to approximate the range 0-1 which gave something practically identical to atan() for my purposes (~0.0052 max relative error):</p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/06/atan_minimax.png"><img class="aligncenter size-full wp-image-906" title="atan_minimax" src="http://mmack.files.wordpress.com/2010/06/atan_minimax.png?w=524&#038;h=511" alt="" width="524" height="511" /></a></p>
<p><pre class="brush: cpp;">
float MiniMax3(float x)
{
   return ((-0.130234*x - 0.0954105)*x + 1.00712)*x - 0.00001203333;
}

float atanMiniMax3(float x)
{
   // range reduction
   if (x &lt; 1)
      return MiniMax3(x);
   else
      return kPi*0.5 - MiniMax3(1.0/x);
}

Fragment Performance Setup: Driver 174.74, GPU G80, Flags 0x1000
Results 40 cycles, 8 r regs, 4,239,359,951 pixels/s
</pre></p>
<p><em>Disclaimer: This isn&#8217;t designed as a general replacement for atan(), for a start it doesn&#8217;t handle values of x &lt; 0 and it hasn&#8217;t had anywhere near the love put into other approximations you can find online (optimising for floating point representations for example).</em></p>
<p>As a bonus I found that putting the polynomial evaluation into <a href="http://en.wikipedia.org/wiki/Horner_scheme">Horner form</a> shaved 4 cycles from the shader.</p>
<p>Cedrick also had an idea to use something a little different:</p>
<p><img src='http://s0.wp.com/latex.php?latex=%5Ctan%5E%7B-1%7D%28x%29+%5Capprox+%5Cfrac%7B%5Cpi%7D%7B2%7D%5Cfrac%7Bkx%7D%7B1%2Bkx%7D+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;tan^{-1}(x) &#92;approx &#92;frac{&#92;pi}{2}&#92;frac{kx}{1+kx} ' title='&#92;tan^{-1}(x) &#92;approx &#92;frac{&#92;pi}{2}&#92;frac{kx}{1+kx} ' class='latex' />.</p>
<p>This might look familiar to some as the basic Reinhard <a href="http://filmicgames.com/archives/category/tonemapping">tone mapping</a> curve!  We eyeballed values for k until we had one that looked close (you can tell I&#8217;m being very rigorous here), in the end k=1 was close enough and is one cycle faster <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/06/atan_rational1.png"><img class="aligncenter size-full wp-image-1003" title="atan_rational" src="http://mmack.files.wordpress.com/2010/06/atan_rational1.png?w=523&#038;h=511" alt="" width="523" height="511" /></a></p>
<p><pre class="brush: cpp;">
float atanRational(float x)
{
   return kPi*0.5*x / (1.0+x);
}

Fragment Performance Setup: Driver 174.74, GPU G80, Flags 0x1000
Results 34 cycles, 8 r regs, 4,869,120,025 pixels/s
</pre></p>
<p>To get it down to 34 cycles we had to expand out the expression for x and perform some more grouping of terms which shaved another cycle and a register off it.  I was surprised to see the rational approximation be so close in terms of performance to the linear one, I guess the scheduler is doing a good job at hiding some work there.</p>
<p>In the end all three approximations gave pretty good visual results:</p>
<p>Original (cycle count 76):</p>
<p><a href="http://mmack.files.wordpress.com/2010/06/original.png"><img class="size-thumbnail wp-image-922 alignnone" title="original" src="http://mmack.files.wordpress.com/2010/06/original.png?w=150&#038;h=86" alt="" width="150" height="86" /></a></p>
<p>MiniMax3, Error 8x (cycle count 40):</p>
<p><a href="http://mmack.files.wordpress.com/2010/06/minimax3.png"> <img title="minimax3" src="http://mmack.files.wordpress.com/2010/06/minimax3.png?w=150&#038;h=86" alt="" width="150" height="86" /></a><a href="http://mmack.files.wordpress.com/2010/06/minimax3_diff.png"><img title="minimax3_diff" src="http://mmack.files.wordpress.com/2010/06/minimax3_diff.png?w=150&#038;h=86" alt="" width="150" height="86" /></a></p>
<p>Rational, Error 8x (cycle count 34):</p>
<p><a href="http://mmack.files.wordpress.com/2010/06/rational.png"><img class="size-thumbnail wp-image-923 alignnone" title="rational" src="http://mmack.files.wordpress.com/2010/06/rational.png?w=150&#038;h=86" alt="" width="150" height="86" /></a><a href="http://mmack.files.wordpress.com/2010/06/rational_diff2.png"><img class="size-thumbnail wp-image-924 alignnone" title="rational_diff" src="http://mmack.files.wordpress.com/2010/06/rational_diff2.png?w=150&#038;h=86" alt="" width="150" height="86" /></a></p>
<p>Linear, Error 8x (cycle count 34):</p>
<p><a href="http://mmack.files.wordpress.com/2010/06/linear.png"><img title="linear" src="http://mmack.files.wordpress.com/2010/06/linear.png?w=150&#038;h=86" alt="" width="150" height="86" /></a><a href="http://mmack.files.wordpress.com/2010/06/linear_diff.png"><img title="linear_diff" src="http://mmack.files.wordpress.com/2010/06/linear_diff.png?w=150&#038;h=86" alt="" width="150" height="86" /></a></p>
<p>Links:</p>
<p><a href="http://realtimecollisiondetection.net/blog/?p=9">http://realtimecollisiondetection.net/blog/?p=9</a></p>
<p><a href="http://www.research.scea.com/gdc2003/fast-math-functions.html">http://www.research.scea.com/gdc2003/fast-math-functions.html</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/856/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/856/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/856/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=856&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/06/10/faster-fog/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/atan.png" medium="image">
			<media:title type="html">atan</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/atan_approx.png" medium="image">
			<media:title type="html">atan_approx</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/atan_minimax.png" medium="image">
			<media:title type="html">atan_minimax</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/atan_rational1.png" medium="image">
			<media:title type="html">atan_rational</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/original.png?w=150" medium="image">
			<media:title type="html">original</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/minimax3.png?w=150" medium="image">
			<media:title type="html">minimax3</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/minimax3_diff.png?w=150" medium="image">
			<media:title type="html">minimax3_diff</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/rational.png?w=150" medium="image">
			<media:title type="html">rational</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/rational_diff2.png?w=150" medium="image">
			<media:title type="html">rational_diff</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/linear.png?w=150" medium="image">
			<media:title type="html">linear</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/06/linear_diff.png?w=150" medium="image">
			<media:title type="html">linear_diff</media:title>
		</media:content>
	</item>
		<item>
		<title>In-Scattering Demo</title>
		<link>http://mmack.wordpress.com/2010/05/29/in-scattering-demo/</link>
		<comments>http://mmack.wordpress.com/2010/05/29/in-scattering-demo/#comments</comments>
		<pubDate>Sat, 29 May 2010 23:32:07 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Demo]]></category>
		<category><![CDATA[Fog Volumes]]></category>
		<category><![CDATA[Graphics]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=684</guid>
		<description><![CDATA[This demo shows an analytic solution to the differential in-scattering equation for light in participating media. It&#8217;s a similar but simplified version of equations found in [1], [2] and as I recently discovered [3]. However I thought showing the derivation might be interesting for some out there, plus it was a good excuse for me [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=684&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This demo shows an analytic solution to the differential in-scattering equation for light in participating media.  It&#8217;s a similar but simplified version of equations found in<a href="http://www.eecs.berkeley.edu/~ravir/papers/singlescat/scattering.pdf"> [1]</a>, <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.3787&amp;rep=rep1&amp;type=pdf">[2]</a> and as I recently discovered <a href="http://research.microsoft.com/en-us/um/people/johnsny/papers/fogshop-pg.pdf">[3]</a>.  However I thought showing the derivation might be interesting for some out there, plus it was a good excuse for me to brush up on my<strong> </strong> <img src='http://s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=ffffff&amp;fg=555555&amp;s=0' alt='&#92;LaTeX' title='&#92;LaTeX' class='latex' />.</p>
<p>You might notice I also updated the site&#8217;s theme, unfortunately you need a white background to make wordpress.com LaTeX rendering play nice with RSS feeds (other than that it&#8217;s very convenient).</p>
<p><a href="http://mmacklin.dreamhosters.com/FogVolumes.zip">Download the demo here</a></p>
<p>The demo uses GLSL and shows point and spot lights in a basic scene with some tweakable parameters:</p>
<p><a href="http://mmack.files.wordpress.com/2010/05/fogvolumes1.png"><img class="aligncenter size-full wp-image-712" title="FogVolumes1" src="http://mmack.files.wordpress.com/2010/05/fogvolumes1.png?w=493&#038;h=565" alt="" width="493" height="565" /></a></p>
<h2>Background</h2>
<p>Given a view ray defined as:</p>
<p><img src='http://s0.wp.com/latex.php?latex=%5Cmathbf%7Bx%7D%28t%29+%3D+%5Cmathbf%7Bp%7D+%2B+t%5Cmathbf%7Bd%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;mathbf{x}(t) = &#92;mathbf{p} + t&#92;mathbf{d} &#92;nonumber ' title='&#92;mathbf{x}(t) = &#92;mathbf{p} + t&#92;mathbf{d} &#92;nonumber ' class='latex' /></p>
<p>We would like to know the total amount of light scattered towards the viewer (in-scattered) due to a point light source.  For the purposes of this post I will only consider single scattering within isotropic media.</p>
<p>The differential equation that describes the change in radiance due to light scattered into the view direction inside a differential volume is given in <a href="http://www.pbrt.org/">PBRT </a>(p578), if we assume equal scattering in all directions we can write it as:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=dL_%7Bs%7D%28t%29+%3D+%5Csigma_%7Bs%7DL_%7Bi%7D%28t%29+dt+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='dL_{s}(t) = &#92;sigma_{s}L_{i}(t) dt ' title='dL_{s}(t) = &#92;sigma_{s}L_{i}(t) dt ' class='latex' /> (1)</p>
<p>Where <img src='http://s0.wp.com/latex.php?latex=%5Csigma_%7Bs%7D+&amp;bg=ffffff&amp;fg=555555&amp;s=0' alt='&#92;sigma_{s} ' title='&#92;sigma_{s} ' class='latex' />    is the scattering probability which I will assume includes the normalization term for an isotropic phase funtion of <img src='http://s0.wp.com/latex.php?latex=%5Cfrac%7B1%7D%7B4%5Cpi%7D+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;frac{1}{4&#92;pi} ' title='&#92;frac{1}{4&#92;pi} ' class='latex' />.  For a point light source at distance d with intensity I we can calculate the radiant intensity at a receiving point as:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=L_%7Bi%7D+%3D+%5Cfrac%7BI%7D%7Bd%5E2%7D&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{i} = &#92;frac{I}{d^2}' title='L_{i} = &#92;frac{I}{d^2}' class='latex' /></p>
<p>Plugging in the equation for a point along the view ray we have:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=L_%7Bi%7D%28t%29+%3D+%5Cfrac%7BI%7D%7B%7C%5Cmathbf%7Bx%7D%28t%29-%5Cmathbf%7Bs%7D%7C%5E2%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{i}(t) = &#92;frac{I}{|&#92;mathbf{x}(t)-&#92;mathbf{s}|^2} &#92;nonumber ' title='L_{i}(t) = &#92;frac{I}{|&#92;mathbf{x}(t)-&#92;mathbf{s}|^2} &#92;nonumber ' class='latex' /></p>
<p>Where s is the light source position. The solution to (1) is then given by:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Cint_%7B0%7D%5E%7Bd%7D+%5Csigma_%7Bs%7DL_%7Bi%7D%28t%29dt+%5Cnonumber+%5C%5C+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;int_{0}^{d} &#92;sigma_{s}L_{i}(t)dt &#92;nonumber &#92;&#92; ' title='L_{s} = &#92;int_{0}^{d} &#92;sigma_{s}L_{i}(t)dt &#92;nonumber &#92;&#92; ' class='latex' /></p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Cint_%7B0%7D%5E%7Bd%7D+%5Cfrac%7B%5Csigma_%7Bs%7DI%7D%7B%7C%5Cmathbf%7Bx%7D%28t%29-%5Cmathbf%7Bs%7D%7C%5E2%7Ddt+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;int_{0}^{d} &#92;frac{&#92;sigma_{s}I}{|&#92;mathbf{x}(t)-&#92;mathbf{s}|^2}dt &#92;nonumber ' title='L_{s} = &#92;int_{0}^{d} &#92;frac{&#92;sigma_{s}I}{|&#92;mathbf{x}(t)-&#92;mathbf{s}|^2}dt &#92;nonumber ' class='latex' /></p>
<p>To find this integral in closed form we need to expand the distance calculation in the denominator into something we can deal with more easily:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI%5Cint_%7B0%7D%5E%7Bd%7D+%5Cfrac%7Bdt%7D%7B%28%5Cmathbf%7Bp%7D+%2B+t%5Cmathbf%7Bd%7D+-+%5Cmathbf%7Bs%7D%29%5Ccdot%28%5Cmathbf%7Bp%7D+%2B+t%5Cmathbf%7Bd%7D+-+%5Cmathbf%7Bs%7D%29%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d} &#92;frac{dt}{(&#92;mathbf{p} + t&#92;mathbf{d} - &#92;mathbf{s})&#92;cdot(&#92;mathbf{p} + t&#92;mathbf{d} - &#92;mathbf{s})} &#92;nonumber ' title='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d} &#92;frac{dt}{(&#92;mathbf{p} + t&#92;mathbf{d} - &#92;mathbf{s})&#92;cdot(&#92;mathbf{p} + t&#92;mathbf{d} - &#92;mathbf{s})} &#92;nonumber ' class='latex' /></p>
<p>Expanding the dot product and gathering terms, we have:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI%5Cint_%7B0%7D%5E%7Bd%7D%5Cfrac%7Bdt%7D%7B%28%5Cmathbf%7Bd%7D%5Ccdot%5Cmathbf%7Bd%7D%29t%5E2+%2B+2%28%5Cmathbf%7Bm%7D%5Ccdot%5Cmathbf%7Bd%7D%29t+%2B+%5Cmathbf%7Bm%7D%5Ccdot%5Cmathbf%7Bm%7D+%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{(&#92;mathbf{d}&#92;cdot&#92;mathbf{d})t^2 + 2(&#92;mathbf{m}&#92;cdot&#92;mathbf{d})t + &#92;mathbf{m}&#92;cdot&#92;mathbf{m} } &#92;nonumber ' title='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{(&#92;mathbf{d}&#92;cdot&#92;mathbf{d})t^2 + 2(&#92;mathbf{m}&#92;cdot&#92;mathbf{d})t + &#92;mathbf{m}&#92;cdot&#92;mathbf{m} } &#92;nonumber ' class='latex' /></p>
<p>Where:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=%5Cmathbf%7Bm%7D+%3D+%28%5Cmathbf%7Bp%7D-%5Cmathbf%7Bs%7D%29+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='&#92;mathbf{m} = (&#92;mathbf{p}-&#92;mathbf{s}) &#92;nonumber ' title='&#92;mathbf{m} = (&#92;mathbf{p}-&#92;mathbf{s}) &#92;nonumber ' class='latex' /></p>
<p>Now we have something a bit more familiar, because the direction vector is unit length we can remove the coefficient from the quadratic term and we have:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI%5Cint_%7B0%7D%5E%7Bd%7D%5Cfrac%7Bdt%7D%7Bt%5E2+%2B+2bt+%2B+c%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{t^2 + 2bt + c} &#92;nonumber ' title='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{t^2 + 2bt + c} &#92;nonumber ' class='latex' /></p>
<p>At this point you could look up the integral in standard tables but I&#8217;ll continue to simplify it for completeness.  Completing the square we obtain:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI%5Cint_%7B0%7D%5E%7Bd%7D%5Cfrac%7Bdt%7D%7B+%28t%5E2+%2B+2bt+%2B+b%5E2%29+%2B+%28c-b%5E2%29%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{ (t^2 + 2bt + b^2) + (c-b^2)} &#92;nonumber ' title='L_{s} = &#92;sigma_{s}I&#92;int_{0}^{d}&#92;frac{dt}{ (t^2 + 2bt + b^2) + (c-b^2)} &#92;nonumber ' class='latex' /></p>
<p>Making the substitution:</p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=u+%3D+%28t+%2B+b%29+++++%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='u = (t + b)     &#92;nonumber ' title='u = (t + b)     &#92;nonumber ' class='latex' /></p>
<p style="text-align:left;"><img src='http://s0.wp.com/latex.php?latex=v+%3D+%5Csqrt%7B%28c-b%5E2%29%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='v = &#92;sqrt{(c-b^2)} &#92;nonumber ' title='v = &#92;sqrt{(c-b^2)} &#92;nonumber ' class='latex' /></p>
<p>And updating our limits of integration, we have:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI%5Cint_%7Bb%7D%5E%7Bb%2Bd%7D%5Cfrac%7Bdu%7D%7B+u%5E2+%2B+v%5E2%7D+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='L_{s} = &#92;sigma_{s}I&#92;int_{b}^{b+d}&#92;frac{du}{ u^2 + v^2} &#92;nonumber ' title='L_{s} = &#92;sigma_{s}I&#92;int_{b}^{b+d}&#92;frac{du}{ u^2 + v^2} &#92;nonumber ' class='latex' /></p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Csigma_%7Bs%7DI+%5Cleft%5B+%5Cfrac%7B1%7D%7Bv%7Dtan%5E%7B-1%7D%5Cfrac%7Bu%7D%7Bv%7D+%5Cright%5D_b%5E%7Bb%2Bd%7D%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=1' alt='L_{s} = &#92;sigma_{s}I &#92;left[ &#92;frac{1}{v}tan^{-1}&#92;frac{u}{v} &#92;right]_b^{b+d}&#92;nonumber ' title='L_{s} = &#92;sigma_{s}I &#92;left[ &#92;frac{1}{v}tan^{-1}&#92;frac{u}{v} &#92;right]_b^{b+d}&#92;nonumber ' class='latex' /></p>
<p>Finally giving:</p>
<p><img src='http://s0.wp.com/latex.php?latex=L_%7Bs%7D+%3D+%5Cfrac%7B%5Csigma_%7Bs%7DI%7D%7Bv%7D%28+tan%5E%7B-1%7D%5Cfrac%7Bd%2Bb%7D%7Bv%7D+-+tan%5E%7B-1%7D%5Cfrac%7Bb%7D%7Bv%7D+%29+%5Cnonumber+&amp;bg=ffffff&amp;fg=555555&amp;s=2' alt='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( tan^{-1}&#92;frac{d+b}{v} - tan^{-1}&#92;frac{b}{v} ) &#92;nonumber ' title='L_{s} = &#92;frac{&#92;sigma_{s}I}{v}( tan^{-1}&#92;frac{d+b}{v} - tan^{-1}&#92;frac{b}{v} ) &#92;nonumber ' class='latex' /></p>
<p>This is what we will evaluate in the pixel shader, here&#8217;s the GLSL snippet for the integral evaluation (direct translation of the equation above):</p>
<p><pre class="brush: cpp;">
float InScatter(vec3 start, vec3 dir, vec3 lightPos, float d)

// light to ray origin
vec3 q = start - lightPos;

// coefficients
float b = dot(dir, q);
float c = dot(q, q);

// evaluate integral
float s = 1.0f / sqrt(c - b*b);
float l = s * (atan( (d + b) * s) - atan( b*s ));

return l;
}
</pre></p>
<p>Where d is the distance traveled, computed by finding the entry / exit points of the ray with the volume.</p>
<p>To make the effect more interesting it is possible to incorporate a particle system, I apply the same scattering shader to each particle and treat it as a thin slab to obtain an approximate depth, then simply multiply by a noise texture at the end.</p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/05/fogvolumes2.png"><img class="aligncenter" title="FogVolumes2" src="http://mmack.files.wordpress.com/2010/05/fogvolumes2.png?w=490&#038;h=550" alt="" width="490" height="550" /></a></p>
<p style="text-align:center;"><a href="http://mmack.files.wordpress.com/2010/05/fogvolumes4.png"><img class="aligncenter" title="FogVolumes4" src="http://mmack.files.wordpress.com/2010/05/fogvolumes4.png?w=492&#038;h=562" alt="" width="492" height="562" /></a></p>
<h2 style="text-align:left;">Optimisations</h2>
<ul>
<li>As it is above the code only supports lights with infinite extent, this implies drawing the entire frame for each light.  It would be possible to limit it to a volume but you&#8217;d want to add a falloff to the effect to avoid a sharp transition at the boundary.</li>
</ul>
<ul>
<li>Performing the full evaluation per-pixel for the particles is probably unnecessary, doing it at a lower frequency, per-vertex or even per-particle would probably look acceptable.</li>
</ul>
<h2>Notes</h2>
<ul>
<li>Generally objects appear to have wider specular highlights and more ambient lighting in the presence of particpating media.  <a href="http://www.eecs.berkeley.edu/%7Eravir/papers/singlescat/scattering.pdf">[1]</a> Discusses this in detail but you can fudge it by lowering the specular power in your materials as the scattering coefficient increases.</li>
</ul>
<ul>
<li>According to <a href="http://en.wikipedia.org/wiki/Rayleigh_scattering">Rayliegh scattering</a> blue light at the lower end of the spectrum is scattered considerably more than red light.  It&#8217;s simple to account for this wavelength dependence by making the scattering coefficient a constant vector weighted towards the blue component.  I found this helps add to the realism of the effect.</li>
</ul>
<ul>
<li>I&#8217;m curious to know how the torch light was done in Alan Wake as it seems to be high quality (not just billboards) with multiple light shafts.. maybe someone out there knows?</li>
</ul>
<h2 style="text-align:left;">References</h2>
<p style="text-align:left;"><a href="http://www.eecs.berkeley.edu/~ravir/papers/singlescat/scattering.pdf">[1] Sun, B., Ramamoorthi, R., Narasimhan, S. G., and Nayar, S. K. 2005. A practical analytic single scattering model for real time rendering. </a></p>
<p><a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.3787&amp;rep=rep1&amp;type=pdf">[2] Wenzel, C. 2006. Real-time atmospheric effects in games. </a></p>
<p><a href="http://research.microsoft.com/en-us/um/people/johnsny/papers/fogshop-pg.pdf">[3] Zhou, K., Hou, Q., Gong, M., Snyder, J., Guo, B., and Shum, H. 2007. Fogshop: Real-Time Design and Rendering of Inhomogeneous, Single-Scattering Media. </a></p>
<h2>Related</h2>
<p><a href="http://www.vis.uni-stuttgart.de/eng/research/pub/pub2010/espmss10.pdf">[4] Engelhardt, T. and Dachsbacher, C. 2010. Epipolar sampling for shadows and crepuscular rays in participating media with single scattering.</a></p>
<p><a href="http://www.cse.chalmers.se/~billeter/pub/volumetric/index.html">[5] Volumetric Shadows using Polygonal Light Volumes</a> (upcoming HPG2010)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/684/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/684/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/684/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=684&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/05/29/in-scattering-demo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/05/fogvolumes1.png" medium="image">
			<media:title type="html">FogVolumes1</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/05/fogvolumes2.png" medium="image">
			<media:title type="html">FogVolumes2</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/05/fogvolumes4.png" medium="image">
			<media:title type="html">FogVolumes4</media:title>
		</media:content>
	</item>
		<item>
		<title>Threading Fun</title>
		<link>http://mmack.wordpress.com/2010/05/24/threading-fun/</link>
		<comments>http://mmack.wordpress.com/2010/05/24/threading-fun/#comments</comments>
		<pubDate>Tue, 25 May 2010 06:01:41 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
		
		<guid isPermaLink="false">http://mmack.wordpress.com/?p=641</guid>
		<description><![CDATA[So we had an interesting threading bug at work today which I thought I&#8217;d write up here as I hadn&#8217;t seen this specific problem before (note I didn&#8217;t write this code, I merely helped debug it).  The set up was a basic single producer single consumer arrangement something like this: So where&#8217;s the problem? What [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=641&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So we had an interesting threading bug at work today which I thought I&#8217;d write up here as I hadn&#8217;t seen this specific problem before (note I didn&#8217;t write this code, I merely helped debug it).  The set up was a basic single producer single consumer arrangement something like this:</p>
<p><pre class="brush: cpp;">
#include &lt;Windows.h&gt;
#include &lt;cassert&gt;

volatile LONG gAvailable = 0;

// thread 1
DWORD WINAPI Producer(LPVOID)
{
	while (1)
	{
		InterlockedIncrement(&amp;gAvailable);
	}
}

// thread 2
DWORD WINAPI Consumer(LPVOID)
{
	while (1)
	{
		// pull available work with a limit of 5 items per iteration
		LONG work = min(gAvailable, 5);

		// this should never fire.. right?
		assert(work &lt;= 5);

		// update available work
		InterlockedExchangeAdd(&amp;gAvailable, -work);
	}
}

int main(int argc, char* argv[])
{
	HANDLE h[2];

	h[0] = CreateThread(0, 0, Consumer, NULL, 0, 0);
	h[1] = CreateThread(0, 0, Producer, NULL, 0, 0);

	WaitForMultipleObjects(2, h, TRUE, INFINITE);

	return 0;
}
</pre></p>
<p>So where&#8217;s the problem?  What would make the assert fire?</p>
<p>We triple-checked the logic and couldn&#8217;t see anything wrong (it was more complicated than the example above so there were a number of possible culprits) and unlike the example above there were no asserts, just a hung thread at some later stage of execution.</p>
<p>Unfortunately the bug reproduced only once every other week so we knew we had to fix it while I had it in a debugger.  We checked all the relevant in-memory data and couldn&#8217;t see any that had obviously been overwritten (&#8220;memory stomp&#8221; is usually the first thing called out when these kinds of bugs show up).</p>
<p>It took us a while but eventually we checked the disassembly for the call to min().  Much to our surprise it was performing two loads of gAvailable instead of the one we had expected!</p>
<p>This happened to be on X360 but the same problem occurs on Win32, here&#8217;s the disassembly for the code above (VS2010 Debug):</p>
<p><pre class="brush: cpp;">
// calculate available work with a limit of 5 items per iteration
LONG work = min(gAvailable, 5);

// (1) read gAvailable, compare against 5
002D1457  cmp         dword ptr [gAvailable (2D7140h)],5
002D145E  jge         Consumer+3Dh (2D146Dh)

// (2) read gAvailable again, store on stack
002D1460  mov         eax,dword ptr [gAvailable (2D7140h)]
002D1465  mov         dword ptr [ebp-0D0h],eax
002D146B  jmp         Consumer+47h (2D1477h)
002D146D  mov         dword ptr [ebp-0D0h],5

// (3) store gAvailable from (2) in 'work'
002D1477  mov         ecx,dword ptr [ebp-0D0h]
002D147D  mov         dword ptr [work],ecx

</pre></p>
<p>The question is what happens between (1) and (2)?  Well the answer is that any other thread can add to gAvailable, meaning that the stored value at (3) is now &gt; 5.</p>
<p>In this case the simple solution was to read gAvailable outside of the call to min():</p>
<p><pre class="brush: cpp;">
// pull available work with a limit of 5 items per iteration
LONG available = gAvailable;
LONG work = min(available, 5);
</pre></p>
<p>Maybe this is obvious to some people but it sure caused me and some smart people a headache for a few hours <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Note that you may not see the problem in some build configurations depending on whether or not the compiler generates code to perform the second read of the variable after the comparison.  As far as I know there are no guarantees about what it may or may not do in this case, FWIW we had the problem in a release build with optimisations enabled.</p>
<p>Big props to Tom and <a href="http://twitter.com/aruslan">Ruslan</a> at Lucas for helping track this one down.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/641/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/641/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/641/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=641&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/05/24/threading-fun/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>
	</item>
		<item>
		<title>GOW III: Shadows</title>
		<link>http://mmack.wordpress.com/2010/03/11/gow-iii-shadows/</link>
		<comments>http://mmack.wordpress.com/2010/03/11/gow-iii-shadows/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 06:09:31 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[GDC2010]]></category>
		<category><![CDATA[Graphics]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=624</guid>
		<description><![CDATA[I checked out this session at GDC today &#8211; I&#8217;ll try and sum up the main takeaways (at least for me): Artist controlled cascaded shadow maps, each cascade is accumulated into a &#8216;white buffer&#8217; (new term coined?) in deferred style passes using standard PCF filtering Shadow accumulation pass re-projects world space position from an FP32 [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=624&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I checked out this session at GDC today &#8211; I&#8217;ll try and sum up the main takeaways (at least for me):</p>
<ul>
<li>Artist controlled cascaded shadow maps, each cascade is accumulated into a &#8216;white buffer&#8217; (new term coined?) in deferred style passes using standard PCF filtering</li>
<li>Shadow accumulation pass re-projects world space position from an FP32 depth buffer (separate from the main depth buffer).  The motivation for the separate depth buffer is performance so I assume they store linear depth which means they can reconstruct the world position using just a single multiply-add (saving a reciprocal).</li>
<li>They have the ability to tile individual cascades to achieve arbitrary levels of sampling within a fixed size memory (render cascade tile, apply into white buffer, repeat)</li>
<li>Often up to 9 mega-texel resolution used for in game scenes</li>
<li>White buffer is blended to using MIN blend mode to avoid double darkening (old school)</li>
<li>Invisible &#8216;caster only&#8217; geometry to make baked shadows match on dynamic objects</li>
<li>Stencil bits used to mask off baked geometry, fore-ground, back-ground characters</li>
</ul>
<p>&nbsp;<br />
The most interesting part (in my opinion) was the optimisation work, Ben creates a light direction aligned 8x8x4 grid that he renders extruded bounding spheres into (on the SPUs).  Each cell records whether or not it is in shadow and the rough bounds of that shadow.  To take advantage of this information the accumulation pass (where the expensive filtering is done) breaks the screen up into tiles, checks the tile against the volume and adjusts it&#8217;s depth and 2D bounds accordingly, potentially rejecting entire tiles.</p>
<p>Looking forward to the the rest of the talks, this is my first year at GDC and it&#8217;s pretty great <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/624/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/624/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/624/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=624&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/03/11/gow-iii-shadows/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>
	</item>
		<item>
		<title>Stochastic Pruning (2)</title>
		<link>http://mmack.wordpress.com/2010/02/07/stochastic-pruning-2/</link>
		<comments>http://mmack.wordpress.com/2010/02/07/stochastic-pruning-2/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 07:39:41 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Graphics]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=594</guid>
		<description><![CDATA[A quick update for anyone who was having problems running my stochastic pruning demo on NVIDIA cards, I&#8217;ve updated the demo with a fix (I had forgotten to disable a vertex array). While I was at it I added some grass: The grass uses stochastic pruning but still generates a lot of geometry, it&#8217;s just [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=594&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A quick update for anyone who was having problems running my stochastic pruning demo on NVIDIA cards, I&#8217;ve updated <a href="http://mmacklin.dreamhosters.com/Plant.zip">the demo</a> with a fix (I had forgotten to disable a vertex array).</p>
<p>While I was at it I added some grass: </p>
<p><a href="http://mmack.files.wordpress.com/2010/02/tree_large.png"><img src="http://mmack.files.wordpress.com/2010/02/tree_large.png?w=510&#038;h=302" alt="" title="tree_large" width="510" height="302" class="aligncenter size-full wp-image-595" /></a></p>
<p>The grass uses stochastic pruning but still generates a lot of geometry, it&#8217;s just one grass tile flipped around and rendered multiple times.  I wanted to see if it would be practical for games to render grass using pure geometry but really you&#8217;d need to be much more aggressive with the LOD (Update: apparently the same technique was used in Flower, see comments).</p>
<p>Kevin Boulanger has done some impressive real time <a href="http://www.kevinboulanger.net/grass.html">grass rendering</a> using 3 levels of detail with transitions.  Cool stuff and quite practical by the looks of it.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/594/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/594/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/594/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=594&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/02/07/stochastic-pruning-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/02/tree_large.png" medium="image">
			<media:title type="html">tree_large</media:title>
		</media:content>
	</item>
		<item>
		<title>Stochastic Pruning for Real-Time LOD</title>
		<link>http://mmack.wordpress.com/2010/01/12/stochastic-pruning-for-real-time-lod/</link>
		<comments>http://mmack.wordpress.com/2010/01/12/stochastic-pruning-for-real-time-lod/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 07:28:31 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Demo]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Trees]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=480</guid>
		<description><![CDATA[Rendering plants efficiently has always been a challenge in computer graphics, a relatively new technique to address this is Pixar&#8217;s stochastic pruning algorithm. Originally developed for rendering the desert scenes in Cars, Weta also claim to have used the same technique on Avatar. Although designed with offline rendering in mind it maps very naturally to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=480&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Rendering plants efficiently has always been a challenge in computer graphics, a relatively new technique to address this is <a href="http://graphics.pixar.com/library/StochasticPruning/paper.pdf">Pixar&#8217;s stochastic pruning algorithm</a>.  Originally developed for rendering the desert scenes in Cars, Weta also <a href="http://www.cgw.com/Publications/CGW/2009/Volume-32-Issue-12-Dec-2009-/CG-In-Another-World.aspx">claim </a>to have used the same technique on Avatar.</p>
<p>Although designed with offline rendering in mind it maps very naturally to the GPU and real-time rendering.  The basic algorithm is this:</p>
<ol>
<li>Build your mesh of N elements (in the case of a tree the elements would be leaves, usually represented by quads)</li>
<li>Sort the elements in random order (a robust way of doing this is to use the <a href="http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Fisher-Yates shuffle</a>)</li>
<li>Calculate the proportion U of elements to render based on distance to the object.</li>
<li>Draw N*U unpruned elements with area scaled by 1/U</li>
</ol>
<p>So putting this onto the GPU is straightforward, pre-shuffle your index buffer (element wise), when you come to draw you can calculate the unpruned element count using something like:</p>
<p><pre class="brush: cpp;">
// calculate scaled distance to viewer
float z = max(1.0f, Length(viewerPos-objectPos)/pruneStartDistance);
// distance at which half the leaves will be pruned
float h = 2.0f;
// proportion of elements unpruned
float u = powf(z, -Log(h, 2));
// actual element count
int m = ceil(numElements * u);
// scale factor
float s = 1.0f / u;
</pre></p>
<p>Then just submit a modified draw call for m quads:</p>
<p><pre class="brush: cpp;">
glDrawElements(GL_QUADS, m*4, GL_UNSIGNED_SHORT, 0);
</pre></p>
<p>The scale factor computed above preserves the total global surface area of all elements, this ensures consistent pixel coverage at any distance.  The scaling by area can be performed efficiently in the vertex shader meaning no CPU involvement is necessary (aside from setting up the parameters of course).  In a basic implementation you would see elements pop in and out as you change distance but this can be helped by having a transition window that scales elements down before they become pruned (discussed in the original paper).</p>
<div id="attachment_535" class="wp-caption aligncenter" style="width: 500px"><a href="http://mmack.files.wordpress.com/2010/01/tree_unpruned.png"><img class="size-full wp-image-535" title="tree_unpruned" src="http://mmack.files.wordpress.com/2010/01/tree_unpruned.png?w=490&#038;h=476" alt="" width="490" height="476" /></a><p class="wp-caption-text">Tree unpruned</p></div>
<div id="attachment_534" class="wp-caption aligncenter" style="width: 500px"><a href="http://mmack.files.wordpress.com/2010/01/tree_pruned.png"><img class="size-full wp-image-534" title="tree_pruned" src="http://mmack.files.wordpress.com/2010/01/tree_pruned.png?w=490&#038;h=476" alt="" width="490" height="476" /></a><p class="wp-caption-text">Tree pruned to 10% of original</p></div>
<p>Billboards still have their place but it seems like this kind of technique could have applications for many effects, grass and particle systems being obvious ones.</p>
<p>I&#8217;ve updated my previous tree demo with an implementation of stochastic pruning and a few other changes:</p>
<ul>
<li>Fixed some bugs with ATI driver compatability</li>
<li>Preetham based sky-dome</li>
<li>Optimised shadow map generation</li>
<li>Some new example plants</li>
<li>Tweaked leaf and branch shaders</li>
</ul>
<p>You can download the demo <a href="http://mmacklin.dreamhosters.com/Plant.zip">here</a></p>
<p>I use the <a href="http://algorithmicbotany.org/papers/selforg.sig2009.html">Self-organising tree models for image synthesis</a> algorithm (from SIGGRAPH09) to generate the trees which I have posted about <a href="http://mmack.wordpress.com/2009/09/28/trees-the-green-kind/">previously</a>.</p>
<p>While I was researching I also came across <a href="http://www.cg.tuwien.ac.at/research/publications/2009/Habel_09_PGT/">Physically Guided Animation of Trees</a> from Eurographics 2009, they have some great videos of real-time animated trees.</p>
<p>I&#8217;ve also posted <a href="http://www.mendeley.com/collections/729981/Algorithmic-Botany/">my collection of plant modelling papers</a> onto Mendeley (great tool for organising pdfs!).</p>
<div id="attachment_527" class="wp-caption aligncenter" style="width: 500px"><a href="http://mmack.files.wordpress.com/2010/01/tree_lowsym1.png"><img class="size-full wp-image-527" title="tree_lowsym" src="http://mmack.files.wordpress.com/2010/01/tree_lowsym1.png?w=490&#038;h=429" alt="" width="490" height="429" /></a><p class="wp-caption-text">Tree pruned to 70% of original</p></div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/480/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/480/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/480/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=480&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2010/01/12/stochastic-pruning-for-real-time-lod/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/01/tree_unpruned.png" medium="image">
			<media:title type="html">tree_unpruned</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/01/tree_pruned.png" medium="image">
			<media:title type="html">tree_pruned</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2010/01/tree_lowsym1.png" medium="image">
			<media:title type="html">tree_lowsym</media:title>
		</media:content>
	</item>
		<item>
		<title>Sky</title>
		<link>http://mmack.wordpress.com/2009/12/31/sky/</link>
		<comments>http://mmack.wordpress.com/2009/12/31/sky/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 22:46:48 +0000</pubDate>
		<dc:creator>Miles</dc:creator>
				<category><![CDATA[Graphics]]></category>

		<guid isPermaLink="false">http://mmack.wordpress.com/?p=447</guid>
		<description><![CDATA[I had been meaning to implement Preetham&#8217;s analytic sky model ever since I first came across it years ago. Well I finally got around to it and was pleased to find it&#8217;s one of those few papers that gives you pretty much everything you need to put together an implementation (although with over 50 unique [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=447&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I had been meaning to implement <a href="http://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf">Preetham&#8217;s analytic sky model</a> ever since I first came across it years ago.  Well I finally got around to it and was pleased to find it&#8217;s one of those few papers that gives you pretty much everything you need to put together an implementation (although with over 50 unique constants you need to be careful with your typing).</p>
<p>I integrated it into my path tracer which made for some nice images:</p>
<p><a href="http://mmack.files.wordpress.com/2009/12/sky_t2.png"><img src="http://mmack.files.wordpress.com/2009/12/sky_t2.png?w=510&#038;h=352" alt="" title="sky_t2" width="510" height="352" class="aligncenter size-full wp-image-459" /></a></p>
<p><a href="http://mmack.files.wordpress.com/2009/12/sky_t2_am.png"><img src="http://mmack.files.wordpress.com/2009/12/sky_t2_am.png?w=510&#038;h=352" alt="" title="sky_t2_am" width="510" height="352" class="aligncenter size-full wp-image-456" /></a></p>
<p>Also a small <a href="http://www.youtube.com/watch?v=Ptrq16x20rk">video</a>.</p>
<p>It looks like the technique has been surpassed now by <a href="http://hal.archives-ouvertes.fr/docs/00/28/87/58/PDF/article.pdf">Precomputed Atmospheric Scattering</a> but it&#8217;s still useful for generating environment maps / SH lights.</p>
<p>I also fixed a load of bugs in my path tracer, I was surprised to find that on my new i7 quad-core (8 logical threads) renders with 8 worker threads were only twice as fast as with a single worker, given the embarrassingly parallel nature of path-tracing you would expect at least a factor of 4 decrease in render time.</p>
<p>It turns out the problem was contention in the OS allocator, as I allocate BRDF objects per-intersection there was a lot of overhead there (more than I had expected).  I added a per-thread memory arena where each worker thread has a pool of memory to allocate from linearly during a trace, allocations are never freed and the pool is just reset per-path.</p>
<p>This had the following effect on render times:</p>
<p><code>1 thread:  128709ms-&gt;35553ms  (3.6x faster)<br />
8 threads: 54071ms-&gt;8235ms   (6.5x faster!)</code></p>
<p>You might also notice that the total speed up is not linear with the number of workers.  It tails off as the 4 &#8216;real&#8217; execution units are used up, so hyper-threading doesn&#8217;t seem to be too effective here, I suspect this is due to such simple scenes not providing enough opportunity for swapping the thread states.</p>
<p>The HT numbers seems to roughly agree with what people are <a href="http://ompf.org/forum/viewtopic.php?f=1&amp;t=1076&amp;p=10626&amp;hilit=hyperthreading#p10626">reporting</a> on the Ompf forums (~20% improvement).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/mmack.wordpress.com/447/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/mmack.wordpress.com/447/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/mmack.wordpress.com/447/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=mmack.wordpress.com&amp;blog=551482&amp;post=447&amp;subd=mmack&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://mmack.wordpress.com/2009/12/31/sky/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7a2afa150679090614485574c0368582?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">mmack</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2009/12/sky_t2.png" medium="image">
			<media:title type="html">sky_t2</media:title>
		</media:content>

		<media:content url="http://mmack.files.wordpress.com/2009/12/sky_t2_am.png" medium="image">
			<media:title type="html">sky_t2_am</media:title>
		</media:content>
	</item>
	</channel>
</rss>
