<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>malmer.nu</title>
	<atom:link href="http://www.malmer.nu/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.malmer.nu</link>
	<description>coding for 3ds max and beyond</description>
	<lastBuildDate>Sat, 04 Apr 2009 17:33:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Energy minimization is your friend</title>
		<link>http://www.malmer.nu/index.php/2008-04-11_energy-minimization-is-your-friend/</link>
		<comments>http://www.malmer.nu/index.php/2008-04-11_energy-minimization-is-your-friend/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 16:08:29 +0000</pubDate>
		<dc:creator>Malmer</dc:creator>
				<category><![CDATA[3ds max]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Ambient Occlusion]]></category>
		<category><![CDATA[Energy Minimization]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SSAO]]></category>

		<guid isPermaLink="false">http://www.malmer.nu/?p=19</guid>
		<description><![CDATA[I continued developing my method for SSAO and worked a bit on making it look better over a series of frames in an animation. So basically I ended up generating the same sphere for any given number of samples (same random seed) and then rotate the samples using by reflecting them with a per-pixel random [...]]]></description>
			<content:encoded><![CDATA[<p>I continued developing my method for SSAO and worked a bit on making it look better over a series of frames in an animation. So basically I ended up generating the same sphere for any given number of samples (same random seed) and then rotate the samples using by reflecting them with a per-pixel random normal, as described <a href="http://rgba.scenesp.org/iq/computer/articles/ssao/ssao.htm">here</a>.</p>
<p>That is all fine, but the real improvement came when I used energy minimization on my sampling sphere. Instead of just settling with random spherical coordinates I put my sphere through a energy minimization routine, and the difference is staggering. I&#8217;ll let the pictures speak for themselves:</p>
<p style="text-align: center;"><a href="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_no_minimization.png"><img class="aligncenter size-full wp-image-17" title="SSAO without energy minimization" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_no_minimization.png" alt="" width="258" height="173" /></a></p>
<p style="text-align: center;"><strong>SSAO without energy minimization<br />
</strong>Notice how noisy and high contrast this looks.</p>
<p style="text-align: center;">
<p style="text-align: center;"><a href="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_with_minimization.png"><img class="alignnone size-full wp-image-18" title="SSAO with energy minimization" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_with_minimization.png" alt="" width="258" height="173" /></a></p>
<p style="text-align: center;"><strong>SSAO with energy minimization<br />
</strong>Much less noise with the same number of samples, and more realistic contrast.</p>
<p style="text-align: left;">
<p style="text-align: left;">So how does one do this? It is quite simple. Just generate your sample sphere with normalized vectors. Then iterate through them and apply some force between each point until they reach and equilibrium. About 100 iterations should be more than enough, and since this is done in a pre-process stage it really doesn&#8217;t matter how long it takes.</p>
<p style="text-align: left;">Here is some code:<span id="more-19"></span></p>
<blockquote>
<p style="text-align: left;">// Energy minimization<br />
int iter = 100;<br />
while( iter&#8211; )<br />
{<br />
for( int i = 0; i &lt; samples; i++ )<br />
{<br />
Point3 force;<br />
Point3 res = Point3( 0.0f, 0.0f, 0.0f );<br />
Point3 vec;<br />
float fac;</p>
<p>vec = sampleSphere[ i ];<br />
// Minimize with other samples<br />
for( int j = 0; j &lt; samples; j++ )<br />
{<br />
force = vec &#8211; sampleSphere[ j ];</p>
<p>fac = DotProd( force, force );<br />
if( fac != 0.0f )<br />
{<br />
fac = 1.0f / fac;<br />
res.x += fac * force.x;<br />
res.y += fac * force.y;<br />
res.z += fac * force.z;<br />
}<br />
}</p>
<p>res = res * 0.5f;<br />
sampleSphere[ i ] += res;<br />
sampleSphere[ i ] = Normalize( sampleSphere[ i ] );<br />
}<br />
}</p></blockquote>
<p>After this we can randomize sphere radius lenghts&#8230;</p>
<blockquote><p>// Randomize sphere radiuses<br />
for( int i = 0; i &lt; samples; i++ )<br />
{<br />
sampleSphere[ i ] *= random.Rand01() * radius;<br />
}</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.malmer.nu/index.php/2008-04-11_energy-minimization-is-your-friend/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SSAO C-style pseudo source code</title>
		<link>http://www.malmer.nu/index.php/2008-04-09_ssao-c-style-pseudo-source-code/</link>
		<comments>http://www.malmer.nu/index.php/2008-04-09_ssao-c-style-pseudo-source-code/#comments</comments>
		<pubDate>Wed, 09 Apr 2008 12:46:22 +0000</pubDate>
		<dc:creator>Malmer</dc:creator>
				<category><![CDATA[3ds max]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Ambient Occlusion]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Source code]]></category>
		<category><![CDATA[SSAO]]></category>

		<guid isPermaLink="false">http://www.malmer.nu/?p=14</guid>
		<description><![CDATA[Ok, now it is time to actually show how the method I use works. This is C style code, but with some changes from my original code, for clarity. That is because my code handles the many layers of the 3ds max G-buffer and how pixels are weighted and works with transparency. Also, my code [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, now it is time to actually show how the method I use works. This is C style code, but with some changes from my original code, for clarity. That is because my code handles the many layers of the 3ds max G-buffer and how pixels are weighted and works with transparency. Also, my code also has a method for simulating ambient radiance (more on that in a later post).</p>
<p><strong>Read on for the actual code.</strong></p>
<p><span id="more-14"></span></p>
<p><strong>Input:</strong></p>
<p><code>x</code><br />
Screen space x-coordinate (unit: pixels).<br />
<code>y</code><br />
Screen space y-coordinate (unit: pixels).<br />
<code>zbuffer</code><br />
Depth buffer with pixel z coordinates in camera space.<br />
<code>normalbuffer</code><br />
Buffer with pixel normals in camera space.<br />
<code>samples</code><br />
Constant with number of samples<br />
<code>radius</code><br />
Radius of sample sphere. Very scene scale dependant.<br />
<code>coneAngle</code><br />
The cosine of the cone angle of the occlusion.<br />
coneAngle = cos( angle / 2 * DEG_TO_RAD )<br />
where angle around 150 is a good value.<br />
<code>strength</code><br />
Multiplier that can be used to tweak the strength of the occlusion.</p>
<p><strong>The code:</strong></p>
<pre>for each pixel(x, y)
{
	// Get current pixel depth
	float z = zbuffer[ x, y ];

	// Do nothing with pixels that are the background
	if( z &lt;= -1.0e30f || z == 0.0f )
		continue;

	// Set initial variables
	float occlusion = 0.0f;
	int actualSamples = 0;

	// Map screen pixel to camera space point
	Ray cameraRay = MapScreenToCamRay( x, y );
	cameraRay.dir = Normalize( cameraRay.dir );
	Point3 p = -z * cameraRay.dir;
	Point3 normal = normalbuffer[ x, y ];

	for( int i = 0; i &lt; samples; i++ )
	{
		// Calculate a random position within the radius.
		// The distribution below gives a good random sampling
		// This should be pre-calculated
		float rad = random01() * radius;
		float a = random01() * TWOPI;
		float b = random01() * TWOPI;
		Point3 vector;
		vector.x = rad * Sin( a ) * Cos( b );
		vector.y = rad * Sin( a ) * Sin( b );
		vector.z = rad * Cos( a );

		// Get sample point, in camera space
		Point3 samplePoint = p + vector;

		// Get screen coordinate of the sample point
		Point2 screenSamplePoint = MapCamToScreen( samplePoint );
		int sx = int( screenSamplePoint.x + 0.5f );
		int sy = int( screenSamplePoint.y + 0.5f );

		// If sample point is outside the bitmap then ignore it.
		// This code could potentially be skipped in a realtime scenario
		if( sx &lt; 0 || sy &lt; 0 || sx &gt;= w || sy &gt;= h )
			continue;

		// Get z-buffer depth at sample point
		float sampleZ = zBuffer[ sx, sy ];
		// Do nothing with samples that are the background
		if( sampleZ &lt;= -1.0E30f || sampleZ == 0.0f )
			return;

		// Get the difference of the depth at the sample and the depth at p
		float zd = sampleZ - z;

		// Ignore samples with a depth outside the radius or further away than p
		if( zd &lt; radius )
		{
			// Calculate difference in distance to sample point and the z depth at that point
			// Optimized by using squared, ok due to the nature of how we will use it
			// One could probably use samplePoint.z instead of length though.
			float zd2 = LengthSquared( samplePoint ) - sampleZ*sampleZ;

			// Check that the sample point is in front of the z-buffer depth at that point
			if( zd2 &gt; 0.0f )
			{
				// Now get a new point that is samplePoint, but with an adjusted z depth
				Point3 p2 = Normalize( samplePoint ) * -sampleZ;

				// Get cosine of angle between the normal in p and a vector from p to p2
				float dp = DotProd( -normal, Normalize( p2 - p ) );
				// Check that the angle is inside the cone angle
				if( dp &gt; coneAngle )
					occlusion += 1.0f;
			}
		}
		actualSamples++;
	}

	// Calculate final occlusion.
	// Multiply by 2 since we roughly lose quite a lot of samples with the normal check
	occlusion *= 2.0f * strength / float( actualSamples );
	LimitValue( occlusion, 0.0f, 1.0f );
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.malmer.nu/index.php/2008-04-09_ssao-c-style-pseudo-source-code/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>SSAO pretty render</title>
		<link>http://www.malmer.nu/index.php/2008-04-09_ssao-pretty-render/</link>
		<comments>http://www.malmer.nu/index.php/2008-04-09_ssao-pretty-render/#comments</comments>
		<pubDate>Wed, 09 Apr 2008 10:16:29 +0000</pubDate>
		<dc:creator>Malmer</dc:creator>
				<category><![CDATA[3ds max]]></category>
		<category><![CDATA[Ambient Occlusion]]></category>
		<category><![CDATA[Depth of Field]]></category>
		<category><![CDATA[Motion Blur]]></category>
		<category><![CDATA[Rendering]]></category>
		<category><![CDATA[SSAO]]></category>

		<guid isPermaLink="false">http://www.malmer.nu/?p=12</guid>
		<description><![CDATA[To complement the previous post. Here is a &#8220;pretty&#8221; render of the SSAO effect. This also utilizes my custom DOF/motionblur plugin that, contrary to the crappy built-in 3ds max versions, handles both at the same time and with better sampling and high dynamic range support. All built into a sweet package that now also has [...]]]></description>
			<content:encoded><![CDATA[<p>To complement the previous post. Here is a &#8220;pretty&#8221; render of the SSAO effect. This also utilizes my custom DOF/motionblur plugin that, contrary to the crappy built-in 3ds max versions, handles both at the same time and with better sampling and high dynamic range support. All built into a sweet package that now also has ambient occlusion.</p>

<a href='http://www.malmer.nu/index.php/2008-04-09_ssao-pretty-render/ssao_pretty/' title='Pretty render of SSAO'><img width="150" height="150" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_pretty-150x150.jpg" class="attachment-thumbnail" alt="" title="Pretty render of SSAO" /></a>

]]></content:encoded>
			<wfw:commentRss>http://www.malmer.nu/index.php/2008-04-09_ssao-pretty-render/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Screen Space Ambient Occlusion (SSAO)</title>
		<link>http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/</link>
		<comments>http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/#comments</comments>
		<pubDate>Wed, 09 Apr 2008 10:01:44 +0000</pubDate>
		<dc:creator>Malmer</dc:creator>
				<category><![CDATA[3ds max]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[Ambient Occlusion]]></category>
		<category><![CDATA[Lighting]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Render Effect]]></category>
		<category><![CDATA[Render Element]]></category>
		<category><![CDATA[SSAO]]></category>

		<guid isPermaLink="false">http://www.malmer.nu/?p=5</guid>
		<description><![CDATA[Crysis introduced it, the world said wow!, and from there everyone wanted to do their own 3d-engine screen space ambient occlusion.
I implemented it in 3ds max as a render effect using the fine article written by Iñigo Quilez, and with a little help from a render element I managed to get it to only modify [...]]]></description>
			<content:encoded><![CDATA[<p>Crysis introduced it, the world said wow!, and from there <a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=463075" target="_blank">everyone</a> wanted to do their own 3d-engine screen space ambient occlusion.</p>
<p>I implemented it in 3ds max as a render effect using the fine <a href="http://rgba.scenesp.org/iq/computer/articles/ssao/ssao.htm">article written by Iñigo Quilez</a>, and with a little help from a render element I managed to get it to only modify the ambient channel. Well, I didn&#8217;t actually implement it. I reimplemented it. because this and every text I&#8217;ve read about it on the web has some artifacts that are unacceptable in a vfx scenario, and can actually be avoided without any major performance penalties (if any).</p>
<p>In a later post I will detail what modifications I did to remove these artifacts, but in the mean time here are some screenshots. These are rendered in 3dsmax, but I&#8217;ve lowered the number of samples to <strong>32</strong> (which is what real-time engines should be able to handle) and I&#8217;ve turned off anti-aliasing. I&#8217;ve also, for clarity made the SSAO affect all channels, the way most game engines will do it, instead of just the ambient channel. Usually I also apply gamma to the render to make it more realistic, but I&#8217;ve removed that aswell so we get the pure linear pixel experience.</p>
<p>In other words, this is an image that a 3d engine should be able to produce without any problems. </p>
<p>Naturally, if you want to use these few samples you probably should do some blurring of it before presenting it, but this is a better reference for real-time scenarios. In software renders using 500 samples is fast and gives very smooth results.</p>

<a href='http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/ssao_off/' title='ssao_off'><img width="150" height="150" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_off-150x150.png" class="attachment-thumbnail" alt="No occlusion" title="ssao_off" /></a>
<a href='http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/ssao_on/' title='ssao_on'><img width="150" height="150" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_on-150x150.png" class="attachment-thumbnail" alt="SSAO occlusion applied" title="ssao_on" /></a>
<a href='http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/ssao_only/' title='ssao_only'><img width="150" height="150" src="http://www.malmer.nu/wp-content/uploads/2008/04/ssao_only-150x150.png" class="attachment-thumbnail" alt="SSAO occlusion only" title="ssao_only" /></a>

]]></content:encoded>
			<wfw:commentRss>http://www.malmer.nu/index.php/2008-04-09_screen-space-ambient-occlusion-ssao/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Hello world!</title>
		<link>http://www.malmer.nu/index.php/2008-04-09_hello-world/</link>
		<comments>http://www.malmer.nu/index.php/2008-04-09_hello-world/#comments</comments>
		<pubDate>Wed, 09 Apr 2008 08:04:02 +0000</pubDate>
		<dc:creator>Malmer</dc:creator>
				<category><![CDATA[Rant]]></category>

		<guid isPermaLink="false">http://malmer.nu/?p=1</guid>
		<description><![CDATA[Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!
So this is how it starts. Well, I plan to not update this blog too often, I might as well say that from the beginning. I will, however, try to post things that are more than what I ate for breakfast.
Topics [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!</p></blockquote>
<p>So this is how it starts. Well, I plan to not update this blog too often, I might as well say that from the beginning. I will, however, try to post things that are more than what I ate for breakfast.</p>
<p>Topics will probably be things relating to programming and stuff I bump into at work. So expect lots of posts about frustrating things in the 3ds max sdk, but also some things about 3d programming in general. Oh, and I really like my xbox 360, so some post might come from that aswell.</p>
<p>Until then, take care!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.malmer.nu/index.php/2008-04-09_hello-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
