<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8648559575280961442</id><updated>2012-02-16T14:45:57.795-08:00</updated><category term='python boost'/><category term='glsl wireframe'/><title type='text'>Clipping Space</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>54</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2233137662837778346</id><published>2011-10-24T20:16:00.000-07:00</published><updated>2011-10-25T21:52:15.030-07:00</updated><title type='text'>Upgrage to Ubuntu 11</title><content type='html'>&lt;b&gt;Broken Upgrade Dialog - Bad Omen&lt;/b&gt;&lt;br /&gt;With the release 11.10, my previous version of Ubuntu started receiving popup dialogs urging me to upgrade to the latest and greatest. &amp;nbsp;Options: "Don't Ask Again", "Ask Me Later", and "Upgrade Now" (more or less). &amp;nbsp;I had postponed the upgrade several times because I'm usually wary to upgrade since Ubuntu seems to have had many rough edges as of late. &amp;nbsp;I noticed "Ask Me Later" did nothing, not even close the dialog, so I had simply killed it myself. &amp;nbsp;Bad omen, I guess. &amp;nbsp;In the dialog I also saw some type of web-based page with some of the new features offered. &amp;nbsp;Much of it was cropped off in the little dialog. &amp;nbsp;Not only was the dialog non-resizeable so I couldn't expand this small page to see the new features, my mouse wheel didn't respect it so I had to use the painful overlay scrollbars that came out in 11.04 (more on that later). &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dash Improvements&lt;/b&gt;&lt;br /&gt;There have been several improvements on the dash including expanded right-click support. &amp;nbsp;Some tasks have more functionality like the terminal button can open new windows and the CD/DVD button has standard options you'd expect like "Eject" or "Open". &amp;nbsp;Still a little confused about what options come from where. &amp;nbsp;I can't create new windows for chrome, but can for firefox. &amp;nbsp;Not sure what the distinction is besides some internal setting allowing firefox to do this. &amp;nbsp;Seems like if there were a default, it would be to allow the user to have as many sessions opened of whatever as they want. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-9vTBLTN-WIM/TqYGKFNDEPI/AAAAAAAABSk/WBAc2136SBg/s1600/improved_dash.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-9vTBLTN-WIM/TqYGKFNDEPI/AAAAAAAABSk/WBAc2136SBg/s320/improved_dash.png" width="109" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The workspace icon still has no options to change the number of workspaces (at least via right-click). &amp;nbsp;I like to have around ten. &amp;nbsp;I'm told I can install compiz to configure this, but why don't I just get the option via right-click to bring up a properties dialog. &amp;nbsp;If it's important enough to be on the Dash by default, why doesn't it get custom options? &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Global Menu&lt;/b&gt;&lt;br /&gt;The global menu is still a little rough. &amp;nbsp;As mentioned on several other sites, LibreOffice isn't configured correctly to use this menu, which isn't a big deal. &amp;nbsp;The bigger problem lies with multi-window programs like gimp, which are incredibly annoying to deal with. &amp;nbsp;If the main window is not selected, the global menu defaults to... nothing. &amp;nbsp;That means if I change a layer or select a tool, I have to go back and select the main window to access the menu options at the top of the screen. &amp;nbsp;To me, this seems to be a bug in Unity. &amp;nbsp;On the other hand, how should it behave if the subwindow has its own menu? &amp;nbsp;In the short couple of days using 11.10, this has been an extreme annoyance using gimp. &amp;nbsp;I don't like how the menu is even hidden until mouseover, but that's another direction the Ubuntu team has taken up as a design goal (more on that later). &amp;nbsp;I don't care how familiar one gets with the menu layout in your applet of choice. &amp;nbsp;The fact of the matter is menu items are now harder to find because one has to move the mouse up the the menubar, wait for the menu to appear, and then move over to it. &amp;nbsp;I'm convinced this will slow down every single trip to the menu and I'm hoping the designers of this feature go crazy over it and disable the hiding in the next release. &amp;nbsp;While it doesn't make any sense to copy Apple's design decisions for the sake of copying Apple's design decisions, the fact that they don't do this should merit some serious thought as to why they didn't. &amp;nbsp;It's slower to use. &amp;nbsp;Period. &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Tc2FtCjFHIM/TqYIDaBjY0I/AAAAAAAABSs/LzSfasif4BU/s1600/libre_menus.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="140" src="http://1.bp.blogspot.com/-Tc2FtCjFHIM/TqYIDaBjY0I/AAAAAAAABSs/LzSfasif4BU/s320/libre_menus.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;can just use default scroll bars&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-jRcR_P5kD78/TqYJatofOhI/AAAAAAAABS0/g3MhPHCoYAM/s1600/gimp_main.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="271" src="http://3.bp.blogspot.com/-jRcR_P5kD78/TqYJatofOhI/AAAAAAAABS0/g3MhPHCoYAM/s320/gimp_main.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;main window selected - main menu accessible&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-v_j3ZZzycLk/TqYJiFLTbtI/AAAAAAAABS8/Dp73499Xis0/s1600/gimp_secondary.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="271" src="http://2.bp.blogspot.com/-v_j3ZZzycLk/TqYJiFLTbtI/AAAAAAAABS8/Dp73499Xis0/s320/gimp_secondary.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;secondary window selected - no menu for you :(&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Speaking of the menubar at the top, I've caught myself dragging windows close to the top of the screen and accidentally maximized them. &amp;nbsp;The double-click still works, so I don't know why a user would need a secondary option that potentially isn't what they really want to do. &amp;nbsp;I have multiple windows up side by side all the time and this just makes resizing them all the more annoying. &amp;nbsp;I can work around this issue by being more careful, but its a pointless feature that does nothing but increase the possibility of the desktop manager doing something other than intended. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Overlay Scrollbars&lt;/b&gt;&lt;br /&gt;While some of the features I've discussed were introduced in 11.04, I'm seeing them now as I've finally moved away from the classic interface, and committed myself to becoming comfortable with this new version. &amp;nbsp;One feature that's appeared (or disappeared) in Ubuntu 11 is the scrollbars as many know and love. &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The goal is to help people immerse themselves in their stuff, without being burdened with large amounts of widgetry which isn’t relevant to the thing they are trying to concentrate on. And when it comes to widgetry, there are few things left which take up more space than scrollbars. --Mark Shuttleworth&lt;/blockquote&gt;&lt;br /&gt;As mentioned earlier, Ubuntu designers have publicly stated the design goal to reduce the amount of "widgetry" on the page. &amp;nbsp;Mark Shuttleworth actually has a lengthy &lt;a href="http://www.markshuttleworth.com/archives/615"&gt;blog post&lt;/a&gt; on this topic and delves into great description of this new scrollbar design. &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-T0pl2yKE1bw/TqYdkoGglJI/AAAAAAAABTE/dfid_BVte14/s1600/overlay_scrollbar.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/-T0pl2yKE1bw/TqYdkoGglJI/AAAAAAAABTE/dfid_BVte14/s320/overlay_scrollbar.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;one overlay scrollbar among many&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;People are usually resistant to change and I certainly have to work as hard as most to take things in with an open mind. &amp;nbsp;At first I felt they had a webpage-javascript-menu feel to them, but I'm starting to tolerate them. &amp;nbsp;Unlike Mac OS X Lion, which has also recently removed the scrollbar in a similar fashion (to the dismay of some much frustrated users), Ubuntu at least keeps a small sliver of bar on the screen at all times to give an idea of where the user is on the page. &lt;br /&gt;&lt;br /&gt;Ignoring the pomp and circumstance the Ubuntu design team seems to have made over the rollout of this feature (almost to a ridiculous level of pride), I really think it is a rather useless and even problematic problem for several reasons. &lt;br /&gt;&lt;br /&gt;First, the display of these overlay scrollbars is application dependent. &amp;nbsp;As shown in the picture above, only one window in this particular screenshot uses this feature. &amp;nbsp;Since most of the time I'm in a web browser or my own IDE, I won't see this new feature they seem so proud of. &amp;nbsp;Having multiple types of scrollbars on the page seems to go against years of work Linux developers have done to get a consistent visual style across applications using different libraries, yet Ubuntu obviously felt reducing widgetry on a few of their applications was more important. &amp;nbsp;While this isn't a terrible problem for me, it also makes it harder to get used to as I'm now using normal scrollbars 95% of the time and the overlay scrollbars when I open up one of their Ubuntu-based apps. &amp;nbsp;I have to remember that the lack of scrollbar doesn't mean there's nothing to scroll. &amp;nbsp;So while Ubuntu is very proud of this feature, it just creates unneeded variation between windows at very little benefit except for making Ubuntu-related screenshots prettier. &lt;br /&gt;&lt;br /&gt;Second, when innovating new design features, it's really important (to me at least), to justify the change. &amp;nbsp;Christian Giordano, one of the main implementers of the design, actually has a lengthy post, &lt;a href="http://design.canonical.com/2011/03/introducing-overlay-scrollbars-in-unity/"&gt;Introducing Overlay Scrollbars in Unity&lt;/a&gt;, discussing the overall design goals of the project. &amp;nbsp;He notes that removing "widgetry"--something they've obviously succeeded at--is one of the motivations to "provide a more immersive experience". &amp;nbsp;That's a nice way of saying prettier. &amp;nbsp;Regaining screenspace is hardly a problem given the 15-pixel-wide widget is a sliver on a one-to-two-thousand-pixel-wide screen. &amp;nbsp;He also adds an seemlingly ignored prerequisite in that it "shouldn’t conflict with the window resizing functionalities". &amp;nbsp;I think this has been brushed over by many critics. &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-dr7UwJnXqgg/TqYls9VYEaI/AAAAAAAABTM/gtUva5LmRHE/s1600/overlay_scrollbar_resizing.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="262" src="http://4.bp.blogspot.com/-dr7UwJnXqgg/TqYls9VYEaI/AAAAAAAABTM/gtUva5LmRHE/s320/overlay_scrollbar_resizing.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;shown in red, these are the areas of the border I&lt;br /&gt;must now use to resize that side of the window&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;As shown above, resizing has indeed been affected. &amp;nbsp;The amount of content off page determines how much border real estate one has to resize the window. &amp;nbsp;The designers added a feature so if one mouses over the overlay for a certain amount of time (~3 seconds), it will dissolve out and one can resize using the full border. &amp;nbsp;I'm not interested in waiting to resize my window. &amp;nbsp;I have a feeling this will annoy many who mouse over the scrollbar while reading to get ready to move down the page only to click and find the scrollbar has since evaporated. &lt;br /&gt;&lt;br /&gt;Why not just use a scroll wheel, one might ask? &amp;nbsp;Well, I have a scroll wheel so this doesn't greatly affect me (except in certain cases as described in the beginning where Ubuntu has overlay scrollbars, but doesn't respect the scroll wheel). &amp;nbsp;However, many users out there still don't have scroll wheels on their mouse. &amp;nbsp;70% of Apple computers sold have built-in touchpads, and all iMacs come with Apple's smart mouse with a built-in trackpad of sorts as the base mouse. &amp;nbsp;I do not expect similar numbers for Ubuntu Linux users--many of whom are probably using outdated lab machines without any scroll wheel on the keyboard or mouse. &lt;br /&gt;&lt;br /&gt;Despite all my whining, it is apparently possible to &lt;a href="http://www.webupd8.org/2011/04/how-to-disable-overlay-scrollbars-in.html"&gt;disable&lt;/a&gt; the feature, but again, why put it in there in the first place? &amp;nbsp;While Ubuntu has been a pleasure over the last few years as a stable and user-friendly operating system, the new UI-drive championed by Shuttleworth has made for a rockier transition between iterations and bugs have become more and more common during upgrades. &amp;nbsp;While I'll probably continue with Ubuntu for awhile, I'm hoping they'll change their focus to something that will really improve my desktop experience... like building device drivers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;&lt;i&gt;I got a bit of feedback from a few sources regarding my closing comment on device drivers--one in particular angrily commenting that it's device manufacturers' responsibility to create Linux drivers. &amp;nbsp;I try not to go into debates online as I feel like one can &lt;a href="http://xkcd.com/438/"&gt;argue online&lt;/a&gt; with a stranger for hours, with whom I might find some quick concensus in person. &amp;nbsp;I've seen this phenomenon even with family members, where online arguments seem to flair over otherwise menial things. &amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Anyway, despite my preference for Linux, I'm of the mind that a manufacturer has little moral or ethical obligation to write Linux drivers. &amp;nbsp;While driver availability for certain products has certainly improved a lot in the last ten years, its still in a very poor,&amp;nbsp;&lt;a href="http://www.apreche.net/linux-doesnt-lack-drivers-it-lacks-complete-drivers/"&gt;incomplete state&lt;/a&gt;. &amp;nbsp;Saying manufacturers "should" write their own drivers for non-profitable platforms is a little idealistic, simply shown by the fact that so many new and popular devices don't support Linux. &amp;nbsp;As such, I was just stating that Ubuntu's engineers would do better in my opinion joining the ranks of many other Linux-advocating contributors by coordinating, creating, and polishing Linux drivers. &amp;nbsp;And that's all I have to say about that. &amp;nbsp;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2233137662837778346?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2233137662837778346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2233137662837778346' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2233137662837778346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2233137662837778346'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/10/upgrage-to-11.html' title='Upgrage to Ubuntu 11'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-9vTBLTN-WIM/TqYGKFNDEPI/AAAAAAAABSk/WBAc2136SBg/s72-c/improved_dash.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6854411038312952934</id><published>2011-09-11T08:10:00.000-07:00</published><updated>2011-09-11T08:38:20.322-07:00</updated><title type='text'>Single-Pass Wireframe Rendering Explained and Extended</title><content type='html'>I got a pretty good followup in my previous post with how to implement &lt;a href="http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html"&gt;"Single-Pass Wireframe Rendering"&lt;/a&gt;.  I thought I'd take a second to briefly explain how the edge detection actually worked.  &lt;br /&gt;&lt;br /&gt;As I said before, the basic idea is that we want each fragment to know about how far it is from any given edge so we can color it appropriately. &amp;nbsp;First, we have to remember that OpenGL is an interpolation engine and it is very good at that. &amp;nbsp;When some attribute is assigned to a vertex and the triangle is rasterized, fragments created inside that triangle get some interpolated value of that attribute depending on how far it is from the surrounding vertices. &lt;br /&gt;&lt;br /&gt;Shown below, a triangle has a three-channel attribute assigned to each vertex. &amp;nbsp;In the fragment shader, those values will be some mixture of the three channels. &amp;nbsp;You'll notice, for example that the triangle in the image below gets less red from left to right. &amp;nbsp;The first RGB channel starts at 1, but as one moves towards that channel goes to zero.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MQAsgQKjNDs/TmyWrBZnzXI/AAAAAAAABR0/dMkq9MeDHHg/s1600/interpolation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="282" src="http://3.bp.blogspot.com/-MQAsgQKjNDs/TmyWrBZnzXI/AAAAAAAABR0/dMkq9MeDHHg/s320/interpolation.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;That's the basic gist of the attribute interpolation. &amp;nbsp;The nice thing about modern GPUs is it lets us put anything we want in these attributes. &amp;nbsp;They may be used in the fragment shader as colors, normals, texture coordinates, etc. &amp;nbsp; but OpenGL doesn't really care about how you plan on using these attributes as they all get interpolated the same way. &amp;nbsp;In the fragment shader, we can decide how to make sense of the interpolated values. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Finding Edges Programmatically&lt;/b&gt;&lt;br /&gt;Notice the pixel values along the top-left area of the triangle above have a low green value because the left and top vertices have no green in them, so pixels moving towards that edge have less and less green. &amp;nbsp;Similarly, the right side of the triangle has pretty much no red in it, because the values in the vertices above and below it have no red. &amp;nbsp;The same holds true for the bottom edge of the triangle having no blue. &amp;nbsp;The insight to be gained here and which is used in "Single-Pass Wireframe Rendering" is that values along the edges of the triangle will have a very low value in at least one of the three channels. &amp;nbsp;If ANY of the channels is close to zero, that fragment is sitting on or very near an edge. &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-CyWq6xkuKQY/TmyfjvNwCII/AAAAAAAABR4/bvRFzivmMdY/s1600/altitudes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-CyWq6xkuKQY/TmyfjvNwCII/AAAAAAAABR4/bvRFzivmMdY/s400/altitudes.png" width="368" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;images taken from nVidia's&amp;nbsp;&lt;a href="http://developer.download.nvidia.com/whitepapers/2007/SDK10/SolidWireframe.pdf"&gt;Solid Wireframe&lt;/a&gt;&amp;nbsp;paper&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;We could just assign similar values as here and just render edges if the value is below some threshold. &amp;nbsp;The problem, though, is that these values aren't in viewport space and we probably want to measure our line thickness in terms of pixels. &amp;nbsp;Otherwise the edge thickness on our screen would change depending on the size of the triangle (maybe you want that, whatever). &lt;br /&gt;&lt;br /&gt;As shown in the picture above, we calculate the altitudes of each vertex in screen space and store them in some vertex attribute. &amp;nbsp;In the fragment shader, the value (d0,d1,d2) will be somewhere between the three vertex attributes. &amp;nbsp;As described above, if any of these channels d0, d1 or d2 is close to zero, that means we're sitting on an edge. &lt;br /&gt;&lt;br /&gt;nVidia has an excellent paper called&amp;nbsp;&lt;a href="http://developer.download.nvidia.com/whitepapers/2007/SDK10/SolidWireframe.pdf"&gt;Solid Wireframe&lt;/a&gt;, which goes into a bit more detail how this works and provides some really great illustrations. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Excluding Edges on polygons&lt;/b&gt;&lt;br /&gt;While rendering edges is nice, I may not want every edge of a given triangle to be rendered. &amp;nbsp;For example, if I have some five-sided polygon concave polygon that I break into triangles using some technique like ear clipping (&lt;a href="http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf"&gt;pdf&lt;/a&gt;), I may not want the interior edges inside the polygon to be rendered. &lt;br /&gt;&lt;br /&gt;A simple way to exclude an edge of a given polygon is to make sure that that value never goes to zero by setting the channels of the other vertices to some high amount &lt;i&gt;Q&lt;/i&gt;. &amp;nbsp;This &lt;i&gt;Q &lt;/i&gt;can be any&amp;nbsp;value higher than your maximum edge-width. &amp;nbsp;In my program, I set it to 100 since I'll probably never be drawing edges thicker than that. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-k9qIcifyxXA/Tmyofzsn2dI/AAAAAAAABSA/dRIPd2DxUFA/s1600/edge_removal.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-k9qIcifyxXA/Tmyofzsn2dI/AAAAAAAABSA/dRIPd2DxUFA/s400/edge_removal.png" width="368" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;If &lt;i&gt;Q&lt;/i&gt; is relatively high, fragments along that edge will not have low values in any channel&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Designating which edges to exclude requires an additional vertex attribute sent down from the program. &amp;nbsp;I attach a float to each vertex with a 0 or 1 whether or not I want to exclude that edge from being rendered. &amp;nbsp;I then update my geometry shader accordingly. &lt;br /&gt;&lt;br /&gt;my updated vertex shader...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#version 120&lt;br /&gt;#extension GL_EXT_gpu_shader4 : enable&lt;br /&gt;in vec3 vertex;&lt;br /&gt;in vec4 color;&lt;br /&gt;in vec3 normal;&lt;br /&gt;in float excludeEdge;&lt;br /&gt;varying vec3 vertWorldPos;&lt;br /&gt;varying vec3 vertWorldNormal;&lt;br /&gt;&lt;u&gt;varying float vertExcludeEdge;&lt;/u&gt;&lt;br /&gt;uniform mat4 objToWorld;&lt;br /&gt;uniform mat4 cameraPV;&lt;br /&gt;uniform mat4 normalToWorld;&lt;br /&gt;void main() {&lt;br /&gt;vertWorldPos = (objToWorld * vec4(vertex,1.0)).xyz;&lt;br /&gt;vertWorldNormal = (normalToWorld * vec4(normal,1.0)).xyz;&lt;br /&gt;gl_Position = cameraPV * objToWorld * vec4(vertex,1.0);&lt;br /&gt;&lt;u&gt;vertExcludeEdge = excludeEdge;&lt;/u&gt;&lt;br /&gt;gl_FrontColor = color;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and my updated geometry shader...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#version 120&lt;br /&gt;#extension GL_EXT_gpu_shader4 : enable&lt;br /&gt;#extension GL_EXT_geometry_shader4 : enable&lt;br /&gt;varying in vec3 vertWorldPos[3];&lt;br /&gt;varying in vec3 vertWorldNormal[3];&lt;br /&gt;&lt;u&gt;varying in float vertExcludeEdge[3];&lt;/u&gt;&lt;br /&gt;varying out vec3 worldNormal;&lt;br /&gt;varying out vec3 worldPos;&lt;br /&gt;uniform vec2 WIN_SCALE;&lt;br /&gt;noperspective varying vec3 dist;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;&lt;u&gt;float MEW = 100.0; // max edge width&lt;/u&gt;&lt;br /&gt;// adapted from 'Single-Pass Wireframe Rendering'&lt;br /&gt;vec2 p0 = WIN_SCALE * gl_PositionIn[0].xy/gl_PositionIn[0].w;&lt;br /&gt;vec2 p1 = WIN_SCALE * gl_PositionIn[1].xy/gl_PositionIn[1].w;&lt;br /&gt;vec2 p2 = WIN_SCALE * gl_PositionIn[2].xy/gl_PositionIn[2].w;&lt;br /&gt;vec2 v0 = p2-p1;&lt;br /&gt;vec2 v1 = p2-p0;&lt;br /&gt;vec2 v2 = p1-p0;&lt;br /&gt;float area = abs(v1.x*v2.y - v1.y * v2.x);&lt;br /&gt;dist = vec3(area/length(v0),&lt;u&gt;vertExcludeEdge[1]*MEW,vertExcludeEdge[2]*MEW&lt;/u&gt;);&lt;br /&gt;worldPos = vertWorldPos[0];&lt;br /&gt;worldNormal = vertWorldNormal[0];&lt;br /&gt;gl_Position = gl_PositionIn[0];&lt;br /&gt;EmitVertex();&lt;br /&gt;dist = vec3(&lt;u&gt;vertExcludeEdge[0]*MEW&lt;/u&gt;,area/length(v1),&lt;u&gt;vertExcludeEdge[2]*MEW&lt;/u&gt;);&lt;br /&gt;worldPos = vertWorldPos[1];&lt;br /&gt;worldNormal = vertWorldNormal[1];&lt;br /&gt;gl_Position = gl_PositionIn[1];&lt;br /&gt;EmitVertex();&lt;br /&gt;dist = vec3(&lt;u&gt;vertExcludeEdge[0]*MEW,vertExcludeEdge[1]*MEW&lt;/u&gt;,area/length(v2));&lt;br /&gt;worldPos = vertWorldPos[2];&lt;br /&gt;worldNormal = vertWorldNormal[2];&lt;br /&gt;gl_Position = gl_PositionIn[2];&lt;br /&gt;EmitVertex();&lt;br /&gt;EndPrimitive();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-2JvwZUykkro/TmypCdShfuI/AAAAAAAABSE/sURqGJqKlJ0/s1600/edges.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="350" src="http://1.bp.blogspot.com/-2JvwZUykkro/TmypCdShfuI/AAAAAAAABSE/sURqGJqKlJ0/s400/edges.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Without edge removal, each triangle has its own edge&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-axAaFaBkw0E/TmyU3yO-p5I/AAAAAAAABRw/ym5asG6C3yw/s1600/no_diagonals.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="339" src="http://4.bp.blogspot.com/-axAaFaBkw0E/TmyU3yO-p5I/AAAAAAAABRw/ym5asG6C3yw/s400/no_diagonals.png" width="362" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Triangle mesh rendered excluding certain edges&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6854411038312952934?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6854411038312952934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6854411038312952934' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6854411038312952934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6854411038312952934'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html' title='Single-Pass Wireframe Rendering Explained and Extended'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-MQAsgQKjNDs/TmyWrBZnzXI/AAAAAAAABR0/dMkq9MeDHHg/s72-c/interpolation.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1736398767827896343</id><published>2011-09-10T08:20:00.000-07:00</published><updated>2011-09-10T08:41:53.588-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='glsl wireframe'/><title type='text'>Single-Pass Wireframe Rendering</title><content type='html'>It came time for me to add a wireframe to my mesh and just when I was about to do the standard two-pass approach of rendering out my mesh faces and then rendering my wireframe with GL_LINES over that, I came across&amp;nbsp;&lt;a href="http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/4884/pdf/imm4884.pdf"&gt;Single-Pass Wireframe Rendering&lt;/a&gt;, a simple idea for rendering my faces and lines in just one pass. &amp;nbsp;The idea, to put it simply, is to add some smarts to the fragment code so when it's rendering fragments close to the sides of a face, it blends in an edge color. &amp;nbsp;The paper gives several reasons why this is a better approach including better performance and some really cool added abilities. &amp;nbsp;The best part is it's very easy to add to existing code without much modification.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Adding the Geometry Shader&lt;/b&gt;&lt;br /&gt;My code already had a basic vertex/fragment shader for doing some basic lighting and I just needed to add geometry shader in between that could add an attribute to each vertex specifying how far the fragment would be from the edge in screen space. &lt;br /&gt;&lt;br /&gt;Here's the geometry shader taken almost straight from their full paper off their &lt;a href="http://www2.imm.dtu.dk/~jab/Wireframe/"&gt;site&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#version 120&lt;br /&gt;#extension GL_EXT_gpu_shader4 : enable&lt;br /&gt;#extension GL_EXT_geometry_shader4 : enable&lt;br /&gt;varying in vec3 vertWorldPos[3];&lt;br /&gt;varying in vec3 vertWorldNormal[3];&lt;br /&gt;varying out vec3 worldNormal;&lt;br /&gt;varying out vec3 worldPos;&lt;br /&gt;uniform vec2 WIN_SCALE;&lt;br /&gt;noperspective varying vec3 dist;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;  // taken from 'Single-Pass Wireframe Rendering'&lt;br /&gt;  vec2 p0 = WIN_SCALE * gl_PositionIn[0].xy/gl_PositionIn[0].w;&lt;br /&gt;  vec2 p1 = WIN_SCALE * gl_PositionIn[1].xy/gl_PositionIn[1].w;&lt;br /&gt;  vec2 p2 = WIN_SCALE * gl_PositionIn[2].xy/gl_PositionIn[2].w;&lt;br /&gt;  vec2 v0 = p2-p1;&lt;br /&gt;  vec2 v1 = p2-p0;&lt;br /&gt;  vec2 v2 = p1-p0;&lt;br /&gt;  float area = abs(v1.x*v2.y - v1.y * v2.x);&lt;br /&gt;&lt;br /&gt;  dist = vec3(area/length(v0),0,0);&lt;br /&gt;  worldPos = vertWorldPos[0];&lt;br /&gt;  worldNormal = vertWorldNormal[0];&lt;br /&gt;  gl_Position = gl_PositionIn[0];&lt;br /&gt;  EmitVertex();&lt;br /&gt;  dist = vec3(0,area/length(v1),0);&lt;br /&gt;  worldPos = vertWorldPos[1];&lt;br /&gt;  worldNormal = vertWorldNormal[1];&lt;br /&gt;  gl_Position = gl_PositionIn[1];&lt;br /&gt;  EmitVertex();&lt;br /&gt;  dist = vec3(0,0,area/length(v2));&lt;br /&gt;  worldPos = vertWorldPos[2];&lt;br /&gt;  worldNormal = vertWorldNormal[2];&lt;br /&gt;  gl_Position = gl_PositionIn[2];&lt;br /&gt;  EmitVertex();&lt;br /&gt;  EndPrimitive();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If you're already familiar with the vertex/fragment shader pipeline, which has been around quite a few years longer than the geometry shader, you'll recognize nothing is too out of the ordinary.  It takes a world position and normal, which is basically just passed off to the fragment shader for lighting purposes.  Although I've done quite a bit of GLSL, this was my first attempt at using a geometry shader, and once I learned the basic idea, I found it pretty intuitive.  &lt;br /&gt;&lt;br /&gt;First, there are &lt;strong&gt;varying&lt;/strong&gt; inputs from the vertex shader that come in as arrays--one element for each vertex.  The names have to match up, so for the &lt;strong&gt;in vec3 vertWorldPos[3]&lt;/strong&gt; attribute, there must be a corresponding &lt;b&gt;out vec3 vertWorldPos&lt;/b&gt; designated in the vertex shader.  The exception to this is predefined variables like &lt;b&gt;gl_Position&lt;/b&gt;, which comes in as &lt;b&gt;gl_PositionIn[]&lt;/b&gt;.  Not sure why the OpenGL designers decided to add those two letters, but whatever.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;WIN_SCALE&lt;/b&gt; is the screen size, which we multiply be the vertex position XY.  This takes our vertex positions in viewport space and converts them to screen space since we want to measure our distances in pixels in the fragment shader.  That's followed by some basic trig to calculate the area of the triangle, which is used to find the &lt;i&gt;altitude&lt;/i&gt; of each vertex (the closest distance to the opposing edge).  Because the altitude is already in screen space, the &lt;b&gt;noperspective&lt;/b&gt; keyword is added to disable perspective correction.  &lt;br /&gt;&lt;br /&gt;The geometry shader is responsible for actually creating the primitives via the &lt;b&gt;EmitVertex()&lt;/b&gt; and &lt;b&gt;EndPrimitive()&lt;/b&gt; functions.  When &lt;b&gt;EmitVertex()&lt;/b&gt; function is called, it sends a vertex down the pipeline with attributes based on whatever the &lt;b&gt;out&lt;/b&gt; attributes happen to be set to at the time.  &lt;b&gt;EndPrimitive()&lt;/b&gt; just tells OpenGL that the vertices already sent down are ready to be rasterized as a primitive.  &lt;br /&gt;&lt;br /&gt;The geometry shader can actually create additional geometry on the fly, but it comes with some caveats.  We must designate in our C++ code an upper bound of how many vertices we might want to create.  This geometry shader doesn't create any additional geometry, but it's still useful as it provides knowledge of the neighboring vertices to calculate the outgoing vertex altitudes.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Setting Up the Geometry Shader&lt;/b&gt;&lt;br /&gt;Using &lt;i&gt;Qt&lt;/i&gt;, the geometry shader is compiled just like the vertex and fragment shader.  &lt;br /&gt;&lt;code&gt;&lt;br /&gt;QGLShader* vertShader = new QGLShader(QGLShader::Vertex);&lt;br /&gt;vertShader-&amp;gt;compileSourceCode(vertSource);&lt;br /&gt;&lt;br /&gt;&lt;u&gt;QGLShader* geomShader = new QGLShader(QGLShader::Geometry);&lt;br /&gt;geomShader-&amp;gt;compileSourceCode(geomSource);&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;QGLShader* fragShader = new QGLShader(QGLShader::Fragment);&lt;br /&gt;fragShader-&amp;gt;compileSourceCode(fragSource);&lt;br /&gt;&lt;br /&gt;QGLShaderProgramP program = QGLShaderProgramP(new QGLShaderProgram(parent));&lt;br /&gt;program-&amp;gt;addShader(vertShader);&lt;br /&gt;&lt;u&gt;    program-&amp;gt;addShader(geomShader);&lt;/u&gt;&lt;br /&gt;program-&amp;gt;addShader(fragShader);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The only other adjustment is when we bind our shader.  Because the geometry shader can create more geometry than inputted, it requires giving OpenGL a heads up of how much geometry you might create.  You don't necessarily have to create all the vertices you allocate, but it's just a heads up for OpenGL.  You can all also configure the geometry shader to output a different type of primitive than inputted like creating &lt;b&gt;GL_POINTS&lt;/b&gt; from &lt;b&gt;GL_TRIANGLES&lt;/b&gt;.  Because this geometry shader is just taking a triangle in and outputting a triangle, we can just set the number of outgoing vertices to the number going in.  &lt;b&gt;GL_GEOMETRY_INPUT_TYPE&lt;/b&gt;, &lt;b&gt;GL_GEOMETRY_OUTPUT_TYPE&lt;/b&gt;, and &lt;b&gt;GL_GEOMETRY_VERTICES_OUT&lt;/b&gt; need to be specified prior to linking the shader.  &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;QGLShaderProgram* meshShader = panel-&amp;gt;getShader();&lt;br /&gt;&lt;br /&gt;// geometry-shader attributes must be applied prior to linking&lt;br /&gt;&lt;u&gt;meshShader-&amp;gt;setGeometryInputType(GL_TRIANGLES);&lt;/u&gt;&lt;br /&gt;&lt;u&gt;meshShader-&amp;gt;setGeometryOutputType(GL_TRIANGLES);&lt;/u&gt;&lt;br /&gt;&lt;u&gt;meshShader-&amp;gt;setGeometryOutputVertexCount(numTriangles*3);&lt;/u&gt;&lt;br /&gt;meshShader-&amp;gt;bind();&lt;br /&gt;meshShader-&amp;gt;setUniformValue("WIN_SCALE", QVector2D(panel-&amp;gt;width(),panel-&amp;gt;height()));&lt;br /&gt;meshShader-&amp;gt;setUniformValue("objToWorld", objToWorld);&lt;br /&gt;meshShader-&amp;gt;setUniformValue("normalToWorld", normalToWorld);&lt;br /&gt;meshShader-&amp;gt;setUniformValue("cameraPV", cameraProjViewM);&lt;br /&gt;meshShader-&amp;gt;setUniformValue("cameraPos", camera-&amp;gt;eye());&lt;br /&gt;meshShader-&amp;gt;setUniformValue("lightDir", -camera-&amp;gt;lookDir().normalized());&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We also need to modify the fragment shader to take this distance variable into account to see if our fragment is close to the edge.  &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#version 120&lt;br /&gt;#extension GL_EXT_gpu_shader4 : enable&lt;br /&gt;varying vec3 worldPos;&lt;br /&gt;varying vec3 worldNormal;&lt;br /&gt;&lt;u&gt;noperspective varying vec3 dist;&lt;/u&gt;&lt;br /&gt;uniform vec3 cameraPos;&lt;br /&gt;uniform vec3 lightDir;&lt;br /&gt;uniform vec4 singleColor;&lt;br /&gt;uniform float isSingleColor;&lt;br /&gt;void main() {&lt;br /&gt;// determine frag distance to closest edge&lt;br /&gt;&lt;u&gt;float nearD = min(min(dist[0],dist[1]),dist[2]);&lt;/u&gt;&lt;br /&gt;&lt;u&gt;float edgeIntensity = exp2(-1.0*nearD*nearD);&lt;/u&gt;&lt;br /&gt;vec3 L = lightDir;&lt;br /&gt;vec3 V = normalize(cameraPos - worldPos);&lt;br /&gt;vec3 N = normalize(worldNormal);&lt;br /&gt;vec3 H = normalize(L+V);&lt;br /&gt;vec4 color = isSingleColor*singleColor + (1.0-isSingleColor)*gl_Color;&lt;br /&gt;float amb = 0.6;&lt;br /&gt;vec4 ambient = color * amb;&lt;br /&gt;vec4 diffuse = color * (1.0 - amb) * max(dot(L, N), 0.0);&lt;br /&gt;vec4 specular = vec4(0.0);&lt;br /&gt;edgeIntensity = 0.0;&lt;br /&gt;&lt;br /&gt;// blend between edge color and normal lighting color&lt;br /&gt;&lt;u&gt;gl_FragColor = (edgeIntensity * vec4(0.1,0.1,0.1,1.0)) + ((1.0-edgeIntensity) * vec4(ambient + diffuse + specular));&lt;/u&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And that's it!  It takes a bit more work to get it working with quads, but once done you can do some pretty wild and awesome tricks as shown on the author's &lt;a href="http://www2.imm.dtu.dk/~jab/Wireframe/"&gt;wireframe site&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-bBs2afJfS7g/Tmt_zLoC1oI/AAAAAAAABRg/s0zQFIqwLek/s1600/no_edges.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="356" src="http://4.bp.blogspot.com/-bBs2afJfS7g/Tmt_zLoC1oI/AAAAAAAABRg/s0zQFIqwLek/s400/no_edges.png" width="367" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Before&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HeAp4RFR5Kw/Tmt_zRnsutI/AAAAAAAABRo/Kb8wQO-UNbU/s1600/edges.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="330" src="http://3.bp.blogspot.com/-HeAp4RFR5Kw/Tmt_zRnsutI/AAAAAAAABRo/Kb8wQO-UNbU/s400/edges.png" width="377" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;After&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And here's the vertex shader for reference, but as you can see it's quite simple because a bit of the processing it's did has been moved to the geometry shader.  Nothing here really even has to do with the edge rendering.  &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#version 120&lt;br /&gt;#extension GL_EXT_gpu_shader4 : enable&lt;br /&gt;in vec3 vertex;&lt;br /&gt;in vec4 color;&lt;br /&gt;in vec3 normal;&lt;br /&gt;varying vec3 vertWorldPos;&lt;br /&gt;varying vec3 vertWorldNormal;&lt;br /&gt;uniform mat4 objToWorld;&lt;br /&gt;uniform mat4 cameraPV;&lt;br /&gt;uniform mat4 normalToWorld;&lt;br /&gt;void main() {&lt;br /&gt;  vertWorldPos = (objToWorld * vec4(vertex,1.0)).xyz;&lt;br /&gt;  vertWorldNormal = (normalToWorld * vec4(normal,1.0)).xyz;&lt;br /&gt;  gl_Position = cameraPV * objToWorld * vec4(vertex,1.0);&lt;br /&gt;  gl_FrontColor = color;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1736398767827896343?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1736398767827896343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1736398767827896343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1736398767827896343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1736398767827896343'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html' title='Single-Pass Wireframe Rendering'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-bBs2afJfS7g/Tmt_zLoC1oI/AAAAAAAABRg/s0zQFIqwLek/s72-c/no_edges.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2817222390033811380</id><published>2011-09-07T06:02:00.000-07:00</published><updated>2011-09-07T06:14:35.088-07:00</updated><title type='text'>Sunshine: Fixed Normals</title><content type='html'>I'm finally starting to make some noticeable headway in my Sunshine app. &amp;nbsp;It feels like everything I do has such a little impact on the UI, but then I tell myself it's all "infrastructure" and soon I'll be able to start adding features like crazy. &amp;nbsp;I'm probably lying to myself. &lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-9kn4K2PZP5M/TmdmGGaICeI/AAAAAAAABRQ/O-xSl1UsNk4/s1600/fixed_normals.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="258" src="http://1.bp.blogspot.com/-9kn4K2PZP5M/TmdmGGaICeI/AAAAAAAABRQ/O-xSl1UsNk4/s400/fixed_normals.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Imported lamp OBJ with calculated normals&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;Infrastructure - boost::python bindings&lt;/b&gt;&lt;br /&gt;After a lot of help from the boost::python mailing list, I've managed to expose my Scene object to python. &amp;nbsp;Although there isn't a lot of the C++ code exposed, the "infrastructure" for it is there so I can expose classes and individual functions quickly on a need-to-expose basis. &amp;nbsp;Right now I have a python script, which compiles to a Qt resource in the binary and use it to import OBJs. &amp;nbsp;Although it's fairly generic (lacks material support, ignores normals/UVs), it would be plenty trivial to import other geometry types with very little effort. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fixed Normals&lt;/b&gt;&lt;br /&gt;As I mentioned, I'm ignoring the normals provided in the lamp OBJ for now and recompute the normals per face (no smoothing). &amp;nbsp;I've had a bug in the fragment shader for the longest time that I've ignored until I started moving the cube mesh away from the origin. &amp;nbsp;Looking at the GLSL, it looks like I was transforming my incoming normal by my object-to-world. &amp;nbsp;That made the translation factor muck up the vector. &amp;nbsp;I ended up adding a normal object-to-world matrix that right now just consists of the model rotation matrix. &amp;nbsp;It looks a lot better! &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Basic Features&lt;/b&gt;&lt;br /&gt;Import OBJs&lt;br /&gt;Write python-based mesh importers&lt;br /&gt;Tumble around scene in Maya-like camera&lt;br /&gt;Render "test" to aqsis window&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Next Step&lt;/b&gt;&lt;br /&gt;Add a face mode and some tools (?in python?)&lt;br /&gt;Send scene to aqsis&lt;br /&gt;Make render settings (resolution at least) adjustable&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Download&lt;/b&gt;&lt;br /&gt;&lt;a href="https://github.com/strattonbrazil/Sunshine"&gt;https://github.com/strattonbrazil/Sunshine&lt;/a&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2817222390033811380?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2817222390033811380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2817222390033811380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2817222390033811380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2817222390033811380'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/09/sunshine-fixed-normals.html' title='Sunshine: Fixed Normals'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-9kn4K2PZP5M/TmdmGGaICeI/AAAAAAAABRQ/O-xSl1UsNk4/s72-c/fixed_normals.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1473398937084835246</id><published>2011-09-03T09:05:00.000-07:00</published><updated>2011-09-03T09:12:39.439-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python boost'/><title type='text'>Adding Python Support using Boost::Python</title><content type='html'>&lt;b&gt;Choosing an Embedded Language&lt;/b&gt;&lt;br /&gt;In my multi-year toy project, I decided it would be useful to incorporate an embedded programming language into the app to make adding features a little easier. &amp;nbsp;It basically came down to three possible languages that I thought would be appropriate: python, javascript, and lua. &amp;nbsp;Lua is known for being light-weight and fast, and is used in many games like World of Warcraft to provide scripting to the user. &amp;nbsp;Javascript itself seems to have had a bit of a resurgence in recent years in terms of stepping outside of web development. &amp;nbsp;Both languages have a variety of implementations that seemed workable including luabind for lua and V8 (produced by Google) for javascript specificially for embedding into an application. &amp;nbsp;Both provide a reasonable interface for mapping C++ classes. &lt;br /&gt;&lt;br /&gt;Although both languages seemed appealing, I wasn't really satisfied with how the mappings were written to expose the C++ classes. &amp;nbsp;Also, I have much more experience with python, so I had to decide if I wanted to learn how to bind a scripting engine to my application AND learn a new scripting language. &amp;nbsp;I've done quite a bit of javascript, but never for a large application and wasn't sure how well things would map between it and C++, as both lua and javascript don't technically support objects the same way as python. &amp;nbsp;I finally decided just to go with python. &amp;nbsp;Although not as fast or light-weight as lua or javascript, I felt it provided a better one-to-one mapping of my classes, and figured users might be more comfortable with a more C-like language for application scripting. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Which Python Binding?&lt;/b&gt;&lt;br /&gt;I ended up trying several different libraries to embed python into my app. &amp;nbsp;&lt;a href="http://pythonqt.sourceforge.net/"&gt;PythonQt&lt;/a&gt; seemed like a good candidate as I was writing my app using the &lt;i&gt;Qt&lt;/i&gt;&amp;nbsp;libraries, but I encountered a few strange bugs and the community seemed to be stagnating--unfortunate as the API seemed really intuitive. &amp;nbsp;Both &lt;a href="http://wiki.python.org/moin/SIP"&gt;SIP&lt;/a&gt; and &lt;a href="http://www.swig.org/"&gt;SWIG&lt;/a&gt; are popular for binding, but both require a special syntax in external files, and I wanted to modify my qmake build as little as possible and didn't want to learn a new syntax. &amp;nbsp;After finally experimenting with &lt;a href="http://www.boost.org/doc/libs/1_47_0/libs/python/doc/"&gt;boost::python&lt;/a&gt;, I found the library allowed me to write my mappings inside C++ without learning any new syntax or much with my build system. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using boost::python&lt;/b&gt;&lt;br /&gt;I had a Scene class, which naturally handles everything in my scene, which I wanted to expose to python. &amp;nbsp;&lt;i&gt;boost::python&lt;/i&gt; has a special function called &lt;i&gt;BOOST_PYTHON_MODULE&lt;/i&gt;, which puts a class into a particular module, which is imported into python. &amp;nbsp;Once wrapping my Scene class with the &lt;i&gt;class_&lt;/i&gt;&amp;nbsp;function, I could then import the Scene class into python from the "scene" module. &amp;nbsp;The&lt;i&gt;&amp;nbsp;boost::noncopyable&lt;/i&gt;&amp;nbsp;is an optional argument that notes not to pass the Scene object to python by value, since my scene might be rather large in memory and I didn't want multiple copies. &amp;nbsp;This is more of a compiler rule as I still have to make sure I'm not passing the scene by value, but with that I get a compiler error if I try. &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;BOOST_PYTHON_MODULE(scene)&lt;/code&gt;&lt;br /&gt;&lt;code&gt;{&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; class_&amp;lt;Scene, boost::noncopyable&amp;gt;("Scene");&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I have also been trying to use smart pointers for heap-allocated objects. &amp;nbsp;I started out using QSharedPointer, but boost::shared_ptr is already supported by boost, so I ended up switching my smart pointers over to boost's. &lt;br /&gt;&lt;code&gt;typedef boost::shared_ptr&lt;scene&gt; SceneP;&lt;/scene&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sending Yourself to Python&lt;/b&gt;&lt;br /&gt;Once that is setup, I could then pass my Scene object over to python. &amp;nbsp;I immediately hit a snag. &amp;nbsp;In particular to my Scene class, the Scene actually contained my python engine and called the python code. &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object ignored = exec(EXAMPLE_PY_FUNCTION, pyMainNamespace);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object processFileFunc = pyMainModule.attr("Foo").attr("processFile");&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; processFileFunc(this, "test.txt"); // "this" being the Scene object&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Although I created the scene in a smart pointer outside the class, I didn't have access to that smart pointer inside member functions to pass to python unless I passed it into the function, which seemed unnecessary to pass a Scene member function a smart pointer to itself. &amp;nbsp;I couldn't use "this" inside the member function as boost::python wouldn't know by default how to keep that in memory since other boost pointers were already pointing to my Scene object. &amp;nbsp;I couldn't just create a &lt;i&gt;shared_ptr &lt;/i&gt;in the function either, because I didn't want my Scene deleted when the shared pointer goes out of scope when the function returns. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I was actually getting this error because boost didn't know how to deal with the &lt;i&gt;this&lt;/i&gt;&amp;nbsp;pointer without passing it by value (which I explicitly said I didn't want copied, right?). &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;Error in Python: &lt;type 'exceptions.typeerror'=""&gt;: No to_python&lt;/type&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;(by-value) converter found for C++ type: Scene&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It turns out boost::python has a special way to do deal with this&amp;nbsp;situation using a special class called &amp;nbsp;&lt;i&gt;boost::enable_shared_from_this&lt;/i&gt;, which my Scene class can inherit from. &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;class Scene : public boost::enable_shared_from_this&amp;lt;Scene&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;boost::enable_shared_from_this&lt;/i&gt;&amp;nbsp;provides two functions that allow the Scene object to create shared pointers inside member functions by calling&amp;nbsp;&lt;i&gt;shared_from_this()&lt;/i&gt;, which is inherited from &lt;i&gt;boost::enable_shared_from_this&lt;/i&gt;. &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object ignored = exec(EXAMPLE_PY_FUNCTION, pyMainNamespace);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object processFileFunc = pyMainModule.attr("Foo").attr("processFile");&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // pass the python function a shared pointer instead of "this"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; processFileFunc(shared_from_this(), "test.txt"); // can't use boost::shared_ptr&lt;scene&gt;(this) either&lt;/scene&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;After updating the member function, the error went away and I could then send my Scene object to python inside and outside of the member function. &amp;nbsp;Python now has access to my scene object and I can start exposing some more functions and variables inside my Scene class. &lt;br /&gt;&lt;br /&gt;Below is a short working example of sending a shared pointer to python inside and outside of a member function (or you can look &lt;a href="http://pastebin.com/z3mdGpDr"&gt;here&lt;/a&gt;). &amp;nbsp;Special thanks to the boost::python mailing list, which was very helpful in getting me going. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#include &amp;lt;boost/python.hpp&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#include &amp;lt;boost/python/class.hpp&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#include &amp;lt;boost/python/module.hpp&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#include &amp;lt;boost/python/def.hpp&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#include &amp;lt;boost/enable_shared_from_this.hpp&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;using namespace boost::python;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;object pyMainModule;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;object pyMainNamespace;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;#define EXAMPLE_PY_FUNCTION \\&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; \"from scene import Scene\\n\" \\&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; \"class Foo(object):\\n\" \\&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; \" &amp;nbsp;@staticmethod\\n\" \\&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; \" &amp;nbsp;def processFile(scene, filename):\\n\" \\&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; \" &amp;nbsp; &amp;nbsp;print(\'here\')\\n\"&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;std::string parse_python_exception();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;class Scene : public boost::enable_shared_from_this&amp;lt;Scene&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;public:&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; void sendYourselfToPython()&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; try {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object ignored = exec(EXAMPLE_PY_FUNCTION, pyMainNamespace);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; object processFileFunc = pyMainModule.attr(\"Foo\").attr(\"processFile\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; processFileFunc(shared_from_this(), \"test.txt\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; } catch (boost::python::error_already_set const &amp;amp;) {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; std::string perror = parse_python_exception();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; std::cerr &amp;lt;&amp;lt; \"Error in Python: \" &amp;lt;&amp;lt; perror &amp;lt;&amp;lt; std::endl;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;};&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;typedef boost::shared_ptr&amp;lt;Scene&amp;gt; SceneP;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;BOOST_PYTHON_MODULE(scene)&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; class_&amp;lt;Scene, boost::noncopyable&amp;gt;(\"Scene\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;main(int argc, char**argv)&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; std::cout &amp;lt;&amp;lt; \"starting program...\" &amp;lt;&amp;lt; std::endl;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; Py_Initialize();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; pyMainModule = import(\"__main__\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; pyMainNamespace = pyMainModule.attr(\"__dict__\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; boost::python::register_ptr_to_python&amp;lt; boost::shared_ptr&amp;lt;Scene&amp;gt; &amp;gt;();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; PyImport_AppendInittab(\"scene\", &amp;amp;initscene);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; SceneP scene(new Scene());&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; // sending Scene object to python inside member function&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; scene-&amp;gt;sendYourselfToPython();&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; try {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; object ignored = exec(EXAMPLE_PY_FUNCTION, pyMainNamespace);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; object processFileFunc = pyMainModule.attr(\"Foo\").attr(\"processFile\");&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; // send Scene object to python using smart pointer&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; processFileFunc(scene, \"test.txt\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; } catch (boost::python::error_already_set const &amp;amp;) {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; std::string perror = parse_python_exception();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; std::cerr &amp;lt;&amp;lt; \"Error in Python: \" &amp;lt;&amp;lt; perror &amp;lt;&amp;lt; std::endl;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;// taken from http://thejosephturner.com/blog/2011/06/15/embedding-python-in-c-applications-with-boostpython-part-2/&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;namespace py = boost::python;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;std::string parse_python_exception() {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; PyErr_Fetch(&amp;amp;type_ptr, &amp;amp;value_ptr, &amp;amp;traceback_ptr);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; std::string ret(\"Unfetchable Python error\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; if (type_ptr != NULL) {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::handle&amp;lt;&amp;gt; h_type(type_ptr);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::str type_pstr(h_type);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::extract&amp;lt;std::string&amp;gt; e_type_pstr(type_pstr);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(e_type_pstr.check())&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret = e_type_pstr();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret = \"Unknown exception type\";&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; if (value_ptr != NULL) {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::handle&amp;lt;&amp;gt; h_val(value_ptr);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::str a(h_val);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::extract&amp;lt;std::string&amp;gt; returned(a);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(returned.check())&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret += &amp;nbsp;\": \" + returned();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret += std::string(\": Unparseable Python error: \");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; if (traceback_ptr != NULL) {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::handle&amp;lt;&amp;gt; h_tb(traceback_ptr);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::object tb(py::import(\"traceback\"));&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::object fmt_tb(tb.attr(\"format_tb\"));&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::object tb_list(fmt_tb(h_tb));&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::object tb_str(py::str(\"\\n\").join(tb_list));&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; py::extract&amp;lt;std::string&amp;gt; returned(tb_str);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(returned.check())&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret += \": \" + returned();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret += std::string(\": Unparseable Python traceback\");&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; return ret;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;b&gt;Compiling the Code&lt;/b&gt;&lt;br /&gt;To compile the code, I used &lt;i&gt;python-config&lt;/i&gt; to get the includes and flags. &amp;nbsp;&lt;i&gt;python-config&lt;/i&gt; is a simple utility that queries the path of your python headers and libs depending on which version of python is installed and designated on you system. &amp;nbsp;It's a useful utility as I usually have several versions of python on my machine at a time. &amp;nbsp;It's especially nice not having to hard code your application's build system to a particular version of python. &lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;python-config --includes&lt;/code&gt;&lt;br /&gt;&lt;code&gt;python-config --libs&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;g++ test.cpp -I/usr/include/python2.7 -I/usr/include/python2.7 -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -lpthread -ldl -lutil -lm -lpython2.7 -lboost_python&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1473398937084835246?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1473398937084835246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1473398937084835246' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1473398937084835246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1473398937084835246'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/09/adding-python-support-using-boostpython.html' title='Adding Python Support using Boost::Python'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-7626505614148015222</id><published>2011-08-07T05:41:00.000-07:00</published><updated>2011-08-07T11:13:08.790-07:00</updated><title type='text'>Performance Gains in Jython 2.5.2</title><content type='html'>&lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt;, the java implementation of the python language, has long been slower than it's cpython counterpart. &amp;nbsp;I've personally seen some simple benchmarks from years past such as &lt;a href="http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/"&gt;this&lt;/a&gt;, where jython would actually run 3-10 times slower. &amp;nbsp;Benchmarks between the two implementations can be tricky, as I'm sure there are are some things one does better than the other depending on each developer's design decisions. &amp;nbsp;jython 2.5.2 was released this last March and has noted several performance improvements on its updated features. &lt;br /&gt;&lt;br /&gt;I wanted to do a quick test just to compare the latest performance improvements implemented by jython's development team. &amp;nbsp;I had a simple ray tracer lying around (&lt;a href="http://pastebin.com/h9ZenF0s"&gt;link&lt;/a&gt;) from when I was learning python at my current employer. &amp;nbsp;This is a very simple script that renders the scene at 512x512 resolution in about half a minute. &amp;nbsp;The scene has no acceleration structures to speak of and no texturing, so it's just a series of brute force calculations and pretty much zero to cache compared to a more complex scene. &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-jwAtadoTsso/Tj6B6848P7I/AAAAAAAABQw/tDbLYd-DJP8/s1600/simple_scene.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-jwAtadoTsso/Tj6B6848P7I/AAAAAAAABQw/tDbLYd-DJP8/s320/simple_scene.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Scene consisting of a procedurally-checkered sphere, a reflective sphere, and a Lambertian plane lit from above by a point light. &amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;a href="http://www.chartgo.com/linkshare.do?id=7111f434aa"&gt; &lt;img alt="Online Graphing" border="0" src="http://www.chartgo.com/link.do?id=7111f434aa" title="ChartGo.com" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.chartgo.com/"&gt; Graphing &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I repeatedly ran the script using each implementation and averaged each result. &amp;nbsp;I reran the cpython implementation a couple more times to make sure a jump for one run was a fluke. &amp;nbsp;Apparently it was. &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;cpython 2.7.1 -&amp;nbsp;34s, 38s, 33s, 32s, 33s&lt;/li&gt;&lt;li&gt;jython 2.5.1 -&amp;nbsp;37s, 37s, 36s&lt;/li&gt;&lt;li&gt;jython 2.5.2 -&amp;nbsp;26s, 27s, 26s&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Just a few thoughts and comments:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jython 2.5.2 seems to definitely have some noticeable performance increases over 2.5.1&lt;/li&gt;&lt;li&gt;jython may now be faster than cpython in certain situations (like the script above)&lt;/li&gt;&lt;li&gt;jvm startup time was not taken into account as timing was done inside python&lt;/li&gt;&lt;li&gt;for both jythons, JIT seemed to consistently kick in at around 10% of the run (I'm assuming it was JIT), where the script started to run faster&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Although I use cpython for pretty much all my work, I'm pretty happy with the results and am excited to see jython make a bit a progess. &amp;nbsp;While one implementation may be faster than another in different circumstances, I think this shows jython's performance is at least similar to cpython for certain tasks. &amp;nbsp;Maybe future decisions to use one over the other will now depend on which libraries are more appropriate for a given project. &amp;nbsp;Of course, that may also change as I see importing cmodules on the jython TODO list. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;update:&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In response to a handful of commenters, they asked for &lt;a href="http://pypy.org/"&gt;pypy&lt;/a&gt; to be included with the test. &amp;nbsp;I downloaded the latest x86 build for my system and reran the script three times--all three runs completing in eleven seconds. &lt;br /&gt;&lt;br /&gt;Someone also mentioned if I had tried the new Java 7 build, which is the answer is yes. &amp;nbsp;I orginally downloaded java 7 to compare jython 2.5.2 against the newer version of java (which led to this benchmark). &amp;nbsp;I've heard a couple of features in particular slated for Java 7 would provide huge performance gains over Java 6 for the JVM scripting languages. &amp;nbsp;After running the two JVMs, however, I couldn't see much of a difference in performance. &amp;nbsp;Because of the newness of Java 7, I'm going to do some more investigating to make sure I had everything setup correctly to take advantage of these improvements. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.chartgo.com/linkshare.do?id=146ef289aa"&gt; &lt;img alt="Online Graphing" border="0" src="http://www.chartgo.com/link.do?id=146ef289aa" title="ChartGo.com" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.chartgo.com/"&gt; Graphing &lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-7626505614148015222?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/7626505614148015222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=7626505614148015222' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7626505614148015222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7626505614148015222'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/08/performance-gains-in-jython-252.html' title='Performance Gains in Jython 2.5.2'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-jwAtadoTsso/Tj6B6848P7I/AAAAAAAABQw/tDbLYd-DJP8/s72-c/simple_scene.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-838491176442842069</id><published>2011-05-03T06:03:00.000-07:00</published><updated>2011-05-03T06:03:35.957-07:00</updated><title type='text'>My thoughts on Ubuntu Unity</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-SCQze0-rF1s/Tb_1K9WoBXI/AAAAAAAABQQ/4FtvDfC9Ofs/s1600/ubuntu-unity.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="239" src="http://4.bp.blogspot.com/-SCQze0-rF1s/Tb_1K9WoBXI/AAAAAAAABQQ/4FtvDfC9Ofs/s320/ubuntu-unity.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Over the weekend, I made the painful mistake of upgrading to Natty Narwhal 11.04, the newest release of Ubuntu Linux. &amp;nbsp;I was previously running 10.04 and realized I was stuck with Qt 4.6 and I desperately needed a feature in 4.7. &amp;nbsp;After starting the upgrade process, I realized I actually had missed the last upgrade 10.10, which was required before upgrading to 11.04. &amp;nbsp;I installed that and realized it contained Qt 4.7. &amp;nbsp;I could have stopped there and be content, but I didn't. &lt;br /&gt;&lt;br /&gt;I love Ubuntu for various reasons but mostly for its usability. &amp;nbsp;I can do okay on other distributions, but as my life gets busier and busier, I need my operating system to "just work". &amp;nbsp;Sometimes I'm tempted to upgrade my distribution instantly when a new one comes out, but I usually regret it getting bit by stupid bugs and such. &amp;nbsp;Jumping to Natty Narwhal 11.04 was no different. &amp;nbsp;I had read several negative reviews on Natty Narwhal and wanted desperately to believe they were wrong, but I sadly had to change back to the classic interface. &amp;nbsp;And it only took me a few days. &lt;br /&gt;&lt;br /&gt;Here are a few of the hurdles I hit--all of which having to do with Ubuntu's new Unity system. &lt;br /&gt;&lt;ol&gt;&lt;li&gt;Restarting my machine, I couldn't log into X. &amp;nbsp;I found that my nvidia driver module wasn't being built for the upgraded kernel. &amp;nbsp;Somehow installing a package and skipping a seemingly-required module is totally okay. &amp;nbsp;To me, though, it continually hung on the Ubunutu "five-dot" splash screen. &amp;nbsp;I had to actually go get the &lt;i&gt;linux-headers&lt;/i&gt; package for my kernel and then reinstall the &lt;i&gt;nvidia-current&lt;/i&gt; package, which rebuilt the module correctly. &amp;nbsp;Couldn't the former be a dependency of the latter? &amp;nbsp;&lt;/li&gt;&lt;li&gt;Unity's "taskbar" is a little buggy. &amp;nbsp;I'm not sure the rules for it staying out or autohiding, but it certainly wasn't consistent&lt;/li&gt;&lt;li&gt;I don't consider myself a power user, but I like to have widgets like workspace tracking and the CPU histogram&lt;/li&gt;&lt;li&gt;I missed all my icons at the top of the screen. &amp;nbsp;I open multiple terminals all the time for programming. &amp;nbsp;With the Unity taskbar, when I click on the terminal icon, it will either create one terminal, or take me to the workspace where my terminal is already opened. &amp;nbsp;I just want a new terminal window&lt;/li&gt;&lt;li&gt;It's hard seeing what's on the screen without the traditional taskbar. &amp;nbsp;Windows got buried under each other and I didn't know where they were (the taskbar in Unity doesn't help, while the more classic taskbar shows me exactly what's running on this workspace). &amp;nbsp;Also, how do I change the number of workspaces? &amp;nbsp;I had ten--and I used every one--and now I have four&lt;/li&gt;&lt;li&gt;This is a minor complaint that I can get used to, but Unity uses the "Universal Menubar" style ala Mac OS X, where the focused application has it's menubar at the top of the screen. &amp;nbsp;This isn't necessarily bad, but it hides all the menus until you mouse over the bar. &amp;nbsp;Why? &amp;nbsp;&lt;/li&gt;&lt;li&gt;I actually had some random bugs including loading windows that appeared with no border and certain programs not receiving mouse input after I returned from a different workspace&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-yEgDNMDzBHk/Tb_4ewtC2lI/AAAAAAAABQU/arbjGzWsego/s1600/cpuinfo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-yEgDNMDzBHk/Tb_4ewtC2lI/AAAAAAAABQU/arbjGzWsego/s1600/cpuinfo.png" style="cursor: move;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-hAM9h5X5OJQ/Tb_4guAEjNI/AAAAAAAABQY/oYtyNWvJpcQ/s1600/workspaces.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-hAM9h5X5OJQ/Tb_4guAEjNI/AAAAAAAABQY/oYtyNWvJpcQ/s1600/workspaces.png" style="cursor: move;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: left;"&gt;To me Unity was like &lt;a href="http://www.rottentomatoes.com/m/knight_and_day/"&gt;Knight and Day&lt;/a&gt; with Tom Cruise. &amp;nbsp;I sat down to watch it and I really, really wanted to like it despite all the negative reviews. &amp;nbsp;But it just didn't work. &amp;nbsp;Like this mediocre movie, it wasn't a horrible premise (besides a cliche hacker and a mystical power source the size of a AA battery), but it just wasn't executed correctly. &amp;nbsp;I believe most of these issues are fixable, but I'm afraid this new desktop has left a bad taste in a lot of people's mouths. &amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-838491176442842069?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/838491176442842069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=838491176442842069' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/838491176442842069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/838491176442842069'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/05/my-thoughts-on-ubuntu-unity.html' title='My thoughts on Ubuntu Unity'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-SCQze0-rF1s/Tb_1K9WoBXI/AAAAAAAABQQ/4FtvDfC9Ofs/s72-c/ubuntu-unity.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6725375519695655404</id><published>2011-04-24T13:52:00.000-07:00</published><updated>2011-04-26T11:00:27.580-07:00</updated><title type='text'>Integrating Sunflow</title><content type='html'>I've been playing around with some utilities for moving lights around a scene and rendering it in&amp;nbsp;&lt;a href="http://sunflow.sourceforge.net/"&gt;Sunflow&lt;/a&gt;&amp;nbsp;for years. &amp;nbsp;I've done so much rewriting just to destroy it over and over again, I decided to just take much smaller bites and try doing something very tiny with the program. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;import a PLY object (buggy)&lt;/li&gt;&lt;li&gt;add an attentuated spotlight&lt;/li&gt;&lt;li&gt;camera controls (incomplete)&lt;/li&gt;&lt;li&gt;adjust basic global illumination&lt;/li&gt;&lt;/ul&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-OaRol3zWrJE/TbSJgctna9I/AAAAAAAABQA/NYZkfjRPYKg/s1600/sunshine.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="250" src="http://3.bp.blogspot.com/-OaRol3zWrJE/TbSJgctna9I/AAAAAAAABQA/NYZkfjRPYKg/s400/sunshine.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;My silly toy&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-5W3AMc-8IiA/TbSNQMcBiDI/AAAAAAAABQE/0yCtJ5jhjIk/s1600/happy_0.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="300" src="http://4.bp.blogspot.com/-5W3AMc-8IiA/TbSNQMcBiDI/AAAAAAAABQE/0yCtJ5jhjIk/s400/happy_0.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;no bounces&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6725375519695655404?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6725375519695655404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6725375519695655404' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6725375519695655404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6725375519695655404'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/04/integrating-sunflow.html' title='Integrating Sunflow'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-OaRol3zWrJE/TbSJgctna9I/AAAAAAAABQA/NYZkfjRPYKg/s72-c/sunshine.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2412735325735951793</id><published>2011-03-26T14:27:00.000-07:00</published><updated>2011-03-26T14:27:54.274-07:00</updated><title type='text'>Using jQuery UI's date picker on all django forms</title><content type='html'>After getting over the initial learning curves of django's forms, I've begun to really appreciate the level of customizability the developers have incorporated into the API. &amp;nbsp;By default, when sending a model to a form, any DateField members are converted to form DateField instances, which translates to a simple textfield. &amp;nbsp;This isn't very attractive and quickly leads to formatting complaints from users (and supervisors). There's another widget django provides for picking dates--three comboboxes for month, date, and year--but it's not a very elegant solution. &amp;nbsp;I thought it would be nice if, by default, all my forms could use jQuery UI's datepicker. &amp;nbsp;Here's what I did. &lt;br /&gt;&lt;br /&gt;First, after some searching online, it seemed several people have experienced similar issues. &amp;nbsp;I happened to run across this answer on &lt;a href="http://stackoverflow.com/questions/660929/how-do-you-change-the-default-widget-for-all-django-date-fields-in-a-modelform"&gt;stackoverflow&lt;/a&gt; for customizing widgets for all forms. &lt;br /&gt;&lt;br /&gt;Here's my final code. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;def make_custom_datefield(f):&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;formfield = f.formfield()&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if isinstance(f, models.DateField):&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;formfield.widget.format = '%m/%d/%Y'&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;formfield.widget.attrs.update({'class':'datePicker', 'readonly':'true'})&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return formfield&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;class ProjectForm(ModelForm):&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;formfield_callback = make_custom_datefield&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;class Meta:&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;model = Project&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First, on &lt;i&gt;ProjectForm&lt;/i&gt; I specify a custom callback function for handling form fields. &amp;nbsp;This is actually really nice as I can apply this code to any form I want instead of marking individual fields for a form or applying the entire fix to every single model. &lt;br /&gt;&lt;br /&gt;In &lt;i&gt;make_custom_datefield&lt;/i&gt; I do a quick check to see if it's a model &lt;i&gt;DateField&lt;/i&gt; instance. &amp;nbsp;If it is, I do some modifying. &amp;nbsp;First, I change the format of the widget so incoming data from the model match jQuery's format. &amp;nbsp;It might be possible to modify jQuery to match Django, but whatever. &amp;nbsp;Then I add on two custom attributes to the widget. &amp;nbsp;Both of these directly map to html attributes of the &lt;i&gt;input&lt;/i&gt; tag. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre id="line181"&gt;&amp;lt;&lt;span class="start-tag"&gt;input&lt;/span&gt;&lt;span class="attribute-name"&gt; &lt;/span&gt;&lt;span class="attribute-name"&gt;class&lt;/span&gt;=&lt;span class="attribute-value"&gt;"datePicker" &lt;/span&gt;&lt;span class="attribute-name"&gt;readonly&lt;/span&gt;=&lt;span class="attribute-value"&gt;"true" &lt;/span&gt;&lt;span class="attribute-name"&gt;type&lt;/span&gt;=&lt;span class="attribute-value"&gt;"text" &lt;/span&gt;&lt;span class="attribute-name"&gt;id&lt;/span&gt;=&lt;span class="attribute-value"&gt;"id_dateDue" &lt;/span&gt;&lt;span class="error"&gt;&lt;span class="attribute-name"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;datePicker&lt;/i&gt; class is important so I can mark this input as a jQuery calendar in the browser. &amp;nbsp;I also mark it as &lt;i&gt;readonly&lt;/i&gt; so users can't modify the date with bad formats. &amp;nbsp;Marking the input as read-only is a double-edged sword as it also prevents users from quickly entering dates months or years away. &lt;br /&gt;&lt;br /&gt;Once that is working, I just need to add some code to my page that will mark all &lt;i&gt;datePicker&lt;/i&gt; instances in javascript as being datepicker widgets. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;// on page load&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$(function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;$( ".datePicker" ).datepicker();&lt;/code&gt;&lt;br /&gt;&lt;code&gt;});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/-hXI8lps1naI/TY5aCJRzhXI/AAAAAAAABP8/euK5lQx-1i8/s1600/datepicker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="223" src="https://lh6.googleusercontent.com/-hXI8lps1naI/TY5aCJRzhXI/AAAAAAAABP8/euK5lQx-1i8/s320/datepicker.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And that's it! &amp;nbsp;I can now make jQuery UI datepickers the default widget on any django form I choose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2412735325735951793?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2412735325735951793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2412735325735951793' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2412735325735951793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2412735325735951793'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/03/using-jquery-uis-date-picker-on-all.html' title='Using jQuery UI&apos;s date picker on all django forms'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh6.googleusercontent.com/-hXI8lps1naI/TY5aCJRzhXI/AAAAAAAABP8/euK5lQx-1i8/s72-c/datepicker.png' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1724691684864792183</id><published>2011-02-05T08:41:00.000-08:00</published><updated>2011-02-05T08:52:59.384-08:00</updated><title type='text'>PHP vs Python: A followup</title><content type='html'>I received a lot more commentary for my previous &lt;a href="http://strattonbrazil.blogspot.com/2011/02/php-to-python-why-php-is-now-dead-to-me.html"&gt;post&lt;/a&gt; than I anticipated, so I thought I'd followup with some comments and feedback I received. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;PHP not dead, just out of use&lt;/strong&gt;&lt;br /&gt;First, the title of my previous post included the phrase "dead to me". &amp;nbsp;I in no way wanted to imply PHP was worthless to anyone and its large community was going away. &amp;nbsp;I honestly don't care if PHP sticks around forever. &amp;nbsp;My point is that as templating libraries for the web have gotten so good, much of the code is outside the template and the small benefit of embedding PHP directly into html is much less useful than it used to be. &amp;nbsp;&lt;a href="http://www.php.net/"&gt;www.php.net&lt;/a&gt;'s first description for those who might be new to the language are immediately shown, "PHP is a widely-used general-purpose scripting language that is especially suited for Web development and can be embedded into HTML." &amp;nbsp;Within the first sentence they advertise PHP as being html-embeddable. &amp;nbsp;My point is, big woop. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;PHP's gotten boring&lt;/strong&gt;&lt;br /&gt;Many people have commented on other forums about leaving PHP, because its gotten too boring. &amp;nbsp;And vice versa, leaving another language like python because it too got old and went back to PHP. &amp;nbsp;Whatever floats your boat, I guess. &amp;nbsp;In some ways arguing about the pleasure of programming in PHP over python is like arguing the merits of Spanish over German. &amp;nbsp;Clearly, German is superior. &lt;br /&gt;&lt;br /&gt;People tend to have relatively strong opinions over rather mundane things ranging from favorite foods to their preferred brand of socks. &amp;nbsp;Programmers similarly can have very strong opinions over their languages of choice when sometimes it's their our to express themselves. &amp;nbsp;Reading blogs comparing lines of python to lines of ruby tend to put me to sleep. &amp;nbsp;Some comments on this subject included the ugliness of php or python. &amp;nbsp;Ugliness, of course, is a very subjective word. &lt;br /&gt;&lt;br /&gt;Years ago I encountered a site railing against the java language. &amp;nbsp;I found most of the author's points, however, to be mostly an issue of taste. &amp;nbsp;One issue he mentioned was the case-sensitive nature java required/assumed. &amp;nbsp;This perplexed me seriously as almost every language I've ever used in my life was case sensitive. &amp;nbsp;Indeed, jumping over to &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;TIOBE&lt;/a&gt;, it looks like the top ten languages all have case-sensitive syntax. &amp;nbsp;To OO developers, this style is often used to easily distinguish between class and object. &amp;nbsp;Calling java ugly for using a industry standard? &amp;nbsp;That's like calling a girl ugly because she's not a blonde asian. &amp;nbsp;My point is what exactly is ugly about python? &amp;nbsp;To me calling a programming language ugly demonstrates an inability to express one's possibly valid thoughts on a language. &amp;nbsp;For example, some perl I might considered "ugly" for its compact, symbol-based syntax and parameter passing. &amp;nbsp;Some find python ugly simply for lacking the C-style angle brackets between blocks--are they by contract considered beautiful? &amp;nbsp;One might call java ugly for its extreme use of compositing just do simple file I/O. &amp;nbsp;Or are these people literally calling some language visually displeasing? &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9O8xhktq4RU/TU13uVDZM4I/AAAAAAAABPw/WcM9BvMlz4o/s1600/2246383366_c874e3c1dc_o.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/_9O8xhktq4RU/TU13uVDZM4I/AAAAAAAABPw/WcM9BvMlz4o/s320/2246383366_c874e3c1dc_o.jpg" width="317" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;So beautiful...&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;PHP's Community&lt;/strong&gt;&lt;br /&gt;One of PHP's biggest strengths is its availability across a large range of hosting providers. &amp;nbsp;PHP currently is the standard web language any hosting service must provide. &amp;nbsp;Hosts providing alternatives such as python and ruby-on-rails usually are a little harder to come by, which is a boon for PHP. &amp;nbsp;One commenter strongly disagreed with my statement of the python community's size compared to php. &amp;nbsp;The community can mean different things, so I'll admit it my mistake. &amp;nbsp;Again, looking at the &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;TIOBE&lt;/a&gt; data, PHP is shown to be more popular than python (though the latter looks to overtake it next year). &amp;nbsp;Or you can simply google &lt;i&gt;"php community"&lt;/i&gt; and see it garners more than 77 times the hits as &lt;i&gt;"python community"&lt;/i&gt;. &amp;nbsp;Maybe python programmers are anti-social...&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Long live templating engines!&lt;/strong&gt;&lt;br /&gt;Concluding with my previous post's title, templating engines have replaced my "need" of PHP. &amp;nbsp;PHP isn't horrible by any means, but with capable templating engines in so many languages, anyone can just program in &lt;i&gt;_insert_favorite_language_here_&lt;/i&gt;. &amp;nbsp;In this case, PHP is just another scripting language. &amp;nbsp;I thought about porting blocks of PHP code to python for readers to compare, but after a brief perusal I found the endeavor totally pointless considering the relatively little changes I'd make between them. &amp;nbsp;So instead of ending with a quip, I'll end with a question: Supposing a script-savvy developer was entering web development, what are some motivations for using PHP I haven't mentioned?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1724691684864792183?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1724691684864792183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1724691684864792183' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1724691684864792183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1724691684864792183'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/02/php-vs-python-followup.html' title='PHP vs Python: A followup'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/TU13uVDZM4I/AAAAAAAABPw/WcM9BvMlz4o/s72-c/2246383366_c874e3c1dc_o.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6547673806914018228</id><published>2011-02-02T19:56:00.000-08:00</published><updated>2011-02-02T20:07:23.657-08:00</updated><title type='text'>php to python: Why PHP is now dead to me</title><content type='html'>PHP started in 1995 and was a well-known web language by the time I was getting into web development around 2001.&amp;nbsp; At that time I had just picked up perl--yes, perl, which at the time seemed like the end-all, be-all sexiest language ever.&amp;nbsp; The only thing I liked about PHP, which I admit was a very big draw was the seemless fusion of content and code.&amp;nbsp; With PHP's delimiters, one could easily blend between the content and wiring.&amp;nbsp; Almost ten years later, though, PHP is starting to show serious age to the point of being a deprecated tool in the toolbox (like no one making Phillips screws anymore).&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;PHP as a web language&lt;/strong&gt;&lt;br /&gt;My first grudge against PHP is it's not a very generic language.&amp;nbsp; People have successfully written non-web-based PHP applications, but this seems to be more of a PHP programmer, who doesn't want to learn a more robust language. After a brief scan of various PHP support sites, PHP development outside the realm of web development is basically negligible.&amp;nbsp; I see no reason, in fact, besides some amazing library I might not be aware of, for me to use PHP for a non-web-based application.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;acronym title="recursive acronym for PHP: Hypertext Preprocessor"&gt;PHP&lt;/acronym&gt;  is a widely-used general-purpose scripting language that is  especially suited for Web development and can be embedded into HTML.&amp;nbsp; -http://www.php.net/&lt;/blockquote&gt;&lt;br /&gt;The syntax is ugly, in my opinion: requred semi-colons, arrows instead of periods to reference data, global functions to manage things like arrays instead of a more object-oriented approach, etc.&amp;nbsp; After several iterations of the language, features seem tacked on to the early implementations.&amp;nbsp; With python being faster and providing a larger development community, what motivates me to use PHP?&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The MVC architecture&lt;/strong&gt;&lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller"&gt;MVC&lt;/a&gt; architecture is a design philosophy of separating the application into three sections: the models, which manage the data of the application; the views, which typically represent the user interface of the application; and the controllers, which handle a lot of the management between the views and models.&amp;nbsp; While this design can be strictly conceptual to a programmer separating out functionality, various frameworks like Qt and CodeIgniter strictly separate these entities.&amp;nbsp; Here's where I believe php has lost it's magic.&lt;br /&gt;&lt;br /&gt;The main allure of PHP that stole a lot of perl's magic was putting the &lt;i&gt;controller&lt;/i&gt; elements doing the processing directly into the html.&amp;nbsp; Instead of managing large perl files mixed with html, people could make a mostly html-based file with a little PHP, which was much cleaner to read.&amp;nbsp; In that sense, all the view implementation was usually separated from the model and controller.&amp;nbsp; This seemed great at the time, but as MVC has gotten more prevalent, more and more PHP frameworks remove model/controller components from the html leaving small bits and pieces in its place.&amp;nbsp; In my experience, and what seems to be the practice now in PHP, large controllers and models are created completely separate to the actual html.&amp;nbsp; This creates a more coherent architecture, but it raises the question: now that we've moved so much PHP code away from html, why are we still using PHP? &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The rise of templates&lt;/strong&gt;&lt;br /&gt;Templating libraries have been around for many, many years-even before PHP was popular.&amp;nbsp; However, since some programming language had to drive the application anyway, I believe, there was no reason to use one if one had to do his/her coding in C/C++ or perl still.&amp;nbsp; Now, however, many new languages have emerged such as ruby and python that provide a very small and more robust scripting experience.&amp;nbsp; Because they are so general purpose, many more examples exist outside of web development.&amp;nbsp; This is important as web applications have continually provided more and more functionality than just serving up semi-static web pages.&amp;nbsp; The little bits of php code that was once in my html files are now easily replaced with some templating library like &lt;i&gt;mako&lt;/i&gt; or &lt;i&gt;genshi&lt;/i&gt;, and I can program in a more general-purpose language, whose techniques will apply to non-web-development tasks as well.&amp;nbsp; Again, now that PHP has been moved outside of html, why should I use it over python or ruby?&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Things I'll miss&lt;/strong&gt;&lt;br /&gt;Alas, PHP, I hardly knew thee.&amp;nbsp; One thing I'll slightly miss, though, is the startup time in PHP.&amp;nbsp; Almost every apache configuration on Linux typically comes with PHP configured.&amp;nbsp; After opening up a .php file and typing a few lines, I can access the file directly in my web browser and I'm immediately seeing the results.&amp;nbsp; With python, I have to do a little bit more typically to get things running via apache. &amp;nbsp;This requires setting up a cgi-bin, creating a proper script alias, etc. &amp;nbsp;Newer python frameworks like web.py and turbogears now come with a mini-web-server included, however, so I can hold off on configurations until I'm farther in to production. &lt;br /&gt;&lt;br /&gt;I'll also miss PHP's documentation, which I believe is generally more accessible than python's. &amp;nbsp;Many of PHP's functions get an entire page dedicated to them like &lt;a href="http://php.net/manual/en/function.explode.php"&gt;explode()&lt;/a&gt;. &amp;nbsp;The page features the basics you'd expect from an API doc--parameters, description, and return value--but includes a huge swath of examples of how to use the function. &amp;nbsp;It's like an entire programming cookbook dedicated to that function. &amp;nbsp;I find a lot of python docs to be a little too wordy (ex. &lt;a href="http://docs.python.org/library/datetime.html"&gt;datetime&lt;/a&gt; and difficult to browse to a particular function--especially if I'm searching by functionality and not name. &amp;nbsp;If I'm unfamiliar with a language, I'd like to know what functions are available for a given class before treading through each and every description. &amp;nbsp;The function name should typically provide sufficient description to investigate it further. &amp;nbsp;Anyway, the PHP wiki/comment style of documentation is something I hope more languages adopt. &amp;nbsp;Wikis are already prevalent on many projects, but it seems people are much more willing to contribute through a brief comment box instead of stepping into an entire editing mode. &amp;nbsp;Is it fear? &amp;nbsp;Laziness? &amp;nbsp;Regardless, it seems more accessible to contribute something beneficial to the doc. &lt;br /&gt;&lt;br /&gt;Anyway, PHP. &amp;nbsp;Thanks for everything. &amp;nbsp;It was fun while it lasted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6547673806914018228?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6547673806914018228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6547673806914018228' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6547673806914018228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6547673806914018228'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/02/php-to-python-why-php-is-now-dead-to-me.html' title='php to python: Why PHP is now dead to me'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-9020829187525075898</id><published>2011-01-08T10:22:00.000-08:00</published><updated>2011-01-08T10:23:01.260-08:00</updated><title type='text'>Using Redbean with Code Igniter 1.7.3</title><content type='html'>I started playing around with codeigniter for a quick project, and wanted a simple ORM for manipulating databases quickly.  After looking briefly at &lt;a href="http://redbeanphp.com/"&gt;RedbeanPHP&lt;/a&gt;, I decided to give it a spin.  &lt;a href="http://www.creolab.hr/"&gt;Boris Strahija&lt;/a&gt; had actually shown how to do it last year in the &lt;a href="http://codeigniter.com/forums/viewthread/133981/#661618"&gt;forums&lt;/a&gt;, but I just wanted to post my files for reference.  This assumes the &lt;i&gt;database.php&lt;/i&gt; file in your config dir is already pointing to a valid database.  I was using &lt;i&gt;mysql&lt;/i&gt;.  &lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download RedbeanPHP and drop the two files (&lt;i&gt;._rb.php&lt;/i&gt; and &lt;i&gt;rb.php&lt;/i&gt;) in &lt;i&gt;system/application/libraries&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Create a library class called &lt;i&gt;Redbean.php&lt;/i&gt; with the contents shown below, and drop it in the same directory&lt;/li&gt;&lt;li&gt;Use it in your controller&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;strong&gt;Redbean.php&lt;/strong&gt;&lt;br /&gt;&lt;pre&gt;ci =&amp;amp; get_instance();&lt;br /&gt;&lt;br /&gt;// Include database configuration&lt;br /&gt;include(APPPATH.'/config/database.php');&lt;br /&gt;&lt;br /&gt;// Include required files&lt;br /&gt;include(APPPATH.'/libraries/rb.php');&lt;br /&gt;&lt;br /&gt;// Database data&lt;br /&gt;$hostname     = $db[$active_group]['hostname'];&lt;br /&gt;$username     = $db[$active_group]['username'];&lt;br /&gt;$password     = $db[$active_group]['password'];&lt;br /&gt;$database     = $db[$active_group]['database'];&lt;br /&gt;&lt;br /&gt;// Create RedBean instance&lt;br /&gt;$toolbox = RedBean_Setup::kickstartDev('mysql:host='.$hostname.';dbname='.$database, $username, $password);&lt;br /&gt;$this-&amp;gt;ci-&amp;gt;rb = $toolbox-&amp;gt;getRedBean(); &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Using it somewhere in your controller&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;// example code of creating a 'post' table&lt;br /&gt;$post = $this-&amp;gt;rb-&amp;gt;dispense("post");&lt;br /&gt;$post-&amp;gt;title = 'My first post from CodeIgniter';&lt;br /&gt;$post-&amp;gt;body ='Lorem ipsum dolor sit amet, consectetur adipisicing elit....';&lt;br /&gt;$post-&amp;gt;created = time();&lt;br /&gt;$id = $this-&amp;gt;rb-&amp;gt;store($post); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After running this controller, you should see a 'post' table created.  Done!  &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9O8xhktq4RU/TSiqVX-HvdI/AAAAAAAABPk/pIHSy2n_qyI/s1600/redbean.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="210" src="http://3.bp.blogspot.com/_9O8xhktq4RU/TSiqVX-HvdI/AAAAAAAABPk/pIHSy2n_qyI/s400/redbean.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;What you should see in phpMyAdmin&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-9020829187525075898?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/9020829187525075898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=9020829187525075898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9020829187525075898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9020829187525075898'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2011/01/using-redbean-with-code-igniter-173.html' title='Using Redbean with Code Igniter 1.7.3'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/TSiqVX-HvdI/AAAAAAAABPk/pIHSy2n_qyI/s72-c/redbean.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-4008988749063186461</id><published>2010-10-10T10:06:00.000-07:00</published><updated>2010-10-10T19:46:51.584-07:00</updated><title type='text'>Incorporating scala, java, sbt, JOGL, Qt, and Ruby/Python</title><content type='html'>For several years now, I've been iterating on a small project that allows the user to build a &lt;a href="http://sunflow.sourceforge.net/"&gt;Sunflow&lt;/a&gt; scene file.  When starting it, I tried to effectively design the program with the write technologies for the task.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;The language of choice&lt;/b&gt;&lt;br /&gt;First, Sunflow is written in java and as such runs on the JVM.  Not only do I want to be able to build a Sunflow file, but I want to render it interactively using Sunflow's libraries.  There are many langauges available on the JVM right now, but only a few sparked my interest.  First, I had done everything in Java previously, which was okay but was at times a little tedious.  The languages I looked at as possible replacements were &lt;a href="http://www.scala-lang.org/"&gt;scala&lt;/a&gt; and &lt;a href="http://clojure.org/"&gt;clojure&lt;/a&gt;.  Although I was very interested in clojure, I thought at the time of starting that it was too foreign to me and I would end up doing something extremely naive in my design.  &lt;br /&gt;&lt;br /&gt;Scala is a statically-typed language that can at times closely matches the java language.  Scala has built a large type-system, which includes many data structures that are both mutable or immutable depending on what you're using them for (functional programming, for example, would probably favor the immutable structures).  Scala treats it's functions as first-class citizens, so they're easily passed around to other functions.  I can even make large anonymous functions that fit right within another function call.  It's syntax is also slightly less verbose than java, and it provides an excellent getter/setter infrastructure that's extremely clean.  &lt;br /&gt;&lt;br /&gt;Scala isn't all roses, however.  First, scala seems to be growing faster than my app, so as I tried to stay up to date with the latest scala features, it's often broken compatibility in significant ways, which has been a bit of a distraction fixing.  Second, some of the code is illegible to me.  It has a complicated type system and weird language symbols sometimes that seem to pull from esoteric languages for the sake of it instead of creating a simpler style.  My scala is probably pretty java-like, so it's fairly easy to read.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Building with scala&lt;/b&gt;&lt;br /&gt;Another advantages of scala is its ability to cross-compile with java.  I was previously using ant, which was my foray into a java build system.  First, I don't like work in XML for a myriad of reasons.  After the ant scala compiler tool started throwing bogus errors, I was advised to move over to the &lt;a href="http://code.google.com/p/simple-build-tool/"&gt;simple-build-tool&lt;/a&gt; or &lt;i&gt;sbt&lt;/i&gt;.  &lt;br /&gt;&lt;br /&gt;After adding a launcher to my class path, sbt allowed me to quickly setup a new project, whose project file is written in scala, a much more preferred way to configure my app.  I simply put all my scala code in ./src/scala and all my java code in ./src/java and sbt combines them.  Although it took a moderate amount of time to setup my project, in the end it's been a joy to work with sbt.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;JOGL&lt;/b&gt;&lt;br /&gt;The JVM requires &lt;a href="http://kenai.com/projects/jogl/pages/Home"&gt;JOGL&lt;/a&gt; to do OpenGL rendering.  This can be tedious to setup as I'm used to just tossing a jar onto the classpath and having my build system include it.  Because JOGL requires native libraries, which need to be included separately to the java library path.  This took a while for me to figure out, but ended up being a simple setup in the end.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import sbt._&lt;br /&gt;import java.io.File&lt;br /&gt;&lt;br /&gt;class SunshineProject(info:ProjectInfo) extends DefaultProject(info)&lt;br /&gt;{&lt;br /&gt;  // tells sbt which class to run&lt;br /&gt;  override def mainClass:Option[String] = Some("com.googlecode.sunshine.Sunshine")&lt;br /&gt;&lt;br /&gt;  def nativeJOGL:String = {&lt;br /&gt;    var os = System.getProperty("os.name").toLowerCase&lt;br /&gt;    var arch = System.getProperty("os.arch").toLowerCase&lt;br /&gt;&lt;br /&gt;    // this is to match the JOGL builds&lt;br /&gt;    if (arch.matches("i386")) arch = "i586"&lt;br /&gt;&lt;br /&gt;    if (os.contains("windows")) {&lt;br /&gt;      os = "windows"&lt;br /&gt;      arch = "i586"&lt;br /&gt;    }&lt;br /&gt;    println("OS: %s".format(os))&lt;br /&gt;    println("JOGL Path: %s".format("./lib/jogl-2.0-%s-%s".format(os, arch)))&lt;br /&gt;&lt;br /&gt;    "./lib/jogl-2.0-%s-%s".format(os, arch)&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  override def fork = forkRun("-Djava.library.path=%s".format(nativeJOGL) :: Nil)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;All this basically does is query the OS and architecture from the JVM and adds it's respective JOGL directory to the library path.  This required me to fork the JVM, as adding paths to the current JVM doesn't seem to work.  Notice I just had to override the &lt;i&gt;fork&lt;/i&gt; command and sbt knows I want to fork.  Overriding the &lt;i&gt;run&lt;/i&gt; command won't fork the JVM when starting.  I did something similar in ant, but it was much longer and more difficult to read.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using Qt&lt;/b&gt;&lt;br /&gt;Java Swing is usually an okay GUI library for my small java projects, but it's slightly cumbersome when trying to do something complex.  Trolltech's Qt is a very popular framework that has continually gained popularity over the years for it's great documentation, intuitive API, and it's event handling system.  &lt;br /&gt;&lt;br /&gt;&lt;a href="http://qtjambi.sourceforge.net/"&gt;QtJambi&lt;/a&gt; is the java binding for using the Qt libraries.  A few months ago Trolltech dropped support of QtJambi, but pushed it off to the community to continue updating.  So far, they seem to be doing a decent job, although they have been continually asking for help.  &lt;br /&gt;&lt;br /&gt;sbt supports automatic library manage via &lt;a href="http://ant.apache.org/ivy/"&gt;Apache Ivy&lt;/a&gt;.  Instead of shipping every build of Qt for a given architecture, I can setup Qt as a managed library.  By pointing sbt to the QtJambi servers, sbt will automatically fetch them during compilation.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;val qtDepSnapshots = "Qt Maven2 Snapshots Repository" at "http://qtjambi.sourceforge.net/maven2/"&lt;br /&gt;val qtDep = "net.sf.qtjambi" % "qtjambi" % "4.5.2_01"&lt;br /&gt;val qtjambiBase = "net.sf.qtjambi" % "qtjambi-base-linux32" % "4.5.2_01"&lt;br /&gt;val qtjambiPlatform = "net.sf.qtjambi" % "qtjambi-platform-linux32" % "4.5.2_01"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Right now, I'm only fetching Linux x86 libraries as that's what I'm working off of.  Adding the block above directly into my build class will tell sbt to grab them for me.  There's a bit of magic going on here for me as I don't understand how sbt knows these variables are library dependencies or just values I've created in my program.  Regardless, it's enough to get Qt downloaded and onto the classpath.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Incorporating a scripting language&lt;/b&gt;&lt;br /&gt;At this point, I could just start coding my application, but since I'm doing a lot of designing on the fly, it takes a long time to compile my application to see a small change.  I wanted to incorporate a scripting language that lets me make changes to the interface quickly without existing the program.  &lt;br /&gt;&lt;br /&gt;As much as I complain about python, I use it a lot at work and am fairly productive programming in it.  The &lt;a href="http://www.jython.org/"&gt;jython&lt;/a&gt; project provides a python implementation that runs on the JVM.  I've used this library before a year ago, but had to scrap it as it was too slow latency-wise.  I've heard it's gotten significantly faster recently, so I gave it another shot and found it to be much faster.  Working with Qt, however, seemed to turn up a bug blocker.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;[error] Exception caught after invoking slot&lt;br /&gt;[error] Traceback (most recent call last):&lt;br /&gt;[error]   File "&lt;iostream&gt;", line 15, in &lt;module&gt;&lt;br /&gt;[error]   File "&lt;iostream&gt;", line 9, in __init__&lt;br /&gt;[error] TypeError: Proxy instance reused&lt;br /&gt;&lt;/iostream&gt;&lt;/module&gt;&lt;/iostream&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I was initially wondering if working with Qt from a scripting language was not stable, however, this seemed to be only a jython issue.  I reported it to the jython team, which seems to be resolving the issue right now for their upcoming build.  &lt;br /&gt;&lt;br /&gt;In the mean time, I thought I would give ruby a spin.  I'm rather unfamiliar with the &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; language, although I haven't been oblivious to the huge success it has garnered in web community with Ruby on Rails.  I've also heard great things about &lt;a href="http://jruby.org/"&gt;JRuby&lt;/a&gt;, the Ruby implementation on the JVM.  At one point it was actually faster than the C++ build of Ruby, although I'm not sure this is necessarily true anymore.  &lt;br /&gt;&lt;br /&gt;The ruby language seems to be something between python and perl, although that's another comment that will possibly get me shot by a Ruby developer.  It's a purely object-oriented language--more so than python--and provides a bit more syntax flexibility than python (for better or for worse) including some parsing syntax from perl.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;val factory = new ScriptEngineManager()&lt;br /&gt;val ruby = factory.getEngineByName("jruby")&lt;br /&gt;&lt;br /&gt;val urlFile = "clear_scene.rb"&lt;br /&gt;val url = getClass().getResource(urlFile)&lt;br /&gt;&lt;br /&gt;ruby.eval(new InputStreamReader(url.openStream()))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With my main scala code, I open a Qt main window.  Then hand things over to jruby.  My ruby code clears out the window and fills the UI programmatically.  I can add menus and event handlers as I go and when I'm ready to see the change, I simply restart the ruby evaluator and my UI rebuilt instantly with no recompilation.  I literally see no latency continually reloading my ruby code and seeing my interface changes change on the fly.  I plan to do most of my designing in ruby and gradually move the classes I create over to the scala-side once they become stable for a performance boost.  &lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_9O8xhktq4RU/TLHyQucvaQI/AAAAAAAABPQ/CPWWoU9KVz0/s1600/workspace.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/_9O8xhktq4RU/TLHyQucvaQI/AAAAAAAABPQ/CPWWoU9KVz0/s320/workspace.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;I like to keep one terminal open running sbt with the "~copy-resources" action continually copying my ruby changes over to the build path, while the other terminal compiles and runs my app as I go through the code changes in scala/ruby. &amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;I've just barely started with it, but I've been enjoying ruby for the most part.  A ruby developer would probably say I'm programming like a python programmer (a scala developer would probably say my scala looks like java).  Anyway, I haven't had any road blocks importing the various Qt or scala classes besides two minor inconviences.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;scala hashmaps&lt;/b&gt;&lt;br /&gt;The classes I've built in scala are compiled to byte code and I've been able to read them from java and jruby without any problem.  However, I use a few hashmaps in scala and I'd like to be able to iterate through them in my ruby code.  JRuby provides some hooks to iterate through java collections, but not for scala, so I made a simple wrapper for my scala hashmaps so I can iterate through them in ruby normally.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class ScalaHashMap&lt;br /&gt;  def initialize(hash)&lt;br /&gt;    @hash = hash&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def each&lt;br /&gt;    @hash.size().times{|key| yield key,@hash.get(key).get}&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Getting QtJambi to see the JOGL Context&lt;/b&gt;&lt;br /&gt;JOGL provides some useful widgets that directly tie into java swing.  These widgets don't exist in JOGL for Qt.  As such, it was slightly confusing trying to find documentation on getting a GL3 context from JOGL while inside a QGLWidget.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class PanelGL &amp;lt; QGLWidget   &lt;br /&gt;  def initialize(parent = nil)     &lt;br /&gt;    super     &lt;br /&gt;    @camera = Register.cameras.get(0).get      &lt;br /&gt;    profile = GLProfile.get(GLProfile::GL3)     &lt;br /&gt;    glCaps = GLCapabilities.new(profile)     &lt;br /&gt;    glCaps.setPBuffer true     &lt;br /&gt;    @pBuffer = GLDrawableFactory.getFactory(profile).createGLPbuffer(glCaps,DefaultGLCapabilitiesChooser.new(),       1, 1, nil)   &lt;br /&gt;  end   &lt;br /&gt;  attr_reader :camera    &lt;br /&gt;&lt;br /&gt;  def initializeGL     &lt;br /&gt;    @ctx = @pBuffer.getContext()   &lt;br /&gt;  end   &lt;br /&gt;  attr_reader :gl    &lt;br /&gt;&lt;br /&gt;  def resizeGL(width,height)     &lt;br /&gt;    @ctx.makeCurrent() # this line isn't required for the JOGL Swing components     &lt;br /&gt;    gl = @pBuffer.getContext().getGL.getGL3     &lt;br /&gt;    gl.glViewport(0,0,width,height)   &lt;br /&gt;  end    &lt;br /&gt;&lt;br /&gt;  def paintGL     &lt;br /&gt;    @gl = @pBuffer.getContext().getGL.getGL3     &lt;br /&gt;    @gl.glClearColor(0.3, 0.3, 0.3, 0.0)     &lt;br /&gt;    @gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)                  &lt;br /&gt;    @gl.glEnable(GL.GL_DEPTH_TEST)      &lt;br /&gt;&lt;br /&gt;    ...      &lt;br /&gt;&lt;br /&gt;    @gl.glDisable(GL.GL_DEPTH_TEST)   &lt;br /&gt;  end &lt;br /&gt;end &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I first create an pBuffer, so I can use it's context across GL widgets and share things like display lists and VBOs.  The big difference in the Qt code is having to call makeCurrent() in the first GL callback that my program executes, which happens to be &lt;i&gt;resizeGL&lt;/i&gt;.  Calling makeCurrent() there beforehand makes sure the GL context is running on the same thread as the Qt GUI (or vice versa, I guess).  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;That's my basic setup and now I've got a lot of coding to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-4008988749063186461?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/4008988749063186461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=4008988749063186461' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4008988749063186461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4008988749063186461'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2010/10/incorporating-scala-java-sbt-jogl-qt.html' title='Incorporating scala, java, sbt, JOGL, Qt, and Ruby/Python'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/TLHyQucvaQI/AAAAAAAABPQ/CPWWoU9KVz0/s72-c/workspace.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2466947900253675844</id><published>2010-01-26T12:41:00.000-08:00</published><updated>2010-01-26T12:48:29.701-08:00</updated><title type='text'>Example of Cache Coherency</title><content type='html'>In my almost popular article &lt;a href="http://www.cs.utah.edu/%7Ejstratto/state_of_ray_tracing"&gt;The State of Ray Tracing in Games&lt;/a&gt;, I've frequently mentioned the coherency of rasterization being much better than ray tracing, which is pretty incoherent in many respects.  I think programmers often address algorithms in a very high-level manner focusing on the big-O, which is important, but I wanted to present how coherency can directly and significantly affect run-time performance.  &lt;br /&gt;&lt;br /&gt;First, what is &lt;i&gt;coherency&lt;/i&gt;?  Coherency is defined by one dictionary as being &lt;i&gt;logically or aesthetically ordered or integrated&lt;/i&gt;.  The word comes up frequently when someone hears a disorganized speech or discussion, where the speaker jumps back and forth between topics.  No one sentence or idea is wrong per se, but as a listener it's easier to bundle ideas together on a topic instead of having to jump around.  &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Cache_coherence"&gt;Cache coherency diagram&lt;/a&gt; I stole from wikipedia&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_9O8xhktq4RU/S18g8I0dzRI/AAAAAAAAA1Y/DrLXmF12DNA/s1600-h/Cache_Coherency_Generic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_9O8xhktq4RU/S18g8I0dzRI/AAAAAAAAA1Y/DrLXmF12DNA/s320/Cache_Coherency_Generic.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Processors are incredibly complex now a days, but generally speaking there are registers which do the operations, the memory which holds the data and the program, and the cache, which sits in between.  One purpose of the cache is to provide a buffer of surrounding data, so I don't have to go all the way back to system memory to get it.  That trip might seem relatively fast, but it's pretty slow compared to just looking in the cache.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Diligent Secretary Example&lt;/b&gt;&lt;br /&gt;Imagine I was typing at my office desk and wanted to know the names on a numbered list down the hall.  I send my secretary down the hall to pull the name off the list and come back with it.  I use the name.  I move on to the next name.  This trip down the hall is relatively slow since I'm waiting for the secretary to come back.  It doesn't make sense for him/her to go all the way down and come back with just one name--even if at that moment I just want one name.  My secretary being the witty person that he/she is, goes and writes down ten names on this long list and comes back.  I ask for the requested name and he/she gives it to me.  I ask for the next name and the secretary instantly gives it to me without going down the hall again.  This happens eight more times before he/she has to go down the hall to get more names off the list, but he/she has saved both of us lots of time just by grabbing the names around what I wanted.  This is coherency.  Because I was asking for names in order down the list, my secretary could easily &lt;i&gt;cache&lt;/i&gt; extra names to save the trip down there.  It didn't work every time, but when it did it was significantly faster.  &lt;br /&gt;&lt;br /&gt;Now, what happens if I asked for the names in an incoherent manner?  My secretary comes back with the first group of names.  I ask for name #3, which he/she quickly gives me.  I then ask for name #47.  My secretary sees he/she only has 1-10 on his/her list, so he/she needs to make another trip.  This time my secretary remembers the names 40-49 and comes back.  I then ask him/her for number #212.  Once again the secretary has to go back to the list down the hall.  I'm not asking anything more complex.  I'm just asking in a seemingly incoherent order.  This same phenomenon is easily presentable in a real-world example.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Real Example&lt;/b&gt;&lt;br /&gt;Just as the secretary grabs the numbers around what I asked for with the possibility of not making another trip down the hall, processors will often pull out blocks or pages of memory around what the program requested hoping not to make the trip to system memory again.  If I ask for data close (in terms of memory layout) to what I previously requested, there's a possible chance the cache will already have it and provide it faster.  &lt;br /&gt;&lt;br /&gt;Here's a really simple python script that tries to add up a bunch of integers in a coherent and incoherent manner.  In the coherent function, the numbers are added up sequentially based on their order in memory.  In the incoherent function, the numbers are pulled randomly from memory.  Both functions provide the exact same result, but with a noticeable difference in performance.  Let's see how the two compare for different sizes of data.  &lt;br /&gt;&lt;br /&gt;&lt;pre style='color: gray;'&gt;import random, time&lt;br /&gt;&lt;br /&gt;n = 10000000&lt;br /&gt;&lt;br /&gt;# make an array of coherent and incoherent indices&lt;br /&gt;coherentIndices = [number for number in xrange(0,n)]&lt;br /&gt;incoherentIndices = [number for number in xrange(0,n)]&lt;br /&gt;random.shuffle(incoherentIndices)&lt;br /&gt;&lt;br /&gt;def print_timing(func):&lt;br /&gt;    def wrapper(*arg):&lt;br /&gt;        t1 = time.time()&lt;br /&gt;        res = func(*arg)&lt;br /&gt;        t2 = time.time()&lt;br /&gt;        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)&lt;br /&gt;        return res&lt;br /&gt;    return wrapper&lt;br /&gt;&lt;br /&gt;# create some random values&lt;br /&gt;values = []&lt;br /&gt;for i in xrange(0,n):&lt;br /&gt;    values.append(random.randint(-10,10))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# add up all the numbers coherently&lt;br /&gt;@print_timing&lt;br /&gt;def coherentAdding():&lt;br /&gt;    total = 0&lt;br /&gt;    for i in xrange(0,n):&lt;br /&gt;        total += values[coherentIndices[i]]&lt;br /&gt;&lt;br /&gt;# add up all the numbers incoherently&lt;br /&gt;@print_timing&lt;br /&gt;def incoherentAdding():&lt;br /&gt;    total = 0&lt;br /&gt;    for i in xrange(0,n):&lt;br /&gt;        total += values[incoherentIndices[i]]&lt;br /&gt;&lt;br /&gt;coherentAdding()&lt;br /&gt;incoherentAdding()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Results&lt;/b&gt;&lt;br /&gt;&lt;a href='http://manyeyes.alphaworks.ibm.com/manyeyes/visualizations/coherent-vs-incoherent-access/comments/49e82f780aa411df9afd000255111976' style='margin: 0pt; padding: 0pt;'&gt;  &lt;img alt="48e80eea-0aa4-11df-ae8a-000255111976" src="http://manyeyes.alphaworks.ibm.com/manyeyes/files/thumbnails/48e80eea-0aa4-11df-ae8a-000255111976.png?size=400x300" style="border: 1px solid #AF755D; margin: 0; padding-top: 10px; padding-bottom: 15px;" /&gt;  &lt;img alt="Blog_this_caption" src="http://manyeyes.alphaworks.ibm.com/manyeyes/images/blog_this_caption.jpg" style="border: 0pt none ; margin: 0pt; padding: 0pt; display: block; position: relative; top: -5px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With a quick graph using &lt;a href='http://manyeyes.alphaworks.ibm.com/manyeyes/'&gt;Many Eyes&lt;/a&gt;, you can see the performance differences.  For small numbers, the performance between the coherent and incoherent data is neglible.  In the secretary example, this would be the equivalent of the secretary having all the names in his/her head so regardless of the order I ask them, no extra trips down the hall are necessary.  &lt;br /&gt;&lt;br /&gt;As the problem scales, however, the memory fetching becomes less and less efficient.  For the largest test I did, incoherent access is almost 13 seconds longer than the 8 seconds it took for coherent access.  In this simple example where both functions are running at &lt;i&gt;O(n)&lt;/i&gt;, it's easy to see coherency makes a huge difference.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Relevance to Ray Tracing&lt;/b&gt;&lt;br /&gt;From a memory perspective, ray tracing is incredibly incoherent.  Firing a ray from the camera to shade a pixel, the next ray over might hit a different geometry requiring different textures and instructions to be fetched.  That's bad geometry and texture coherency.  Plus ray tracing is touted for it's secondary effects like reflections and refractions.  These rays are extremely incoherent.  One ray might self-intersect the object being shaded while another ray next to it might fly off into the distant corners of the scene.  Rasterization on the other hand is extremely coherent.  A model is pulled in once for every pass and thrown out again.  When rasterizing textured surfaces, the texture cache can grab large chunks of texture because there's good chance the next fragment being rendered is going to be in that cache.  In fact the biggest reason rasterization is probably so much faster than ray tracing is its coherency.  It makes hardware extremely easy and cheap to build.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2466947900253675844?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2466947900253675844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2466947900253675844' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2466947900253675844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2466947900253675844'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2010/01/example-of-cache-coherency.html' title='Example of Cache Coherency'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/S18g8I0dzRI/AAAAAAAAA1Y/DrLXmF12DNA/s72-c/Cache_Coherency_Generic.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1017841284433007893</id><published>2009-12-27T11:36:00.000-08:00</published><updated>2009-12-27T17:14:29.601-08:00</updated><title type='text'>ngons: Are they really that evil?</title><content type='html'>Playing around with polygons and trying to code them, I've seen a variety problems that can occur working with polygonal geometry.  More than once I've hit a snag in my program and I scratch my head and think, "How do the big guys handle that?"  Then I crack open Maya, build the same topology and see it break there as well.  What I've come to find is different modeling applications handle polygons in different ways--some are deficiencies and some are just design choices.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem with Tris and Quads&lt;/b&gt;&lt;br /&gt;A polygon as most people know requires at least three points.  This of course makes a triangle.  A triangle is an ideal planar figure as the three points--assuming they all don't lie on the same line--form a plane.  No matter where you move the points, they will always form a plane.  Interpolating attributes between the points is easy.  Triangles are simple to rasterize, ray trace, and are pretty much universal across modeling applications.  &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In geometry a polygon (pronounced /ˈpɒlɪɡɒn/) is traditionally a plane figure that is bounded by a closed path or circuit, composed of a finite sequence of straight line segments (i.e., by a closed polygonal chain).  -http://en.wikipedia.org/wiki/Polygon&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Stepping up to four points already begins to create problems with modeling applications.  This is because unlike a triangle, not all four points have to lie on the same plane.  The modeler can be restrictive to the user requiring all points to lie on the same plane (making it extremely difficult for an artist), or it can make certain assumptions about how to render a non-planar quad.  Sometimes this may or may not be what the artist wants.  There's not really a set definition of how to manipulate/render a non-planar polygon.  &lt;br /&gt;&lt;br /&gt;Take a look at the examples below.  In the first two images, the user grabs two vertices at opposite ends of the cube and pulls down forming what looks like a roof.  For many people, this maybe what they expect as the program--Blender in this case--just treats the quad as two triangles with the long edge going across the two unselected vertices.  This may seem perfectly acceptable, but look at the second example.  Now we grab the other two vertices and pull down.  One might look at the first example and now assume that it will also form the house, but instead it forms some kind of double-steeple with a rain gutter in between.  &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;b&gt;Pulling down to opposite vertices&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/Szeh5JGc9EI/AAAAAAAAArU/ctDwaQM0bY0/s1600-h/threshold1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Szeh5JGc9EI/AAAAAAAAArU/ctDwaQM0bY0/s320/threshold1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_9O8xhktq4RU/Szeh3kHIkeI/AAAAAAAAArM/F00Enn9rock/s1600-h/threshold2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_9O8xhktq4RU/Szeh3kHIkeI/AAAAAAAAArM/F00Enn9rock/s320/threshold2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Pulling down the other two vertices&lt;/b&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_9O8xhktq4RU/Szeh1iB9gRI/AAAAAAAAArE/RwQ2lM8BrKU/s1600-h/threshold3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Szeh1iB9gRI/AAAAAAAAArE/RwQ2lM8BrKU/s320/threshold3.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_9O8xhktq4RU/SzehzW3qV_I/AAAAAAAAAq8/9K4-rv5_UgY/s1600-h/threshold4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9O8xhktq4RU/SzehzW3qV_I/AAAAAAAAAq8/9K4-rv5_UgY/s320/threshold4.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What's going on?  Well, Blender just knows it has to render this quad face, so it looks at the first vertex on the face and says, &lt;i&gt;"Okay, let's render these as triangles since rendering non-planar quads doesn't make sense and a planar quad is just two triangles anyway."&lt;/i&gt;  So it looks at the next two vertices around the face--the one that was pulled down and the opposite unselected vertex and says, &lt;i&gt;"That's three"&lt;/i&gt; and renders a nice roof.  If you pull the other two vertices down like in the second example, Blender starts rendering at the same vertex as before, but goes up to the unselected vertex, and then back down to the other selected vertex forming that steeple/trench.  &lt;br /&gt;&lt;br /&gt;Here's the question.  Which one is correct?  If you pick one and assume that's what the program should always do, you've restricted the artist to never being able to make that other shape easily.  You may think Blender's not very smart not knowing how to render non-planar polygons, but that wouldn't be fair.  There's no rule.  If some program makes a certain decision about how to render that, it's just how they want to deal with it.  It doesn't make their solution correct, or Blender's solution incorrect.  &lt;br /&gt;&lt;br /&gt;You may be thinking, &lt;i&gt;"Hrmm, I bet I could write an algorithm that changes around the order of the rendering to guess what the artist wants..."&lt;/i&gt;.  It's been done.  If you go into Maya and try doing this example, you can actually get the model to &lt;i&gt;"pop"&lt;/i&gt; in between these two examples as Maya tries to figure out by some threshold what you're trying to do.  Is Maya right and Blender wrong?  Like I said there's no rule for handling non-planar polygons.  If you really want to bend a quad into a two triangles with guaranteed results, just make the two triangles before you bend them (as shown below).  Now there's no ambiguity at all.  The computer doesn't have to make any decisions about bending anything.  You're just moving the points on the triangle, and it knows how to do that no questions asked.  &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_9O8xhktq4RU/Szemsnel-cI/AAAAAAAAArk/TGLaLDlrfOY/s1600-h/threshold5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Szemsnel-cI/AAAAAAAAArk/TGLaLDlrfOY/s320/threshold5.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Not only do quads introduce problems like these when they're non-planar, but happens when the quad is not convex?  In the example below, I have pulled a vertex over to so the resulting polygon is concave.  If I grabbed a different vertex, the renderer might have done what you expencted rendering two nice triangles inside the quad.  But because I grabbed that vertex, the renderer made a triangle where it shouldn't have and you see visual tearing, where one triangle is sitting on top of another.  &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9O8xhktq4RU/SzeoNiMjG-I/AAAAAAAAArs/01CRk1_pk7Q/s1600-h/concavity1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_9O8xhktq4RU/SzeoNiMjG-I/AAAAAAAAArs/01CRk1_pk7Q/s320/concavity1.png" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/_9O8xhktq4RU/SzeoR0EM7KI/AAAAAAAAAr0/xIHsysTv_jI/s1600-h/concavity2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9O8xhktq4RU/SzeoR0EM7KI/AAAAAAAAAr0/xIHsysTv_jI/s320/concavity2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Here you might say, &lt;i&gt;"Well, if the Blender programmers made their modeler smarter, they could just look at that quad, see that it's concave, and render it with the correct triangles"&lt;/i&gt;.  That's certainly a valid point, but that takes processor time to figure out.  Assuming the polygon is planar, which as I already stated is iffy, the algorithm has to look at the quad and see how to best divide it up without going outside the polygon.  Maya does this and it may seem like a great idea, but that's processing power that could be doing other things like rendering larger meshes.  Which would you prefer?  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;No standards across programs&lt;/b&gt;&lt;br /&gt;Not only does the designers have to decide and implement these rules, but what happens when the model leaves the program?  Bending a quad may give you what you want in the modeler, but there's no guarantee the program where you're sending that quad handles it the exact same way.  Take a ray tracer, for instance.  I've never seen an ray intersection that handles a generic four-sided polygon.  It will usually divide it up into triangles as would a rasterizer.  There's no "correct" way to do handle non-planar polygons or concave polygons, so when you decide you want to model that way, you might get bitten later on.  Some programs might handle these issues better than others, but they are just making an arbitrary decision.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;N-gons are evil&lt;/b&gt;&lt;br /&gt;I have shown that just by moving from a triangle to a quad opens up a whole set of problems--one little extra vertex now allows an artist to create non-planar, concave polygons.  &lt;i&gt;"Yuck!"&lt;/i&gt;, I hope you are saying to yourself.  What about ngons?  &lt;i&gt;ngons&lt;/i&gt; are typically what people call polygons with five or more sides.  They have all the same problems as quads, except with infinitely more bad situations.  For someone whose never used ngons, he/she may ask, &lt;i&gt;"Well, why don't see just stay far away from ngons to avoid the problems?"&lt;/i&gt;.  This is yet another design decision.  Here are a somes reasons why ngons should or should not be included in a modeler.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;ngons are good&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;i&gt;"clean"&lt;/i&gt; topology&lt;/b&gt; - when working with a polygons that are going to be planar anyway, ngons don't display a bunch of edges across it, which makes the model look a little cleaner&lt;/li&gt;&lt;li&gt;&lt;b&gt;nice cuts&lt;/b&gt; - some tools create n-sided polygons.  Although they may create poor geometry, they can be extremely convenient&lt;/li&gt;&lt;li&gt;&lt;b&gt;power to the artist&lt;/b&gt; - allowing ngons in modelers gives the artist a chance to work more efficiently even though it may screw him/her up later.  Plus, once they're ready to export, they can always clean the mesh up afterwards (some artists prefer this workflow)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;An image I stole from the &lt;a href="http://www.blender.org/forum/viewtopic.php?t=4367"&gt;Blender forums&lt;/a&gt;.  The extrude-vertex tool creates two visible ngons I've marked with a red dot.  These ngons are very "clean" in the sense that they are planar, convex, and thus will break down to triangles without any funky results&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/Szey9weRj8I/AAAAAAAAAr8/nN05cfd5RiM/s1600-h/extrude_vertex.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Szey9weRj8I/AAAAAAAAAr8/nN05cfd5RiM/s320/extrude_vertex.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Two images I stole from &lt;a href="http://www.blender3darchitect.com/2009/09/3d-modeling-for-architecture-using-n-gons-and-b-mesh/"&gt;blender3darchitect.com&lt;/a&gt;.  The artist has replaced the distracting quads over the arches with a simple concave ngon.  It is debatable whether it is more pleasing to the eye--the former to me looks like keystones.  The artist will probably have to clean that up somehow (like triangulating it) before exporting the model&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/Szez51n1q0I/AAAAAAAAAsE/JkUqKEnkfcM/s1600-h/3d-modeling-architecture-ngons-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Szez51n1q0I/AAAAAAAAAsE/JkUqKEnkfcM/s320/3d-modeling-architecture-ngons-01.jpg" /&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/Szez_R-XcDI/AAAAAAAAAsM/kZc_C4ki8Bs/s1600-h/3d-modeling-architecture-ngons-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Szez_R-XcDI/AAAAAAAAAsM/kZc_C4ki8Bs/s320/3d-modeling-architecture-ngons-03.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;ngons are bad&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;no standards&lt;/b&gt; - there are no guarantees that ngons will import/export as expected.  I have read that Cinema 4D, for example, supports ngons, but triangulates ngons on import&lt;/li&gt;&lt;li&gt;&lt;b&gt;subdivision&lt;/b&gt; - working in realtime subdivion is very popular now a days, but how do you subdivide an ngon?  Most algorithms require very strict rules for mesh topology like the popular Catmull-Clark subdivision, that requires all quads.  People have implemented/published additions to these algorithms to make them more robust, but it's up to the designer to pick which one is best for them&lt;/li&gt;&lt;li&gt;&lt;b&gt;tool support&lt;/b&gt; - ngons require more complex data structures than quads or triangles meaning tools that work with the polygon have to be smarter--some tools just break or don't handle ngons&lt;/li&gt;&lt;li&gt;&lt;b&gt;processing power&lt;/b&gt; - nothing is for free and at some point the program has to decide how to render the ngons to the screen.  If it's a concave polygon, the program has to divide it into triangles that are contained in the original polygon.  Would the artist rather be spending this processing power on something else?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;What's the conclusion?&lt;/b&gt;&lt;br /&gt;I can't take sides with how important or useful ngons are.  I've heard several times that once an artist models with ngons, it's hard to go without them.  I'm not sure if that's a good thing or not.  ngons seem to make things easier at certain stages of modeling, while they often need to be cleaned up later in the pipeline.  Working with just triangles and quads can be extremely difficult in many situations, but several powerful tools like loop cut and loop select only work because of the special nature of quad loops, which is why some artists try to keep the model as quads as long as possible.&lt;br /&gt;&lt;br /&gt;Below is a screenshot from CGSociety, which has a wiki comparing the various modeling programs.  It's apparent that nearly every application now supports ngons.  &lt;i&gt;zBrush&lt;/i&gt; is excused since I'm sure it has insane data structures to handle what only zBrush can handle, and &lt;i&gt;Blender&lt;/i&gt; supposedly has ngon support on the way, so regardless of whether an artist needs it or should use it, support for them is/will be pretty much standard.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Table of modeling applications that provide &lt;i&gt;ngon&lt;/i&gt; support taken from CGSociety's &lt;a href='http://wiki.cgsociety.org/index.php/Comparison_of_3d_tools'&gt;wiki&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_9O8xhktq4RU/SzgGJ7MDSOI/AAAAAAAAAsU/tXRfKZXxdhI/s1600-h/comparison.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9O8xhktq4RU/SzgGJ7MDSOI/AAAAAAAAAsU/tXRfKZXxdhI/s320/comparison.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1017841284433007893?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1017841284433007893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1017841284433007893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1017841284433007893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1017841284433007893'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/12/ngons-are-they-really-that-evil.html' title='ngons: Are they really that evil?'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9O8xhktq4RU/Szeh5JGc9EI/AAAAAAAAArU/ctDwaQM0bY0/s72-c/threshold1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-3644276567633535368</id><published>2009-10-21T20:21:00.000-07:00</published><updated>2009-10-22T08:52:56.879-07:00</updated><title type='text'>Next-Gen 3D Rendering Technology: Voxel Ray Casting</title><content type='html'>Tom's Hardware recently did a follow up to their ray tracing article specifically on &lt;a href="http://www.tomshardware.com/reviews/voxel-ray-casting,2423.html"&gt;Voxel Ray Casting&lt;/a&gt;.  I thought it was a good review of the technology and did a good job presenting the pros and cons associated with it.  &lt;br /&gt;&lt;br /&gt;One of the most critical bottlenecks in any rendering technique is managing coherency.  The scene in a typical game may contain gigabytes of geometry and textures and it is important most of the time isn't wasted pulling the data in and out of the cache.  &lt;br /&gt;&lt;br /&gt;No graphics article/post would be complete without at least one comment in the discussion section referencing the Matrix and how it's so close to becoming a reality.  I guess that's optimistic considering we can't even predict the weather or have self-driving cars.  I did see a few other comments, which I thought deserved a bit more follow up.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;kikireeki   10/21/2009 7:28 PM&lt;/b&gt;&lt;br /&gt;&lt;i&gt;What happened to Normal Mapping?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Normal mapping is used when one wants to render limited geometry but apply a variety of normals the the otherwise flat surface giving the illusion of detail.  The point of this is to use really high amounts of geometry to do the job.  Normal mapping can't fix jagged silhouettes, for instance.  Each corner of a voxel has a stored normal value, and since these voxels will be less than a pixel when evaluated, the interpolated normal between these eight points is satisfactory.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;spiketheaardvark 10/21/2009 8:43 PM&lt;/b&gt;&lt;br /&gt;&lt;i&gt;I wish the article discussed how such a system would handle transparent objects and refracted light sources, such as an image of a glass of water.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;It doesn't.  Big disappointment, I guess.  If it could, it would be sparse-voxel ray tracing, wouldn't it?  The idea of ray casting is you only fire rays from the camera directly into the scene.  No secondary rays.  A big reason ray tracing is so slow is when secondary rays are fired to other parts of the scene for things like transparency, reflection, and shadows, you have to go get that geometry to intersect against and shade (including fetching the associated textures).  This is really difficult when rays are shooting off at random directions requiring everything to be paged in just to render a metallic sphere.  If you have multiple reflections around the scene, there's going to be a lot of paging going on.  Don't fire off enough rays for something like color bleeding and you get something like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/St_KeMk4aoI/AAAAAAAAAp4/p0ftSZy7gaE/s1600-h/amedeh.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_9O8xhktq4RU/St_KeMk4aoI/AAAAAAAAAp4/p0ftSZy7gaE/s320/amedeh.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Ray casting like rasterization is very coherent.  With rasterization the applicaition streams in geometry piece by piece and hopefully only has to do it one time.  With ray casting, part of the octree that fits in a given area of the screen can be paged in, ray casted, and paged out of memory.  If you want to add secondary effects, many secondary rays leave the paged in part of the octree and need the geometry for that part of the scene brought it.  And another secondary ray from the next pixel might shoot into a different part of the scene requiring another geometry fetch.  That's why voxelized octrees won't get us any closer to ray-tracing-style secondary effects.  It's just to give us more geometry.  It's just to give us more geometry!  IT'S JUST TO GIVE US MORE GEOMETRY!  I'm happy enough with that.  Even if it is only static geometry.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here's Jon Olick's demo video from Siggraph 2008.  If you're wondering what those funky blocks are, those are the individual blocks of the octree paged in and out of memory.  &lt;/b&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/VpEpAFGplnI&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/VpEpAFGplnI&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Adroid   10/22/2009 1:32 AM&lt;/b&gt;&lt;br /&gt;&lt;i&gt;Great Article. Its an interesting point that about 10 years ago the whole market went to polygons instead of voxels. Who knows where we would be if the industry went that direction. Nowadays processors are becoming more and more capable of such a feat.&lt;br /&gt;&lt;br /&gt;I think the sweet spot is finding a mix of both... Maximizing both processor and GPU use in games. Its a heck of alot of programming, but thats why they get paid the big bucks to make games we love right?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;If the whole industry went this way 10 years ago we'd be playing a lot more beautiful chess games and fewer 1st-person shooters.  I was at the conference when Jon Olick was presenting.  Of course, someone had to ask the question, "How do you handle animations and rebuild your octree?".  He simply replied that they're not out to solve a problem ray tracing researchers have been investigating for years.  This only works on static geometry.  This only works for static geometry! THIS ONLY WORKS FOR STATIC GEOMETRY!  To get these voxels, they model in polygons, then sample them into voxels.  To do this in a game with animations, they'd have to animate the character in polygons, voxelize, and render again to get all the data back.  And from what Jon Olick has mentioned, voxelizing is too slow for real time and has to be precomputed.  &lt;br /&gt;&lt;br /&gt;The idea certainly is to find the sweet spot.  Rasterize animated geometry and ray cast static geometry.  Developers can still model and rig everything with polygons and the engine can voxelize anything declared static.  Voxelized objects lose the ability to deform, but are rendered faster.  They can use the same surface shaders and even the same shadow maps, too.  It can be completely transparent to the developer using the engine besides choosing what's static and what's dynamic.  If the guys excitedly pushing this say it's not going to completely replace rasterization, they have no reason to lie, right?  I personally still think the GPU is still best suited for rendering as most games now like Crysis are CPU-limited already doing other things like AI, physics, etc. &lt;br /&gt;&lt;br /&gt;Here's the full pdf of Jon Olick's &lt;a href='http://s08.idav.ucdavis.edu/olick-current-and-next-generation-parallelism-in-games.pdf'&gt;slides&lt;/a&gt;.  They're pretty complex and don't have many shiny pictures, but it was a great presentation.  The best part of all this is the technology is available now on current hardware and will get more prominent as more and more developers become proficient in it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-3644276567633535368?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/3644276567633535368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=3644276567633535368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3644276567633535368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3644276567633535368'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/10/next-gen-3d-rendering-technology-voxel.html' title='Next-Gen 3D Rendering Technology: Voxel Ray Casting'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9O8xhktq4RU/St_KeMk4aoI/AAAAAAAAAp4/p0ftSZy7gaE/s72-c/amedeh.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-4228511271126358166</id><published>2009-08-15T14:55:00.000-07:00</published><updated>2009-08-15T16:13:28.859-07:00</updated><title type='text'>Step into Interactive Ray Tracing</title><content type='html'>I overheard someone commenting recently that ray tracing was the next logical step in interactive rendering.  Although this is surely a popular idea, he continued that switching to a ray tracer soon before secondary effects (like reflections and refractions) were practical would be worthwhile.  His argument was that since ray tracers can use the same graphical "hacks" like environment maps and shadow maps to match rasterization, when more performance comes down the road the developers could just swap out a given hack with the physically-accurate equivalent.  Why not, right?  Well, that's a tough pill to swallow.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Games are bottlenecking&lt;/b&gt;&lt;br /&gt;The fact of the matter is that interactive rendering--especially in games--is a very performance-intensive medium.  As opposed to most applications like a word processor or database, every AAA game title is developed to suck every last drop of performance out of the CPU and GPU.  If the developers are only getting 50% CPU/GPU utilitization, they naturally would tweak the game to get more visual quality out of the system.  This is natural considering most game players aren't multi-tasking between applicationss while running these programs and can dedicate the hardware to that one game.  &lt;br /&gt;&lt;br /&gt;This is the problem with transitioning to ray tracing.  To move to ray tracing while providing the same quality effects adds more work to an already bottle-necked system.  Ray tracing interactive scenes is inherently slower for the same perceptive quality.  Optics, BRDFs, and light-transport-related topics have been researched for hundreds of years.  Today's ray tracing researchers are focused on speed.  Problems include rebuilding dynamic acceleration structures, corralling rays into coherent packets, and getting all the operations to march in lock step on these SIMD-plentiful architectures.   It's all about performance.  The only time games will implement ray tracing is when they can do the same important effects as efficiently as rasterization.  Using rasterization techniques in ray tracers is still slower then rasterization: one still has to build acceleration structures, one still has to do crazy optimizations, and one still has to deal the incoherent texture and geometry accesses inherent in ray tracing.  So why on Earth would any developer opt for a ray tracer with half the performance for the same graphics just so fifty years down the road, it's easier to add secondary effects?  Blah.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rasterization's Bang for the Buck&lt;/b&gt;&lt;br /&gt;I've stated this before, but many production companies still use rasterization because they care about visual quality.  Pixar and Dreamworks, for example, still rasterize the scene first before adding any secondary effects.  After all these years these companies are still using basic shadow maps to shade direct illumination.  And it's their business to make pretty pictures!  The only people saying ray-traced games can do soft shadows interactively are ray tracing researchers and marketers.  I could write a rasterizer to do physically-accurate shadows, but it wouldn't be interactive either.  That's why I don't brag about it.  &lt;br /&gt;&lt;br /&gt;With the current growth of processing power, I am guessing that sometime in my life I will see ray tracing become the normal rendering technique in interactive computer graphics, but I doubt it will be in the next thirty years.  Rasterization will only fall behind the second it fails to keep improving.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Five-Years Difference&lt;/b&gt;&lt;br /&gt;Rasterization is moving at an incredible rate.  In a separate &lt;a href='http://www.cs.utah.edu/~jstratto/state_of_ray_tracing/'&gt;article&lt;/a&gt;, I compared a screenshot of two games only five years apart:  Battlefield 1942 released in 2002, and Crysis released only five years later.  This is what ray tracing is competing with.  A rapid, cut-throat industry where GPUs are getting more and more powerful and developers are creating more and more dazzling hacks.  Years from now when  a ray tracer can produce images comparable Crysis, we'll be looking back wondering how we ever tolerated such mediocre graphics.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/Soc8-EnnRII/AAAAAAAAAmw/VFM8nFpMH_k/s1600-h/bf1942.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Soc8-EnnRII/AAAAAAAAAmw/VFM8nFpMH_k/s400/bf1942.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5370328117752054914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/Soc9BqC5cYI/AAAAAAAAAm4/-rJsutkU8JM/s1600-h/Crysis_screen8.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Soc9BqC5cYI/AAAAAAAAAm4/-rJsutkU8JM/s400/Crysis_screen8.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5370328179338211714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What's coming down the pipeline?&lt;/b&gt;&lt;br /&gt;Interactive rasterization certainly hasn't stopped moving and will continue to provide a lot of one-sided competition for ray tracers in games.  &lt;br /&gt;&lt;br /&gt;Here are some things coming down the pipeline that we can look forward to that will continue to choke up interactive ray tracers:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Highly-tesselated subdivision surfaces&lt;br /&gt;&lt;li&gt;Movie-quality anti-aliasing&lt;br /&gt;&lt;li&gt;Realistic hair&lt;br /&gt;&lt;li&gt;Interactive deforming&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/SodAp74fvqI/AAAAAAAAAnI/oIlSJ9mQsgM/s1600-h/valvecritter02_160.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 160px; height: 184px;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/SodAp74fvqI/AAAAAAAAAnI/oIlSJ9mQsgM/s400/valvecritter02_160.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5370332169856073378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/SodAl4JcEEI/AAAAAAAAAnA/MSVG7SYs-J0/s1600-h/blondeHairRotate4_160.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 160px; height: 249px;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/SodAl4JcEEI/AAAAAAAAAnA/MSVG7SYs-J0/s400/blondeHairRotate4_160.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5370332100133916738" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-4228511271126358166?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/4228511271126358166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=4228511271126358166' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4228511271126358166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4228511271126358166'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/08/step-into-interactive-ray-tracing.html' title='Step into Interactive Ray Tracing'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9O8xhktq4RU/Soc8-EnnRII/AAAAAAAAAmw/VFM8nFpMH_k/s72-c/bf1942.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6901440019895436994</id><published>2009-08-13T15:34:00.000-07:00</published><updated>2009-08-13T15:46:27.363-07:00</updated><title type='text'>Shortest Ray Tracer In the World (not really)</title><content type='html'>I saw &lt;a href='http://www.cs.utah.edu/~aek/'&gt;Andrew Kensler&lt;/a&gt;'s newest &lt;i&gt;back-of-a-business-card&lt;/i&gt; ray tracer.  It's some pretty short and simple code to render his initials in reflective spheres.  I'm not sure he could find the way to shorten the code even more, without losing any kind of coherence.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This took 2 minutes on my workstation&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/SoSWTMj9QII/AAAAAAAAAmo/W4mtBsYijGU/s1600-h/aek.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/SoSWTMj9QII/AAAAAAAAAmo/W4mtBsYijGU/s400/aek.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5369581912266195074" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;And here's the code (butchered by my browser)&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &lt;stdlib.h&gt;   // card &gt; aek.ppm&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;#include &lt;math.h&gt;&lt;br /&gt;typedef int i;typedef float f;struct v{&lt;br /&gt;f x,y,z;v operator+(v r){return v(x+r.x&lt;br /&gt;,y+r.y,z+r.z);}v operator*(f r){return&lt;br /&gt;v(x*r,y*r,z*r);}f operator%(v r){return&lt;br /&gt;x*r.x+y*r.y+z*r.z;}v(){}v operator^(v r&lt;br /&gt;){return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.&lt;br /&gt;y-y*r.x);}v(f a,f b,f c){x=a;y=b;z=c;}v&lt;br /&gt;operator!(){return*this*(1/sqrt(*this%*&lt;br /&gt;this));}};i G[]={247570,280596,280600,&lt;br /&gt;249748,18578,18577,231184,16,16};f R(){&lt;br /&gt;return(f)rand()/RAND_MAX;}i T(v o,v d,f&lt;br /&gt;&amp;t,v&amp;n){t=1e9;i m=0;f p=-o.z/d.z;if(.01&lt;br /&gt;&lt;p)t=p,n=v(0,0,1),m=1;for(i k=19;k--;)&lt;br /&gt;for(i j=9;j--;)if(G[j]&amp;1&lt;&lt;k){v p=o+v(-k&lt;br /&gt;,0,-j-4);f b=p%d,c=p%p-1,q=b*b-c;if(q&gt;0&lt;br /&gt;){f s=-b-sqrt(q);if(s&lt;t&amp;&amp;s&gt;.01)t=s,n=!(&lt;br /&gt;p+d*t),m=2;}}return m;}v S(v o,v d){f t&lt;br /&gt;;v n;i m=T(o,d,t,n);if(!m)return v(.7,&lt;br /&gt;.6,1)*pow(1-d.z,4);v h=o+d*t,l=!(v(9+R(&lt;br /&gt;),9+R(),16)+h*-1),r=d+n*(n%d*-2);f b=l%&lt;br /&gt;n;if(b&lt;0||T(h,l,t,n))b=0;f p=pow(l%r*(b&lt;br /&gt;&gt;0),99);if(m&amp;1){h=h*.2;return((i)(ceil(&lt;br /&gt;h.x)+ceil(h.y))&amp;1?v(3,1,1):v(3,3,3))*(b&lt;br /&gt;*.2+.1);}return v(p,p,p)+S(h,r)*.5;}i&lt;br /&gt;main(){printf("P6 512 512 255 ");v g=!v&lt;br /&gt;(-6,-16,0),a=!(v(0,0,1)^g)*.002,b=!(g^a&lt;br /&gt;)*.002,c=(a+b)*-256+g;for(i y=512;y--;)&lt;br /&gt;for(i x=512;x--;){v p(13,13,13);for(i r&lt;br /&gt;=64;r--;){v t=a*(R()-.5)*99+b*(R()-.5)*&lt;br /&gt;99;p=S(v(17,16,8)+t,!(t*-1+(a*(R()+x)+b&lt;br /&gt;*(y+R())+c)*16))*3.5+p;}printf("%c%c%c"&lt;br /&gt;,(i)p.x,(i)p.y,(i)p.z);}}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'm still waiting for his &lt;i&gt;back-of-a-napkin&lt;/i&gt; photon mapper.  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6901440019895436994?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6901440019895436994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6901440019895436994' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6901440019895436994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6901440019895436994'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/08/shortest-ray-tracer-in-world-not-really.html' title='Shortest Ray Tracer In the World (not really)'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/SoSWTMj9QII/AAAAAAAAAmo/W4mtBsYijGU/s72-c/aek.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-5243246572224388268</id><published>2009-06-13T23:28:00.000-07:00</published><updated>2009-06-14T12:51:33.992-07:00</updated><title type='text'>Scala Review: Quite Refreshing</title><content type='html'>Since my first programming course in college, I've been told to use the right programming tool for the job.  This was back in the day where perl was the ideal CGI and scripting language.  I think even without python, perl was still the wrong tool for the job.  &lt;br /&gt;&lt;br /&gt;Regardless, I have used java many times for testing any idea floating around in my head.  It had the relative speed of C++ and came with many more libraries than C++ making it a lot easier to perform some arbitrary task like load an image without having to find a special C++ library like libpng.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;It's hard being number 2&lt;/b&gt;&lt;br /&gt;Java sure has its faults.  It certainly isn't the sexy language it was ten years ago, but it sometimes gets flak it really doesn't deserve.  It is always criticized for being slower than C++, while no one mentions it being faster than most other languages.  I guess it's hard being the number 2 in performance.  &lt;br /&gt;&lt;br /&gt;Java is a relatively simple language in the sense that it's pretty easy to understand what the code is doing.  C++ trivia questions abound that make you ask yourself, "Why?!  Why?!  Why?!  That must be a compiler bug!" until you see it in a C++ specification.  Java dropped function passing, pointers, multiple inheritance, operating overloading, and a lot of other features to create a language one might call dumbed down.  &lt;br /&gt;&lt;br /&gt;This, in my opinion, is one of Java's main complaints.  It's a simple language.  Usually when someone will start listing examples, it's them lamenting that Java can't do it their way like designing classes with multiple inheritance--sure, it means you have to rethink your problem, or you may have to type a bit more for a given problem, but I think deep down the person just wants to be different.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Scala building off of Java's success&lt;/b&gt;&lt;br /&gt;For many tasks, Java is everything I need it to be&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;The built-in packaging is much better than many other languages.  Those who refer to it as "jar hell" are just bitter C++ developers&lt;br /&gt;&lt;li&gt;It is a relatively fast language.  Java is usually not at the top on many language performance benchmarks, but it often comes as a close second.  &lt;br /&gt;&lt;li&gt;Java comes with some great libraries.  Some have gone as far as to criticize Java for having too many libraries, but these are just bitter C++ developers.  It's not like one library is obscuring another by popularity.  If I need java networking, an image library isn't going to throw me off the trail to find it&lt;br /&gt;&lt;li&gt;It has tons of examples.  I can't even count how many times I want to do some mundane task and a google takes me to an &lt;span style="font-weight:bold;"&gt;EXACT&lt;/span&gt; example in the java almanac&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Now, as much as I like Java, it will never displace all the other tools in my toolbox.  It's just a really handy tool I'm glad to have there.  Yet despite all the bonuses of Java as a language, there were always some features I didn't need or know I wanted, but when I found Scala, it literally opened my eyes.  Well, maybe not literally...  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Adding some nice features&lt;/b&gt;&lt;br /&gt;It's hard to summarize from a global perspective why I enjoy Scala, so here are a few small features that stood out to me.  &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Scala compiles to java byte code, so it has access to all java libraries ever written.  Java code can even use compiled scala code&lt;br /&gt;&lt;li&gt;In many tests I've seen, it is comparatively fast to java&lt;br /&gt;&lt;li&gt;Scala allows function passing, but in a better way than python.  An entire function block can be written inside a function call, which is a lot more powerful than python's lambda&lt;br /&gt;&lt;li&gt;Fun &lt;i&gt;match&lt;/i&gt; ability, which many refer to as a switch statement on steroids.  I recently learned it is an easy way to do type checking&lt;br /&gt;&lt;li&gt;Syntax-supported singleton objects, lazy evaluation of members, ...&lt;br /&gt;&lt;li&gt;The package system syntax is more flexible than java, where multiple public classes can be in the same file.  I believe even several classes from different packages can be stored in the same file&lt;br /&gt;&lt;li&gt;Tuples!  I never appreciated tuples until I started working in python.  Going back to java and having to write a separate class just to return two or three values is incredibly frustrating.  Java wants them; Scala has them&lt;br /&gt;&lt;li&gt;Scala is strongly-typed.  Some people may loathe this, but I actually prefer it.  When writing difficult code, I have never met a developer whose bottleneck is having to decide what type a variable should be.  It's writing code the compiler can heavily optimize, which is easier in a strongly-typed language and shows a lot of the problems at compile time instead of run time&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A note on syntax&lt;/b&gt;&lt;br /&gt;One of the Scala complaints I feel I must address is the syntax.  Some people would have preferred Scala to have a C-like syntax like so many other popular languages.  Now I myself also look at a language and sometimes cringe at the lack of curly-brace-separated blocks or not passing functions with parenthesis, but Scala is actually very simple to get used to.  Here are a few little differences that come to my head.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;object SingletonThing {&lt;br /&gt;   def display(name:String) { &lt;br /&gt;      println("I'm ready to work")&lt;br /&gt;      println("Thank you for calling me, " + name)&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's a singleton object.  It's very similar to the static methods one would put inside a class in java.  To make a singleton, just use the &lt;i&gt;object&lt;/i&gt; keyword instead of &lt;i&gt;class&lt;/i&gt;.  Also functions begin with the keyword &lt;i&gt;def&lt;/i&gt;.  I was adamantly resistant to this syntax for about ten minutes.  Also, parameter strings reverse the C++ order of types and variables.  I actually prefer this order now.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class GiveMeAFunction(someNumber:int) {&lt;br /&gt;   println("This is part of the GiveMeAFunction constructor")&lt;br /&gt;   val anotherNumber = someNumber + 5&lt;br /&gt;&lt;br /&gt;   def doSomethingWithTheNumbers(someFunctionYouGiveMe:(int,int) =&gt; Unit) {&lt;br /&gt;      someFunctionYouGiveMe(someNumber, anotherNumber)&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This example gives a few more insights into scala basics.  First, scala classes are declared with a default constructor parameter string and its constructor code trickles into the body.  It is possible to have secondary constructors, but I haven't needed them yet.  &lt;br /&gt;&lt;br /&gt;Second, you'll notice the &lt;i&gt;val&lt;/i&gt; keyword with member declared.  The two main ways to store a reference is with &lt;i&gt;val&lt;/i&gt; meaning that that value will remain constant, and &lt;i&gt;var&lt;/i&gt; meaning it is a variable.  Using &lt;i&gt;val&lt;/i&gt; supposedly allows the compiler to make certain optimizations, but it is more useful as a quick way to not accidentally mess up the value you have stored in it.  This syntax is somewhere in between C++ and python.  You can declare a value as variable or constant like C++, yet you don't have to manually retype the type similar to python.  I consider Scala's implementation superior to python's as once you declare a variable, it will remain that type where python will let you put whatever you want into it at any time.  This has been a headache for me when coding in python and I'll accidentally put a function into a variable instead the function's return value, which it won't complain about until somewhere later in execution.  &lt;br /&gt;&lt;br /&gt;And lastly is the function passing.  I created a method which takes a function &lt;i&gt;someFunctionYouGiveMe&lt;/i&gt;, which has to take two integers as parameters with &lt;i&gt;Unit (means void)&lt;/i&gt; return type.  I can then call that function or save it off to be used later.  I have grown to love this syntax.  &lt;br /&gt;&lt;br /&gt;Other than that, there are only minor differences to Java.  &lt;i&gt;if&lt;/i&gt; statements must be on the same line as their code if one doesn't used a code block.  Semi-colons aren't needed unless you really want to put two commands on the same line.  Also, importing is a little more robust than Java.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Scala is what Java should have been&lt;/b&gt;&lt;br /&gt;I encourage any person who enjoys Java or wants a little experience to toy around in Scala.  It's a functional/object-oriented hybrid that has been a really fun transition from Java.  &lt;br /&gt;&lt;br /&gt;A question I might be asked is if Scala is really so cool, why would I ever use Java again?  Well, the only reason I use Java now is to take advantage of Netbean's GUI-building forms.  Other than that, I will probably use Scala for everything else.  Some may consider Scala a fad, but I think with it's added features and friendly play with the Java language, it will be around as long as the JVM will be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-5243246572224388268?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/5243246572224388268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=5243246572224388268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/5243246572224388268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/5243246572224388268'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/06/scala-review-quite-refreshing.html' title='Scala Review: Quite Refreshing'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-7015505841311701811</id><published>2009-04-27T13:27:00.000-07:00</published><updated>2009-05-17T18:47:45.498-07:00</updated><title type='text'>Ray Tracing Simpler than Rasterizing?</title><content type='html'>In one short word... depends.  &lt;br /&gt;&lt;br /&gt;I would definitely agree that someone can sit down and bust out a simple ray tracer.  When I was learning python, I hacked a 500-line script to render a simple scene.  It has shadows, reflective materials, and a couple of primitives that would have to be discretized into triangles to render with a rasterizer.  The only real library I used was an image library to actually put the image into a window.  &lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;For handling reflections, I just reflect the ray direction off the surface and send it out again&lt;br /&gt;&lt;li&gt; When shading something, I fire a ray towards the light source and if I hit something before I get there, I shadow the surface  &lt;br /&gt;&lt;li&gt;I added a procedural checker material with only a few lines of code based on the surface position&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;In my opinion, it's some pretty simple code to implement these rather significant features.  If I wanted to add more complicated features like &lt;a href='http://strattonbrazil.blogspot.com/2006_12_01_archive.html'&gt;shade trees&lt;/a&gt;, it would have been a relatively simple addition.  Not only was this script straight forward, but I implemented it right off the top of my head.  I don't have the best of memory, so I'd like to reinforce these concepts are quite intuitive to remember.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple python ray tracer featuring procedural shading, Lambertian and reflective materials, and simple shadows&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/SfsbMprMREI/AAAAAAAAAks/o-4R6xi2524/s1600-h/example.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/SfsbMprMREI/AAAAAAAAAks/o-4R6xi2524/s400/example.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330884488082506818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href='http://www.cs.utah.edu/~jstratto/ray_tracer.zip'&gt;(source code)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Same work with a rasterizer&lt;/b&gt;&lt;br /&gt;Now, let's imagine that I had to write the same kind of functionality in a simple scanline rasterizer.  &lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;the procedural geometry is out--both the plane and the sphere have to be broken up into triangles, which isn't complicated, but surely not as elegant as some vector algebra&lt;br /&gt;&lt;li&gt;I would need to implement or find a matrix library to handle all my projections, and since I don't have the projection matrix memorized, I'd need to go get a reference of that&lt;br /&gt;&lt;li&gt;I would also need to implement the actual scanline algorithm to sweep through these polygons and implement a simple depth map&lt;br /&gt;&lt;li&gt;For shadows, I'd need to render a shadow map making sure the objects casting the shadows are in the light frustum&lt;br /&gt;&lt;li&gt;For reflections, I'd have to render an environment map, which would involve texture lookups and alignments, etc.  &lt;br /&gt;&lt;li&gt;The procedural checker material would probably be the easiest thing to implement, but I would have to interpolate the vertex attributes to the different pixels&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;I certainly can't elegantly fit all that in under 500 lines of code.  It's pretty evident that implementing a few basic visual effects is obviously much simpler with ray tracing.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Where is Rasterization Simpler?&lt;/b&gt;&lt;br /&gt;Ray tracing models light transport in a very physically-realistic manner.  It handles pretty much any "effect" rasterization can do, but it comes at a big cost--mostly performance.  Most ray tracing research currently is all about making the algorithm faster, which requires some very complex code to be written.  &lt;br /&gt;&lt;br /&gt;First, ray tracing pretty much requires the entire the scene including textures to fit into local memory.  For example, if you fire a ray into the scene above and it hits the ball, that ball needs to know about the plane below it and the ball to the left of it to do a reflection.  That's simple enough in this case, but what happens if your scene is five gigabytes and you have four gigabytes of RAM?  You have to go through the incredibly slow process of getting that primitive from the hard drive and load it into memory.  That's a ridiculously slow.  And the very next ray may require another hard drive swap if it hits something not in memory.  &lt;br /&gt;&lt;br /&gt;One easy solution is to break your scene up into manageable layers and composite them, but then you have to start keeping track of what layer needs what.  Like if you have a lake reflecting the far off mountains, both need to be in the same layer.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;What's with these acceleration structures?&lt;/b&gt;&lt;br /&gt;And what of these acceleration structures?  Ray tracing is often touted as being able to push more geometry than rasterization as an acceleration structure typically allows the ray to prune large groups of primitives and avoid costly intersections.  That's certainly nice if you happen to have one, but where do these structures come from?  You build it yourself!  And if you happen to be playing a game that requires any kind of deforming animation (almost any 3D game now a days), you have to rebuild these structures every frame.  &lt;br /&gt;&lt;br /&gt;Despite the research in this field, it's still expensive to maintain them as the scene changes.  &lt;a href='http://www.sci.utah.edu/~wald/Publications/2007///Star07/download//star07rt.pdf'&gt;State of the Art in Ray Tracing Animated Scenes&lt;/a&gt; discusses some of the more recent techniques to speed up this process, but as Dr. Wald says, &lt;i&gt;"There's no silver bullet."&lt;/i&gt;.  You have to pick which acceleration structure to use in a given situation, and then you have to efficiently implement them.  &lt;br /&gt;&lt;br /&gt;With a rasterizer, you have to linearly go through your entire list of geometry.  But if we're animating and deforming that geometry anyway, that's fine.  With a ray tracer, animation means having to rebuild your acceleration structures.  Why does ray tracing make animation so complicated when it should be so simple?  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ray Tracing Incoherency&lt;/b&gt;&lt;br /&gt;Ray tracing is inherently &lt;a href='http://en.wikipedia.org/wiki/Cache_coherence'&gt;incoherent&lt;/a&gt; in many ways.  Firing a ray (or rays) through every pixel makes it difficult to know what object the renderer will want in the cache.  For example, if one pixel hits a blade of grass, that geometry needs to be loaded into the cache.  If the very next pixel is another piece of geometry, that blade may need to be swapped out again.  For visibility rays you can optimize this a little bit, but with secondary rays (the entire purpose of ray tracing) these rays are going all over the place.  Many elaborate schemes have been developed to attack this problem, but it's a difficult property that comes with ray tracing and won't be solved any time soon.  &lt;br /&gt;&lt;br /&gt;A rasterizer is inherently coherent.  When you load a gigabyte-sized model into RAM and bring its gigabyte of textures, you render the entire scene, you're working with that one model until you need the next one.  When doing a texture lookup, there's a really good chance that chunk of texture is still in your cache since the pixel before probably used an adjacent texture lookup.  And when this model is completely rendered, you can throw it away and move onto the next one and let the &lt;a href='http://en.wikipedia.org/wiki/Depth_buffer'&gt;depth buffer&lt;/a&gt; take care of the overlaps.  Doesn't the depth buffer rock?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Both are Complex&lt;/b&gt;&lt;br /&gt;In general, there's nothing really simple about production-quality ray tracing.  It basically trades "graphics hacks" for system optimization hacks.  David Luebke said in Siggraph 2008, "Rasterization is fast, but needs cleverness to support complex visual effects.  Ray tracing supports complex visual effects, but needs cleverness to be fast".  Every scene is bottlenecked by time and trying to get ray tracing working in that time isn't always "simple".  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;nVidia's Interactive Ray Tracing with CUDA presentation&lt;/b&gt;&lt;br /&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="512" height="447" id="soundslider" align="middle"&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="movie" value="http://http.developer.nvidia.com/NVISION2008/IRT_CUDA/soundslider.swf?size=2&amp;format=xml" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="menu" value="false" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed src="http://http.developer.nvidia.com/NVISION2008/IRT_CUDA/soundslider.swf?size=2&amp;format=xml" quality="high" bgcolor="#FFFFFF" width="512" height="447" name="soundslider" align="middle" menu="false" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-7015505841311701811?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/7015505841311701811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=7015505841311701811' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7015505841311701811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7015505841311701811'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/04/ray-tracing-simpler-than-rasterizing.html' title='Ray Tracing Simpler than Rasterizing?'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/SfsbMprMREI/AAAAAAAAAks/o-4R6xi2524/s72-c/example.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6742141649798851627</id><published>2009-04-20T18:41:00.000-07:00</published><updated>2009-04-27T13:26:06.673-07:00</updated><title type='text'>Rasterization: King of Anti-Aliasing?</title><content type='html'>With the ongoing marketing of interactive ray tracing, I have continued to &lt;a href='http://www.cs.utah.edu/~jstratto/state_of_ray_tracing/'&gt;evaluate&lt;/a&gt; why rasterization will continue to be the dominant rendering method in games for quite some time.  Ray tracing is considered by many as the end-all-be-all in computer graphics and some people seem to simply turn their brain off when it comes time to discuss its disadvantages.  While conversing with an old colleague on that note, I realized I've never met a rasterization fanatic that insists everything has to be rasterized.  Wouldn't it make more since to use them in areas they excelled in?  As you read the next part, keep telling yourself rasterization still dominates the movie industry for good reasons and why those same principles apply in games.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rasterization: King (or Queen) of Anti-Aliasing&lt;/b&gt;&lt;br /&gt;It's pretty much undisputed (to sane individuals) that rasterization trumps ray tracing in terms of anti-aliasing.  When Pixar's &lt;a href='http://en.wikipedia.org/wiki/Reyes_rendering'&gt;REYES&lt;/a&gt; renderer was being developed, one of their primary goals was providing high-quality anti-aliasing.  This is one of rasterization's biggest advantages and one of the principal reasons off-line renderers still use rasterization for visibility rays.  This has to do with the basic difference between ray tracers and rasterizes.  With a ray tracer, one ray is fired per pixel and an intersection is computed for that ray.  With anti-aliasing, more rays are fired into the scene per pixel.  Thus if you want &lt;i&gt;n&lt;/i&gt; samples, you fire &lt;i&gt;n&lt;/i&gt; rays and do &lt;i&gt;n&lt;/i&gt; intersections.  These intersections are in 3D and are relatively expensive to compute.  Rasterization, on the other hand, does a lot of work to get a primitive onto the screen.  Once it's there, however, it can be sampled efficiently in 2D.  So, rasterizers project geometry into 2D, and we'd like to sample in 2D since we're making a 2D image anyways.  How convenient.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Once the primitive is on the screen, rasterizers can crank out the samples&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/Se010Hr_-cI/AAAAAAAAAkc/BQGb06mBz3s/s1600-h/sampling.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 350px;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/Se010Hr_-cI/AAAAAAAAAkc/BQGb06mBz3s/s400/sampling.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5326973103782230466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Imagine a pixel on screen as you see above and one desires to perform nine samples instead of one to provide a more alias-free image.  With ray tracing, each sample is an expensive intersection test.  With rasterization, the renderer simply has to decide, "Does this sample lie inside the primitive or outside?"  Hrmm, which one seems simpler?  That that may seem trite since a computer is doing all the work, but it's the difference between solving a complex 3D intersection or a 2D region test.  With ray tracing, firing &lt;i&gt;n&lt;/i&gt;-times more rays is &lt;i&gt;n&lt;/i&gt;-times slower.  With rasterization, the brunt of the work is getting it on the screen.  Once it's projected into 2D, samples are dirt cheap.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Who cares about anti-aliasing?&lt;/b&gt;&lt;br /&gt;The topic of anti-aliasing certainly isn't sexy.  It doesn't require secondary rays, funky texture maps, or any complex data structure.  It's usually just more work.  But it's one thing we haven't seen really pushed on GPUs--more settled on.  A modern video card can do 16x full screen anti-aliasing and certainly could do much more.  &lt;br /&gt;&lt;br /&gt;Look at the image below.  There's nothing really complicated in this scene.  Certainly nothing that would &lt;i&gt;require&lt;/i&gt; a ray tracer--mirrored reflections, simple smoke, some large textures, and a lot of little details.  For all I know this image could have been ray traced--probably considering every modeler comes with some kind of ray tracer--but it screams for a rasterizer.  You'll see games soon turning this stuff out in real time.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/SfYSNoo_AhI/AAAAAAAAAkk/VadOst3Tp4w/s1600-h/fullimg.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 180px;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/SfYSNoo_AhI/AAAAAAAAAkk/VadOst3Tp4w/s400/fullimg.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5329467234496479762" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Anti-aliasing in games&lt;/b&gt;&lt;br /&gt;With production studios sometimes requiring more than 64x samples per pixel, it's no wonder why companies are still rasterizing away.  With current graphics cards easily performing 8x sampling per pixel while ray tracers chug away on beastly machines to compete, it would take very little for GPUs to flex their anti-aliasing muscle with even more samples.  Anti-aliasing right now is pretty good and it's only getting better.  Movie quality anti-aliasing in a game?  Woo hoo!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6742141649798851627?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6742141649798851627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6742141649798851627' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6742141649798851627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6742141649798851627'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2009/04/rasterization-king-of-anti-aliasing.html' title='Rasterization: King of Anti-Aliasing?'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/Se010Hr_-cI/AAAAAAAAAkc/BQGb06mBz3s/s72-c/sampling.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-3940098758558932270</id><published>2008-12-28T22:47:00.000-08:00</published><updated>2008-12-29T09:06:27.121-08:00</updated><title type='text'>PC to PS3 (Little Big Planet, Orange Box, etc.)</title><content type='html'>&lt;b&gt;Accepting console gaming&lt;/b&gt;&lt;br /&gt;I have run Linux for several years now.  It is a great operating system--&lt;i&gt;yeah, I know it's really a kernel&lt;/i&gt;.  I can always brag to my Windows and Mac friends of the ease of pulling down development libraries, packages, and files within seconds without having to scour the web.  &lt;br /&gt;&lt;br /&gt;I am a gamer, however, and have always wanted to play games without any hassle; to own a game and have everything just work.  &lt;a href="http://www.winehq.org/"&gt;WINE&lt;/a&gt; has come a long way and has run World of Warcraft for me just fine, but with many other games I'm forced to tweak settings, use sub-par graphics, or worst-case scenario boot into Windows.  To solve my woe, I decided to get a console.  Hence, the PS3 sitting on my cabinet.  I'm also looking forward to buying used games at discount, which is pretty much unavailable for PC gamers.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Configuring the PS3&lt;/b&gt;&lt;br /&gt;Having not owned a console since the Sega Genesis--&lt;i&gt;I had Resident Evil 4 and a Gamecube for a few months&lt;/i&gt;--I've fallen a little behind on the console world.  The PS3 video snapped into my monitor via HDMI and I plugged the component audio cables into an old surround sound receiver.  On starting the system, I passed through a brief configuration menu.  One screen asked, &lt;i&gt;"Do you want video and audio to go through HDMI?"&lt;/i&gt;.  Well, technically no, I just want HDMI for the video.  So I answered no and my screen went black.  I restarted the PS3 and answered yes to get video and setup audio afterwards, but I thought it was a funny question to ask if you're going to make a user's screen go black.  &lt;br /&gt;&lt;br /&gt;The PS3 menu is pretty sleek.  It's a long horizontal bar of menus, where each focused menu will display vertical submenus of options.  It works well and although I got used to it quickly, I don't see it as replacing a typical vertical menu.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pleasant graphics&lt;/b&gt;&lt;br /&gt;Both the PS3 and XBox 360 have had many consumer complaints in reference to the resolution many games and videos run at.  For example, a game might render at 720p and be stretched to 1080 on the actual display.  Although this is noticeable, all the games and videos that do it still look decent.  &lt;br /&gt;&lt;br /&gt;I had a chance to play a few demos and realized the incredible difference in graphical quality between video games.  The aliasing in &lt;a href="http://www.mirrorsedge.com/"&gt;Mirror's Edge&lt;/a&gt;, for example, is horrible.  The game looks well enough and has cool-colored art direction, but I can't help wonder if they couldn't at least do some post-process anti-aliasing.  I've heard Microsoft actually has a stricter policy on anti-aliasing, but I can't reference that.  I have been having fun with features and like having such quick access to all the different playable demos.  It has been a lot of fun to download these demos and see if they're worthy of my wish list.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Orange Box&lt;/b&gt;&lt;br /&gt;I enjoyed Half-Life 2 and always wanted to see how the first and second episodes turned out.  The graphics are starting to show their age and the textures appear a bit blander than I'm used to compared to my PC.  I'm still surprised how bad the loading times are in this game.  Dying can take what feels like a minute to reload a level even if I died a few feet from the last load.  What is the system paging in and out?  Portal is a refreshing change.  It satisfies that little first-person-shooter-puzzle-genre craving I never knew I had.  &lt;br /&gt;&lt;br /&gt;Although I haven't gotten into Team Fortress 2 to its full degree, I have seen it in action and have been very impressed with the graphics this game puts out.  Some people were disappointed that Valve didn't attempt a realistic rendering system like everyone else in the industry.  Their loss, I guess, because the game looks great.  They have a great presentation, &lt;a href="http://www.valvesoftware.com/publications.html"&gt;Illustrative Rendering in Team Fortress 2&lt;/a&gt;, that really showcases the art direction to make such a great looking game.  Here's the &lt;a href="http://www.valvesoftware.com/publications/2007/NPAR2007_IllustrativeRenderingInTeamFortress2.wmv"&gt;high-quality video&lt;/a&gt;.  If you like art direction or new shader designs, I highly recommend reading their slides and technical article.  &lt;br /&gt;&lt;center&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-8c5fbfd6b43cb276" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v17.nonxt4.googlevideo.com/videoplayback?id%3D8c5fbfd6b43cb276%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1332991478%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6C2F3E483C98E527D942B859DF896349927C3C8C.562B01613BBA5360B5B0A173F482C6C1EA36F9EB%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D8c5fbfd6b43cb276%26offsetms%3D5000%26itag%3Dw160%26sigh%3D28rj2JvFND7J0bv9R_PHfIhLMfk&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v17.nonxt4.googlevideo.com/videoplayback?id%3D8c5fbfd6b43cb276%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1332991478%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6C2F3E483C98E527D942B859DF896349927C3C8C.562B01613BBA5360B5B0A173F482C6C1EA36F9EB%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D8c5fbfd6b43cb276%26offsetms%3D5000%26itag%3Dw160%26sigh%3D28rj2JvFND7J0bv9R_PHfIhLMfk&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ratchet and Clank: Tools of Destruction&lt;/b&gt;&lt;br /&gt;I played parts of the full version at a friend's house and downloaded the demo on my home machine.  This is one the best looking games I have ever seen.  The animations are smooth, the palettes are nicely colored, and everything is supremely sharp.  The draw distances are incredible.  Insomniac does Playstation exclusives and has always done a great job pushing a system.  It also handles really well and is just fun to whack things with a wrench.  I have included a couple screenshots stolen from Insomniac's site.  The game looks even better in motion.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/SVj-4du0KbI/AAAAAAAAAkE/fSOwoKZ5-tI/s1600-h/rcf_05.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/SVj-4du0KbI/AAAAAAAAAkE/fSOwoKZ5-tI/s400/rcf_05.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5285254408726391218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/SVj-4Iabc7I/AAAAAAAAAj8/d6QdEllsL5k/s1600-h/rcf_02.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/SVj-4Iabc7I/AAAAAAAAAj8/d6QdEllsL5k/s400/rcf_02.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5285254403003741106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Folklore&lt;/b&gt;&lt;br /&gt;This game got polar reviews with reviewers conflicted between its poor gameplay and great art direction.  The game features about three art styles sometimes jumping between 2D and 3D cutscenes and looks great.  It's a unique genre, but the first "boss battle" had me constantly fighting with the camera just to keep the enemy on my screen.  I stopped after completing that section fearing the rest of the game would include the same tedious and frustrating camera coordination.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Playstation Home&lt;/b&gt;&lt;br /&gt;&lt;i&gt;Playstation Home&lt;/i&gt; got terrible &lt;a href="http://penny-arcade.com/comic/2008/12/12/"&gt;reviews&lt;/a&gt; days before I received my PS3.  I wasn't excited to enter this online world, so I was ambivalent to these postings.  I was a little curious though, and gave it a quick pass through.  I can add to other statements that there is no reason why anyone should use &lt;i&gt;Playstation Home&lt;/i&gt;.  &lt;br /&gt;&lt;br /&gt;After a boring session of creating a customizable character, I ran around the courtyard waiting for other characters' skins to load on my machine while an empty shell of a person modeled their movements.  Moving into new buildings required additional downloads.  While I realize this happens only once, it is still annoying for the first visit to this online world.  &lt;br /&gt;&lt;br /&gt;Entering the theater, I sat down in an available chair and waited for the video to play.  Many people were standing up in front of the screen talking to each other, while others sitting in the audience with me were calling those in front to stop being duchebags and sit down.  I realized then that &lt;i&gt;Playstation Home&lt;/i&gt; is the 3D visualization of all the people on the internet I try to avoid put in the same room as me.  &lt;br /&gt;&lt;br /&gt;There is nothing redeeming about it and although it's in &lt;i&gt;beta&lt;/i&gt;, I can see no reason for anyone to use it.  I believe a product should enter &lt;i&gt;beta&lt;/i&gt; to work out bugs and get customers excited, but I believe most people like me will get a glance at it be extremely reluctant to return.  &lt;i&gt;Home&lt;/i&gt; might one day be a really excellent product, but it's going to take some extreme makeovers to make it such.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Little Big Planet&lt;/b&gt;&lt;br /&gt;I have heard complaints about this game lacking &lt;i&gt;game&lt;/i&gt; and being more of a tech demo.  I must say that this game is amazing.  I have always enjoyed platformers, and this game is a great platformer by itself.  It features a zany story, where players can pass through levels in coop &lt;i&gt;(either offline or online)&lt;/i&gt; with up to three others.  Most levels can be completed alone, but it's funner to play with a friend(s).  &lt;br /&gt;&lt;br /&gt;The graphics looks sharp and feature crisp textures, HDR effects like bloom, and decent camera work.  Every once and a while the camera will zoom too far in or out, but it's tolerable most of the time.  Smoke and fire effects aren't perfect, but they're pleasant to watch.  &lt;br /&gt;&lt;br /&gt;The gameplay implements a simple jump and grab mechanic so the controls are easy to master.  Like most platformers, the characters are required to do a lot of jumping, but this game includes a simple grab mechanic where the player can grab certain objects if they have a &lt;i&gt;"grab-able"&lt;/i&gt; material like sponge instead of stone.  This is used for hanging, swinging, pulling boxes and levers, etc.  There's also a depth or layer component where players can move closer or farther from the camera.  This is usually done automatically such that a player jumping from a depth of say 3 will naturally move forward to land on a platform of depth 2.  The mechanic isn't perfect and sometimes causes problems &lt;i&gt;(like totally unfair deaths)&lt;/i&gt; but is forgivable since it generally works well.  &lt;br /&gt;&lt;br /&gt;The gameplay is somewhat forgiving.  There are frequent save points littered throughout the game that allow players to restart there after dying--this only works a few times before the save point runs out of lives and the players must restart the level.  Also, objects that can kill the player by squishing or burning him/her usually give the player the benefit of the doubt by squeezing him/her through the crack or lightly singeing the player.  &lt;br /&gt;&lt;br /&gt;The real innovation of Little Big Planet is the excellent use of physics in the game.  Each object has its own material with corresponding properties like friction coefficient, mass, texture, etc.  It is fun to see your avatar catapulted over a wall or balancing on a teeter-totter-style platform.  &lt;br /&gt;&lt;br /&gt;The best thing about LBP is the level design.  The game has been in production for quite some and the developers have mastered the engine creating many beautiful and crazy levels.  I have seen almost every non-combative platforming mechanic put into these levels as well as new components that add new challegnes using physics, requiring teamwork with cooperative players, and just some new creative puzzles.  Some levels require two, three, or even four players to pass certain puzzles.  These are usually optional off-the-route treks to obtain additional collectibles.  &lt;br /&gt;&lt;br /&gt;It's hard to find good cooperative games these days so it's gratifying to see one that has really done such a great job nailing so many features.  I haven't any gotten to the level editor, but it's on the to-do list.  I can't imagine a video-game playing PS3 owner not purchasing this game unless they adamantly hate platformers.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/NhJHAc2HQao&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/NhJHAc2HQao&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;My first few days using a console have been very satisfying.  That feeling of running a game I own and not having to fight the system to get it to play is most pleasant and I urge other Linux users to consider having a separate machine like the PS3 to handle most of the their gaming needs.  It's also a great Bluray player.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-3940098758558932270?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=8c5fbfd6b43cb276&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/3940098758558932270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=3940098758558932270' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3940098758558932270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3940098758558932270'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/12/pc-to-ps3-little-big-planet-orange-box.html' title='PC to PS3 (Little Big Planet, Orange Box, etc.)'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/SVj-4du0KbI/AAAAAAAAAkE/fSOwoKZ5-tI/s72-c/rcf_05.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-7265779731809985572</id><published>2008-12-11T13:41:00.000-08:00</published><updated>2010-01-13T09:38:08.228-08:00</updated><title type='text'>Ray Tracing Basics</title><content type='html'>Dr. Steve Parker, who's academic team has done much to advance the field of ray tracing--specifically &lt;i&gt;interactive&lt;/i&gt; ray tracing has allowed me host his lecture slides on my blog.  Dr. Parker left the University of Utah earlier this year with Dr. Peter Shirley and several students to join nVidia in the hopes to produce high-quality, interactive ray tracing for consumers.  Some have sourced Dr. Parker as writing the first "interactive" ray tracer, which he implemented years ago on some SGI computers.  &lt;br /&gt;&lt;br /&gt;These slides are taken from his CS 6620 - Introduction to Computer Graphics II course.  It was basically all about writing fast and efficient ray tracers.  The slides contain a lot of C++, but start with basic vector math.  The slides have been compressed by me using Multivalent so they're quite a bit smaller than the originals.  &lt;br /&gt;&lt;br /&gt;The first lesson is a typical introduction to the course with pictures of ray-traced images and why ray tracing is useful.  Those wishing to skip these details can probably jump into the second slide.  They also include student project images including mine--the chess set.  Most of these competition images lost a lot of quality for some reason--even uncompressed.  You can see my image in an earlier post to see its original size and quality.  &lt;br /&gt;&lt;br /&gt;Also, if you use these slides, please keep the reference to Dr. Parker and his course.  &lt;br /&gt;Lesson 01 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-01-o.pdf'&gt;Introduction to Ray Tracing&lt;/a&gt;&lt;br /&gt;Lesson 02 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-02-o.pdf'&gt;Geometry for Graphics&lt;/a&gt;&lt;br /&gt;Lesson 03 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-03-o.pdf'&gt;The Ray Tracing Algorithm&lt;/a&gt;&lt;br /&gt;Lesson 04 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-04-o.pdf'&gt;Ray Tracing Software&lt;/a&gt;&lt;br /&gt;Lesson 05 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-05-o.pdf'&gt;Ray Tracing Software&lt;/a&gt;&lt;br /&gt;Lesson 06 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-06-o.pdf'&gt;Ray-Object Intersections&lt;/a&gt;&lt;br /&gt;Lesson 07 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-07-o.pdf'&gt;Triangles and Materials&lt;/a&gt;&lt;br /&gt;Lesson 08 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-08-o.pdf'&gt;Materials&lt;/a&gt;&lt;br /&gt;Lesson 09 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-09-o.pdf'&gt;Materials II&lt;/a&gt;&lt;br /&gt;Lesson 10 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-10-o.pdf'&gt;Materials II&lt;/a&gt;&lt;br /&gt;Lesson 11 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-11-o.pdf'&gt;Materials&lt;/a&gt;&lt;br /&gt;Lesson 12 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-12-o.pdf'&gt;Heightfields&lt;/a&gt;&lt;br /&gt;Lesson 13 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-13-o.pdf'&gt;Sampling I&lt;/a&gt;&lt;br /&gt;Lesson 14 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-14-o.pdf'&gt;Sampling II&lt;/a&gt;&lt;br /&gt;Lesson 15 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-15-o.pdf'&gt;Color Theory&lt;/a&gt;&lt;br /&gt;Lesson 16 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-16-o.pdf'&gt;Texturing I&lt;/a&gt;&lt;br /&gt;Lesson 17 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-17-o.pdf'&gt;Texturing II&lt;/a&gt;&lt;br /&gt;Lesson 18 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-18-o.pdf'&gt;Displacement, Bump, and Volumes&lt;/a&gt;&lt;br /&gt;Lesson 19 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-19-o.pdf'&gt;Acceleration Structures&lt;/a&gt;&lt;br /&gt;Lesson 20 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-20-o.pdf'&gt;Acceleration Structures II&lt;/a&gt;&lt;br /&gt;Lesson 21 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-21-o.pdf'&gt;Acceleration Structures III&lt;/a&gt;&lt;br /&gt;Lesson 22 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-22-o.pdf'&gt;Acceleration Structures 4 Instances&lt;/a&gt;&lt;br /&gt;Lesson 23 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-23-o.pdf'&gt;Monte Carlo I&lt;/a&gt;&lt;br /&gt;Lesson 24 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-24-o.pdf'&gt;Monte Carlo II&lt;/a&gt;&lt;br /&gt;Lesson 25 - &lt;a href='http://www.iinet.com/~janesrevolt/ray_tracing/cs6620-25-o.pdf'&gt;Monte Carlo III&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-7265779731809985572?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/7265779731809985572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=7265779731809985572' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7265779731809985572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7265779731809985572'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/12/ray-tracing-basics.html' title='Ray Tracing Basics'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2263611119374912463</id><published>2008-12-11T10:55:00.001-08:00</published><updated>2008-12-12T15:17:01.551-08:00</updated><title type='text'>Language Shootout</title><content type='html'>I program quite a bit in my free time on various projects.  I try to make sure I'm using the right tool for the job &lt;i&gt;(quote the hammer and screw analogy here)&lt;/i&gt;.  Despite the range of programming tasks I've undertaken, I have only a handful of languages I use frequently: C\C++, Java, Python, and PHP.  I like all these languages, but I try to make sure I choose the right one for the task.  While sometimes I have to use a specific one when I absolutely need a 3rd party library, I have a few flexible ideas of when to use a given language.  &lt;br /&gt;&lt;br /&gt;C\C++ were the first two languages I learned, and they can do quite a bit.  I usually choose this language when I absolutely need the fastest option available and I have the time to do the optimizations necessary to make it faster than Java--like SIMD operations.  &lt;br /&gt;&lt;br /&gt;I find Java to be a great prototyping language.  By prototyping, I do not mean a &lt;a href='http://en.wikipedia.org/wiki/Prototype-based_programming'&gt;prototype-based language&lt;/a&gt;, but a language that I can quickly develop a prototype for an idea I am playing around with.  Java comes with a good GUI library, is faster than scripting languages, and has a good range of libraries to work with.  I always hated doing something in C++ and realizing I needed to go hunt down a image library just to load a PNG file.  &lt;br /&gt;&lt;br /&gt;Despite what some people say, it is fast and has even beaten C\C++ on occasions--mostly where there are a lot of allocations and deallocations and the program isn't starting up and closing frequently.  &lt;a href='http://shootout.alioth.debian.org/gp4/benchmark.php'&gt;The Computer Language Benchmarks Game&lt;/a&gt; provides some performance analysis of several tests against many languages and Java is usually only ~10% slower.  It is faster in some cases such as their &lt;a href='http://shootout.alioth.debian.org/gp4/benchmark.php?test=binarytrees&amp;lang=all'&gt;binary-tree demo&lt;/a&gt;.  I mentioned Chris Kulla's Sunflow ray tracer earlier, which is written in Java.  He states his would be 20% faster if ported to C++, but I think his implementation is currently faster than most people's ray tracers for providing similar features.  &lt;br /&gt;&lt;br /&gt;I don't use Python much, but it's usually great for writing little scripts.  I prefer this to Java as it provides faster programming for simple tasks.  Although it is quite a bit slower than Java, it has a much faster init time so if I'm running the script frequently, it beats loading Java's large VM every time.  Maybe that's a moot point.  &lt;br /&gt;&lt;br /&gt;PHP is only useful for writing web applications.  Although this heavily limits its usefulness, nothing comes close to PHP's simplicity, ability to integrate with HTML, and huge list of useful functions.  I always use PHP for anything related to dynamic web content.  &lt;br /&gt;&lt;br /&gt;I'm sure many will disagree with my criteria for languages.  Some people insist ADA is the most useful language &lt;i&gt;(like the creator of ADA)&lt;/i&gt;.  To each his own, but these languages have been good to me.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Reply to Comment #1&lt;/i&gt;&lt;br /&gt;I received a comment on the "The Computer Language Benchmarks Game" link where I mentioned the test where Java beat C\C++ telling me to &lt;i&gt;"note"&lt;/i&gt; that the Java program used a large heap, only beat C++ on one architecture, and that other C++ implementations were tested that were faster.  &lt;br /&gt;&lt;br /&gt;Language benchmarks will always lead to arguments about implementations, architectures, etc.  I do not think Java is always faster than C++.  I do not think Java is as fast as C++.  But I do think they can be close.  My point was Java beat C++ in one benchmark so to say "Java is slower" is a little unfair.  &lt;br /&gt;&lt;br /&gt;As I stated earlier, you can always make C++ faster than Java if you have the time and if speed is a concern.  Chris Kulla's Sunflow ray tracer is fast--not fast for a &lt;i&gt;Java&lt;/i&gt; ray tracer but fast for a ray tracer.  I'm sure it could be much faster if he switched to C\C++, but he said it allowed faster development time at the cost of maybe 20% performance.  To me, I'd rather take a performance hit like that if I had more time to make it a more feature-rich application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2263611119374912463?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2263611119374912463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2263611119374912463' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2263611119374912463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2263611119374912463'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/12/language-shootout.html' title='Language Shootout'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-9052894628587892460</id><published>2008-12-10T19:12:00.000-08:00</published><updated>2008-12-10T19:55:32.798-08:00</updated><title type='text'>Dreamworks Interview</title><content type='html'>After being on the job hunt a certain amount of time and seeing my carefully chosen list of possible employers start to dwindle, I started sending on tens of unsolicited resumes hoping someone would bite.  One such company was Dreamworks Animation.  &lt;br /&gt;&lt;br /&gt;After putting together an impressive resume and cover that fit me as their ideal candidate, I sent it off.  Seconds later, I received an automated response &lt;i&gt;"The following addresses had permanent fatal errors"&lt;/i&gt;.  That sounded really bad.  Not only were the errors fatal, but they were permanent and would remain so for the rest of time.  I sent off another e-mail to the webmaster asking if my application was in fact received.  That responded with another automated response claiming the mail server itself was down.  I took it as a sign that working at this company was not meant to be.  I received a phone call a few days later.  &lt;br /&gt;&lt;br /&gt;The conversation was typical for a first call--verified my information, my interests, what job they were trying to fill.  Even though I applied for a programming position, they wanted to interview me for technical director.  Since it was an interview, I accepted.  &lt;br /&gt;&lt;br /&gt;The Dreamworks interview process was actually quite simple for me.  They scheduled a video conference and sent me down to a local FedEx Kinkos.  In a large conference room filled only by myself and a TV/camera stand, I sat at the end of the table while I was grilled by Dreamworks employees.  &lt;br /&gt;&lt;br /&gt;The employees interviewed me in pairs or &lt;i&gt;teams&lt;/i&gt;.  The first team was "Team Oddball" as they called it, which asked trivia-like questions.  Unlike my interviews at Intel, they actually remembered the answers to the trivia questions, which made the quiz a much more pleasant experience.  One question, for example, was &lt;i&gt;"If you have a three-gallon and a five-gallon bucket with unlimited water, how do you measure out four gallons?"&lt;/i&gt;.  The other questions ranged in difficulty.  Most of them were pretty fun and allowed me to think and explain how I would do it.  &lt;br /&gt;&lt;br /&gt;The next pair asked more technical questions related to graphics, but it was a pretty simple interview.  Subjects ranged from 2D intersections to level-of-detail.  Every person that interviewed me was a technical director, which I really appreciated.  I used the Q &amp; A time to ask them about a typical day, what they liked, challenges, etc.  &lt;br /&gt;&lt;br /&gt;I was supposed to have an interview with the director of technical directors, Mark McGuire, who oversees all TDs on all movies, but he wasn't available that day.  To make up for it, he called me the next day.  He mostly wanted to make sure, as everyone had, that I had a very clear idea of what this position entailed.  I always found that a difficult question to answer as I don't think I can ever understand a position unless it's a common profession or I spend a day doing it.  &lt;br /&gt;&lt;br /&gt;A few days later I received an actual offer from the company.  The hiring manager explained compensation, the benefits like provided breakfast and lunch, etc.  He worked hard to sell me on it.  Even though I asked for more time to complete the hiring process with some other companies I was interviewing with at the time, I ended up accepting the offer.  I start on the 5th of January.  Although I didn't want to live in California, I'm excited to start at what appears to be a fun and dynamic company.  By the way, if you haven't seen Kung Fu Panda, the humor alone sells it.  The art direction is just more bang for your buck.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-9052894628587892460?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/9052894628587892460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=9052894628587892460' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9052894628587892460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9052894628587892460'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/12/dreamworks-interview.html' title='Dreamworks Interview'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2422437274613178726</id><published>2008-11-20T15:46:00.000-08:00</published><updated>2008-12-03T15:33:35.968-08:00</updated><title type='text'>FBO Multisampling</title><content type='html'>I was using pBuffers in OpenGL when FBOs were coming around.  Moving to FBOs seemed like a huge increase in simplicity and functionality.  I started using them all the time.  However, I have always wanted to add a little bit of anti-aliasing, but never quite knew how.  &lt;br /&gt;&lt;br /&gt;Sometimes googling for OpenGL functions returns pages of garbage and spec files don't always provide clear examples to use.  Well, I have found a web page of someone who has had the same problems and has posted his solution including the setup, blitting, etc.  &lt;br /&gt;&lt;br /&gt;Normally I wouldn't post a blog on a code snippet, but I think this deserves another link so more people will run across this little OpenGL gem.  &lt;br /&gt;&lt;br /&gt;Thanks, Stefan!  &lt;br /&gt;&lt;br /&gt;&lt;a href='http://blog.dexta.ch/2008/08/27/gl_ext_framebuffer_object-with-multisampling/'&gt;(click here)&lt;/a&gt; for multisampling in an FBO.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2422437274613178726?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2422437274613178726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2422437274613178726' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2422437274613178726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2422437274613178726'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/11/fbo-multisampling.html' title='FBO Multisampling'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-4332760181766414235</id><published>2008-11-07T07:50:00.000-08:00</published><updated>2008-11-11T06:54:49.851-08:00</updated><title type='text'>Sunflow - A Java ray tracer</title><content type='html'>After all the posts and &lt;a href='http://www.cs.utah.edu/~jstratto/state_of_ray_tracing/'&gt;articles&lt;/a&gt; I've written on why I don't think interactive ray tracing is the future of games, I have always said ray tracing has its place.  One ray tracer I have become acquainted with a bit ago was &lt;a href='http://sunflow.sourceforge.net'&gt;Sunflow&lt;/a&gt;, a really neat Java ray tracer written by Chris Kulla.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ajax model rendered in Sunflow by Tartiflette&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/SRmbbkturaI/AAAAAAAAAjE/4I1qkJDmG1U/s1600-h/statue_ajax-jpeg.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/SRmbbkturaI/AAAAAAAAAjE/4I1qkJDmG1U/s400/statue_ajax-jpeg.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5267412137200758178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;First of all, this guy knows ray tracing.  He's a programmer at Sony Imageworks and has created a very robust ray tracer with a very intuitive code base.  Some may wonder why someone would write a ray tracer in Java when C++ is clearly faster.  It's true, most C++ code runs faster than Java if its written by a competent programmer &lt;i&gt;(which he is)&lt;/i&gt;, and even Chris admits this.  However, he notes that in his experience C++ is only about 20% faster and for a non-interactive renderer, this isn't much of an issue.  Especially since writing it in Java would make network rendering much simpler &lt;i&gt;(see project &lt;a href='http://sfgrid.geneome.net/'&gt;Helios&lt;/a&gt;)&lt;/i&gt;.  If you are familiar with ray tracers, you can open up the source code and easily navigate around and see what is going on.  &lt;br /&gt;&lt;br /&gt;The Sunflow project is a couple years old now and has a host of features including caustics, normal mapping, photon mapping, multi-threading, and a shader API that allows you to write your own materials in Java.  Many people have provided exporters from Maya, Blender, XSI, and a few other modeling programs.  &lt;br /&gt;&lt;br /&gt;Although it's only version 0.07.2, it is stable and supports many &lt;a href='http://sunflow.sourceforge.net/index.php?pg=feat'&gt;features&lt;/a&gt; that most artists will be satisfied with.  So check out the &lt;a href='http://sunflow.sourceforge.net/'&gt;website&lt;/a&gt; or at least look at the &lt;a href='http://sunflow.sourceforge.net/index.php?pg=gall'&gt;gallery&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-4332760181766414235?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/4332760181766414235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=4332760181766414235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4332760181766414235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4332760181766414235'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/11/sunflow-java-ray-tracer.html' title='Sunflow - A Java ray tracer'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/SRmbbkturaI/AAAAAAAAAjE/4I1qkJDmG1U/s72-c/statue_ajax-jpeg.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1603932192574154404</id><published>2008-10-02T08:42:00.000-07:00</published><updated>2008-10-05T07:02:32.126-07:00</updated><title type='text'>Pixar Interview</title><content type='html'>Everyone knows Pixar would be a great place to work.  At Siggraph it seemed aspiring animators and modelers were lining up with their reels and portfolios eager for a internship or residency at such a production house.  &lt;br /&gt;&lt;br /&gt;Yesterday I went up to Seattle to interview with the Pixar team in charge of the Renderman products.  This office does not handle production.  Instead it deals with the actual technology that the artists use for rendering, shading, and distributing the work among computers.  &lt;br /&gt;&lt;br /&gt;Having spent eight years in the northwest, it was a great feeling to be back.  I had a couple of hours to walk around downtown Seattle before my interview.  If you've never been to Seattle, it's a great city.  The cityscape has a huge variety of architecture; each one has a unique and pleasing style.  Pixar's office is currently located in &lt;a href='http://en.wikipedia.org/wiki/Smith_Tower'&gt;Smith Tower&lt;/a&gt;, the oldest skyscraper in Seattle.  For a moment I thought I had the wrong building until I asked the clerk.  Upon entering, you walk down a narrow hall with an array of shiny golden elevators to your right.  Stepping into these golden boxes, a &lt;i&gt;liftman&lt;/i&gt; manually shuts the door and turns a lever for a given level.  The Pixar office itself was fronted by a reddish office door with the old-style blurry glass and &lt;b&gt;PIXAR&lt;/b&gt; in big black letters like you'd see in a detective's office.  The door was cracked open slightly and I could feel the awesomeness vibes pulsating from the interior.  How do people work in such extreme conditions?  &lt;br /&gt;&lt;br /&gt;The interview process was more involved than I expected.  The actual interviews lasted about 3 hours.  During that time, developers, engineers, prospective bosses, etc. were shuffled in and out.  The interviews were quite casual and they seemed to focus more on my experience than on-the-fly technical quizzes you hear about at some firms.  Most of the technical questions related to something on my resume to the regard of "Why did you do it that way?".  The developers came in pairs of two and I had the chance to meet some really cool people.  &lt;br /&gt;&lt;br /&gt;One pair of developers that came in were &lt;a href='http://www.seanet.com/~myandper/publicat.htm'&gt;Per H. Christensen&lt;/a&gt; and George Harker.  I quoted something I heard from a ray tracing symposium a few years ago in reference to Renderman's code length.  Per replied, "I said that".  I felt a little silly.  Maybe he was flattered.  I also told them I've played around with &lt;a href='http://www.renderpixie.com/'&gt;Pixie&lt;/a&gt;, a Renderman-compliant renderer.  I felt even sillier after George replied, "Yeah, I wrote that."  Oops again.  Need to do a better job keeping track of these things.  After arriving back in Salt Lake and doing some homework, I realized I had actually heard Per's presentation at Siggraph on &lt;a href='http://www.seanet.com/~myandper/abstract/sig08c16.htm'&gt;Practical Global Illumination with Irradiance Caching&lt;/a&gt;.  Triple oops.  I need to pay more attention to people who may one day interview me.  They could be anywhere...  The entire team seemed very talented.  &lt;br /&gt;&lt;br /&gt;After the interviews, I returned to the streets of Seattle.  They recommended a good dinner location at a nearby pub.  Brian Saunders told me I could get sweet potato fries if I asked for them.  Out of curiosity I did.  Sadly, a break down in communication happened and I was rendered sweet-potato fryless, so to speak.  I sat at the bar and ordered, to which the bartender turned to a red head and said, "One burger and sweet potato fries".  She asked how to cook the meat and went off.  Thirty minutes later, I was getting anxious to get to the airport and still no food.  I asked the red head the status of my burger.  After coming back she said, "The guy you talked to didn't actually order it, so we'll give you a burger that was going to someone else".  I was thinking, "Didn't he tell you to do it?".  I didn't say anything.  The burger and normal fries arrived and were delicious, so all turned out well.  If I get the job or happen to return to Seattle, I'll have to go back and try the sweet potato fries.  If so, expect a blog post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1603932192574154404?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1603932192574154404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1603932192574154404' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1603932192574154404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1603932192574154404'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/10/pixar-interview.html' title='Pixar Interview'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2436282631579521713</id><published>2008-09-28T07:11:00.001-07:00</published><updated>2008-10-02T08:39:51.395-07:00</updated><title type='text'>Job Hunting</title><content type='html'>I'm finally leaving academia and searching for a career that provides satisfaction and a real salary.  I've applied to a lot of big names and gotten fairly decent results.  &lt;br /&gt;&lt;br /&gt;Pixar has interviewed me over the phone and is flying me out next week to their Seattle Renderman team.  Although I don't have a ton of experience in film production, I'm hoping any job they offer me will lead to a full-time development position on one of their rendering products.  They didn't ask any technical interview questions besides what I've done, so I expect I'll get some of that face to face.  &lt;br /&gt;&lt;br /&gt;Intel's Visual Computing Group is flying me out to Hillsboro, OR next week for an interview on their driver development team for Larrabee GPU designing the DirectX driver.  I was under the impression that most of this work had been done considering that they provided performance benchmarks for many games like Gears of War in their &lt;a href='http://softwarecommunity.intel.com/UserFiles/en-us/File/larrabee_manycore.pdf'&gt;paper&lt;/a&gt;.  The interviewer said he couldn't specify how complete the implementation was when I asked him, he did say that with Microsoft's active development of the DirectX API, there will always be new additions to the driver.  I've heard working at Intel can be a little intense and they push there employees relatively hard, a couple of people who have worked there say that they actually like that about Intel.  I don't know DirectX very well, but from what I understand, it's a lot easier for driver development than OpenGL for several reasons.  Hrmm, I guess that means I won't be working on a Linux/FreeBSD machine...&lt;br /&gt;&lt;br /&gt;I also had a phone interview with a couple of developers from Google.  I applied to Google without a clear idea what I'd be doing there and just assuming it would be a great place to work.  The first developer to call me was Sean Pidgin, one of the project leads for Pidgin &lt;i&gt;(formerly GAIM)&lt;/i&gt; and the project head for Google Talk.  They started out talking a little about my background, but did have several casual technical questions about threading and networking as well as some formal coding I did over a Google Docs document we shared.  I'm still not used to coding on the fly especially over the phone, but I think I did alright.  I always get nervous when at the end they ask me, "Can this be more efficient?".  Of course it can, but the first thing I say doesn't mean it's the best thing I can do.  Can I writer talk out a scene with the same finesse he/she publishes a work?  They asked questions about things like race conditions with threads, binary tree searches, etc.  Like I said, I still don't have a clear idea what I'd do at Google given that there job descriptions require knowledge of everything, but in a way that's pretty cool.  &lt;br /&gt;&lt;br /&gt;In general I'm fairly content with the interviews I've been able to receive.  I've only been looking for a couple weeks and already have a few flights scheduled for on-site interviews.  We'll see where I finally end up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2436282631579521713?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2436282631579521713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2436282631579521713' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2436282631579521713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2436282631579521713'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/09/job-hunting.html' title='Job Hunting'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-379494920420557228</id><published>2008-09-28T06:26:00.000-07:00</published><updated>2008-09-28T07:10:07.189-07:00</updated><title type='text'>State of Rasterization</title><content type='html'>I was down at Siggraph when the new OpenGL 3.0 specification was released.  I was excited for the OpenGL BoF later that week to see all the specified updates they had promised.  Monday of that same week, I read a slashdot &lt;a href='http://tech.slashdot.org/article.pl?sid=08/08/11/2135259'&gt;article&lt;/a&gt; that kind of broke the news to me that the original enhancements to the specification like the object model were butchered.  I was a little shocked, but was sincerely hoping it was like many slashdot articles, where the commenters simply read the summary and didn't bother reading the article.  I had some naive hope that the webmaster accidentally posted the old specification up using the new file name, but after scanning the entire specification, I can see that wasn't the case.  Many people were angry that they were left in the dark so long about the drop in features and the news that Khronos would drop the ball like ARB has done.  Although I think Khronos screwed up, I still think a much-needed object model will is still on the road map and through these frequent "updates", I can see more state-friendly API.  nVidia already released a new extension that provides texture building with binding that texture.  Even though it's just an extension, I hope to eventually see many other functions go down that road.  &lt;br /&gt;&lt;br /&gt;nvidia has done a good job supporting OpenGL in various ways including graphics demos, presentations, APIs, etc.  Although I don't see much use with some of the new additions to the pipeline--nvidia itself has told developers NOT to use the geometry shader--I do like some of the things presented in this new API.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;nvidia's slides on OpenGL features on the GeForce 8 architecture.  I'm linking them straight from the nvidia &lt;a href='http://origin-developer.nvidia.com/object/nvision08-opengl2.html'&gt;page&lt;/a&gt; until they tell me I can't&lt;/b&gt;&lt;br /&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="512" height="447" id="soundslider" align="middle"&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="movie" value="http://http.developer.nvidia.com/NVISION2008/OpenGL_MJK_GF8/soundslider.swf?size=2&amp;format=xml" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="menu" value="false" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed src="http://http.developer.nvidia.com/NVISION2008/OpenGL_MJK_GF8/soundslider.swf?size=2&amp;format=xml" quality="high" bgcolor="#FFFFFF" width="512" height="447" name="soundslider" align="middle" menu="false" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;One of the cooler additions to the rendering pipeline IMHO is the transform feedback buffer.  Basically when you send vertex data down the pipeline and it gets transformed by various matrices in the vertex shader, you don't really have an idea of what those vertices actually get transformed to.  You could do some GPGPU thing where you print the vertex information to the screen and read it back, but this is tedious to implement and debug.  A better solution would just be to store these transformations in the rendering API.  One of the pesky things about shadow volumes is you have to compute the edge silhouettes.  This has been solved in a respect in "Shadow Volumes on Programmable Graphics Hardware" by Brabec &lt;i&gt;et al.&lt;/i&gt;, and now can be implemented trivially using this new transform feedback buffer.  Other work has been down to use silhouettes to provide some effect, so I can see Brabec's implementation applied to a whole slew of visual effects that require light or camera silhouette information.  In their presentation, they use the geometry shader for silhouette detection, which I think is a mistake.  Much like Barnes and Noble dedicating a section to &lt;i&gt;Vampire Romance&lt;/i&gt; might be considered a mistake.  Maybe that's a stretch.  &lt;br /&gt;&lt;br /&gt;Another exciting extension is the &lt;i&gt;EXT_direct_state_access&lt;/i&gt;.  Although this isn't the "object model" many people were expecting, I believe this kind of extension will generally lead into the state-friendly programming model we all wanted.  How many times have we not known the state of OpenGL coming into a given function and changing the state would possibly break the assumptions a proceeding function would have?  Once again kudos to nvidia for a great support and presentations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-379494920420557228?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/379494920420557228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=379494920420557228' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/379494920420557228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/379494920420557228'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/09/state-of-rasterization.html' title='State of Rasterization'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-9074268239271046660</id><published>2008-09-15T08:38:00.000-07:00</published><updated>2008-09-15T10:00:11.342-07:00</updated><title type='text'>Rasterization versus Ray Tracing</title><content type='html'>&lt;a href='http://home.comcast.net/~tom_forsyth/blog.wiki.html'&gt;"Real-Time Ray Tracing: Holy Grail or Fool's Errand?"&lt;/a&gt; is an older article, but I think it's short, simple, and to the point, which you don't see every day.  The author Dean Calver gives a very brief comparison of rasterization and ray tracing then summarizes some of the problems with ray tracing--specifically aliasing, dynamic scenes, and global illumination.  &lt;br /&gt;&lt;br /&gt;I've written about problems with dynamic scenes in the past.  Although many people prefer ray tracing for its simplicity, it requires acceleration structures to run quickly.  In David Luebke's &lt;a href='http://developer.nvidia.com/object/nvision08-IRT.html'&gt;presentation&lt;/a&gt; he made an excellent statement that I think described the rasterization-versus-ray-tracing debate rather well.  &lt;br /&gt;&lt;br /&gt;&lt;i&gt;"Rasterization is fast, but needs cleverness to support complex visual effects.  Ray tracing supports complex visual effects, but needs cleverness to be fast."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Another problem I think isn't discussed much is texture locality.  Although I don't consider this as big of a problem for ray tracing as dynamic scenes, it's a performance penalty.  The problem involves ray tracing being an image-based algorithm.  If you shoot a ray into the scene and it hits a textured object, you need to fetch the texture into the cache.  If the next pixel uses a different texture, a new texture chunk must be fetched.  This is in contrast to an object-based technique, where adjacent fragments on the object usually use adjacent texels.  A worst case scenario for ray traced scene might be tracing textured grass against a textured wall.  Every couple of pixels, you'd need to refetch the another texture block.  Although this is a generalization since caches are big and the entire texture doesn't need to be fetched, it's still an issue and today's textures are getting rather large.  With rasterization, the wall would be drawn with the texture, then the grass would be drawn with the other possibly creating no duplicate cache misses.  If you read the original &lt;a href='http://graphics.pixar.com/Reyes/paper.pdf'&gt;REYES paper&lt;/a&gt; by Cook &lt;i&gt;et al.&lt;/i&gt;, you'll see that spend a good chunk of the paper talking about texture locality, because it can severely impact performance.  &lt;br /&gt;&lt;br /&gt;I think nvidia isn't concerned whether ray tracing takes over the rendering pipeline as long as it's done on the GPU.  Luebke and Parker's presentation goal was to show what nvidia hardware could do, and allow developer to decide what was best for them.  More options kind of thing.  Although I didn't care too much for the ray tracing portion of the demo, I did think he had compelling screenshots of what rasterization is currently capable of rendering.  &lt;br /&gt;&lt;br /&gt;Both presentations conclude that a hybrid algorithm is the future.  Calver likes the idea of rasterizing the visible portion of the screen and using that information to ray trace secondary rays.  Frankly, I don't think this idea is very promising.  Rasterization is great for the visible rendering of the screen, but if you're doing secondary rays, you'll need the acceleration structures that you didn't want to build in the first place.  If this wasn't an issue problem, then you could just ray trace everything.  Ray tracing is very fast for primary rays if the acceleration structures are already built.  You have tons of coherency assumptions.  David Luebke's idea seems more plausible, where scene assets are sorted into ray-traced and rasterized passes.  You can rasterize animated objects like people without having to build an acceleration structure and ray trace other objects that require effects reflections.  But once again, what are you intersecting you're secondary rays with?  In my diagram below, I have a sample scene using a ray-traced reflective sphere and a rasterized animated person.  It's crude, but I'm trying to give a simple example.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;The ray-traced sphere needs an updated acceleration structure to perform accurate reflections on the animated, rasterized figure&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/SM6JltXgzdI/AAAAAAAAAac/yK38oBqbsC8/s1600-h/hybrid.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/SM6JltXgzdI/AAAAAAAAAac/yK38oBqbsC8/s400/hybrid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5246281896859586002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You rasterize the person just like you would in current games.  Then you ray trace the sphere.  The ray hits the sphere and you want to calculate the intersection of it with the person.  But the person doesn't have an acceleration structure because it's being animated.  If we had the acceleration structure built, we would have just ray traced it.  I'm trying to say that I don't see how ray tracing secondary rays will ever play nice with rasterized, dynamic geometry.  &lt;br /&gt;&lt;br /&gt;Jon Olick's presentation used ray casting for static geometry, which I think provides more immediate benefits.  Most games already have special rendering techniques for static geometry like lightmaps for all the floors and walls, so having special rendering "cheats" for static geometry isn't new.  Although this doesn't provide higher-order effects like ray tracing does, it will significantly increase geometric complexity of static portions of the scene. Furthermore, this technique is relatively easy to incorporate into existing pipelines at relatively no cost.  &lt;br /&gt;&lt;br /&gt;Although I still don't like the current marketing push towards ray tracing including Intel's, I am mildly excited for Intel's Larrabee.  As long as it rasterizes competitively fast, it could allow developers to easily add new features and extensions to the pipeline faster than current GPU hardwares are able.&lt;br /&gt;&lt;br /&gt;Oh, and though I don't have anything to say about the other presentations, kudos to nvidia for always doing a good job posting their &lt;a href='http://developer.nvidia.com/object/siggraph-2008.html'&gt;presentations&lt;/a&gt;.  I did see Sarah Tariq's hair presentation and think we're getting close to seeing scenes with characters with animated, beautiful, frothy, tangly, wavy, shiny hair.  Check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-9074268239271046660?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/9074268239271046660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=9074268239271046660' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9074268239271046660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9074268239271046660'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/09/rasterization-versus-ray-tracing.html' title='Rasterization versus Ray Tracing'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/SM6JltXgzdI/AAAAAAAAAac/yK38oBqbsC8/s72-c/hybrid.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-8992348782052855655</id><published>2008-09-03T08:52:00.000-07:00</published><updated>2008-09-16T09:18:21.824-07:00</updated><title type='text'>Siggraph 2008</title><content type='html'>Well, I went to Siggraph for the first time.  It was an interesting experience.  The convention consisted mostly of presentations/lectures, an exhibition hall of company booths, and the "Art Festival".  &lt;br /&gt;&lt;br /&gt;The presentations were fairly interesting.  Nothing earth-shattering.  A saw a few random posters that showed some novel work.  Blue Sky Studios gave an amazing presentation of the art direction creating &lt;i&gt;Horton Hears a Who&lt;/i&gt;.  I didn't see the movie when it came out.  I guess &lt;i&gt;Cat in the Hat&lt;/i&gt; left a bad taste in my mouth for Suess-movie conversions.  However, this movie looked fantastic.  The speaker discussed several artistic approaches to modeling a Suess-like world of asymmetric trees, heavy, blobby, saggy objects, and color palettes for different scenes.  From the clips I saw the movie looked amazing and was pretty hilarious.  &lt;br /&gt;&lt;br /&gt;Jon Olick from id gave a really good &lt;a href='http://s08.idav.ucdavis.edu/olick-current-and-next-generation-parallelism-in-games.pdf'&gt;presentation&lt;/a&gt;.  He has done a lot of level-of-detail work on games like Ratchet and Clank: Tools of Destruction.  Although I've never played the game, many reviews I've read have commented on the amazing draw distance Insomniac achieved.  I believe some of the implementations involved geomorphing, which he discussed.  Jon finished the talk discussing the sparse-voxel octree for static geometry that John Carmack has proposed.  I must state this proposal is only for STATIC geometry as the octree isn't rebuilt dynamically.  This question was raised at the presentation and Jon quickly stated he wasn't attempting to solve dynamic octree construction that everyone has been working on for years.  Although it only works for static geometry, it should provide a big leap in geometry resolution at comparable storage or traditional triangular meshes--these sparse octrees can be streamed in by the amount of screen footprint supposedly allowing extremely detailed assets.  Furthermore, it should be easily combined to current pipelines that raster dynamic geometry.  And even though ray tracing nuts (not researchers--just enthusiasts) supposed that this was a huge step towards full ray tracing, this method only works for ray casting so one still needs things like shadow maps for global illumination effects (like shadows).  Overall I thought he gave the best presentation--mind he actually gave a demo of the proposal, which makes it much more convincing.  &lt;br /&gt;&lt;br /&gt;Intel gave several presentations on the Larrabee architecture and how it will not suck.  They repeatedly stated how they weren't showing any benchmarks since there's no product for another couple years, so it's hard for me to really get excited about it.  Larry Seiler gave the first presentation even though he's not actually on the Larrabee architecture paper.  Weird as it seems, the guy seemed very cool.  I stopped him in the hallway to ask him a few questions.  He set his bag down and started chatting away happily.  Another time I saw him sitting in a corner with a couple of young geeks with their laptops flipped open asking him questions.  For a mid-50s guy from Intel to just sit on the ground and field questions seemed pretty cool to me.  Although I don't have a lot of confidence that Larrabee will be a competitive GPU, I thought they picked a great spokesman.  He said he was chosen specifically for his past experience with GPU architectures.  &lt;br /&gt;&lt;br /&gt;nVidia gave its ray tracing demo of a car flying through the city.  I saw it first hand sitting on the front row while my old professor Steve Parker explained the technology.  Although I think he's brilliant programmer, I wasn't very impressed with the whole demo.  The scene was a cityscape with a car driving through it.  I've expressed my concerns with ray tracing in previous posts like problems with texture coherency.  The demo had very bland textures and for running on four nvidia quadroplexes, it really wasn't very impressive visually.  They even mentioned a "canyon" shader, which gave the buildings a more realistic look.  From what he explained, the shader was a linear ramp from dark to light just how canyons are typically darker at the bottom.  When a linear luminance ramp is a topic of interest in 2008, I think the demo has failed.  They zoomed in on the headlamps to show 7 bounces of ray tracing, which I guess is really important, but to me it just looked very noisy.  I know it got a lot of people excited, but with the hardware they were running it on, I'd have rather seen a rasterized scene running at 128x anti-aliasing and per-fragment environment mapping.  The demo was basically glorified ray tracing with accurate reflections.  If they want accurate reflections, why didn't they just implement Jen Krueger's &lt;a href='http://wwwcg.in.tum.de/Research/data/Publications/vmv07.pdf'&gt;GPU Rendering of Secondary Effects&lt;/a&gt;.  Sure, 3rd or 4th bounces have less accuracy, but if you saw the demo, the tertiary rays really didn't contribute much to the image quality.  Like I said, I'd rather have seen a rasterized demo running on that beastly hardware.  The talk itself wasn't too bad.  David Luebke talked about effects that developers are eager to use and how nVidia's working to provide them with it--things like better soft shadow, depth of field, caustics, etc.  &lt;br /&gt;&lt;br /&gt;The exhibition hall was comprised of animation/production schools, production companies, development booths from Autodesk, zBrush, a bunch of motion capture companies, etc.  It was fairly exciting at first but lost its appeal after a day.  The Art Festival was also pretty fun.  &lt;br /&gt;&lt;br /&gt;Not sure if I'll attend next year.  I felt like most of the students there only wanted to hit Dreamworks and Pixar for job interviews.  One animator even asked why a CS person was attending Siggraph.  I was a little shocked, but was polite.  It's in New Orleans next year, which just got hit by Gustav.  I remember shoveling mud out of people's second story houses.  Why can't they get rid of the levees and turn New Orleans into the Venice of the US?  It's below sea level and building levees and watching them fail again and again is getting old.  You're below sea level and the current system isn't working.  Time for a change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-8992348782052855655?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/8992348782052855655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=8992348782052855655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/8992348782052855655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/8992348782052855655'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/09/siggraph-2008.html' title='Siggraph 2008'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-3728877704870842113</id><published>2008-07-18T13:16:00.000-07:00</published><updated>2008-07-18T13:18:52.607-07:00</updated><title type='text'>Opinion on Ray-Traced Video Games</title><content type='html'>I've posted a brief commentary of what I feel about this hype mostly Intel is pushing about bringing ray tracing to video games.  Although it's an interesting idea, I don't see it replacing rasterizing GPUs anytime in the near future for several reasons.  &lt;br /&gt;&lt;br /&gt;&lt;a href='http://www.cs.utah.edu/~jstratto/state_of_ray_tracing/'&gt;State of Ray Tracing (in Games)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-3728877704870842113?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/3728877704870842113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=3728877704870842113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3728877704870842113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3728877704870842113'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/07/opinion-on-ray-traced-video-games.html' title='Opinion on Ray-Traced Video Games'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6975560336706464016</id><published>2008-03-12T17:13:00.000-07:00</published><updated>2008-03-12T17:16:04.138-07:00</updated><title type='text'>First Place in Ray Tracing!</title><content type='html'>Our ray tracing class ended with a ray tracing competition that any student could optionally enter.  The only requirement was our ray tracer had to implement at least two Monte-Carlo techniques.  I chose to implement soft shadows using multiple samples on a light sphere and embossed reflections.  &lt;br /&gt;&lt;br /&gt;Although my ray tracer wasn't the most technically superior, it won the top $100 prize judged by an independent panel of professors.  I will probably spend the money on groceries for next week...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6975560336706464016?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6975560336706464016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6975560336706464016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6975560336706464016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6975560336706464016'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2008/03/first-place-in-ray-tracing.html' title='First Place in Ray Tracing!'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6603869894322101500</id><published>2007-04-23T06:42:00.000-07:00</published><updated>2008-12-10T15:23:45.385-08:00</updated><title type='text'>Ray Tracing - Project 10</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;I decided to model a chess set for my image.  All pieces in the scene are modeled with triangles except the board (a box) and the ominous red sphere.  All the chess pieces were modeled using Blender by myself and exported to the OBJ format, for which I wrote a mesh parser.  &lt;br /&gt;&lt;br /&gt;The board is rendered using two different Perlin noises and rendered with soft shadows by displacing the light position using a spherical distribution and many samples per pixel.  The chess pieces have the same two materials as the board, so I tried to place them on opposing colors so the Perlin noise wouldn't match up perfectly.  &lt;br /&gt;&lt;br /&gt;This project took me a long time (close to twenty hours, I imagine), mostly because I took so long trying to decide what scene I wanted.  I decided to do a chess theme since it gave me a lot of control over how I wanted to lay it out, and I didn't want to do anything too terribly abstract (like a bunch of dragons staring at a heightfield).  The final images took around 30 minutes to render using 25 samples per pixel.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Extra Credit&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;My second Monte Carlo effect was embossed reflections.  This was added to materials using a Russian roulette method, where either the diffuse color or the reflected color would be calculated based on the ratio assigned between the two.  The embossed reflections were generated by perturbing the normal over a uniform disk.  The disk size determined the amount of blurriness.  &lt;br /&gt;&lt;br /&gt;I originally blended the two colors together, but that introduced a number of artifacts.  Switching to the Russian roulette method, these dropped significantly, but I still see an occasional blue splotch.  Also, the Russian roulette method looks horrible at low-sampling rates since every other pixel might have a different shading calculation.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is my final rendered scene using soft shadows and embossed reflections.  It took about forty minutes to run using 25 samples per pixel&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/Riy7mkokKaI/AAAAAAAAAG8/lIqNWfLyC4o/s1600-h/chess_set_5_1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Riy7mkokKaI/AAAAAAAAAG8/lIqNWfLyC4o/s400/chess_set_5_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5056622752973466018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code:&lt;/b&gt;&lt;a href='http://www.cs.utah.edu/~jstratto/tracer.tar.bz2'&gt;tracer.tar.bz2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6603869894322101500?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6603869894322101500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6603869894322101500' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6603869894322101500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6603869894322101500'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/04/ray-tracing-project-10.html' title='Ray Tracing - Project 10'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9O8xhktq4RU/Riy7mkokKaI/AAAAAAAAAG8/lIqNWfLyC4o/s72-c/chess_set_5_1.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6193799013889293095</id><published>2007-04-11T22:32:00.000-07:00</published><updated>2008-12-10T15:23:45.768-08:00</updated><title type='text'>Ray Tracing - Project 9</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;To implement instancing, I created an instance class inherited from the Primitive class.  This allowed a simple abstraction for adding groups and other objects and stuff.  The preprocess function called the grid layout preprocess for every instance so I added a check to only preprocess once.  I used a matrix and a vector to hold the translations and rotations and created to functions for rotating and translating.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is a really stupid picture of the Stanford bunny rotated and translated around in a strange manner showing the transformations possible with the new instance class&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/Rh3G0pblTkI/AAAAAAAAAGs/TQSUj0ygdMg/s1600-h/basic.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/Rh3G0pblTkI/AAAAAAAAAGs/TQSUj0ygdMg/s400/basic.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5052412964756606530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;I was feeling patriotic and made a giant bunny flag and just gave it three different colors based on a series of modulos.  I was really bored&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/Rh3HMpblTlI/AAAAAAAAAG0/RHepB3F-9jU/s1600-h/flag.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/Rh3HMpblTlI/AAAAAAAAAG0/RHepB3F-9jU/s400/flag.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5052413377073466962" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code: &lt;/b&gt;&lt;a href='http://www.cs.utah.edu/~jstratto/project9.tar.bz2'&gt;project9.tar.bz2'&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6193799013889293095?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6193799013889293095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6193799013889293095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6193799013889293095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6193799013889293095'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/04/ray-tracing-project-9.html' title='Ray Tracing - Project 9'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/Rh3G0pblTkI/AAAAAAAAAGs/TQSUj0ygdMg/s72-c/basic.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-3283366833583072368</id><published>2007-03-28T19:00:00.000-07:00</published><updated>2008-12-10T15:23:46.883-08:00</updated><title type='text'>Ray Tracing - Project 8</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;Most of the code modifications occurred in the Scene class.  I chose to do this since it seemed logical that different scenes be rendered using different filters and samplings.  Also, the Scene class is where the rays are created, so it was a simple change in code.  &lt;br /&gt;&lt;br /&gt;The code changes had two parts.  One which allowed additional samples to be calculated at different points based on the filter, and another part of the code, which calculated the weight of each sampling.  I chose the Gaussian filter to implement as it seemed simple and provide okay results, although not too much better then the actual triangle filter.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Rendered with 1 sample per pixel (no jittering)&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;The function provided in the homework assignment&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RgseYMImiLI/AAAAAAAAAGQ/cIlMTupMxQ0/s1600-h/a1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RgseYMImiLI/AAAAAAAAAGQ/cIlMTupMxQ0/s400/a1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047161208321771698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A scene of random spheres and five different material types&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RgseT8ImiKI/AAAAAAAAAGI/5McInvrEnQ8/s1600-h/a2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RgseT8ImiKI/AAAAAAAAAGI/5McInvrEnQ8/s400/a2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047161135307327650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Rendered with 9 samples per pixel with jittering and using the triangle filter&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;The function provided in the homework assignment&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/RgsePcImiJI/AAAAAAAAAGA/hgs_m9RfuoI/s1600-h/b1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/RgsePcImiJI/AAAAAAAAAGA/hgs_m9RfuoI/s400/b1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047161057997916306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/RgseLsImiII/AAAAAAAAAF4/LbJ27EcqwhY/s1600-h/b2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/RgseLsImiII/AAAAAAAAAF4/LbJ27EcqwhY/s400/b2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047160993573406850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Rendered with 9 samples per pixel using a Gaussian filter&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The function provided in the homework assignment&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RgseDMImiHI/AAAAAAAAAFw/VWqjCPb7iTc/s1600-h/c1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RgseDMImiHI/AAAAAAAAAFw/VWqjCPb7iTc/s400/c1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047160847544518770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A scene of random spheres and five different material types&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/Rgsd8cImiGI/AAAAAAAAAFo/HKtDMb5XJ_Q/s1600-h/c2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Rgsd8cImiGI/AAAAAAAAAFo/HKtDMb5XJ_Q/s400/c2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5047160731580401762" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Code: &lt;a href='http://www.cs.utah.edu/~jstratto/project8.tar.bz2'&gt;project8.tar.bz2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-3283366833583072368?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/3283366833583072368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=3283366833583072368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3283366833583072368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/3283366833583072368'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/03/ray-tracing-project-8.html' title='Ray Tracing - Project 8'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/RgseYMImiLI/AAAAAAAAAGQ/cIlMTupMxQ0/s72-c/a1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-5358818341413755515</id><published>2007-03-16T18:35:00.000-07:00</published><updated>2008-12-10T15:23:47.234-08:00</updated><title type='text'>Ray Tracing - Project 7</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;For the design of the texture mappers, I followed a scheme similar to the one Dr. Parker recommended.  I created a TexCoordMapper that provided a basic interface for grabbing texture coordinates.  The base object class--from which all primitives are descended--were given a default coordinate mapper, which could be changed through the API.  &lt;br /&gt;&lt;br /&gt;Besides the coordinate mappers, three new materials were created--a checker material(which used two sub-materials assigned to it), a marble material, which used Perlin noise, and a image material.  All three materials were implemented exactly as described in the slides.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Required Image&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RftHmK4d7uI/AAAAAAAAAFY/xBzz7vRei6c/s1600-h/required.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RftHmK4d7uI/AAAAAAAAAFY/xBzz7vRei6c/s400/required.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5042702928853200610" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Creative Image - Triceratops by Rainbow (and sphere)&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RftH9K4d7vI/AAAAAAAAAFg/Dq67wgY1Vn8/s1600-h/creative.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RftH9K4d7vI/AAAAAAAAAFg/Dq67wgY1Vn8/s400/creative.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5042703323990191858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Extra Credit&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;For extra credit, I chose to add an additional procedural texture (I'm shooting for half extra-credit).  This material (shown in the creative image) allows spectrums of color to be display for effects like rainbows.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code:&lt;/b&gt;&lt;a href='http://www.cs.utah.edu/~jstratto/project7.tar.bz2'&gt;http://www.cs.utah.edu/~jstratto/project7.tar.bz2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-5358818341413755515?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/5358818341413755515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/5358818341413755515'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/03/ray-tracing-project-7.html' title='Ray Tracing - Project 7'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/RftHmK4d7uI/AAAAAAAAAFY/xBzz7vRei6c/s72-c/required.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6747115586227233292</id><published>2007-03-07T22:49:00.000-08:00</published><updated>2008-12-10T15:23:47.863-08:00</updated><title type='text'>Ray Tracing - Project 6</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;I originally intended to do a BVH using an quad-tree, where the tree were recurse down to some arbitrary size.  This gave me a strange bug (which I had to use for my original image).  The algorithm itself seemed simple, but and for the small part of the bunny that it did render, it rendered rather quickly.  Much faster than the 2.5 hour attempt without the acceleration structure.  &lt;br /&gt;&lt;br /&gt;I then tried a uniform grid, but had difficulty debugging it (I wasn't getting anything to the screen), mostly due the short amount of time I had left on the assignment.  &lt;br /&gt;&lt;br /&gt;I also tried a octree, which gave me similar results to the quad-tree, which makes me feel the bug lies somewhere in my bounding boxes or something.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bugged Image&lt;/b&gt;-If you look really, really closely you can see the form of the bunny.  From the part that rendered, it seemed to work effectively, but for everything else, it completely ignored it.  It was probably something really small and I probably should have just debugged the quad-tree instead of attempting the other two&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/Re-zyv7mvpI/AAAAAAAAAFI/yGkQvDR6uG0/s1600-h/bunny.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Re-zyv7mvpI/AAAAAAAAAFI/yGkQvDR6uG0/s400/bunny.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5039444192492174994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Required Image&lt;/b&gt;-Here's my final rendering.  It took about 18 seconds, wihich was a lot faster than the 2.5 hour version.  &lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_9O8xhktq4RU/Re_SkP7mvqI/AAAAAAAAAFQ/_R1jKI6Z_iM/s1600-h/bunny.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/Re_SkP7mvqI/AAAAAAAAAFQ/_R1jKI6Z_iM/s400/bunny.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5039478028244532898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code:&lt;/b&gt;&lt;a href='www.cs.utah.edu/~jstratto/project6.tar.bzip2'&gt;project6.tar.bz2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6747115586227233292?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6747115586227233292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6747115586227233292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6747115586227233292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6747115586227233292'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/03/ray-tracing-project-6.html' title='Ray Tracing - Project 6'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9O8xhktq4RU/Re-zyv7mvpI/AAAAAAAAAFI/yGkQvDR6uG0/s72-c/bunny.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6247666293093711494</id><published>2007-02-24T16:54:00.000-08:00</published><updated>2008-12-10T15:23:48.085-08:00</updated><title type='text'>Ray Tracing - Project 5</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;The three new material models were a dielectric, a phong, and a metal.  All three shared specular properties so code was shared somewhat between them.  All materials extended from a general material class which made used of extensive virtual functions to minimize the code base.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Required Image&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/ReDgLnhKodI/AAAAAAAAAE8/wf9y65oy2pQ/s1600-h/non_creative5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/ReDgLnhKodI/AAAAAAAAAE8/wf9y65oy2pQ/s400/non_creative5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5035270873591488978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code:&lt;/b&gt;&lt;a href="www.cs.utah.edu/~jstratto/project5.tar"&gt;project5.tar&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6247666293093711494?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6247666293093711494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6247666293093711494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6247666293093711494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6247666293093711494'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/02/ray-tracing-project-5.html' title='Ray Tracing - Project 5'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/ReDgLnhKodI/AAAAAAAAAE8/wf9y65oy2pQ/s72-c/non_creative5.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-9155896705828494150</id><published>2007-02-06T09:03:00.000-08:00</published><updated>2008-12-10T15:23:48.372-08:00</updated><title type='text'>Ray Tracing - Project 3</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;This assignment added implementation of several primitives including the box, disk, ring, and triangle.  The Moller intersection was used to intersect the triangles, as it was the easiest to implement.  Amy Miller's implementation was used to implement the box intersection.  The new primitives were rendered using existing shaders and the normals were obvious to compute.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is the default scene for Project 3 using the updated rendering&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/Rci1vYxtZuI/AAAAAAAAAD8/w-OxuvkSLhQ/s1600-h/part3_1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/Rci1vYxtZuI/AAAAAAAAAD8/w-OxuvkSLhQ/s400/part3_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5028468809668585186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Creative Image&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;This scene uses two lights: a directional light and a point light.  It features 200 triangles, 60 spheres in a double-helix, a box, and a plane&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/Rci2VoxtZvI/AAAAAAAAAEE/BHxdGTsxSuA/s1600-h/part3_creative1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/Rci2VoxtZvI/AAAAAAAAAEE/BHxdGTsxSuA/s400/part3_creative1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5028469466798581490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;About this project&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;Time Required&lt;/b&gt;: 5 hours&lt;br /&gt;&lt;b&gt;Difficulty&lt;/b&gt;: Easy.  Mostly just implementing intersection algorithms&lt;br /&gt;&lt;b&gt;Code&lt;/b&gt;: &lt;a href='http://www.cs.utah.edu/~jstratto/project2.tar'&gt;project3.tar&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-9155896705828494150?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/9155896705828494150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=9155896705828494150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9155896705828494150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9155896705828494150'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/02/ray-tracing-project-3.html' title='Ray Tracing - Project 3'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9O8xhktq4RU/Rci1vYxtZuI/AAAAAAAAAD8/w-OxuvkSLhQ/s72-c/part3_1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-4380225717569056963</id><published>2007-02-01T12:30:00.000-08:00</published><updated>2008-12-10T15:23:48.886-08:00</updated><title type='text'>Ray Tracing - Project 2</title><content type='html'>&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;Building on the previous assignment, the renderer adds Lambertian shading and two-sided lighting.  The material also casts shadow rays through the image, to give a simulated shadow effect.  A base object class holds basic properties for subclasses to implement, which include a sphere and a plane.  Another base class is for a material, which gives some basic functionality for coloring depending on the vector.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is the default scene for Project 2 using the updated rendering&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RcJPWoxtZqI/AAAAAAAAADM/2B0Jtg7u1iU/s1600-h/part2_1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RcJPWoxtZqI/AAAAAAAAADM/2B0Jtg7u1iU/s400/part2_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5026667384420525730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is the same scene rendered from underneath the default plane.  Although it appears bleak, it demonstrates lighting and shadows are correctly ignored and only ambient light is applied&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/RcJPy4xtZrI/AAAAAAAAADU/LLGV1_qn_d4/s1600-h/part2_2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/RcJPy4xtZrI/AAAAAAAAADU/LLGV1_qn_d4/s400/part2_2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5026667869751830194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Creative Image&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;This image was rendered using 1000 point lights to simulate soft shadows.  It took over two hours to finish and shows the linear scaling of adding point lights to the scene&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/RcNX_4xtZsI/AAAAAAAAADk/f5X8YhHyvqA/s1600-h/part2_creative1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/RcNX_4xtZsI/AAAAAAAAADk/f5X8YhHyvqA/s400/part2_creative1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5026958364159862466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Extra Credit 1 - Directional Lights&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;This image was created using only a directional light instead of two point lights.  Directional lights render slightly faster than directional lights since they do not have to compute the light vector (it's saved in the directional light object), and no distances have to calculated&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RcNjmYxtZtI/AAAAAAAAADw/cq_9H2-2cEg/s1600-h/part2_extra1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RcNjmYxtZtI/AAAAAAAAADw/cq_9H2-2cEg/s400/part2_extra1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5026971120212731602" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;About this project&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;Time Required&lt;/b&gt;: ~10 hours (very approximate)&lt;br /&gt;&lt;b&gt;Difficulty&lt;/b&gt;: Easy.  Lots of typing and organizing&lt;br /&gt;&lt;b&gt;Code&lt;/b&gt;: &lt;a href='http://www.cs.utah.edu/~jstratto/project2.tar'&gt;project2.tar&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-4380225717569056963?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/4380225717569056963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=4380225717569056963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4380225717569056963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/4380225717569056963'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/02/ray-tracing-project-2.html' title='Ray Tracing - Project 2'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/RcJPWoxtZqI/AAAAAAAAADM/2B0Jtg7u1iU/s72-c/part2_1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6612299920893517038</id><published>2007-01-24T22:39:00.000-08:00</published><updated>2008-12-10T15:23:49.268-08:00</updated><title type='text'>Ray Tracing - Project 1</title><content type='html'>This is the first project for Dr. Parker's Ray Tracing class.  &lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Design Choices&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;I chose to do a progressive rendering breaking the image up into frames and sending the frames off to separate threads.  I chose random tiles, because I felt they would give a better visualization of how the overall scene is rendering.  I also liked the idea of using threads as I hope it will get me a bit of a performance boost later.  I wanted a rendering style similar to Modo's renderer.  I chose C++ because my last ray tracer was in Java (pictures in previous blogs) and was decently fast, but I wanted to do some fast C++.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is my viewer as it is being rendered kind of how Modo renders (but not as pretty)&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RbhRyYQn05I/AAAAAAAAAC0/_b2rMzb6Skk/s1600-h/interactive.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RbhRyYQn05I/AAAAAAAAAC0/_b2rMzb6Skk/s400/interactive.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5023855310279267218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;This is my completed image.  I noticed on the assignment after I was done coding, that I didn't need to handle the depth of the objects&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RbhSNYQn06I/AAAAAAAAAC8/G8GXnVQ-984/s1600-h/assignment2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RbhSNYQn06I/AAAAAAAAAC8/G8GXnVQ-984/s400/assignment2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5023855774135735202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;About this project&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;b&gt;Time Required&lt;/b&gt;: ~15 hours (but I rewrote it many, many times... once for my laptop having the code on it and being in the shop, another for file corruption, etc...)&lt;br /&gt;&lt;b&gt;Difficulty&lt;/b&gt;: Not too bad.  Lots of debugging since I wrote most of it without testing it, but I'm hoping later projects will be more incremental&lt;br /&gt;&lt;b&gt;Code&lt;/b&gt;: &lt;a href='http://www.cs.utah.edu/~jstratto/project1.tar'&gt;project1.tar&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6612299920893517038?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6612299920893517038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6612299920893517038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6612299920893517038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6612299920893517038'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2007/01/ray-tracing-project-1.html' title='Ray Tracing - Project 1'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/RbhRyYQn05I/AAAAAAAAAC0/_b2rMzb6Skk/s72-c/interactive.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-6905083994291252886</id><published>2006-12-23T15:27:00.000-08:00</published><updated>2008-12-10T15:23:51.226-08:00</updated><title type='text'>Image Synthesis - Project 14</title><content type='html'>In Project 14,  for my "cool effect" I implemented shade trees.  Shade trees provide a procedural, modular workflow for determining a color at a given point based on various parameters similar to the ones needed in the Heyney-Greenstein Phase Function.  &lt;br /&gt;&lt;br /&gt;These shade trees allow simple modules to be built and combined in chains or branches.  Some common shade trees provide basic shading effects like Phong shading, Lambertian shading, anisotropic shading, ramp shading, etc.  Other modules allow combinations and filters to provide more complex images using these simple modules.  &lt;br /&gt;&lt;br /&gt;Below are a few different spheres using some shading modules...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A sphere shaded using the Heyney-Greenstein module&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3AtS8TrRI/AAAAAAAAABg/gwatjso6mMk/s1600-h/phong.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3AtS8TrRI/AAAAAAAAABg/gwatjso6mMk/s400/phong.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011873844744662290" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A sphere shaded using a ramp module.  This module allows the colors to be colored based on certain points of interest&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/RY2_dy8TrOI/AAAAAAAAABI/RVRJ0yDqAIg/s1600-h/ramp.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/RY2_dy8TrOI/AAAAAAAAABI/RVRJ0yDqAIg/s400/ramp.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011872478945062114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A sphere shaded using a texture module, where the theta and phi of the sphere are mapped from [0,1]x[0,1] on the texture&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9O8xhktq4RU/RY2_9y8TrPI/AAAAAAAAABQ/43lzEb1XwEU/s1600-h/textured.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/RY2_9y8TrPI/AAAAAAAAABQ/43lzEb1XwEU/s400/textured.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011873028700876018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here, a layered filter module with two shaders connected to it.  It also uses another texture shader as a mask to determine which of these to shaders to use&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3AbS8TrQI/AAAAAAAAABY/5Te2jUmDZI8/s1600-h/striped.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3AbS8TrQI/AAAAAAAAABY/5Te2jUmDZI8/s400/striped.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011873535507016962" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;These shade trees scale to as many levels as the effect requires.  The final image at the bottom of this post shows an image using several modules.  A Heyney-Greenstein module provides a shiny metallic surface.  Another is a texture module to provide the metal surface.  These modules must be combined in a combo filter separately from the rust so that the rust doesn't appear shiny.  This combo filter is fed into a mask filter with the rust as it's other shader.  A texture module is fed into the mask filter to use as the mask.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;The sphere with just the metal texture&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3EFC8TrSI/AAAAAAAAABo/Z-saJi8c4AA/s1600-h/metal.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3EFC8TrSI/AAAAAAAAABo/Z-saJi8c4AA/s400/metal.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011877551301438754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The sphere using the Heyney-Greenstein module&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3ENC8TrTI/AAAAAAAAABw/rJON_STyK2k/s1600-h/lambert.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3ENC8TrTI/AAAAAAAAABw/rJON_STyK2k/s400/lambert.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011877688740392242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The sphere with just the rust texture&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3EVS8TrUI/AAAAAAAAAB4/umTjFxBBz40/s1600-h/rust.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3EVS8TrUI/AAAAAAAAAB4/umTjFxBBz40/s400/rust.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011877830474313026" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The sphere mapped using the mask texture&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3EfS8TrVI/AAAAAAAAACA/AfVxgZjRSKw/s1600-h/mask.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RY3EfS8TrVI/AAAAAAAAACA/AfVxgZjRSKw/s400/mask.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011878002273004882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The final sphere using the entire shade tree described above.  This gives the overall feel of the metal, while splotching rust on parts in a natural-looking splat&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3EqC8TrWI/AAAAAAAAACI/hrtuKQebGJw/s1600-h/combo.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RY3EqC8TrWI/AAAAAAAAACI/hrtuKQebGJw/s400/combo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5011878186956598626" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-6905083994291252886?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/6905083994291252886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=6905083994291252886' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6905083994291252886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/6905083994291252886'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/image-synthesis-project-14.html' title='Image Synthesis - Project 14'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/RY3AtS8TrRI/AAAAAAAAABg/gwatjso6mMk/s72-c/phong.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-8949265355603794307</id><published>2006-12-20T12:01:00.000-08:00</published><updated>2008-12-10T15:23:51.405-08:00</updated><title type='text'>Image Synthesis - Project 12</title><content type='html'>In Project 12, the Heyney-Greenstein Phase Function was implemented in the renderer.  The Heyney-Greenstein Phase Function (HGPF) is an imperical formula to simulate diffuse and specular reflection for a variety of materials using only two parameters.  This function uses these these two parameters stored in each object and takes the incidence angle as input.  This provides a much greater flexibility for different materials than using the simpler Lambertian reflection.  &lt;br /&gt;&lt;br /&gt;Finding little data as to proper values, I rendered an image using a wide range of values.  From the image generated, it appears a high &lt;i&gt;g-value&lt;/i&gt; seems important to produce a good image.  This component supposedly relates directly to the angle where most of the light is leaving.  It seems natural that a g-value closer to 1 will produce better pictures where light bounces off at a 90-degree angle, while a 0 value gives very splotchy results.  The &lt;i&gt;w-value&lt;/i&gt; used in the function scales the function and seems to have less of an effect after tone mapping is appled.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;In the image below, 64 spheres are rendered.  All spheres share the same color component, but have differing &lt;i&gt;w&lt;/i&gt; and &lt;i&gt;g&lt;/i&gt; parameters in the HGPF.  From left to right, the &lt;i&gt;g-component&lt;/i&gt; ranges from zero to one.  From top to bottom the &lt;i&gt;w-component&lt;/i&gt; ranges from zero to one&lt;/b&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_9O8xhktq4RU/RYmalC8TrNI/AAAAAAAAAA8/4nGKWSmXl4U/s1600-h/heyney_greenstein_500.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_9O8xhktq4RU/RYmalC8TrNI/AAAAAAAAAA8/4nGKWSmXl4U/s400/heyney_greenstein_500.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5010706021662043346" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-8949265355603794307?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/8949265355603794307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=8949265355603794307' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/8949265355603794307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/8949265355603794307'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/image-synthesis-project-12.html' title='Image Synthesis - Project 12'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9O8xhktq4RU/RYmalC8TrNI/AAAAAAAAAA8/4nGKWSmXl4U/s72-c/heyney_greenstein_500.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1465623416739569326</id><published>2006-12-20T07:17:00.000-08:00</published><updated>2008-12-10T15:23:51.660-08:00</updated><title type='text'>Image Synthesis - Project 11</title><content type='html'>In Project 11, subsurface scattering is added to the renderer.  This implies that light hitting the surface of the material enters and bounces around inside the medium before exiting.  Many materials such as grapes, skin and marble exhibit this quality.  Subsurface scattering in this implementation used ray marching, where the ray enters the medium and bounces around until exiting.  Because the ray actually bounced around inside the object instead of just off the surface, the rendering was far more computationally expensive than rendering this scene without SSC.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;In the image below, two spheres are placed side by side with a large rectangular light source placed overhead.  The sphere on the left uses subsurface scattering while the sphere on the right uses just Lambertian reflections.  Light shining from above simply bounces of the top of the Lambertian sphere, leaving the bottom dark and unilluminated.  The SSC sphere, however, has light shining through the medium and appearing at the bottom of the sphere as many materials would&lt;/b&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_9O8xhktq4RU/RYlXOy8TrMI/AAAAAAAAAAw/U6py0-gJNoM/s1600-h/scatter.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_9O8xhktq4RU/RYlXOy8TrMI/AAAAAAAAAAw/U6py0-gJNoM/s400/scatter.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5010631972130892994" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1465623416739569326?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1465623416739569326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1465623416739569326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1465623416739569326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1465623416739569326'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/image-synthesis-project-11.html' title='Image Synthesis - Project 11'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9O8xhktq4RU/RYlXOy8TrMI/AAAAAAAAAAw/U6py0-gJNoM/s72-c/scatter.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-813771707835591135</id><published>2006-12-16T00:58:00.000-08:00</published><updated>2008-12-10T15:23:51.848-08:00</updated><title type='text'>Image Synthesis - Project 10</title><content type='html'>In Project 10, we were to implement participating media.  Participating media involves computing physical bounces of light in media such as fog, dust, smoke, etc. where the light bounces around inside the volume instead of just diffusing, reflecting, or refracting.  &lt;br /&gt;&lt;br /&gt;To implement this, I used the standard marching technique through an axis-aligned bounding box.  A ray was sampled multiple times across its vector using small steps.  When these steps were inside the bounding volume, they probabilisitcally hit some of the media.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;In the figure below, participating media is used to simulate a gaseous volume under the cube.  Right now my code is very ineffecient and took six hours to get these results.  Earlier images not requiring participating media required far less time to converge&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9O8xhktq4RU/RYO4My8TrLI/AAAAAAAAAAk/DMumHYr0S8Q/s1600-h/fog.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9O8xhktq4RU/RYO4My8TrLI/AAAAAAAAAAk/DMumHYr0S8Q/s400/fog.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5009049740538784946" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-813771707835591135?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/813771707835591135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=813771707835591135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/813771707835591135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/813771707835591135'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/image-synthesis-project-10.html' title='Image Synthesis - Project 10'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9O8xhktq4RU/RYO4My8TrLI/AAAAAAAAAAk/DMumHYr0S8Q/s72-c/fog.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-761793985399905723</id><published>2006-12-14T08:28:00.000-08:00</published><updated>2008-12-10T15:23:51.920-08:00</updated><title type='text'>Image Synthesis - Project 9</title><content type='html'>In Project 9, we were to add the Beere-Lambert Law to our renderer.  The Beere-Lambert Law models the amount of light absorbed while traveling through a medium.  Because different wavelengths are absorbed based on the distance they must travel through the medium, different colors can be absorbed causing different wavelengths to be more pronounced.  Certain types of glass often absorb high and low wavelengths leaving a greenish tint at certain angles.  Usually this effect can be seen when the light is going through the greatest distance of the glass.  To compute the absorbtion at certain frequencies, euler's number &lt;i&gt;e&lt;/i&gt; was taken to the exponent of the distance times a large negative constant (which changes based on the scene metrics).  &lt;br /&gt;&lt;br /&gt;In the picture below, five spheres are modeled.  The back left sphere is a reflective sphere, while the back right is a diffuse sphere.  Theses spheres are only to provide background to the scene. The spheres in front are used for comparison.  The left sphere is a diffuse/reflective sphere with a purplish hue.  The middle sphere is a translucent sphere that implements the Beere-Lambert Law based on the distance of the medium.  This gives the sphere the slightly greenish tint.  The sphere on the right is also a translucent sphere, but does not implement the Beere-Lambert Law.  This was to show the difference in hues generated by this principle.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;This figure shows several spheres.  The front-middle sphere uses the Beere-Lambert Law to absorb certain frequencies of light.  The front-right sphere has the same parameters as this sphere, except it does not implement the Beere-Lambert Law.  This image took 5 hours and 24 minutes to render&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/RYGE02AmvNI/AAAAAAAAAAY/U9Wn-5VE8bA/s1600-h/beer.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/RYGE02AmvNI/AAAAAAAAAAY/U9Wn-5VE8bA/s400/beer.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5008430303998819538" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-761793985399905723?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/761793985399905723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=761793985399905723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/761793985399905723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/761793985399905723'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/image-synthesis-project-9.html' title='Image Synthesis - Project 9'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9O8xhktq4RU/RYGE02AmvNI/AAAAAAAAAAY/U9Wn-5VE8bA/s72-c/beer.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-7996499369499182527</id><published>2006-12-13T09:36:00.000-08:00</published><updated>2008-12-10T15:23:52.063-08:00</updated><title type='text'>Image Synthesis - Project 7 and 8</title><content type='html'>In Project 7, we were to use our renderer to model the Cornell box.  This box was compared against a physical model to compare accuracy in the rendering software.  This scene's walls and light are modeled using the geometry data and color data from the Cornell box at http://www.graphics.cornell.edu/online/box/data.html.  &lt;br /&gt;&lt;br /&gt;In addition to the light source and the walls, Project 8 added fresnel effects to the renderer.  Instead of the two blocks found in the original Cornell box, two diffuse spheres have been placed in the far corners of the room.  A large transparent sphere is placed in the center of the room, which shows the light refracting through it.  &lt;br /&gt;&lt;br /&gt;The scene's light seems rather blurry because it was moved down slightly to not create artifacts with the ceiling, which is one giant polygon.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Below is an image of the scene rendered at 400x400 and tone mapped.  It took 4 hours to render, which is rather sad&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9O8xhktq4RU/RYA8dGAmvMI/AAAAAAAAAAM/gX2KMxIPJlo/s1600-h/cornell_box.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_9O8xhktq4RU/RYA8dGAmvMI/AAAAAAAAAAM/gX2KMxIPJlo/s400/cornell_box.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5008069256163015874" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-7996499369499182527?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/7996499369499182527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=7996499369499182527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7996499369499182527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/7996499369499182527'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/12/project-7-and-8.html' title='Image Synthesis - Project 7 and 8'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9O8xhktq4RU/RYA8dGAmvMI/AAAAAAAAAAM/gX2KMxIPJlo/s72-c/cornell_box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1858769339706005672</id><published>2006-11-01T04:31:00.000-08:00</published><updated>2006-12-18T10:28:40.198-08:00</updated><title type='text'>Image Synthesis - Project 6 and 15</title><content type='html'>In Project 4 &amp; 5, the imager was modified to handle importance sampling and a pinhole camera.  The importance sampling provided much faster rendering times by sending photons only at known objects in the scene, and weighting them based on their angle.  The photons were generated at the sensor grid and sent through the scene until they hit a light source (or bounced too much).  This seemed to provide a good sampling of the scene, but required a major rewrite of the code.  &lt;br /&gt;&lt;br /&gt;This new version of the software adds a lens to the scene as well as motion blur.  To handle motion blur, the red diffuse sphere was moved from (0, 1, 3) to (1, 2, 4) over the course of the rendering.  This created an easy but interesting blur effect as if the object was exposed over many sensor units while the apperture was open.  &lt;br /&gt;&lt;br /&gt;The lense was a simple biconvex lense attached to the pinhole.  Upon contact with the lense, the vector was skewed based on it's angle of incidence and the refractive index of the lense (1.4 for this lense).  As the photon left this lense, it would be skewed again.  Snell's law was used to calculate the angles of refraction for each photon.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rendered using 18,000,000,000 photons -- 200,000 per sensor grid (4 hours, 11 seconds rendering time)&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/motion_blur.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/400/motion_blur.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1858769339706005672?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1858769339706005672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1858769339706005672' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1858769339706005672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1858769339706005672'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/11/project-6.html' title='Image Synthesis - Project 6 and 15'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-248850616205773297</id><published>2006-10-10T06:15:00.000-07:00</published><updated>2006-12-20T07:56:36.551-08:00</updated><title type='text'>Image Synthesis - Project 4 and 5</title><content type='html'>In the previous project, a single sphere-shaped light emitter was placed onto the sensor grid.  In the example, the light source has been moved back and a pinhole has been added between the sensor grid and all other objects in the scene.  This pinhole only allows vectors of photons pass through it if it they travel inside the pinhole to reach the grid.  Other photons are thrown out.  This pinhole-camera scheme provides a much better detailed picture than the previous implementation as it simulates a perspective frustrum just like the eye or a real camera.  A red diffuse sphere bounces light from the light source to the pinhole also.  &lt;br /&gt;&lt;br /&gt;Included in this project was an importance sampling implementation.  This fired photons at the diffuse sphere and directly at the pinhole.  The amount of photons fired to each object was a ratio of their solid angle and the total number of photons previously fired in all directions.  Because only photons sent to the pinhole and the object were fired, the scene was rendered using much fewer photons.  Although more overhead was required to calculate the importance sampling, it greatly reduced the calculation time for every photon collision (having much fewer photons in the scene).  &lt;br /&gt;&lt;br /&gt;Both of these projects were added to the previous code base at the same time.  Importance sampling was required to provide an more interactive debugging of the pinhole code.  Final images look better than the previous project, and took much less time to synthesize.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;313,290,000 emissions (876,964 passed through the pinhole)&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/importance_sampling.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/400/importance_sampling.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-248850616205773297?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/248850616205773297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=248850616205773297' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/248850616205773297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/248850616205773297'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/10/image-synthesis-project-4-5.html' title='Image Synthesis - Project 4 and 5'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-2360394958114502475</id><published>2006-09-13T09:28:00.000-07:00</published><updated>2006-09-13T09:34:02.355-07:00</updated><title type='text'>Image Synthesis - Project 3</title><content type='html'>These are samples from a simulated sensor.  The grid is on the xy-plane and a sphere emitting light from it's surface at random vectors hits the sensor grid and accumulates XYZ factors, which are converted to RGB on the graphics card and displayed to the screen.  Below are images of this program taken at different number of photon emissions.  &lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;b&gt;1000 emissions&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab3_1000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab3_1000.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br&gt;&lt;b&gt;1000000 emissions&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab3_1000000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab3_1000000.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br&gt;&lt;b&gt;100000000 emissions (move over Pixar)&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab3_100000000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab3_100000000.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-2360394958114502475?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/2360394958114502475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=2360394958114502475' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2360394958114502475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/2360394958114502475'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/09/image-synthesis-project-3.html' title='Image Synthesis - Project 3'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-1499942271410456622</id><published>2006-09-04T15:40:00.000-07:00</published><updated>2006-09-04T15:45:42.105-07:00</updated><title type='text'>Image Synthesis - Project 2</title><content type='html'>This second project is similar to the first.  I sampled XYZ estimates using the tristimulus curves and converted the samples on the graphics card to RGB using the Adobe RGB table conversion standard matrix.  It took my poor little laptop almost two minutes to render 1024 time steps at 720x480.  &lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;1 sample&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab2_1.0.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab2_1.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;16 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab2_16.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab2_16.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;256 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab2_256.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab2_256.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;1024 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab2_1024.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab2_1024.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-1499942271410456622?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/1499942271410456622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=1499942271410456622' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1499942271410456622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/1499942271410456622'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/09/image-synthesis-project-2.html' title='Image Synthesis - Project 2'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8648559575280961442.post-9054840121580728289</id><published>2006-09-04T14:54:00.000-07:00</published><updated>2006-09-04T15:39:36.868-07:00</updated><title type='text'>Image Synthesis - Project 1</title><content type='html'>This first project samples various frequencies on the Macbeth color checker.  If it passes a basic sampling check, the image color is sampled to the frame buffer.  All the samples are acculumated over each time step to get a better average color.  All these images were rendered at 720x480 (they seemed like good numbers).  They were rendered on a Toshiba Tecra S2.  &lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;1 sample&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab1_1.0.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab1_1.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;16 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab1_16.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab1_16.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;256 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab1_256.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab1_256.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;b&gt;1024 samples&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/1954/1055732370029414/1600/lab1_1024.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/1954/1055732370029414/200/lab1_1024.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8648559575280961442-9054840121580728289?l=strattonbrazil.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strattonbrazil.blogspot.com/feeds/9054840121580728289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8648559575280961442&amp;postID=9054840121580728289' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9054840121580728289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8648559575280961442/posts/default/9054840121580728289'/><link rel='alternate' type='text/html' href='http://strattonbrazil.blogspot.com/2006/09/image-synthesis-project-1.html' title='Image Synthesis - Project 1'/><author><name>strattonbrazil</name><uri>http://www.blogger.com/profile/00840168161538775436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
