<?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>Robert Kooima</title>
	<atom:link href="http://aoeu.snth.net/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://aoeu.snth.net</link>
	<description>Subtending nearly 1.25x10^-7 steradians of the bl0gosphere</description>
	<lastBuildDate>Sat, 26 Dec 2009 18:15:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The difference between Helvetica and Arial</title>
		<link>http://aoeu.snth.net/?p=135</link>
		<comments>http://aoeu.snth.net/?p=135#comments</comments>
		<pubDate>Sat, 26 Dec 2009 17:50:49 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=135</guid>
		<description><![CDATA[Many people feel deeply about the use of <a href="http://en.wikipedia.org/wiki/Helvetica">Helvetica</a> and <a href="http://en.wikipedia.org/wiki/Arial">Arial</a>.  The prevailing opinion is that Helvetica is a thing of beauty while Arial is an affront to the eye. The use of Arial in place of Helvetica tends to wind a lot of panties into a bunch.

These opinions may be rooted more in the history of these two fonts than in their design.  The scorn may be more toward Microsoft than toward the angled terminals.  Personally, I've got no opinion.  Objectively, the differences are slim.

To make these differences clear, I've overlaid Helvetica in magenta with Arial in cyan, and shown their intersection in black. <a href="http://aoeu.snth.net/static/helvetica-vs-arial.png">Here is a 75K PNG</a>. If you want to look closely, <a href="http://aoeu.snth.net/static/helvetica-vs-arial.pdf">here is a 152K PDF</a>.

<center><a href="http://aoeu.snth.net/static/helvetica-vs-arial.png"><img src="http://aoeu.snth.net/static/helvetica-vs-arial-thumb.png"></a></center>
]]></description>
			<content:encoded><![CDATA[<p>Many people feel deeply about the use of <a href="http://en.wikipedia.org/wiki/Helvetica">Helvetica</a> and <a href="http://en.wikipedia.org/wiki/Arial">Arial</a>.  The prevailing opinion is that Helvetica is a thing of beauty while Arial is an affront to the eye. The use of Arial in place of Helvetica tends to wind a lot of panties into a bunch.</p>
<p>These opinions may be rooted more in the history of these two fonts than in their design.  The scorn may be more toward Microsoft than toward the angled terminals.  Personally, I&#8217;ve got no opinion.  Objectively, the differences are slim.</p>
<p>To make these differences clear, I&#8217;ve overlaid Helvetica in magenta with Arial in cyan, and shown their intersection in black. <a href="http://aoeu.snth.net/static/helvetica-vs-arial.png">Here is a 75K PNG</a>. If you want to look closely, <a href="http://aoeu.snth.net/static/helvetica-vs-arial.pdf">here is a 152K PDF</a>.</p>
<p><center><a href="http://aoeu.snth.net/static/helvetica-vs-arial.png"><img src="http://aoeu.snth.net/static/helvetica-vs-arial-thumb.png"></a></center></p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=135</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Contents of the Universe</title>
		<link>http://aoeu.snth.net/?p=130</link>
		<comments>http://aoeu.snth.net/?p=130#comments</comments>
		<pubDate>Mon, 26 Oct 2009 20:52:30 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Haskell]]></category>
		<category><![CDATA[Vizualization]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=130</guid>
		<description><![CDATA[Here's a little infoviz showing the relative proportion of the contents of the universe.  At a glance, it gives an impression of the relative rarity of normal matter in a universe full of not-yet-understood matter and energy, and the extreme rarity of the heavy elements that comprise our planet and ourselves.

<center><a href="http://snth.net/~rlk/image/universe.pdf"><img src="http://snth.net/~rlk/image/universe.png"></a></center>

This image was algorithmically generated by a Haskell program which output SVG to be loaded into Adobe Illustrator for titling. <a href="http://snth.net/~rlk/image/universe.pdf">Here's a PDF</a>.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little infoviz showing the relative proportion of the contents of the universe.  At a glance, it gives an impression of the relative rarity of normal matter in a universe full of not-yet-understood matter and energy, and the extreme rarity of the heavy elements that comprise our planet and ourselves.</p>
<p><center><a href="http://snth.net/~rlk/image/universe.pdf"><img src="http://snth.net/~rlk/image/universe.png"></a></center></p>
<p>This image was algorithmically generated by a Haskell program which output SVG to be loaded into Adobe Illustrator for titling. <a href="http://snth.net/~rlk/image/universe.pdf">Here&#8217;s a PDF</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=130</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Haskell List Shuffle</title>
		<link>http://aoeu.snth.net/?p=119</link>
		<comments>http://aoeu.snth.net/?p=119#comments</comments>
		<pubDate>Sat, 24 Oct 2009 21:21:36 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Haskell]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=119</guid>
		<description><![CDATA[Pseudo-random number generation is troublesome in a pure functional language like Haskell.  PRNGs work by repeatedly mangling a piece of persistent state which, in imperative languages, is usually a simple global. To support such an operation in Haskell, one either needs to use the PRNG in the IO monad, or pass the state around explicitly.

With that in mind, we turn to the problem of list shuffling.  Given a list, return a copy of the list with the elements reordered. The great Oleg Kiselyov <a href="http://okmij.org/ftp/Haskell/perfect-shuffle.txt">discusses the problem here</a>. Oleg provides two solutions: a straightforward O(n<sup><small>2</small></sup>) solution, and a more sophisticated O(n log n) approach using binary trees.

The sophisticated approach is a little verbose IMO, and it seemed that an equally efficient yet more terse example could result from the realization that list shuffling resembles the Quicksort algorithm. If you replace the value test with a random outcome, the result should be a random ordering of the list in O(n log n) time. Here's an implementation:

<pre>
import Random

shuffle xs g = fst (mix xs (randomRs (True, False) g))
    
    where mix [ ] r0 = ([ ], r0)
          mix [x] r0 = ([x], r0)
          mix  xs r0 = let (ys, zs, r1) = cut xs r0 [] []
                           (cs,     r2) = mix ys r1
                           (ds,     r3) = mix zs r2
                       in  (cs++ds, r3)

          cut    []     rs  ys zs = (ys, zs, rs)
          cut (x:xs) (r:rs) ys zs = if r then cut xs rs (x:ys) zs
                                         else cut xs rs ys (x:zs)
</pre>

The <code>cut</code> function randomly distributes the elements of a list between two new lists.  The <code>mix</code> function recursively shuffles these two new lists and concatenates the results.  The <code>shuffle</code> function takes a Haskell StdGen which it uses to produce an infinite list of pseudo-random booleans.  Note that this list of booleans must be passed to and returned from every function internally. Such is the cost of pure functional code.  Use it like this:

<pre>
*Main Random> shuffle [1..10] (mkStdGen 3)
[1,6,2,5,4,10,3,8,7,9]
*Main Random> shuffle [1..10] (mkStdGen 10)
[2,1,5,3,6,7,10,8,4,9]
</pre>
]]></description>
			<content:encoded><![CDATA[<p>Pseudo-random number generation is troublesome in a pure functional language like Haskell.  PRNGs work by repeatedly mangling a piece of persistent state which, in imperative languages, is usually a simple global. To support such an operation in Haskell, one either needs to use the PRNG in the IO monad, or pass the state around explicitly.</p>
<p>With that in mind, we turn to the problem of list shuffling.  Given a list, return a copy of the list with the elements randomly reordered. The great Oleg Kiselyov <a href="http://okmij.org/ftp/Haskell/perfect-shuffle.txt">discusses the problem here</a>. Oleg provides two solutions: a straightforward O(n<sup><small>2</small></sup>) solution, and a more sophisticated O(n log n) approach using binary trees.</p>
<p>The sophisticated approach is a little verbose IMO, and it seemed that an equally efficient yet more terse example could result from the realization that list shuffling resembles the Quicksort algorithm. If you replace the value test with a random outcome, the result should be a random ordering of the list in O(n log n) time. Here&#8217;s an implementation:</p>
<pre>
import Random

shuffle xs g = fst (mix xs (randomRs (True, False) g))

    where mix [ ] r0 = ([ ], r0)
          mix [x] r0 = ([x], r0)
          mix  xs r0 = let (ys, zs, r1) = cut xs r0 [] []
                           (cs,     r2) = mix ys r1
                           (ds,     r3) = mix zs r2
                       in  (cs++ds, r3)

          cut    []     rs  ys zs = (ys, zs, rs)
          cut (x:xs) (r:rs) ys zs = if r then cut xs rs (x:ys) zs
                                         else cut xs rs ys (x:zs)
</pre>
<p>The <code>cut</code> function randomly distributes the elements of a list between two new lists.  The <code>mix</code> function recursively shuffles these two new lists and concatenates the results.  The <code>shuffle</code> function takes a Haskell StdGen which it uses to produce an infinite list of pseudo-random booleans.  Note that this list of booleans must be passed to and returned from every function internally. Such is the cost of pure functional code.  Use it like this:</p>
<pre>
*Main Random> shuffle [1..10] (mkStdGen 3)
[1,6,2,5,4,10,3,8,7,9]
*Main Random> shuffle [1..10] (mkStdGen 10)
[2,1,5,3,6,7,10,8,4,9]
</pre>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=119</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Real-time Digital Dome Rendering</title>
		<link>http://aoeu.snth.net/?p=114</link>
		<comments>http://aoeu.snth.net/?p=114#comments</comments>
		<pubDate>Wed, 08 Jul 2009 21:26:28 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=114</guid>
		<description><![CDATA[In the summer of 2008 the Adler Planetarium hosted the annual meeting of the International Planetarium Society. At that time I had been working on a number of visualization projects with Adler staff, including the installation of a cluster of Linux PCs in the Adler's digital dome theater. Our goal was to explore ways of generating custom real-time content for dome shows, which were (and largely still are) limited to the playback of pre-rendered movies.

I had prior experience with real-time dome rendering, having done early work with programmable GPUs in a 4-meter dome at NASA Langley Research Center in 2002.  I had spent my years in Chicago adapting real-time visualization code to a wide array of display technologies, and the digital full-dome was another challenge in that vein. It was my further intention to adapt my doctoral work to the full-dome display and defend my dissertation interactively in the Adler dome.  The convergence of these influences coincided with IPS 2008, and I was invited to present an overview of real-time dome rendering techniques at the conference.

The resulting paper gave broad coverage of real-time display and spherical correction techniques, targeted toward the non-technical planetarium crowd, and intended to teach them a bit about the nature of 3D graphics hardware and its incompatibility with domes.  I recently decided to revisit and revise this paper.  <a href="http://aoeu.snth.net/static/real-time-dome.pdf">Here's the PDF.</a>]]></description>
			<content:encoded><![CDATA[<p>In the summer of 2008 the Adler Planetarium hosted the annual meeting of the International Planetarium Society. At that time I had been working on a number of visualization projects with Adler staff, including the installation of a cluster of Linux PCs in the Adler&#8217;s digital dome theater. Our goal was to explore ways of generating custom real-time content for dome shows, which were (and largely still are) limited to the playback of pre-rendered movies.</p>
<p>I had prior experience with real-time dome rendering, having done early work with programmable GPUs in a 4-meter dome at NASA Langley Research Center in 2002.  I had spent my years in Chicago adapting real-time visualization code to a wide array of display technologies, and the digital full-dome was another challenge in that vein. It was my further intention to adapt my doctoral work to the full-dome display and defend my dissertation interactively in the Adler dome.  The convergence of these influences coincided with IPS 2008, and I was invited to present an overview of real-time dome rendering techniques at the conference.</p>
<p>The resulting paper gave broad coverage of real-time display and spherical correction techniques, targeted toward the non-technical planetarium crowd, and intended to teach them a bit about the nature of 3D graphics hardware and its incompatibility with domes.  I recently decided to revisit and revise this paper.  <a href="http://aoeu.snth.net/static/real-time-dome.pdf">Here&#8217;s the PDF.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=114</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generalized Perspective Projection (revised)</title>
		<link>http://aoeu.snth.net/?p=111</link>
		<comments>http://aoeu.snth.net/?p=111#comments</comments>
		<pubDate>Tue, 23 Jun 2009 20:44:15 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=111</guid>
		<description><![CDATA[I've prepared a revised and updated print version of my <a href="http://aoeu.snth.net/?p=43">previous post</a> on Generalized Perspective Projection.  <a href="http://aoeu.snth.net/static/gen-perspective.pdf">Here's the PDF</a>.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve prepared a revised and updated print version of my <a href="http://aoeu.snth.net/?p=43">previous post</a> on Generalized Perspective Projection.  <a href="http://aoeu.snth.net/static/gen-perspective.pdf">Here&#8217;s the PDF</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=111</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LRO/LCROSS Launch and Kennedy Space Center Panoramas</title>
		<link>http://aoeu.snth.net/?p=102</link>
		<comments>http://aoeu.snth.net/?p=102#comments</comments>
		<pubDate>Mon, 22 Jun 2009 14:26:54 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=102</guid>
		<description><![CDATA[One of the applications of my dissertation on planetary-scale data processing is an in-development interactive visualization of the data to be collected by NASA's latest moon probe, <a href="http://lro.gsfc.nasa.gov/">Lunar Reconnaissance Orbiter</a>. I'm working with the <a href="http://www.adlerplanetarium.org/">Adler Planetarium</a>, public outreach center for <a href="http://www.msss.com/lro/lroc/index.html">LROC, the LRO Camera</a>. As a part of this project, I was invited to attend the launch of LRO/<a href="http://lcross.arc.nasa.gov/">LCROSS</a> at Kennedy Space Center. [<a href="http://aoeu.snth.net/?p=102">Read More</a>]]]></description>
			<content:encoded><![CDATA[<p>One of the applications of my dissertation on planetary-scale data processing is an in-development interactive visualization of the data to be collected by NASA&#8217;s latest moon probe, <a href="http://lro.gsfc.nasa.gov/">Lunar Reconnaissance Orbiter</a>. I&#8217;m working with the <a href="http://www.adlerplanetarium.org/">Adler Planetarium</a>, public outreach center for <a href="http://www.msss.com/lro/lroc/index.html">LROC, the LRO Camera</a>. As a part of this project, I was invited to attend the launch of LRO/<a href="http://lcross.arc.nasa.gov/">LCROSS</a> at Kennedy Space Center.</p>
<p>It was a great experience. The Atlas V launched on June 18th, the first available launch day. A bank of low clouds had rolled in just prior to the launch, so the rocket itself was only visible for about a minute before lighting up the overcast and disappearing from view.  It was an impressive spectacle for that minute, burning with an intense orange light. The sound was a massive rumble with a sharp crackle, continuing well after the rocket had gone out of sight.</p>
<p>Shuttle Endeavour had been having trouble on the pad due to a hydrogen leak. They made one last attempt to fuel late in the evening of the 16th.  Had they succeeded, we could have watched an early morning launch from our hotel balcony along the beach to the south.  However, the leak persisted and the launch of Endeavour was scrubbed.  Our bonus rocket launch was not to be.</p>
<p>While waiting for the launch of the Atlas V carrying LRO/LCROSS, I took the opportunity to snap a few photos in and around the Saturn V Facility near the launch viewing stands.  It&#8217;s all huge, so I decided to stitch some panoramas.  These were created using <a href="http://www.autopano.net/en/">Autopano Pro</a> and touched up using Photoshop.</p>
<p><a href="http://aoeu.snth.net/static/kscview.jpg">KSC as seen from the launch viewing stand [9969x719, 1.0MB]</a></p>
<p><a href="http://aoeu.snth.net/static/saturnv-1.jpg">The Saturn V [5290x1272, 1.3MB]</a></p>
<p><a href="http://aoeu.snth.net/static/saturnv-2.jpg">Another view of the Saturn V [4961x950, 1.0MB]</a></p>
<p><a href="http://aoeu.snth.net/static/businessend.jpg">The business end of the Saturn V [2442x2273, 1.2MB]</a></p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=102</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to write IEEE doubles to a binary file in Haskell</title>
		<link>http://aoeu.snth.net/?p=101</link>
		<comments>http://aoeu.snth.net/?p=101#comments</comments>
		<pubDate>Tue, 12 May 2009 21:47:56 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Haskell]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=101</guid>
		<description><![CDATA[Haskell is a great language, but it's got a steep learning curve.  Most of the Haskell examples and tutorials present trivial programs and, as when learning any new language, the best way to get your feet wet is to try to solve an everyday problem.  Unfortunately, if your everyday language is  imperative (which it probably is) then Haskell is going to leave you without many of the basic things you take for granted when you get things done.

In my case, I needed to run a computation involving numerical integration using IEEE double precision floating point values, and output the resulting table of values to a file for visualization. Implementing this computation in Haskell was great fun. However, when it came time to store the output I discovered that Haskell's IO libraries are very much text-oriented.  Binary IO functionality was not to be found... [<a href="http://aoeu.snth.net/?p=101">Read More</a>]]]></description>
			<content:encoded><![CDATA[<p>Haskell is a great language, but it&#8217;s got a steep learning curve.  Most of the Haskell examples and tutorials present trivial programs and, as when learning any new language, the best way to get your feet wet is to try to solve an everyday problem.  Unfortunately, if your everyday language is  imperative (which it probably is) then Haskell is going to leave you without many of the basic things you take for granted when you get things done.</p>
<p>In my case, I needed to run a computation involving numerical integration using IEEE double precision floating point values, and output the resulting table of values to a file for visualization. Implementing this computation in Haskell was great fun. However, when it came time to store the output I discovered that Haskell&#8217;s IO libraries are very text-oriented.  Binary IO functionality was not to be found.</p>
<p>I googled around, as one does, and came up empty-handed.  There is a module called <a href="http://code.haskell.org/binary/">Data.Binary</a>, but its purpose is serialization rather than raw IO, so the binary files it produces include header data.  The <a href="http://haskell.org/ghc/docs/latest/html/libraries/array/Data-Array-IO.html">Data.Array.IO</a> module supports doubles, but only supports IO on bytes, and does not properly maintain the array length when casting from double. Finally, there&#8217;s <a href="http://www.opensubscriber.com/message/haskell-cafe@haskell.org/8348138.html">this ridiculous mailing list thread</a> that actually presents code to pack and unpack IEEE values from raw bytes. I <i>boggled</i> at the notion of a language that forces the programmer to implement their own IEEE 754 packer.</p>
<p>Fortunately, I was looking in the wrong place.  It turns out that Haskell categorizes double IO functionality as &ldquo;foreign&rdquo;.  The Haskell Foreign Function Interface defines sufficient functionality to pack doubles into a buffer and output them to a file.  I guess that makes sense if you consider the operating system (or the floating point processor itself) to be something apart from the Haskell system.</p>
<p>So here&#8217;s some code.  It writes the numbers 1 through 8 to a file named <code>foo.dat</code>.  The <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/System-IO.html">System.IO</a> import provides the file handle and the withBinaryFile function to open and close it.  <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Foreign-Ptr.html">Foreign.Ptr</a> defines the concept of a pointer to an array of doubles.  <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Foreign-Storable.html">Foreign.Storable</a> provides peek and poke functions to manipulate that array.  <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Foreign-Marshal-Array.html">Foreign.Marshal.Array</a> brings malloc to the party.</p>
<pre>
import System.IO
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Array

writebin h = do a <- mallocArray 8 :: IO (Ptr Double)
                pokeElemOff a 0 1.0
                pokeElemOff a 1 2.0
                pokeElemOff a 2 3.0
                pokeElemOff a 3 4.0
                pokeElemOff a 4 5.0
                pokeElemOff a 5 6.0
                pokeElemOff a 6 7.0
                pokeElemOff a 7 8.0
                hPutBuf h a 64

main = withBinaryFile "foo.dat" WriteMode writebin
</pre>
<p>And that's all I need.  I hope you can stop googling now and get something done.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=101</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Generating Source Code Contour Images</title>
		<link>http://aoeu.snth.net/?p=98</link>
		<comments>http://aoeu.snth.net/?p=98#comments</comments>
		<pubDate>Thu, 09 Apr 2009 18:15:22 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=98</guid>
		<description><![CDATA[For many years, <a href="http://www.plt-scheme.org/">DrScheme</a> has had a nifty feature called "Program Contour" that displays a microscopic copy of your source code along side your editor window.  Each character is represented by a single pixel, which allows you to see the entire source file at a glance.  This feature doesn't seem to have gotten much attention, but recently the concept popped up on the radar when <a href="http://www.reddit.com/r/programming/comments/8b0zn/forget_actual_code_can_you_tell_quality_of_code/">this reddit thread</a> and <a href="http://stackoverflow.com/questions/731483/telling-quality-of-source-code-from-its-shape">this stackoverflow</a> question pointed toward <a href="http://imgur.com/HDTGI.png">a similar image</a> and raised the issue of the <i>shape</i> of good code.

I don't claim to know what good code is shaped like, and I don't know what impact an awareness of your code's shape might make on its design, but I think the images are neato and I wanted to see the contour of my current project, which consists of around 34K lines of C++ code spread across 156 source and header files.  The means of generating such images was not immediately obvious to me, so I developed the following technique using utilities commonly found on any Unix-like system. [<a href="http://aoeu.snth.net/?p=98">Read More</a>]]]></description>
			<content:encoded><![CDATA[<p>For many years, <a href="http://www.plt-scheme.org/">DrScheme</a> has had a nifty feature called &#8220;Program Contour&#8221; that displays a microscopic copy of your source code along side your editor window.  Each character is represented by a single pixel, which allows you to see the entire source file at a glance.  This feature doesn&#8217;t seem to have gotten much attention, but recently the concept popped up on the radar when <a href="http://www.reddit.com/r/programming/comments/8b0zn/forget_actual_code_can_you_tell_quality_of_code/">this reddit thread</a> and <a href="http://stackoverflow.com/questions/731483/telling-quality-of-source-code-from-its-shape">this stackoverflow</a> question pointed toward <a href="http://imgur.com/HDTGI.png">a similar image</a> and raised the issue of the <i>shape</i> of good code.</p>
<p>I don&#8217;t claim to know what good code is shaped like, and I don&#8217;t know what impact an awareness of your code&#8217;s shape might make on its design, but I think the images are neato and I wanted to see the contour of my current project, which consists of around 34K lines of C++ code spread across 156 source and header files.  The means of generating such images was not immediately obvious to me, so I developed the following technique using utilities commonly found on any Unix-like system.</p>
<p>As an overview: we convert text to image by way of Postscript.  <a href="http://www.gnu.org/software/enscript/">Enscript</a> generates color syntax-highlighted vector output which is converted to a raster image by <a href="http://www.imagemagick.org/script/index.php">Imagemagick</a>.</p>
<p>The primary difficulty lies in eliminating page breaks and generating a continuous scroll.  To accomplish this, define a new Enscript media type called &ldquo;Scroll,&rdquo; representing a very long narrow page.  To use it, place the following text in the Enscript configuration file, <code>~/.enscriptrc</code>:</p>
<p><code>Media: Scroll 512 32768 0 0 512 32768</code></p>
<p>Given this, here is a command line to generate <code>hello.cpp.png</code> from the text of <code>hello.cpp</code>.  Enscript writes its output to stdout, which is piped into the stdin of convert.</p>
<p><code>enscript --no-header -Ecpp --color -MScroll -p - hello.cpp | convert ps:- -flatten -resize 25% -trim -normalize -quality 100 -colors 16 hello.cpp.png</code></p>
<p>This code&#8230;</p>
<pre style="background-color: #ffd">
#include &lt;iostream&gt;

int main()
{
    std::cout &lt;&lt; "Hello, World." &lt;&lt; std::endl;
}
</pre>
<p>&#8230; produces this image.</p>
<p><img src="http://aoeu.snth.net/wp-content/uploads/2009/04/hellocpp.png" alt="" title="hellocpp" width="70" height="17"/></p>
<p><a href='http://aoeu.snth.net/wp-content/uploads/2009/04/app-hostcpp.png'>Here&#8217;s a larger example (122&#215;2510)</a></p>
<p>There are many opportunities for customization.  Lets begin with the Enscript options.  The <code>--no-header</code> option tells Enscript to print nothing but the file&#8217;s contents, omitting the header line it would normally include.  The <code>-Ecpp</code> option tells Enscript to highlight the syntax of C++ code.  Run <code>enscript --help-pretty-print</code> to see a list of all supported languages. The <code>--color</code> option requests colored syntax, which defaults to an Emacs style. <code>-MScroll</code> selects the long page media type we&#8217;ve just defined. Finally, <code>-p -</code> tells Enscript to write the generated Postscript to stdout.</p>
<p>Now take a look at the Imagemagick options.  Postscript is assumed to be transparent, and I want an opaque image, so the first step is to <code>-flatten</code> the input. Then, we do the work we set out to do in the first place, <code>-resize 25%</code> to scale the image down. A value of 10% is probably more appropriate if you want something resembling one pixel per character, as Enscript renders the text using 10-point Courier.  The <code>-trim</code> option eliminates blank space at the end of a page (more on that issue below).  <code>-normalize</code> enhances the contrast. This is necessary because text tends to have more background than foreground. The default down-sampling filter averages these, resulting in colors near white.  Finally the <code>-quality 100</code> and <code>-colors 16</code> options configure the PNG compression. Sixteen colors are probably enough, as highlighted syntax usually has only a few colors, but we&#8217;d like a few extras for antialiasing.</p>
<p>Now, for this to be really useful we&#8217;ll want to automate it.  We want to generate a complete set of images including every source file in a project.  This can be easily done with GNU <code>make</code>.  Here&#8217;s a Makefile:</p>
<pre style="background-color: #ffd">
SRCS= $(shell find . -name "*.cpp" -or -name "*.hpp")
IMGS= $(SRCS:%=%.png)

ESFLAGS= -Ecpp --no-header --color -MScroll
CVFLAGS= -flatten -resize 25% -trim -normalize -quality 100 -colors 16

%.png : %
	enscript $(ESFLAGS) -p - $< | convert ps:- $(CVFLAGS) $@

images : $(IMGS)
</pre>
<p>Given this, all we need to do is type <code>make images</code> and make will seek out all C++ source and header files (that's the <code>find</code> operation in the definition of <code>SRCS</code>), determine an appropriate PNG image name for each (the definition of <code>IMGS</code>) and generate PNGs as above. As with most make-based processes, the next time we <code>make images</code>, make will generate PNGs only for those source files that changed since the last run.</p>
<p>Lastly, a note on source length: Notice that the Postscript Scroll media type defined above is only 32768 points long.  That's about 5000 lines of program text.  If your source file is longer than that, then it will be paginated on the pipe, and <code>convert</code> will generate only one image.  Yet, we can't freely set that value larger because the generated Postscript will, in fact, always be exactly 32768 points long. Thus when Imagemagick begins processing there is briefly a raster buffer large enough to accept it.  The <code>-trim</code> optimizes this by slicing away any blank space.  This is the ugly side of this technique.  If you know of a way to get Enscript to automatically adapt its media size to the output, let me know.  If you know of a completely different and vastly superior means of program contour image generation, let me know that too.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=98</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Generalized Perspective Projection</title>
		<link>http://aoeu.snth.net/?p=43</link>
		<comments>http://aoeu.snth.net/?p=43#comments</comments>
		<pubDate>Thu, 28 Aug 2008 20:20:59 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=43</guid>
		<description><![CDATA[Perspective projection is a well-understood aspect of 3D graphics. It is not something that 3D programmers spend much time thinking about. Most OpenGL applications simply select a field of view, specify near and far clipping plane distances, and call gluPerspective or glFrustum. These functions suffice in the vast majority of cases. However, the field of Virtual Reality introduces circumstances under which they fail. This article discusses the limitations of these perspective projection functions, and describes a more generalized perspective projection formulation. Implementation and an example application using OpenGL are provided. [<a href="http://aoeu.snth.net/?p=43">Read More.</a>]

<div align='center'><img width='384' height='260' src='http://aoeu.snth.net/wp-content/uploads/2008/08/varrier.jpg' alt='Varrier' /></div>]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Perspective projection is a well-understood aspect of 3D graphics. It is not something that 3D programmers spend much time thinking about. Most OpenGL applications simply select a field of view, specify near and far clipping plane distances, and call <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml"><code>gluPerspective</code></a> or <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml"><code>glFrustum</code></a>. These functions suffice in the vast majority of cases.</p>
<p>But there are a few assumptions implicit in these. <code>gluPerspective</code> assumes that the user is positioned directly in front of the screen, facing perpendicular to it, and looking at the center of it. <code>glFrustum</code> generalizes the position of the view point, but still assumes a perspective rooted at the origin and a screen lying in the XY plane.</p>
<p>The configuration of the user and his screen seldom satisfy these criteria, but perspective projection remains believable in spite of this.  Leonardo&#8217;s <a href="http://upload.wikimedia.org/wikipedia/commons/d/d2/The_Last_Supper_pre_EUR.jpg">The Last Supper</a> appears to be a painting of a room full of people regardless from the position from which you view it, and we still enjoy a movie even when we&#8217;re sitting off to the side of the theater.</p>
<h3>Motivation</h3>
<p>The field of Virtual Reality introduces circumstances under which these assumptions fail and the resulting incorrectness is not tolerable. VR involves a number complicating aspects: first-person motion-tracked perspective, stereoscopic viewing, and multi-screen, non-planar display surfaces. For example, this is the <a href="http://www.evl.uic.edu/core.php?mod=4&#038;type=1&#038;indi=275">Varrier<sup><small>TM</small></sup></a>.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/varrier.jpg' alt='Varrier' /></div>
<p></p>
<p>This technology was invented at the <a href="http://www.evl.uic.edu/">Electronic Visualization Laboratory</a> at the University of Illinois at Chicago. The Varrier installation pictured here can be found at <a href="http://www.calit2.net">Calit2</a> on the campus of the University of California at San Diego. It is a 12&times;5 array of LCD screens arranged in a 180 degree arc, 10 feet in diameter. Each LCD displays 1600&times;1200 pixels, with a parallax barrier affixed to the front, giving autostereoscopic viewing. (That&#8217;s 3D without glasses. See <a href="http://www.evl.uic.edu/files/pdf/Siggraph2005.pdf">this SIGGRAPH 2005 paper</a> for background.) The display as a whole is driven by a cluster of 16 Linux PCs, each with two NVIDIA GeForce 7900 GTXs, with 4 displays connected to each cluster node.</p>
<p>As is common in VR systems, a <a href="http://www.ar-tracking.de/">motion tracking system</a> senses the position and orientation of the user&#8217;s head. This allows the 3D spatial positions of each of his eyes to be computed relative to the position of the display, which leads to the first-person tracked perspective aspect of VR. Here is a top-down view of the 60-panel Varrier showing the coordinate system of the motion tracker.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/user-coord.png' alt='User Coordinates' /></div>
<p></p>
<p>The origin of the tracker coordinate system is on the floor at the center of the arc, the X axis points to the right, Y points up (out of the image), and Z points back. In the photograph above, I&#8217;m standing a bit right of center, and I&#8217;m 5&#8242;10&#8243;, so my tracked head position is around (2.0, 5.8, 0.0).</p>
<p>To display a single coherent virtual environment, all 60 screens must define their projections in a common coordinate system. For convenience, we simply reuse this tracker coordinate system for this purpose. The positions of the corners of all 60 screens have been measured very precisely in this coordinate system using a digital theodolite. Given these positions, plus the tracked position of the user&#8217;s head, we can compute the positions of the users eyes, and thus the 120 distinct perspective projections necessary to render one scene consistently across the entire cluster.</p>
<p>Now, because the user is free to move about the space, the view position does not remain centered upon any of the screens and the <code>gluPerspective</code> function fails.  Because the display wraps around the user, most screens do not lie in the XY plane and the <code>glFrustum</code> function fails. We must therefore formulate a more generalized perspective projection.</p>
<p>In the coming sections we will build up such a <a href="#formulation">formulation</a> from basic principles, mathematically, in stages. Our ultimate degree of generality will surpass even the needs of the Varrier. Following that, we will see the <a href="#implementation">implementation</a> of this more general approach to perspective projection in C using OpenGL. Finally, we will play with a very simple <a href="#example">example</a> which uses the generalized projection to render crossed-eye stereo pairs suitable for viewing on a normal 2D display.</p>
<h3><a name="formulation">Formulation</a></h3>
<p>The perspective projection is determined separately for each screen-eye pair, so we need only consider a single screen being viewed by a single eye.  Here is a screen:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-corners.png' alt='Screen Corners' /></div>
<p></p>
<p>The important characteristics are the screen corners <i>p<sub>a</sub></i> at the lower left, <i>p<sub>b</sub></i> at the lower right, and <i>p<sub>c</sub></i> at the upper left. These values encode the size of the screen, its aspect ratio, and its position and orientation in space.</p>
<p>We can use these three points to compute an orthornormal basis for the screen space. Recall from linear algebra class that an orthonormal basis for a 3D space is a set of three vectors, each of which is perpendicular to the others, and all of which have length one. In screen space, we refer to these vectors as <i>v<sub>r</sub></i>, the vector toward the right, <i>v<sub>u</sub></i>, the vector pointing up, and <i>v<sub>n</sub></i>, the vector normal to the screen (pointing directly out of it.)</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-basis.png' alt='Screen Basis' /></div>
<p></p>
<p>Just as the standard axes <i>x</i>, <i>y</i>, and <i>z</i> give us an orthonormal basis for describing points relative to the origin of 3D Cartesian space, the screen-local axes <i>v<sub>r</sub></i>, <i>v<sub>u</sub></i>, and <i>v<sub>n</sub></i> give us a basis for describing points relative to the screen. We compute these from the screen corners as follows:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/vr.png' alt='vr' /><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/vu.png' alt='vu' /><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/vn.png' alt='vn' /></div>
<p></p>
<h4>On-axis projection</h4>
<p>Now, here is an eye position <i>p<sub>e</sub></i>. </p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-on-axis.png' alt='On-axis Perspective' /></div>
<p></p>
<p>Notice that in this specific example, the eye is centered on the screen. The line drawn perpendicular to the screen along <i>v<sub>n</sub></i> strikes it directly in the middle. We refer that point of intersection as the <em>screen-space origin</em>. This coincides with the origin of the screen-space vector basis depicted above.</p>
<p>Also in this example, the pyramid-shaped volume, or &ldquo;frustum,&rdquo; having the screen as its base and the eye as its apex is perfectly symmetric. This is exactly the type of perspective projection producted by <code>gluPerspective</code>.</p>
<h4>Off-axis projection</h4>
<p>If we move the eye position away from the center of the screen, we get a situation like this:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-off-axis.png' alt='Off-axis Perspective' /></div>
<p></p>
<p>The frustum is no longer symmetric, and the line from the eye drawn along <i>v<sub>n</sub></i> no longer strikes the screen in the middle. We defined the screen-space origin to be this point of intersection, and we continue to do so, thus we see that when the user moves then the screen-space origin moves with him.</p>
<p>This is where <code>glFrustum</code> comes in. As <a href='http://www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml'>documented</a>, this function takes parameters giving the left, right, bottom, and top frustum extents, plus distances to the near and far clipping planes. We will refer to these as variables <i>l</i>, <i>r</i>, <i>b</i>, <i>t</i>, <i>n</i>, and </i>f</i> respectively. The first four frustum extent variables may be understood as <em>tracker</em>-space distances from the screen-space origin to the respective edges of the screen, as shown here:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-extents.png' alt='Screen Extents' /></div>
<p></p>
<p>In this example, <i>l</i> and <i>b</i> are negative numbers, while <i>r</i> and <i>t</i> are positive numbers, but this need not be the case. If the user moves far to the side of the screen, then the screen space origin may not fall within the screen at all, and any of these parameters may be positive or negative.</p>
<h4>Determining frustum extents</h4>
<p>Before we may use these values, we must compute them. As an intermediate step, we will need to know the vectors from the eye position <i>p<sub>e</sub></i> to the screen corners.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/screen-vectors.png' alt='Screen Vectors' /></div>
<p></p>
<p>These vectors are trivially computed as follows:</p>
<div align='center'>
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/va.png' alt='va' /><br />
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/vb.png' alt='vb' /><br />
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/vc.png' alt='vc' />
</div>
<p></p>
<p>It is also useful to know a bit more about the screen-space origin. In particular, let <i>d</i> be the distance from the eye position <i>p<sub>e</sub></i> to the screen-space origin. This also happens to be the length of the shortest path from the eye to the plane of the screen. This value may be computed by taking the dot product of the screen normal <i>v<sub>n</sub></i> with any of the screen vectors. Because these vectors point in opposite directions, the value must be negated.</p>
<div align='center'>
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/d.png' alt='d' />
</div>
<p></p>
<p>Given this, frustum extents may be computed. Take the frustum right extent <i>r</i> for example. When we take the dot product of the <em>unit</em> vector <i>v<sub>r</sub></i> (which points from the screen origin toward the right) with the <em>non-unit</em> vector <i>v<sub>b</sub></i> (which points from the eye to the right-most point on the screen) the result is a scalar value telling us how far to the right of the screen origin the right-most point on the screen is.</p>
<p>Because frustum extents are specified at the near plane, we use similar triangles to scale this distance back from its value at the screen, <i>d</i> units away, to its value at the near clipping plane, <i>n</i> units away.</p>
<div align='center'>
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/l.png' alt='l' /><br />
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/r.png' alt='r' /><br />
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/b.png' alt='b' /><br />
<img src='http://aoeu.snth.net/wp-content/uploads/2008/08/t.png' alt='t' />
</div>
<p></p>
<p>The OpenGL function <code>glFrustum</code> inserts these values into the standard 3D perspective projection matrix, which is defined as follows:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/p.png' alt='P' /></div>
<p></p>
<p>This matrix is clever, and it is worth examining in order to form an intuitive understanding of its function. Perspective projection involves foreshortening. The greater the distance to an object, the smaller that object appears. To accomplish this, the <i>x</i> and <i>y</i> components of a vertex are divided by its <i>z</i> component.</p>
<p>This division is implemented using homogeneous coordinates. A homogeneous 3D vector has 4 components, (<i>x</i>, <i>y</i>, <i>z</i>, <i>w</i>), where <i>w</i> defaults to 1. This implicitly defines the 3D vector (<i>x/w</i>, <i>y/w</i>, <i>z/w</i>). Notice the 3rd component of the bottom row of <i>P</i> is -1. When <i>P</i> is multiplied by a homogeneous vector, this -1 has the effect of moving the vector&#8217;s (negated) <i>z</i> value into the resulting homogeneous vector&#8217;s <i>w</i> component. Later, when this result vector is collapsed down to its equivalent 3D vector, the division by <i>z</i> implicitly occurs.</p>
<p>This implies that the foreshortening effect, and thus perspective projection, only works when the view position is at the origin, looking down the negative Z axis, with the view plane aligned with the XY plane. The foreshortening scaling occurs radially about the Z axis. It is useful to understand these limitations and their source, as we&#8217;ll need to work past all three.</p>
<h4>Deep breath</h4>
<p>Let&#8217;s take a step back and see where we are. We&#8217;ve started with basic constants defining the position of a screen in space <i>p<sub>a</sub></i>, <i>p<sub>b</sub></i>, and <i>p<sub>c</sub></i> along with the position of an eye in space <i>p<sub>e</sub></i>. We&#8217;ve developed formulas allowing us to compute from these the parameters of a standard 3D perspective projection matrix <i>l</i>, <i>r</i>, <i>b</i>, and <i>t</i>.</p>
<p>It&#8217;s a good start, but we haven&#8217;t fundamentally created anything more powerful than <code>glFrustum</code> yet.  While we have the ability to create a frustum for an arbitrary screen viewed by an arbitrary eye, the base of that frustum still lies in the XY plane. If we applied this amount of knowledge to the Varrier, then all 60 screens would display nearly the same limited view of the virtual scene. We need two more capabilities: first we need to rotate the screen out of the XY plane, and second we need to correctly position it relative to the user.</p>
<h4>Projection Plane Orientation</h4>
<p>We would like to rotate our XY-aligned frustum within the tracker space. We may do this with a simple matrix multiplication. To understand how, it becomes more intuitive if we instead consider rotating the tracker space to be aligned with the XY plane.</p>
<p>Let&#8217;s review a bit more linear algebra. Define a 4&times;4 linear transformation matrix <i>M</i> using the screen space basis vectors <i>v<sub>r</sub></i>, <i>v<sub>u</sub></i>, and <i>v<sub>n</sub></i> as columns, like so.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/m.png' alt='m' /></div>
<p></p>
<p>This is the transformation matrix for screen-local coordinates. It maps the Cartesian coordinate system onto the screen space coordinate system, transforming the standard axes <i>x</i>, <i>y</i>, and <i>z</i> into the basis vectors <i>v<sub>r</sub></i>, <i>v<sub>u</sub></i>, and <i>v<sub>n</sub></i>. If something is lying in the XY plane, then this transformation matrix <i>M</i> will realign it to lie in the plane of the screen.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/maxes.png' alt='M Axes' /></div>
<p></p>
<p>This is extremely useful in 3D graphics. A 3D model is created by an artist in its own coordinate system, with its own local orientation. To position such an object in a scene, a transformation such as this <i>M</i> is used. The column basis construction allows the programmer to orient the object in terms of the concepts &ldquo;to the right,&rdquo; &ldquo;up,&rdquo; and &ldquo;backward&rdquo; instead of fumbling with Euler angles, pitch, roll, and yaw.</p>
<p>Unfortunately, this is the exact opposite of what we want. We want something lying in the plane of the screen to be realigned to lie in the XY plane, so that we may apply the standard perspective projection to it.  We need this mapping:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/iaxes.png' alt='I Axes' /></div>
<p></p>
<p>This mapping is produced by the inverse of <i>M</i>. Fortunately, <i>M</i> is orthogonal, so its inverse is simply its transpose, and we can produce the desired transform simply by loading the screen space basis vectors into <i>M</i> as rows instead of as columns.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/i.png' alt='I' /></div>
<p></p>
<p>We compose the perspective projection matrix <i>P</i> defined above with this matrix <i>M</i> and we finally have something more powerful than <code>glFrustum</code>. We have a perspective projection that relaxes the projection plane alignment requirement. But we&#8217;re not quite finished yet. </p>
<h4>View point offset</h4>
<p>The nature of the camera is one of the fundamentally confusing aspects of 3D computer graphics. Consider camera motion. While we would like to imagine that we are free to move the camera freely about 3D space, the mathematics of perspective projection as defined by matrix <i>P</i> disallow this. (Recall, above, the nature of the foreshortening division by <i>z</i>.)</p>
<p>The camera is forever trapped at the origin. If we wish to move the camera 5 units to the left, we must instead move the entire world 5 units to the right.  If we wish to rotate the camera clockwise, we must instead rotate the world counterclockwise.</p>
<p>Above, when we wanted to rotate our frustum to align it within our tracker space, we instead rotated our tracker space to align it with our frustum. Now, we want to move our frustum to position the apex upon the motion-tracked eye position, so we instead must translate our tracked eye position to the apex of of our frustum. The apex of the perspective frustum is necessarily at zero, thus we translate along the vector <em>from</em> the eye.</p>
<p>This can be accomplished using the OpenGL function <code>glTranslatef</code>, which applies the standard 3D transformation matrix:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/translate.png' alt='T' /></div>
<p></p>
<h4>Composition of everything</h4>
<p>That covers everything we need. We can compose these three matrices giving a single projection matrix, sufficiently general to accomplish all of our goals.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/pprime.png' alt='P'' /></div>
<p></p>
<p>Beginning with constant screen corners <i>p<sub>a</sub></i>, <i>p<sub>b</sub></i>, <i>p<sub>c</sub></i>, and varying eye position <i>p<sub>e</sub></i>, we can straightforwardly produce a projection matrix that will work under all circumstances. Most significantly, an arbitrary number of arbitrarily-oriented screens may be defined together in a common coordinate system, and the resulting projection matrices will present these disjointed screen as a single, coherent view into a virtual environment.</p>
<h3><a name="implementation">Implementation</a></h3>
<p>The following C function computes this perspective matrix and applies it to the OpenGL projection matrix stack. It takes four float vectors, <code>pa</code>, <code>pb</code>, <code>pc</code>, <code>pe</code>, which are the screen corner positions and the eye position as define above, plus <code>n</code> and <code>f</code> which are the near and far plane distances, identical to those passed to <code>gluPerspective</code> or <code>glFrustum</code>.</p>
<p>This function uses 4 vector functions: <code>subtract</code>, <code>dot_product</code>, <code>cross_product</code>, and <code>normalize</code>, which are not listed here, but are included in the <a href='http://aoeu.snth.net/wp-content/uploads/2008/08/example.c' title='example.c'>example code</a> described below. In all likelyhood, you already have a library containing functions performing the same tasks.</p>
<p>All variables defined in this function have the same names as in the description above. Note that this function is not optimized. The screen space basis vectors, <code>vr</code>, <code>vu</code>, and <code>vn</code> may be precomputed and stored per screen, as may be the screen-space basis matrix <code>M</code> which uses them. </p>
<pre>
void projection(const float *pa,
                const float *pb,
                const float *pc,
                const float *pe, float n, float f)
{
    float va[3], vb[3], vc[3];
    float vr[3], vu[3], vn[3];

    float l, r, b, t, d, M[16];

    /* Compute an orthonormal basis for the screen. */

    subtract(vr, pb, pa);
    subtract(vu, pc, pa);

    normalize(vr);
    normalize(vu);

    cross_product(vn, vr, vu);

    normalize(vn);

    /* Compute the screen corner vectors. */

    subtract(va, pa, pe);
    subtract(vb, pb, pe);
    subtract(vc, pc, pe);

    /* Compute the shortest distance from the eye to the screen. */

    d = -dot_product(va, vn);

    /* Compute the extents of the perpendicular projection. */

    l = dot_product(vr, va) * n / d;
    r = dot_product(vr, vb) * n / d;
    b = dot_product(vu, va) * n / d;
    t = dot_product(vu, vc) * n / d;

    /* Load the perpendicular projection on the projection matrix stack. */

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(l, r, b, t, n, f);

    /* Rotate the projection by applying the screen orientation. */

    M[0] = vr[0]; M[4] = vr[1]; M[ 8] = vr[2]; M[12] = 0.0f;
    M[1] = vu[0]; M[5] = vu[1]; M[ 9] = vu[2]; M[13] = 0.0f;
    M[2] = vn[0]; M[6] = vn[1]; M[10] = vn[2]; M[14] = 0.0f;
    M[3] =  0.0f; M[7] =  0.0f; M[11] =  0.0f; M[15] = 1.0f;

    glMultMatrixf(M);

    /* Move the apex of the frustum to the origin. */

    glTranslatef(-pe[0], -pe[1], -pe[2]);

    glMatrixMode(GL_MODELVIEW);
}
</pre>
<p>Some may wonder why I&#8217;ve chosen to apply the <code>glMultMatrixf</code> and <code>glTranslatef</code> to the OpenGL projection matrix rather than the model-view matrix. It would work either way. I feel the use of the projection matrix lends the implementation better encapsulation. Applications may use it as a drop-in replacement for the standard perspective functions without worrying about smashing a valuable model-view stack with a <code>glLoadIdentity</code>, as is a very common practice.</p>
<p>This distinction is even wider when you consider the OpenGL 3.0 forward compatible and OpenGL ES 2.0 programming models. Both of these APIs do away with the matrix stacks entirely. Applications that use them must construct their projection matrices on the CPU and upload them to vertex shader uniforms on the GPU. By composing the screen-space orientation and eye position translation matrices with the perspective projection on the CPU, the vertex shader need not concern itself with the nature of the projection.</p>
<h3><a name="example">Example</a></h3>
<p>To make this discussion as concrete as possible, there is a <a href='http://aoeu.snth.net/wp-content/uploads/2008/08/example.c' title='example.c'>complete example application for you to compile and run</a>. It is based upon <a href="http://www.opengl.org/resources/libraries/glut/">GLUT</a>, so you should be able to compile and run it under your OS of choice. I have tested it under Linux and OSX. Feel free to copy and paste the source for any purpose you see fit.</p>
<p>A full-fledged multi-screen example would be beyond the scope of this document, given that a great deal of hardware and supporting software is necessary before we can even begin. For this reason, we present a simple, real-time, stereo pair renderer. Here&#8217;s a screenshot.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/teapot.jpg' alt='teapot.jpg' /></div>
<p></p>
<p>This is a crossed-eye stereo pair. Cross your eyes such that your right eye focuses upon the left image, and your left eye focuses upon the right image. If you have trouble perceiving this image in stereo, see <a href="http://aoeu.snth.net/?p=85">this related post</a>.</p>
<p>Stereo rendering is an excellent application of our projection function, because many stereo application implementors do it wrong. They offset the eyes horizontally but leave the view axes parallel, or they introduce a simple &ldquo;toe-in&rdquo; rotation without accounting for the off-axis perspectives.  Neither of these approaches cause the left-eye and right-eye projection rectangles to coincide in virtual space, as they should.</p>
<p>The generalized perspective projection formulation allows you to do it correctly and automatically.  You need only select one set of screen corners and a pair of eye positions, and the projection function produces a correctly skewed projection. Here is a top-down depiction of the <em>virtual</em> scene depicted by the example code.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/teapot-scene.png' alt='Teapot scene'' /></div>
<p></p>
<p>This scene is designed to be roughly correct when displayed on a PC or laptop with a display resolution of 100dpi, viewed from a distance of 18&#8243;.  The 500&times;250 pixel window should appear approximately 5&#8243;&times;2.5&#8243;. The eyes are positioned near the origin, and offset based upon an average interocular distance of 2.5&#8243;. The virtual teapot is positioned at <i>z</i>=-16&#8243;, and the screen corners have <i>z</i>=-18&#8243;. If your display is scaled correctly, then the teapot should appear to hover 2&#8243; in front of your screen.</p>
<h3>Extended capabilities</h3>
<p>As suggested in the motivation, this perspective function has generality beyond what is commonly needed. In particular, screens may have arbitrary orientation.  They may even be rotated, installed upside down, laid flat on the floor, or hung from the ceiling. This makes the approach applicable to <a href="http://www.evl.uic.edu/pape/CAVE/oldCAVE/CAVE.html">CAVE</a>-like projector-based installations. The only requirement is that <i>p<sub>a</sub></i> describe the screen&#8217;s structural lower left corner, rather its spatial lower left corner. (And so with <i>p<sub>b</sub></i> and <i>p<sub>c</sub></i>.)</p>
<p>Also note that the ostensibly rectangular screen is configured using only three points. The position of the fourth point is implicit. The <a href="#formulation">formulation</a> discussion refers to the screen-space basis (<i>v<sub>r</sub></i>, <i>v<sub>u</sub></i>, <i>v<sub>n</sub></i>) as &ldquo;orthonormal&rdquo;, and the <a href="#implementation">implementation</a> does normalize it, but does not <em>ortho</em>normalize it. Thus, the configuration is free to introduce a skew transform, in addition to the screen-orientating rotation transform. I have never seen a circumstance where this is useful. If you ever find a rhombic display, let me know!</p>
<h3>Conclusion</h3>
<p>This has been a rather lengthy document describing a fairly brief bit of code. By discussing it in detail, I hope to convey a thorough understanding of its function, correctness, and usefulness. This code has found use in several virtual reality research projects at <a href="http://www.evl.uic.edu">EVL</a>, and its value to us has been great. I hope you find it useful as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=43</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to view crossed-eye stereo pairs</title>
		<link>http://aoeu.snth.net/?p=85</link>
		<comments>http://aoeu.snth.net/?p=85#comments</comments>
		<pubDate>Wed, 27 Aug 2008 18:15:55 +0000</pubDate>
		<dc:creator>rlk</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://aoeu.snth.net/?p=85</guid>
		<description><![CDATA[Despite being the easiest stereo technique to view, many people still have trouble viewing cross-eye image pairs. It is a skill that gets easier with practice, and some might need a little push to get started. This page exists to offer advice and explanation which will hopefully help some of those who continue to be baffled. [<a href="http://aoeu.snth.net/?p=85">Read More</a>]

<div align='center'r><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/teapot.png' alt='Stereo Teapot' /></div>
]]></description>
			<content:encoded><![CDATA[<p>There are many methods for displaying strereoscopic 3D imagery on normal displays. <a href="http://en.wikipedia.org/wiki/Anaglyph_image">Anaglyphic (red-blue)</a> stereo is perhaps the most well-known, but it requires colored glasses and doesn&#8217;t handle color imagery well. <a href="http://en.wikipedia.org/wiki/Autostereogram">Random-dot autostereograms</a> enjoyed a brief spike of popularity in the mid 90s, but many people (like me) have trouble seeing the image through the dots, and the 3D content may have only structure, with no color or shading allowed. Wall-eyed and crossed-eye autostereograms (<a href="http://en.wikipedia.org/wiki/Autostereogram">same wiki article</a>) are related techniques that do away with the random dots, but require horizontal repetition in the scene. </p>
<p>Of all of the existing standard-display stereoscopic techniques, wall-eyed and crossed-eye stereo image pairs are the most flexible and reliable. Most people find crossing their eyes to be much easier than wall-eyeing, since we cross our eyes automatically anytime we focus on an object near us. For this reason, I tend to focus upon cross-eyed stereo pairs as a preferred method of presenting stereo imagery on the web.</p>
<p>But despite being the easiest stereo technique to view, many people still have trouble with cross-eye image pairs. It is a skill that gets easier with practice, and some might need a little push to get started. This page exists to offer advice and explanation which will hopefully help some of those who continue to be baffled.</p>
<p>Here is a cross-eye stereo pair of the famous teapot.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/teapot.png' alt='Stereo Teapot' /></div>
<p></p>
<p>When you focus on this image normally, you see a pair of teapots. They are similar, but not identical.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/cross-merging-a.png' alt='Step 1' /></div>
<p></p>
<p>Now, if you cross your eyes you&#8217;ll begin to see everything doubled. You&#8217;ll see two of each of your hands, two of your computer, and two of the image on your display. You&#8217;ll see four teapots.</p>
<p>If you have trouble crossing your eyes intentionally, position your finger half way between your face and your screen. Look at your finger, and in the background you will see the four teapots.</p>
<p>In this image, the pair of teapots that your left eye sees are drawn in red, and the pair of teapots that your right eye sees are drawn in blue.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/cross-merging-c.png' alt='Step 3' /></div>
<p></p>
<p>If the two pairs of teapots are not vertically aligned, then your head is tilted with respect to your screen.  This can happen if you&#8217;re not sitting directly in front of the screen. Tilt your head until all four teapots are lined up vertically.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/cross-merging-b.png' alt='Step 2' /></div>
<p></p>
<p>Once they&#8217;re aligned vertically, adjust the crossing of your eyes until the two teapots in the middle overlap one another.</p>
<p>If you&#8217;re using your finger to help you cross your eyes, then move your finger forward and back. While continuing to look at your finger, you will see the pairs of teapots shift horizontally. Adjust the position of your finger until the two middle teapots overlap. Once they are aligned, attempt to shift your focus from your finger to the teapot.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/cross-merging-d.png' alt='Step 4' /></div>
<p></p>
<p>With these two teapots aligned, something in your mind will snap. It will flip on like a switch. What was once a baffling jumble of double vision will suddenly merge into clear 3D image. Once your mind has latched on to this 3D image, you will find it very easy to maintain the illusion.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/cross-merging-e.png' alt='Step 5' /></div>
<p></p>
<p>The solid 3D teapot will be flanked on each side by another teapot afterimage. As you concentrate on the middle teapot, these ghost teapots will become easy to ignore. If they bother you, then you may block these flanking images with your hands, and the 3D illusion will remain.</p>
<p>Here is the stereo pair again. Take a look.</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/teapot.png' alt='Stereo Teapot' /></div>
<p></p>
<p>The size and resolution of your display should be such that the distance between the two teapot images is roughly the same as the distance between your eyes. It doesn&#8217;t really matter much if this isn&#8217;t the case, but it is optimal. It is also more intuitive to understand what&#8217;s going on.  Here&#8217;s a view from above:</p>
<div align='center'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/crosseye.png' alt='Crossed Eyes' /></div>
<p></p>
<p>Your eyes are crossed. Rather than converging on the screen, as they normally do, they are converging on a point <em>half</em> of the distance to the screen. When you position your finger at that point, you trick your eyes into merging the teapot images on the screen.</p>
<p>The teapot image is an easy one. It displays a single, isolated object against a plain background. This isolated object gives the viewer a well-defined reference to apply the merging described above. Not all stereo pairs have such a useful feature, but most images have <em>some</em> contrast that can be focused upon.</p>
<p>As an example, here is a stereo pair of the constellation Orion and the Hyades cluster. Focus on the large red star Betelgeuse at Orion&#8217;s shoulder. Merge that feature, and you will find his club poking out at you. After you&#8217;ve settled in to the image, examine the detail in the Hyades cluster at the lower right, and the subtle variation in the carpet of background stars.</p>
<div align='center'><a href='http://aoeu.snth.net/wp-content/uploads/2008/08/orion-big.png' title='orion-big.png'><img src='http://aoeu.snth.net/wp-content/uploads/2008/08/orion.png' alt='Orion' /></a></div>
<p></p>
<p>Click the image for a larger version. While the larger image will show more detail, it will be more difficult to view, as it will require you to cross your eyes farther.</p>
<p>To find other examples to practice upon, search Google Images for &ldquo;<a href="http://images.google.com/images?gbv=2&#038;hl=en&#038;q=cross+eye+stereo+pair&#038;btnG=Search+Images">cross eye stereo pair</a>&rdquo;.</p>
]]></content:encoded>
			<wfw:commentRss>http://aoeu.snth.net/?feed=rss2&amp;p=85</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
