<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DkIHRHwyeCp7ImA9WhRUEEU.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289</id><updated>2012-01-20T10:35:35.290-08:00</updated><title>c0de517e</title><subtitle type="html">Rendering et alter</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://c0de517e.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>208</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/C0de517e" /><feedburner:info uri="c0de517e" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CkUNSHYzfyp7ImA9WhRUEE0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7245402042285490286</id><published>2012-01-19T11:11:00.000-08:00</published><updated>2012-01-19T11:11:39.887-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T11:11:39.887-08:00</app:edited><title>Replacing google share: zootool</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;There are quite a few bookmarking services on the web today, and I never felt the need to find one until Google shut down its handy reader share feature. So, kinda randomly I picked Zootool and I've been working on sharing some links for a few weeks, so now there is a bit of content and I can publish its feed. Let me know if there are problems, otherwise I'll stick to this one to share my finds in the "rendering et al." category, at least until &lt;a href="http://reederapp.com/"&gt;Reeder&lt;/a&gt; does not add support for Google+ :)&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a href="http://zootool.com/feeds/user/c0de517e/type:all"&gt;http://zootool.com/feeds/user/c0de517e/type:all&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/6950833531562942289-7245402042285490286?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AO2DTSbWGOSFoA9T1n2AcIvyFXM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AO2DTSbWGOSFoA9T1n2AcIvyFXM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AO2DTSbWGOSFoA9T1n2AcIvyFXM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AO2DTSbWGOSFoA9T1n2AcIvyFXM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/_FX9IuX_uyA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7245402042285490286/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7245402042285490286" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7245402042285490286?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7245402042285490286?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/_FX9IuX_uyA/replacing-google-share-zootool.html" title="Replacing google share: zootool" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2012/01/replacing-google-share-zootool.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIBQX45fSp7ImA9WhRUEE0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-1820944512929535550</id><published>2012-01-18T17:01:00.004-08:00</published><updated>2012-01-19T11:15:50.025-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T11:15:50.025-08:00</app:edited><title>Prototyping frameworks</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Every now and then, I look around for prototyping frameworks for my rendering work. I always end up with very little but maybe I'm too picky or too lazy. Here are some I've found:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;I actually use:&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;FXComposer, both&amp;nbsp;&lt;a href="http://2.0.0.5/"&gt;2.5&lt;/a&gt;&amp;nbsp;and 1.8 (Nvidia does not host it anymore, so you have to google it) as they both crash/have problems in different ways. In particular, 2.5 seems to have problems clearing rendering targets (I use a pass with ztest always to clear), 1.8 crashes in some situations. 1.8 is also nicer for a programmer, but 2.5 is fairly usable. I use SAS and NVidia has some documentation (finally!) about it, to script render passes. In theory both also support proper scripting, but the documentation is thin. A few times when I wanted to look inside FXC 2.5 I used something like ILSpy or .net reflector to delve in the undocumented parts (that's to say, almost everything).&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Wolfram's&amp;nbsp;&lt;a href="http://www.wolfram.com/mathematica/"&gt;Mathematica&lt;/a&gt;. I wrote a couple of articles on this blog about it, it's great and I love it, I love the language, it's not what you would expect if you're a mathematician but for a programmer is pretty neat (well at least, if you like lisp-ish things, which you should, syntax apart)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://slimdx.org/"&gt;SlimDX&lt;/a&gt;&amp;nbsp;or&amp;nbsp;&lt;a href="http://code.google.com/p/sharpdx/"&gt;SharpDX&lt;/a&gt;, to tell you the truth I mixed them up a few times, the names are similar. Bottom line, a DX wrapper for C#, I love C#. SharpDevelop if I don't have an updated visual studio which supports the last .net framework.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://processing.org/"&gt;Processing&lt;/a&gt;. I wrote an article on the blog about using it with Eclipse for live-coding, it's neat, it's simple, it has a ton of libraries at this point, even to do 3d stuff and shaders but I use it mostly for 2d prototypes.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;3D Studio Max. It has an horrible support for shaders (at least it used to, and I suspect not much has changed since) and I never loved it (I love Maya even less though), but I used to know it (six years ago or so) and know maxscript, so I ended up prototyping in Max a few things. It can be handy because you can obviously manipulate meshes all the ways you want and define vertex streams and visually paint attributes on meshes. You can't really control the rendering passes though, so doing non-surface shaders or stuff other than the most basic post-effects is hard. Nowadays I don't use it much if at all.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Seem promising:&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://research.scee.net/files/presentations/gdc2011/2011-GDC-PhyreEngine.pdf"&gt;PhyreEngine&lt;/a&gt;, if you have access to the Sony stuff... Might be a bit overkill as it's a fully fledged engine, so the learning curve is not so steep per se but there are tons of examples.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Erik-Faye Lund published the sources of his "&lt;a href="https://github.com/kusma/vlee"&gt;very last engine ever&lt;/a&gt;" which is used in a bunch of great &lt;a href="http://pouet.net/prod.php?which=58005"&gt;demos&lt;/a&gt; (as in demoscene) I didn't have the time to look into it much yet, but the name sounds great!&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://hieroglyph3.codeplex.com/"&gt;Hyeroglyph 3&lt;/a&gt;, it's the 3d engine that "ships" with the&lt;a href="http://www.amazon.com/Practical-Rendering-Computation-Direct3D-11/dp/1568817207/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1309555438&amp;amp;sr=1-1"&gt;&amp;nbsp;Practical Rendering and Computation with DirectX11 book&lt;/a&gt;&amp;nbsp;(which is nice). It still has a bit more things that I'd like to (more of an engine than a framework) but it's nice...&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://libcinder.org/"&gt;Cinder&lt;/a&gt;&amp;nbsp;looks still a bit young, it has many nice things but it lacks some other which I would consider "basics". I feel the same about&amp;nbsp;&lt;a href="http://www.openframeworks.cc/"&gt;openFrameworks&lt;/a&gt;&amp;nbsp;and to me Cinder looks nicer. Plus I don't love C++ :)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Humus&amp;nbsp;&lt;a href="http://www.humus.name/index.php?page=3D"&gt;Framework 3&lt;/a&gt;. This is great, it's simpler than a full fledged engine, it's easy to read and it has tons of examples and Humus is notorious for his graphic demos, which all come with sourcecode and were made with his framework!&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Intel's&amp;nbsp;&lt;a href="http://software.intel.com/en-us/articles/vcsource-samples-nulstein/"&gt;Nulstein&lt;/a&gt;. I didn't spend much time looking at this, Intel "makets" it as the most bare-bones, next-gen engine source possible. Which sounds good, but from the little I saw, it's still not simple enough for my purposes (I really would like not needing to learn anything :) otherwise I could just write my own stuff). Also Intel with its&amp;nbsp;&lt;a href="http://software.intel.com/sites/billboard/"&gt;Visual Adrenaline&lt;/a&gt;&amp;nbsp;initiative seems committed to providing great support, articles,&amp;nbsp;&lt;a href="http://software.intel.com/en-us/articles/code/"&gt;sourcecode&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="http://software.intel.com/en-us/articles/vcsource-tools-intel-gpa/"&gt;tools&lt;/a&gt;&amp;nbsp;for graphics development.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://vvvv.org/"&gt;VVVV&lt;/a&gt;. It's a node-based graphic thingie. Which would seem like the least suitable thing for rendering prototypes, but it supports shaders, and it supports "code" nodes where you can write C#, so it might be worth a try...&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://www.opencldev.com/"&gt;OpenCL Studio&lt;/a&gt;&amp;nbsp;looks great to me but I didn't have the time yet to test it out properly&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Python. Lots of people love it and there are tons of libraries, environments, wrappers and so on. The latest someone told me about is&amp;nbsp;&lt;a href="http://code.google.com/p/pythonxy/"&gt;python(x,y)&lt;/a&gt;&amp;nbsp;for scientific computing. I don't use python. Maybe I should...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;What I'd love? I'd love to have a very simple wrapper, just slightly more high-level than the base API to get me some of the most common stuff already coded (i.e. a camera system, parameter manipulation, mesh management and loading...), and I'd love if this wrapper was embedded in a live-coding language, like Lua with script hot-swapping, and if it supported hot-swapping of all the assets as well (shaders, textures etc...). I always think I should code such a thing sooner or later but I never find the time to do it :(&lt;/span&gt;&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/6950833531562942289-1820944512929535550?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/4ISkrZmDqd4PiQLJUsaJXpj_ajE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4ISkrZmDqd4PiQLJUsaJXpj_ajE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/4ISkrZmDqd4PiQLJUsaJXpj_ajE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4ISkrZmDqd4PiQLJUsaJXpj_ajE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/JPUYQx3b3Eo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/1820944512929535550/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=1820944512929535550" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/1820944512929535550?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/1820944512929535550?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/JPUYQx3b3Eo/prototyping-frameworks.html" title="Prototyping frameworks" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>9</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2012/01/prototyping-frameworks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEGQ3Y8fSp7ImA9WhRUEE0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-340594325424963289</id><published>2012-01-17T23:58:00.009-08:00</published><updated>2012-01-19T11:17:02.875-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T11:17:02.875-08:00</app:edited><title>Videogame photography</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;For some reasons, videogames and photography are more linked that people might suspect. In my career I've noticed that many if not most of the top engineers I know, also dabble quite a bit in photography (well, I'm biased as I'm a rendering guy and my friends tend to be in the rendering circle). That includes myself (&lt;a href="http://www.kenpex.it/"&gt;NFSW&lt;/a&gt;). But there is more...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://soic.design.free.fr/wp-content/Francois-Soulignac-Virtual-tourisme-Skyrim-b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="180" src="http://soic.design.free.fr/wp-content/Francois-Soulignac-Virtual-tourisme-Skyrim-b.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://shotbyrobert.com/wordpress/wp-content/uploads/2010/07/Facade.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="180" src="http://shotbyrobert.com/wordpress/wp-content/uploads/2010/07/Facade.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.tumblr.com/photo/1280/enwandrews/8907286417/1/tumblr_lpx9bgF7mT1qlqnp3" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="200" src="http://www.tumblr.com/photo/1280/enwandrews/8907286417/1/tumblr_lpx9bgF7mT1qlqnp3" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://deadendthrills.com/wp-content/uploads/2010/10/highres_screenshot_000009a1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="180" src="http://deadendthrills.com/wp-content/uploads/2010/10/highres_screenshot_000009a1.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Some notable videogame photographers are &lt;b&gt;&lt;a href="http://shotbyrobert.com/wordpress/?page_id=102"&gt;Robert Overweg&lt;/a&gt;, &lt;a href="http://kotaku.com/5866739/the-man-behind-the-worlds-best-video-game-screenshots"&gt;Duncan Harris&lt;/a&gt; (&lt;a href="http://deadendthrills.com/?cat=142"&gt;Dead End Thills&lt;/a&gt;), &lt;a href="http://soic.design.free.fr/"&gt;Francois Soulignac&lt;/a&gt; and &lt;a href="http://enwandrews.tumblr.com/"&gt;Iain Andrews&lt;/a&gt;&lt;/b&gt;, but I'm sure there are way more out there, if you have links to share please comment on this post.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Robert's work focus on exploiting the limits and bugs of games to create artistic fine art series (which is not &lt;a href="http://www.idealmilk.com/project/evidencia/evidencia_02.htm"&gt;uncommon&lt;/a&gt; either), while Dead End Thills and Iain Andrews are more "conventional" screenshot artists: games get hacked to gain more control or improve quality and the end results are quite amazing! &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.mrtoledano.com/store/image/file/08/aa/7rbnku/PTReallyAngry-Final-Flat.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="241" src="http://www.mrtoledano.com/store/image/file/08/aa/7rbnku/PTReallyAngry-Final-Flat.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://golem13.fr/wp-content/uploads/2011/04/RobbiecooperAlterEgo1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="199" src="http://golem13.fr/wp-content/uploads/2011/04/RobbiecooperAlterEgo1.png" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Professional photographers also dabble in the media time to time. Of course, the main attraction seem still to be the players, and not the games, as in these series by &lt;a href="http://www.mrtoledano.com/gamers"&gt;Phillip Toledano&lt;/a&gt; and &lt;a href="http://golem13.fr/robbie-cooper-photographie-les-gamers-de-mmorpg-et-leur-avatar/"&gt;Robbie Cooper&lt;/a&gt; (&lt;a href="http://video.nytimes.com/video/2008/11/21/magazine/1194833565213/immersion.html"&gt;also here&lt;/a&gt;), but there are examples of photographers leaving their cameras for the PC to record for example this &lt;a href="http://kotaku.com/5865005/this-skyrim-timelapse-photography-is-breathtakingly-beautiful"&gt;Skyrim timelapse&lt;/a&gt; (was this inspired by &lt;a href="http://www.eurogamer.net/articles/digitalfoundry-skyrim-timelapse-world-in-motion"&gt;a similar video&lt;/a&gt; on Eurogamer? or viceversa?) oe using &lt;a href="http://www.flickr.com/photos/audreypenven/5197405215/in/photostream/"&gt;videogame equipment&lt;/a&gt; in their photography.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.staticflickr.com/4128/5197405215_5220ceaaa1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="213" src="http://farm5.staticflickr.com/4128/5197405215_5220ceaaa1.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Videogame references is photography are of course countless, like this &lt;a href="http://pixelgarten.de/index.php?id=163"&gt;fashion editorial&lt;/a&gt; in Neon Magazine.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://i.imgur.com/vqPNK.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="228" src="http://i.imgur.com/vqPNK.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://images.fastcompany.com/upload/3.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="213" src="http://images.fastcompany.com/upload/3.jpeg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Lastly even gamers are becoming photographers, not only in games that specifically feature this profession in their characters (&lt;a href="http://en.wikipedia.org/wiki/Fatal_Frame"&gt;Fatal Frame&lt;/a&gt; series and &lt;a href="http://en.wikipedia.org/wiki/Beyond_Good_%26_Evil"&gt;Beyond Good and Evil&lt;/a&gt; come to mind but I'm sure there are &lt;a href="http://www.petapixel.com/2009/11/18/oh-snap-9-games-that-feature-photography/"&gt;more&lt;/a&gt;), but by twisting game rules.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Virtual war photographers enter multiplayer shooter games with the intent not to kill but to report (and not die), like &lt;a href="http://www.fastcodesign.com/1663584/photos-use-call-of-duty-videogames-to-capture-the-ravages-of-modern-war"&gt;Brunet Thibault&lt;/a&gt; (who also enjoys other forms of &lt;a href="http://www.thibaultbrunet.fr/"&gt;videogame photography&lt;/a&gt;). There are staring to be quite &lt;a href="http://imgur.com/a/hCfl8#0"&gt;a few&lt;/a&gt; &lt;a href="http://imgur.com/a/PmZxC"&gt;examples&lt;/a&gt; of this, which is probably going to piss the other players though, it would be great if modern FPS started to support this option (spectator modes are sort-of there, but you can't die and thus don't really "simulate" the role, there is at least &lt;a href="http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=sQlkYY88wLM"&gt;one game &lt;/a&gt;that is all about war photography, but it doesn't seem on the contrary to allow other roles, so it's still not quite the same).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://stellastapleton.files.wordpress.com/2008/07/5864253419_eecf49f200_z-2.jpg?w=629" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="320" src="http://stellastapleton.files.wordpress.com/2008/07/5864253419_eecf49f200_z-2.jpg?w=629" width="314" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.gamerbc.com/wp-content/uploads/2011/05/eve-cc-gallente-jin-mei-head-01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="180" src="http://www.gamerbc.com/wp-content/uploads/2011/05/eve-cc-gallente-jin-mei-head-01.png" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;A notable game which supports photography (and &lt;a href="http://stellastapleton.com/"&gt;fashion&lt;/a&gt;!) without being centered on photographer is &lt;a href="http://wiki.secondlife.com/wiki/Taking_snapshots"&gt;Second Life&lt;/a&gt;. These guys go so crazy that they actually &lt;a href="http://www.youtube.com/watch?v=2WVhvs9JX1w"&gt;photoshop their work&lt;/a&gt;! Eve Online is another game worth mentioning, not only its &lt;a href="http://www.youtube.com/watch?v=tJ_DQFVuixM"&gt;avatar creator&lt;/a&gt; &lt;a href="http://health-food-stores.org/lady-gagas-fashion-director-plans-to-sell-virtual-clothes-for-real-money.html"&gt;is&lt;/a&gt; &lt;a href="http://www.gamesetwatch.com/2011/09/ccp_mugler_debut_zombie_boy_at.php"&gt;amazing&lt;/a&gt;, but taking your avatar picture puts you in a (simple) virtual photography studio and the results are fairly decent.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://xbox360media.gamespy.com/xbox360/image/object/143/14320288/red-dead-redemption02_blog.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="131" src="http://xbox360media.gamespy.com/xbox360/image/object/143/14320288/red-dead-redemption02_blog.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.padsandpanels.com/wp-content/uploads/2010/05/alanwake1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="180" src="http://www.padsandpanels.com/wp-content/uploads/2010/05/alanwake1.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;If only Red Dead Redemption or Alan Wake could get more love... Unfortunately being console only titles (I still hope for an Alan Wake &lt;a href="http://www.pcgamer.com/2011/12/14/alan-wake-pc-confirmed-will-arrive-early-next-year/"&gt;on the PC&lt;/a&gt;), they lend themselves less to photography, but at least for the former there are a couple of amazing &lt;a href="http://www.eurogamer.net/videos/red-dead-redemption-time-lapse-video"&gt;videos&lt;/a&gt; out there, including a short film made by &lt;a href="http://www.youtube.com/watch?v=cZUUVV2rjoc"&gt;John Hillcoat&lt;/a&gt;...&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-340594325424963289?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qp5vweWFuV6YlvV2taSFJCB3TYs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qp5vweWFuV6YlvV2taSFJCB3TYs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qp5vweWFuV6YlvV2taSFJCB3TYs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qp5vweWFuV6YlvV2taSFJCB3TYs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/G2utEzn8MUU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/340594325424963289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=340594325424963289" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/340594325424963289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/340594325424963289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/G2utEzn8MUU/videogame-photography.html" title="Videogame photography" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2012/01/videogame-photography.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ICQH05eSp7ImA9WhRWF08.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-8660489175089071102</id><published>2012-01-04T15:58:00.001-08:00</published><updated>2012-01-04T15:59:21.321-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-04T15:59:21.321-08:00</app:edited><title>Current-gen DOF and MB</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;I was thinking to publish this somewhere else, but Crytek at the last Siggraph already disclosed a technique that is close to this one, so at the end I guess it's not worth it and I'm going to spill the beans here instead.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Depth of field and motion blur, from a post-processing standpoint, look similar. They both are scattering filters, they both need to respect depths. So it makes sense to try to combine both effects in the same filter. And if you think about doing it that way, you're almost already done, it's quite obvious that it's possible to combine the DOF kernel with the MB one by skewing the DOF towards the motion-blur direction.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--U0QPIXUlE8/TwTjoytIHiI/AAAAAAAAAKQ/aqcApjgAQdY/s1600/DOFandMB.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="243" src="http://2.bp.blogspot.com/--U0QPIXUlE8/TwTjoytIHiI/AAAAAAAAAKQ/aqcApjgAQdY/s320/DOFandMB.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;This is what Crytek does, they use a number of taps, their filter is circular and they just transform this circle with a basis that has&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;the motion-blur axis as one vector an a perpendicular one, scaled by the DOF amount, as the second. It's pretty straightforward, the only thing we really have to take care in this process is regions were the motion blur is zero and thus we won't have the required first axis, which might be a bit of a pain.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;As you know, doing these effects in post is an approximation, so when I look at these problems I always think in terms of the "correct" solution first and use that as a background in my head to validate any ideas I have.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;In this case what we really want to do is to sample some extra dimensions in our rendering integral, temporal in the case of the motion-blur and spatial, on the camera's film plane, in case of the DOF. This leads quite naturally to raytracing, but thinking this way is not particularly useful as we know we can't achieve comparable results to that, we don't have in post the ability of sampling more visibility &amp;nbsp;(and shading) than what we have already in our z-buffer, so we should look instead at a model that gives us "the best" of what we can do with the information that we have (to be fair, there is in literature an method which subdivides the scene in ranges with multiple z-buffers and color buffers, and then ray-marches on these z-buffers to emulate raytracing, which I found pretty cool, but I digress even more). With only a z-buffer and its color buffer, that would be scattering.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;You can imagine that as placing a particle at each image point, stretched along the axes we just described, with an opacity that is inversely proportional to its size, and then z-sorting and rendering all these particles (and some PC ports of some games did that, having a lot of GPU power to spare, in general placing some particles is not a bad idea especially if you can avoid having one per pixel but selecting the areas where your DOF highlights would be more visible). This, plus a model to "guess" the missing visibility (remember, we don't have all the information! if an object is moving, for example, it will "show" some of the background behind it, which we don't have, so we need a policy to resolve these cases) is the best we can do in post and should guide us in all the decisions we make in more approximate models.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Ok, going back to the effect we are creating, so far it's clearly a gathering effect. We create a filter kernel at each pixel, and then we gather samples around it. Often, this gathering only respects the depth sorting, we don't gather samples if their depth is farther from the camera than the pixel we're considering. This leads to no missing visibility problems, we assume that the surface on the pixel we're considering fully occludes everything behind it, but it's not really "correct" if we think about the scattering model we explained above.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;A better strategy would gather a sample only if the scattering kernel of the surface at that sample point would have crossed our pixel, this strategy is what I call sometimes "scattering as gathering".&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Now the problem with this is that unless we know that our scattering kernels have a bounded size, and for each pixel we sample everything inside that size to see if there is something that could have scattered towards it, we will miss some scattering, but unfortunately doing so requires a large number of samples.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;In particular, as we size our gather kernel using the information at the surface point of the pixel we're considering, we easily miss effects where a large out of focus object scatters on top of some in focus background pixels, for which the gathering kernel would be really small.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Now there are a variety of solutions for that. We could for example fix a minimum size for our gathering kernel, so in the in-focus areas we still "check" around a bit, and we might end up gathering nothing if we found nothing that scatters towards us. This sort-of works but still won't handle large scattering radii. We might think to cheat and get more samples by separating our gathering filter into two passes, each filtering along a line (axis).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;This works well for gathering, even when the filter is not really separable (DOF and MB are not, as the kernels, even if we use&amp;nbsp;a gaussian&amp;nbsp;or square one, which are separable, are sized by a function which varies per pixel and is not itself separable) the artifacts are not noticeable, but if we push this with a scattering-as-gathering logic it starts to crumble as the second pass does not have the information of where the first-pass gathering took its samples from, so it can't decide if these samples would have scattered towards a given location and it can't even separate the samples anymore. &lt;i&gt;Digression: In the past I've solved this by doing DOF in two passes, using separable gathering in a first pass while detecting the areas where it fails and masking them using early-z to then do a second pass on them with a large gather-as-scatter filter.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;So what we can do? The solution is easy really, we can write our basis vectors to a buffer (which is required anyways if you want to consider MB due to object movement and not only camera movement, the former can't be computed with the information we have from the colour and depth, we need to render the motion of the objects somewhere) and then apply a fixed radius gathering-as-scattering filter there, which as it's only searching to expand the subsequent filtering radii and not sampling colour, can be done with fewer samples without causing too much artifacts, pretty much as "percentage closer soft-shadows" do.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;So far, Crytek does something along the very same lines. The twist where the effect I crafted diverges from theirs is that I still employ a separable filter to compute the final blur, instead of using some taps in a circle. The first time I saw this done for MB and DOF was in EA's first Skate game, so it's nothing particularly novel. Skate's implementation though was "driven" by DOF, the motion blur was only added for the camera and it was only present if the DOF was there too (at least, afaik).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Extending this to behave well with the two effects separately requires computing the "right" gathering weights, or as I wrote above, reasoning about the scattering. Also, once you get the ability of doing motion blur without DOF, you will notice that one of the two blur passes will do nothing in areas of pure MB, as the second axes will have zero length (but you are still "paying" to sample N times the same area...). To avoid that waste, I filter along two diagonals, in case of pure MB these coincide but are both non-zero, so we get a bit better filtering for the same price.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;I don't think you can do much better than this on current-gen (without proper support for scattering) but I'd love to be proved wrong :)&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Example code below (it doesn't include many details and it doesn't include the axis scattering pass, but the "important" parts are all there):&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// --- First pass: Compute camera motion blur and DOF base axes&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float depth = tex2D( DepthSampler, TexCoord );&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float2 MB_axis = ( currentViewPos - previousViewPos ) * MB_MULTIPLIER;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float DOF_amount = ComputeDOFAmount(depth);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float MB_amount = length(MB_axis);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float DOF_MB_ratio = DOF_amount / (MB_amount + EPS_FLOAT);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float2 DOF_axis = MB_axis.yx * float2(1,-1) * DOF_MB_ratio;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;MB_axis *= max(DOF_MB_ratio, 1.f);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// Compute the 2x2 basis&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float4 axis1xy_axis2xy = DOF_axis.xyxy + MB_axis.xyxy * float4(1.0.xx, -1.0.xx);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// Make sure that we are in the positive x hemisphere so the following lerp won't be too bad&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;//axis1xy_axis2xy.xy *= sign(axis1xy_axis2xy.x);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;//axis1xy_axis2xy.zw *= sign(axis1xy_axis2xy.z);&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// We have to take care of too small MB which won't be able to correctly generate a basis&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;float MB_tooSmall = 1.0 - saturate(MB_amount * MB_THRESHOLD - MB_THRESHOLD);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;axis1xy_axis2xy = lerp(axis1xy_axis2xy, float4(DOF_amount.xxx, -DOF_amount), MB_tooSmall);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// --- Second and third passes: separable gathering&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half2 offset;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;if(is_first_separable_blur) offset = GetFirstAxis(TexCoord);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;else offset = GetSecondAxis(TexCoord);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half amount = length(offset);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half4 sum = tex2D(ColorSampler, TexCoord) * FILTER_KERNEL_WEIGHTS[0];&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half sampleCount = FILTER_KERNEL_WEIGHTS[0];&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half4 steps = (offset * TEXEL_SIZE).xyxy;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;steps.zw *= -1;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;for(int i=1; i &amp;lt; 1+NUM_STEPS; i++)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half4 sampleUV = TexCoord.xyxy + steps * i;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// Color samples&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half4 sample0 = tex2D(ColorSamplerHR, sampleUV.xy);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half4 sample1 = tex2D(ColorSamplerHR, sampleUV.zw);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;// Maximum extent of the blur at these samples&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half maxLengthAt0;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half maxLengthAt1;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;if(is_first_separable_blur)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;{ maxLengthAt0 = length(GetFirstAxis(sampleUV.xy)) * (NUM_STEPS+1);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;maxLengthAt1 = length(GetFirstAxis(sampleUV.zw)) * (NUM_STEPS+1); }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;else&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;{ maxLengthAt0 = length(GetSecondAxis(sampleUV.xy)) * (NUM_STEPS+1);&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;maxLengthAt1 = length(GetSecondAxis(sampleUV.zw)) * (NUM_STEPS+1); }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half currentLength = amount * i;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half weight0 = saturate(maxLengthAt0 - currentLength) * FILTER_KERNEL_WEIGHTS[i];&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;sum += sample0 * weight0;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;sampleCount += weight0;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;half weight1 = saturate(maxLengthAt1 - currentLength) * FILTER_KERNEL_WEIGHTS[i];&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;sum += sample1 * weight1;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;sampleCount += weight1;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;return sum / sampleCount;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-8660489175089071102?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/TqPLxKpM5GMjKSRqVkVGMnIgx8w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TqPLxKpM5GMjKSRqVkVGMnIgx8w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/TqPLxKpM5GMjKSRqVkVGMnIgx8w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TqPLxKpM5GMjKSRqVkVGMnIgx8w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/6E-Z5XMDbXM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/8660489175089071102/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=8660489175089071102" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8660489175089071102?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8660489175089071102?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/6E-Z5XMDbXM/current-gen-dof-and-mb.html" title="Current-gen DOF and MB" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/--U0QPIXUlE8/TwTjoytIHiI/AAAAAAAAAKQ/aqcApjgAQdY/s72-c/DOFandMB.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2012/01/current-gen-dof-and-mb.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIHRn89fip7ImA9WhRWF00.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-9005968089571677148</id><published>2012-01-04T11:15:00.000-08:00</published><updated>2012-01-04T11:15:37.166-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-04T11:15:37.166-08:00</app:edited><title>This is golden...</title><content type="html">This video, by a Bill Dally (NVidia) about chip architectures is so great it deserves its own post:&amp;nbsp;&lt;a href="http://mediasite.colostate.edu/Mediasite/SilverlightPlayer/Default.aspx?peid=22c9d4e9c8cf474a8f887157581c458a1d#"&gt;http://mediasite.colostate.edu/Mediasite/SilverlightPlayer/Default.aspx?peid=22c9d4e9c8cf474a8f887157581c458a1d#&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
It probably will tell you thinks you already know, but even if it does, it's worth to see it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-9005968089571677148?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zYEGG3E2Fy1v4pbzSmsIU6fvMPY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zYEGG3E2Fy1v4pbzSmsIU6fvMPY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zYEGG3E2Fy1v4pbzSmsIU6fvMPY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zYEGG3E2Fy1v4pbzSmsIU6fvMPY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/HxGnyN3y2S8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/9005968089571677148/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=9005968089571677148" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/9005968089571677148?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/9005968089571677148?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/HxGnyN3y2S8/this-is-golden.html" title="This is golden..." /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2012/01/this-is-golden.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUEQHk4fip7ImA9WhRWFU4.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-8264304518418779324</id><published>2011-12-12T14:50:00.022-08:00</published><updated>2012-01-02T13:03:21.736-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-02T13:03:21.736-08:00</app:edited><title>The three skin rendering horrors you want to avoid</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;It's 2011 and still most games come with some truly horrific skin rendering. I don't think skin is that hard to get decent, but you have to understand what's important and how to hack it in your lighting/rendering model.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;This article won't focus on the state of the art skin rendering techniques or on the state of the art acquired data for skin, these things are really important, fundamental, go ahead and google them, there's plenty to read and it's not hidden knowledge at all (start with &lt;a href="http://www.pauldebevec.com/"&gt;Debevec&lt;/a&gt; and &lt;a href="http://scholar.google.ca/scholar?q=related:3H8Wormo6doJ:scholar.google.com/&amp;amp;hl=en&amp;amp;as_sdt=0,5"&gt;Jensen&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;What I want to do here is just a write up of what I've learned about skin in my experience, and some of the common technical mistakes I've seen.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;1- Bad tone&lt;/span&gt;&lt;/b&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/-duT3GzJdMdI/TuZvpmiUyrI/AAAAAAAAAIw/UJ0AzP_VofI/s1600/fallout3-2008-12-02-11-0.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-duT3GzJdMdI/TuZvpmiUyrI/AAAAAAAAAIw/UJ0AzP_VofI/s320/fallout3-2008-12-02-11-0.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;Fallout 3: Radiation really does some numbers on your skin...&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;By far, the &lt;/span&gt;&lt;a href="http://c0de517e.blogspot.com/2010/03/skin.html" style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;worst offender&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;. Nailing the right colours from the day to the nightside of the skin is the most important, and most often neglected things. And yes, it is mostly (but not only) a matter of subsurface scattering, as most of the skin diffuse lighting comes from it, but it's not about complicated techniques. It's about understanding what happens, what's important to model and how to hack it in whatever lighting model you have in your rendering.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&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/-7DJzkQoUsf4/Tuj3s81Yi9I/AAAAAAAAAJQ/sKW3rnd8vZI/s1600/5.jpg" imageanchor="1" style="font-size: medium; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="189" src="http://4.bp.blogspot.com/-7DJzkQoUsf4/Tuj3s81Yi9I/AAAAAAAAAJQ/sKW3rnd8vZI/s320/5.jpg" 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;Model: Commander Shepard @ Bioware&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;/span&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/-N3Z8e5UQIE0/Tuj3P6LfntI/AAAAAAAAAJI/1lRK5DKKzfk/s1600/skinball.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="188" src="http://1.bp.blogspot.com/-N3Z8e5UQIE0/Tuj3P6LfntI/AAAAAAAAAJI/1lRK5DKKzfk/s320/skinball.jpg" 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;Model: Charlotte Free @ IMG/NY&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;You can get great skintones with even the simplest hacks on top of your basic lambert, and horrible tones by badly tuned texturespace or screenspace diffusion techniques. Penner's &lt;a href="http://www.ericpenner.net/portfolio/"&gt;pre-integrated skin shading&lt;/a&gt; is the current champion of the lambert hacks, but truth is that some sort of ramp on top of your lambert is everything you need (that's to say, you can most often get decent results without even bothering to approximate the geometry with the curvature, as Eric does) if you nail the right hues! Also, remember that scattering will affect all the skin shading, you might want to "ramp" the edges of the shadowmaps (again, Penner's paper covers that) but it's actually often even more important to properly blend AO on skin, especially if you're using a normal-aware SSAO which is capable of capturing very fine details, a straight multiply will create some really questionable gray patches. Again, even simple hacks, like adding a slight constant colour to your SSAO, will go a long way towards creating more organic skin.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-spwZJ8MNFdQ/Tuj5SjKzNTI/AAAAAAAAAJY/Urh-S908uBY/s1600/Clipboard02.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="239" src="http://3.bp.blogspot.com/-spwZJ8MNFdQ/Tuj5SjKzNTI/AAAAAAAAAJY/Urh-S908uBY/s320/Clipboard02.jpg" 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;Debevec, Digital Emily, Acquired Diffuse&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Give your artists the right tools! It's fundamental to be able to tune the skin while comparing the rendered results with some reference material (put an image viewer and color sampler in game!), it's fundamental to tune colors after fixing your tone-mapping operator, and it's fundamental to understand _all_ your sources of color: shading model, parameters, textures.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-MGgux6Vn_9Y/Tuj5oWN8GYI/AAAAAAAAAJg/5Rb9G-kVGz0/s1600/Clipboard04.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="216" src="http://4.bp.blogspot.com/-MGgux6Vn_9Y/Tuj5oWN8GYI/AAAAAAAAAJg/5Rb9G-kVGz0/s320/Clipboard04.jpg" 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;Debevec, Efficient Estimation of Spatially Varying Subsurface Scattering Parameters&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Textures are particularly tricky: remember that skin specular is white (monochromatic), skin diffuse maps really are tied with the subsurface scattering model you implement in the shader, in theory the epidermis is pretty gray, all the colour comes from the blood vessels below the surface. In practice, especially in the realtime rendering world, we mix together all the skin layers and more often than not the problem with skin textures is that they are not saturated enough (consider that the white, additive specular sheen should be responsible for some of the loss of saturation in the final rendering) and have too uniform hues (skin hue shifts quite a lot in many regions, i.e. elbows, joints, hands and &lt;/span&gt;&lt;a href="http://www.3dtotal.com/index_tutorial_detailed.php?id=762" style="font-family: Arial,Helvetica,sans-serif;"&gt;feet&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;, and usually presents quite a few blemishes)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;2- Bad detail&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nd5qUF7vRL8/TuZ0IKODOpI/AAAAAAAAAI4/XDPxazrTALg/s1600/gears-of-war-marcus-fenix.jpg" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-nd5qUF7vRL8/TuZ0IKODOpI/AAAAAAAAAI4/XDPxazrTALg/s320/gears-of-war-marcus-fenix.jpg" width="301" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Skin detail does not come from diffuse! That's quite obvious as we said that diffuse lighting is mostly due to subsurface scattering.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-oLixyjY1jhY/Tuj50fbwICI/AAAAAAAAAJo/ue06Z6kCdWU/s1600/Clipboard03.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-oLixyjY1jhY/Tuj50fbwICI/AAAAAAAAAJo/ue06Z6kCdWU/s320/Clipboard03.jpg" 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;Debevec, Digital Emily, Specular&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Detail is all in the specular layer, ideally, you would need two different normalmaps for diffuse and specular (actually, Debevec achieves good results rendering with different normals for each of the RGB channels of the diffuse), fetching the same at different miplevels (bias) is often good enough and in a pinch, even just using the geometric normals for diffuse (or a lerp between the normalmap normal and the geometric ones) is way better than using the specular normals.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Skin pores are a really, really fine detail which is both&amp;nbsp;difficult&amp;nbsp;to capture and easy to get in the way of your BRDF. Most of the times, it's better to have the pore details as self-occlusion in the specular map than in the normalmaps (which being a derived measure will require higher resolution to capture the same amount of detail). Also, you either have to model skin for a given viewing distance, or you'd better consider that at all but the closest distances the pores will/should fade in your miplevels and their scattering effect should be modeled by varying the specular exponent (broadening it with the distance, you can use ddx and ddy to estimate the filtering width, our use cLEAN), there is no way to tune the specular with a constant exponent that will yield both the right amount of detail up-close and the broad sheen you see from a distance.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Peach fuzz on dry skin is another geometrical source of specular detail perturbation, you might want to model it by adding noise at the grazing angles if you need that amount of detail.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;3- Bad volume&lt;/span&gt;&lt;/b&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://3.bp.blogspot.com/-Dw4o8mNFDR4/TuaAKud3txI/AAAAAAAAAJA/F_NroYBILi0/s1600/0000302928.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://3.bp.blogspot.com/-Dw4o8mNFDR4/TuaAKud3txI/AAAAAAAAAJA/F_NroYBILi0/s320/0000302928.jpg" 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;Fight Night Champion&lt;br /&gt;
When it works is one of the few games that captures volume right...&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Skin texture luminosity is often quite uniform, and in caucasians&amp;nbsp;quite light too, making skin shading more a matter of volume and shape than texture. Three elements here are important: specular, ambient and normals.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Normals are tricky because skin is often... skinned. Conventional bone skinning yields bad geometric normals. I've already &lt;a href="http://c0de517e.blogspot.com/2011/05/skinning-normals-notes.html"&gt;blogged about that&lt;/a&gt; so I won't repeat myself here.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Ambient is "easy" but really important, a simple contant won't do the job, it just flattens everything, even a simple hemispherical (top/bottom, a lerp between two colors based on the geometric normal y component, boils down to a single madd) is way better.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Observe and understand. Look at your references, understand what's important, understand your visual errors and their sources. The "correct hack"&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&amp;nbsp;really depends on the context, if your environment is quite fixed, like in a sport or racing game you can model ambient with different components: a sky layer which does not depend on the position plus a ground reflection that maybe fades on the model based on the distance to the ground and so on...&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-0TeeIIi30ng/TukDBK17Q5I/AAAAAAAAAJ4/6Dgbd98y8kU/s1600/fight-night-champion_3.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://3.bp.blogspot.com/-0TeeIIi30ng/TukDBK17Q5I/AAAAAAAAAJ4/6Dgbd98y8kU/s320/fight-night-champion_3.jpg" 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;Shadows, AO, Ambient model... All coming together nicely&lt;/td&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Ambient occlusion is fundamental, ideally you'd want to have some&amp;nbsp;directionality&amp;nbsp;in the occlusion: bent normals, or encoding the occlusion in some base. Really "occlusion" is fundamental for volume. Each light component (ambient, diffuse, specular etc) should be occluded in a reasonable way.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Again, there are many ways,&amp;nbsp;technically&amp;nbsp;to achieve that, I won't delve into any detail because it depends on the context, you might want to agument SSAO to encode directional information (as I already said), or precompute occlusion at the vertices (SH or similar), cast rays in screenspace (i.e. screenspace reflection occlusion is easy, especially at the all-important fresnel angles, for rim occlusion) or even simpler hacks.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;The important message here is that volume requires occlusion, look at your rendering and understand your visual defects, look for light leaks, compare with real-world references and acquired data and craft your own solution! Sometimes the actual technical answer is dead simple (an example - one of the improvements on Champion over Round 4 was a "downgrade", we went from VSM to simple PCF filtering because VSM even if on average are "nicer" were not able to capture the very important occlusions on the face due to precision issues, the nose shadows and the eye-sockets. Going back to PCF gave us "worse" shadows but way better faces!)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-KyAhIBWLKfE/TukC-3W9I6I/AAAAAAAAAJw/L8pmiVqR7lQ/s1600/Fight+Night+Champion+screenshot+2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;img border="0" height="180" src="http://4.bp.blogspot.com/-KyAhIBWLKfE/TukC-3W9I6I/AAAAAAAAAJw/L8pmiVqR7lQ/s320/Fight+Night+Champion+screenshot+2.jpg" 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;Phong, modified to behave better with Schlick. No lousy round highlights!&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Achieving proper specular on skin is probably one of the trickiest parts as unfortunately, right now in realtime rendering we have either the choice of employing nice material models on simple analytic lights. It's well-known that the &lt;/span&gt;&lt;a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html" style="font-family: Arial,Helvetica,sans-serif;"&gt;Kelemen/Szirmay-Kalos model fits the skin&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt; acquired data very well and if you can afford it it's probably the way to go, especially if you lighting is not very complex (i.e. outdoor, harshly lit scenes).&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Unfortunately, in many&amp;nbsp;contexts&amp;nbsp;we want to use some image-based lighting approach (baking reflection cubemaps), and that restricts the BRDF filtering we can employ pretty much to Phong, and straight Phong is really, really bad on skin.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Again, it's important here to observe and understand what is important, what qualities we want to model or hack. The specular sheen, other than affecting the saturation and the skin detail, as we discussed already, is important for the &lt;a href="http://www.google.ca/search?q=shape+perception+and+specular"&gt;perception of the shape&lt;/a&gt;. Human vision can't really distinguish the effects of the various lights in the specular, we can't relate well the scene lighting with the specular hightlights shapes.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;What we do with the specular is to understand the surface shape and material, so what's important is more to model the general shape of the specular, than the link between the specular and the actual scene lights.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;That's why we can often ignore accurate specular occlusion (and just modulate all the specular light with our single shadowmap and omnidirectional ambient occlusion... or even "worse" multiply some of the diffuse product into phong, not ideal, but decent) and we can often disregard accurate light positions and use reflection cubemaps.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;And that's why what's really important is the shape of the specular sheen, and you get quite some latitude in hacking that in, as we can't really "see" these hacks as long as the final shape behaves "well".&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;What phong get really wrong is the highlight shape, which is too uniformly circular, and the lack of frensel.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;You can "break" the highlights using an&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;exponent&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&amp;nbsp;map (which should always be present, but it's especially important with Phong), adding fresnel is not easy as Phong simply does not reflect enough light at the grazing angles, and thus even multiplying with a decent approximation, like Schlick's, does not usually yield great results, it's better to use fresnel to (also) drive other parameters in the Phong model instead, either bending the reflection normal, or lowering the exponent.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;I probably should have included a fourth horror "bad&amp;nbsp;behavior", as most CG humans (all? in videogames) really lack the proper "fleshiness" in terms of animation and behaviour, but that's a harder problem to tackle which is probably outside the realm of realtime animation, at least for most games where you have many characters on screen and you can't afford having 300 bones in each plus some soft-body system and some UV relaxation and so on...&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Really what I wanted to point out are some &lt;b&gt;simple&lt;/b&gt; things that &lt;b&gt;every game&lt;/b&gt; should do, aspects which can most of the times be fixed to a decent degree with really cheap hacks, but do require an understanding of how the underlying physics work and how our perception works to then&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;focus on what really matters visually.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Then the actual techniques really depend on your project, for those of you that really want to delve into some actual tech, an example of &amp;nbsp;a possible solution for skin rendering is&amp;nbsp;&lt;a href="http://c0de517e.blogspot.com/2011/09/fight-night-champion-gdc.html"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;b&gt;Addendum: Hair, Eyes, Teeth, Ears&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt; Hair is a huge pain, on this generation we're stuck with hair cards. Cards don't sort well, are hard to shadow and hard to shade. My usual suggestion is to avoid spending too much time on it, it's not really worth it.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Shading usually employs Kajiya-Kay for specular (card will require a tangent shifting map to avoid having uniform highlights on a card, which are ok only for very straight hair), some wrap lighting for diffuse and a way of getting good rim.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;For sorting, the usual solution is to go multipass, first doing alpha testing with z-writes, and then alpha blending with z-testing. You can somewhat pre-sort the triangles from in to out, some games do the alpha blending pass in two phases, first the backface cards then the frontfacing ones. It's decent, but defects will still be there, even sorting per triangle, if you can, doesn't solve them all as cards often intersect. I honestly think a better solution is to just alpha test and rely on alpha to coverage, if you can. This is what Fight Night Champion did by the way (Round 4 did a three-pass alpha blending).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Eyes are way, way more important. Shading is not that hard, specular/reflection is done with a&amp;nbsp; cubemap usually, diffuse would need SSS but again some wrap is good, on Fight Night we computed a second set of normals to match the diffuse lighting with the skin around the eyes, probably a bit overkill. Behavior is hard, and getting it right is crucial! On the shading side, one trick I used is to disable the mipmaps, and the bilinear filtering on the reflection cube, to get aliasing far away that in turns create some shimmering in the small highlights. But most of it is in the animation, and some procedural techniques are to be employed.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Ears have lots of translucency, again, it can be faked easily, I won't lose my sleep there. For teeth, the important thing is to use the right occlusion and avoid them to become too bright, shadows from the mouth and lips onto the teeth are very hard to cast so again, you'll have to do some faking.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Bottom line, for each of these elements there are some easy hacks, but it's important to consider them. Once you understand what each of them needs and what physical things are important to model for each (ear: translucency, eyes: SSS and behavior, teeth: occlusion etc...), the actual techniques are "easy" or can be easily faked to a decent standard.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-8264304518418779324?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZRtsa9Fcdo6Z669d_6jsdkNV4qY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZRtsa9Fcdo6Z669d_6jsdkNV4qY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZRtsa9Fcdo6Z669d_6jsdkNV4qY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZRtsa9Fcdo6Z669d_6jsdkNV4qY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/epMwFnDmG5I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/8264304518418779324/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=8264304518418779324" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8264304518418779324?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8264304518418779324?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/epMwFnDmG5I/three-skin-rendering-horrors-you-want.html" title="The three skin rendering horrors you want to avoid" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-duT3GzJdMdI/TuZvpmiUyrI/AAAAAAAAAIw/UJ0AzP_VofI/s72-c/fallout3-2008-12-02-11-0.jpg" height="72" width="72" /><thr:total>9</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/12/three-skin-rendering-horrors-you-want.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AMQH4yeip7ImA9WhRRFU8.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-2063516138191959095</id><published>2011-11-28T15:09:00.000-08:00</published><updated>2011-11-28T15:09:41.092-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-28T15:09:41.092-08:00</app:edited><title>Google reader share</title><content type="html">So, some of you have noticed that my &lt;a href="http://www.google.com/reader/shared/c0de517e"&gt;google reader share&lt;/a&gt; is dead (not updated anymore). That's not me being lazy, but google being a bit evil and trying to shove google+ down our throats by killing the old facilities instead of integrating plus into the existing stuff. So, there is no reader share anymore, and my iPad newsreader (reeder), which was responsible of most of the share posts, does not support google+ yet. Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-2063516138191959095?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EIHxJiHnvkWc4CADQO0b2Z6IjJ4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EIHxJiHnvkWc4CADQO0b2Z6IjJ4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EIHxJiHnvkWc4CADQO0b2Z6IjJ4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EIHxJiHnvkWc4CADQO0b2Z6IjJ4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/4JpqRgkv1_A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/2063516138191959095/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=2063516138191959095" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2063516138191959095?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2063516138191959095?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/4JpqRgkv1_A/google-reader-share.html" title="Google reader share" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>2</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/11/google-reader-share.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04FQH86fCp7ImA9WhRREks.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7964804940478988438</id><published>2011-11-25T13:45:00.002-08:00</published><updated>2011-11-25T17:11:51.114-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-25T17:11:51.114-08:00</app:edited><title>Photoshop scripting - Cleartype for images</title><content type="html">&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/-4DNxJT_Z7W8/TtALwspAi9I/AAAAAAAAAIk/8jb9NXNSMYY/s1600/cleartype_bar_rafaeli.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-4DNxJT_Z7W8/TtALwspAi9I/AAAAAAAAAIk/8jb9NXNSMYY/s1600/cleartype_bar_rafaeli.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Left: bilinear, Right: bilinear with "cleartype"&lt;br /&gt;
note- the effect is configured for a "landscape" RGB pattern LCD&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I always wanted to learn how to script Photoshop (what I learned is that it's a pain and the documentation sucks...), so yesterday I started googling and created a little script to emulate &lt;a href="http://en.wikipedia.org/wiki/ClearType"&gt;cleartype&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.reenigne.org/blog/cleartype-for-images/"&gt;on images&lt;/a&gt;. Here is the source (it assumes that a rgb image is open in PS):&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// 3x "cleartype" shrink script&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var doc = app.activeDocument;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var docWidth = doc.width.as("px");&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var docHeight = doc.height.as("px");&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.flatten();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// let's go linear RGB&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.bitsPerChannel = BitsPerChannelType.SIXTEEN;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.changeMode(ChangeMode.RGB);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// now that's a bit tricky... we have to go through an action, which has binary data... which I'm not sure it will be cross-platform&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// it works on Photoshop CS3 on Win7...&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;function cTID(s) { return app.charIDToTypeID(s); };&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;function sTID(s) { return app.stringIDToTypeID(s); };&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var desc6 = new ActionDescriptor();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var ref5 = new ActionReference();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;ref5.putEnumerated( cTID('Dcmn'), cTID('Ordn'), cTID('Trgt') );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putReference( cTID('null'), ref5 );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putData( cTID('T &amp;nbsp; '), String.fromCharCode( 0, 0, 1, 236, 65, 68, 66, 69, 2, 16, 0, 0, 109, 110, 116, 114, 82, 71, 66, 32, 88, 89, 90, 32, 7, 219, 0, 10, 0, 22, 0, 19,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 25, 0, 58, 97, 99, 115, 112, 65, 80, 80, 76, 0, 0, 0, 0, 110, 111, 110, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 1, 0, 0, 246, 214, 0, 1, 0, 0, 0, 0, 211, 44, 65, 68, 66, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 9, 99, 112, 114, 116, 0, 0, 0, 240, 0, 0, 0, 50, 100, 101, 115, 99, 0, 0, 1, 36, 0, 0, 0, 101, 119, 116, 112, 116,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 1, 140, 0, 0, 0, 20, 114, 88, 89, 90, 0, 0, 1, 160, 0, 0, 0, 20, 103, 88, 89, 90, 0, 0, 1, 180, 0, 0, 0, 20,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;98, 88, 89, 90, 0, 0, 1, 200, 0, 0, 0, 20, 114, 84, 82, 67, 0, 0, 1, 220, 0, 0, 0, 14, 103, 84, 82, 67, 0, 0, 1, 220,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 14, 98, 84, 82, 67, 0, 0, 1, 220, 0, 0, 0, 14, 116, 101, 120, 116, 0, 0, 0, 0, 67, 111, 112, 121, 114, 105, 103, 104,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;116, 32, 50, 48, 49, 49, 32, 65, 100, 111, 98, 101, 32, 83, 121, 115, 116, 101, 109, 115, 32, 73, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;100, 0, 0, 0, 100, 101, 115, 99, 0, 0, 0, 0, 0, 0, 0, 11, 67, 117, 115, 116, 111, 109, 32, 82, 71, 66, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, 90, 32, 0, 0, 0, 0, 0, 0, 235, 194, 0, 1, 0, 0, 0, 1, 65, 50,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;88, 89, 90, 32, 0, 0, 0, 0, 0, 0, 97, 15, 0, 0, 36, 77, 255, 255, 255, 232, 88, 89, 90, 32, 0, 0, 0, 0, 0, 0, 103, 37,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 220, 208, 0, 0, 5, 29, 88, 89, 90, 32, 0, 0, 0, 0, 0, 0, 46, 162, 255, 255, 254, 227, 0, 0, 206, 39, 99, 117, 114, 118,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0 ) );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putEnumerated( cTID('Inte'), cTID('Inte'), cTID('Clrm') );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putBoolean( cTID('MpBl'), true );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putBoolean( cTID('Dthr'), false );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;desc6.putInteger( cTID('sdwM'), 2 );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;executeAction( sTID('convertToProfile'), desc6, DialogModes.NO );&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.backgroundLayer.applyGaussianBlur(0.75); // limit the frequency a bit to avoid too many fringes&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.resizeImage(&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;UnitValue(docWidth, "px"),&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;UnitValue(docHeight / 3,"px"),&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;null,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;ResampleMethod.BILINEAR // To-do: box filter (mosaic + nearest)&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var unitValue = UnitValue(1, "px");&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// RGB pattern, note that the nearest resize will take the center pixel, that's why red shifts by one and not zero&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var redLayer = doc.backgroundLayer.duplicate();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;redLayer.applyOffset(unitValue, 0, OffsetUndefinedAreas.WRAPAROUND);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var greenLayer = doc.backgroundLayer.duplicate();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;greenLayer.applyOffset(-unitValue, 0, OffsetUndefinedAreas.WRAPAROUND);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;var blueLayer = doc.backgroundLayer.duplicate();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;blueLayer.applyOffset(-unitValue*2, 0, OffsetUndefinedAreas.WRAPAROUND);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.resizeImage( // Resize to "select" the RGB columns in the various layers&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;UnitValue(docWidth / 3, "px"),&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;UnitValue(docHeight / 3,"px"),&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;null,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;ResampleMethod.NEARESTNEIGHBOR&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;//var col = new SolidColor(); col.rgb.hexValue = "FF0000"; redLayer.photoFilter(col, 100, false);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;redLayer.mixChannels ([[100,0,0,0],[0,0,0,0],[0,0,0,0]], false);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;greenLayer.mixChannels ([[0,0,0,0],[0,100,0,0],[0,0,0,0]], false);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;blueLayer.mixChannels ([[0,0,0,0],[0,0,0,0],[0,0,100,0]], false);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;redLayer.blendMode = BlendMode.LINEARDODGE; // add!&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;greenLayer.blendMode = BlendMode.LINEARDODGE; // add!&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// blue is the base layer&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.flatten();&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;// let's go to 8bit sRGB&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.convertProfile ("sRGB IEC61966-2.1", Intent.PERCEPTUAL, true, true);&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;doc.bitsPerChannel = BitsPerChannelType.EIGHT;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-7964804940478988438?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UexsBJ4-mVycj_NrMa7NsYyv-Hs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UexsBJ4-mVycj_NrMa7NsYyv-Hs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UexsBJ4-mVycj_NrMa7NsYyv-Hs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UexsBJ4-mVycj_NrMa7NsYyv-Hs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/r9evNgtuPFw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7964804940478988438/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7964804940478988438" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7964804940478988438?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7964804940478988438?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/r9evNgtuPFw/photoshop-scripting-cleartype-for.html" title="Photoshop scripting - Cleartype for images" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-4DNxJT_Z7W8/TtALwspAi9I/AAAAAAAAAIk/8jb9NXNSMYY/s72-c/cleartype_bar_rafaeli.png" height="72" width="72" /><thr:total>13</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/11/photoshop-scripting-cleartype-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IDRHc7eCp7ImA9WhRTF0Q.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7542660693147214673</id><published>2011-11-08T15:30:00.005-08:00</published><updated>2011-11-08T15:39:35.900-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-08T15:39:35.900-08:00</app:edited><title>Silvio Berlusconi</title><content type="html">&lt;i&gt;This is obviously going to be off-topic with the rest of the blog... If you landed here for the first time, this is a rendering related blog and this article is an exception to the rule.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;As the Europe's and Italy's financial crisis deepens, news crossed the wire today that &lt;a href="http://www.guardian.co.uk/world/2011/nov/08/silvio-berlusconi-to-resign-italy?newsfeed=true"&gt;prime minister Berlusconi vowed to resign&lt;/a&gt;. I see many people asking around the world how it was possible that this happens only now, how did Berlusconi manage to be in power for seventeen years even after countless scandals and accusations. While in general I think it's not surprising, and the eight years of Bush administration could be served as an example, I'd like to try to explain what's peculiar about Italy's situation (of course, in my point of view).&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Also, of course, I will make generalizations in the following. In no way I want to express that this is applies to everyone and everything, that should be pretty clear.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;Survivalists&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;One way or another, we keep going on. This is by far what I believe to be the deepest of our problems. We don't care much about our society, we avert our eyes and keep going on, everyone trying to find a hole in which to live their lives.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;We are masters in bending (if there is a profit to be made) or ignoring laws. Even our image outside the country is that of creative, chaotic individuals (at best), known for being obsessed about family and our own small individualities.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;We are not socialists not liberals, we are just driven towards what can get us a gain tomorrow morning. Mind you, to a degree this happens everywhere, but it's not a defining quality of a population quite as it happens in Italy, where is deeply buried everywhere, from how people live their lives to how companies make business.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Even our economy, made mostly of small or family owned companies, with our comparatively large private savings and our huge public debt, is a testimony of this mentality.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;I can't tell why this is the case, we are a young republic and unification was not a smooth deal, but we don't believe in society. Berlusconi is the embodiment of all this, and I don't know how much he was just "born this way" or how much he knowingly acts to please, to be popular, but he is certainly great in leveraging such sentiments. His political message, either explicitly or implicitly has always been "vote for me and I'll let you live your lives without control", "you don't need to be responsible for your actions", "I was successful, don't ask me how, you want to be like me, I won't ask you how"...&lt;br /&gt;
Berlusconi was never a left or right wing politician, he is obsessed about communism and certainly sees Italy's leftists as pure evil, but his actions are not the ones of a liberal. Among other things, he's remembered for saying openly at an entrepreneurs' convention&amp;nbsp; that companies without off-shore operations were not led smartly, and that evading taxes (one of Italy's chief problems) was morally sound in a country like ours (in which taxes are too high). He didn't them proceed to lower the taxes and impose strict controls to have everyone paying the right amount, or to incentive competition and freedom of enterprise.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;In the first months of his government he proceeded in the opposite direction, abrogating liberalization laws that were passed by the previous government, loosening controls over financial transactions and not reducing a single tax. Not touching established interests, not reducing bureaucracy, but just allowing people to just screw each other more freely.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;Shameless&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Berlusconi is probably not the worst individual in Italy's history. Corruption and misgovernment were always there and can be even tracked to the same underlying sentiment. The first republic created a massive debt because political parties were quite literally buying votes by flushing enormous amounts of public money into all kinds of public ventures, creating hundreds of thousands of "fake" jobs, public employers who were pretty much useless. But it came down onto his knees when it was found that politicians also used public money to fund their own parties. There was corruption, but there is was still a sense of shame.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Berlusconi took inspiration from this and pushed it one step further, he was proud of his tricks, every trial he escaped by passing laws in his own favor, every lie and joke he said made him look "smarter", more successful. It's not that the vast majority of Italians do not know he was a thief, that's also why many of his voters were even shy of saying so, especially if singled out.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;It's that deep down, they knew, but they admired his skill, they wanted to live the same dream, to take the easy way and just not have to care. That's also why for years even after all the sex scandals he managed to keep a mostly Catholic country under control. That's why he still now has a huge following...&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;Media and Opposition&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;These two aspects were also important and I'm sure there is a lot more to be said, but I think they don't contribute to explain the Berlusconi phenomenon quite as understanding how much deeply he connects with some Italian sentiments.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Berlusconi owns most of Italy's media and he is renown to be a great communicator. He lies, but his lies are so constant and so fiercely defended by so many, that they slowly become truths. Words slowly lose their meaning and the public becomes divided into factions who do not reason but just mindlessly cheer for one or the other party.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Again, that's partially a "quality" of Italians, being more emotional than rational, being hot headed and profoundly divided. But he managed to exploit that incredibly well.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;His power does not extend over only media of course, most if not everyone in his party is strongly tied to him, he choose men with little political past and respectability of their own, people who depended on him to be elected. Berlusconi IS his party, and everyone sings the song he sings. And he made pretty clear that was the way from the start, his party always had direct references to him in the logo, in the hymns, everywhere. Everyone laughs at his jokes. Everyone follows the same rules, tells the sames words, uses the same dialectic tricks. I'm not sure if it's imitation or doctrine but it's powerful.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;On the other hand the opposition is fragmented and largely seen as made of intellectuals&amp;nbsp; and professional politicians who do not have any connection with the people. (which to a degree can be even very true). They were always bad communicators so it was easy for Berlusconi to play them, routinely saying that there was no better alternative than him, that the left-wing was made of communists that had no real plan other than raising the taxes (even if financial pressure increases or decreases have not really been strongly linked to any particular government). Furthermore they showed no cohesion, being unable to claim even the huge victories they sometimes achieved (Italy was able to enter the Euro as one of the founding parters due to the work of a left-wing government for example) and not being able to look past their divisions. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-7542660693147214673?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0dIZKy8ec-AVfhvH9VZZYcPDFdM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0dIZKy8ec-AVfhvH9VZZYcPDFdM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0dIZKy8ec-AVfhvH9VZZYcPDFdM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0dIZKy8ec-AVfhvH9VZZYcPDFdM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/pn68qc_0H9M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7542660693147214673/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7542660693147214673" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7542660693147214673?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7542660693147214673?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/pn68qc_0H9M/silvio-berlusconi.html" title="Silvio Berlusconi" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>11</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/11/silvio-berlusconi.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08MQXw8fSp7ImA9WhRTE0s.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7411788517788578130</id><published>2011-10-28T14:28:00.002-07:00</published><updated>2011-11-03T16:11:20.275-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-03T16:11:20.275-07:00</app:edited><title>Open questions - my two rules</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As &lt;a href="http://c0de517e.blogspot.com/2011/10/open-questions.html"&gt;I wrote here&lt;/a&gt;, there are some fundamental questions in realtime rendering that I wish I knew more about. I do have though two &amp;nbsp;rules I apply when thinking about rendering techniques&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Reduce variance: It's better to be consistent at a lower quality than have glitches/flickering artifacts at a higher quality.&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Postulate: all graphical effects should be reviewed in motion, crossing quality boundaries&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Less is more: It's better to not have a given effect than have it at a too low quality level.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As an example we can&amp;nbsp;analyze&amp;nbsp;shadows. The first rule tells us that it's better to have stable cascades at a lower resolution than having perspective shadowmaps at high resolution.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The second rule tells us that it's better to have lower filtering and cull shadows from some objects or limit the shadowing maximum distance, than having bad shadows everywhere.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Unrelated, I just saw this as a job opening at &lt;a href="http://www.valvesoftware.com/jobs/job_postings.html"&gt;Valve&lt;/a&gt;... Smart guys!&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div class="job_position_title_active" style="background-color: #d3d6ca; color: #cf381e; display: inline; font-family: Arial, Helvetica, sans-serif; font-size: 18px; text-align: -webkit-auto;"&gt;Psychologist&lt;/div&gt;&lt;div class="close_popup" style="background-color: #d3d6ca; background-image: url(http://www.valvesoftware.com/images/jobs/xClose.png); background-repeat: no-repeat no-repeat; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; height: 14px; position: absolute; right: 10px; text-align: -webkit-auto; top: 10px; width: 15px;"&gt;&lt;/div&gt;&lt;div class="job_description_intro" style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; text-align: -webkit-auto;"&gt;&lt;div style="letter-spacing: 0.3px; line-height: 1.2em; margin-top: 4px; padding-bottom: 6px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;We believe that the more we know about human behavior, about how and why people do what they do, the better our products will be. All game designers are, in a sense, experimental psychologists. That’s why we’re looking for a experimental psychologist to apply knowledge and methodologies from psychology to game design and all aspects of Valve’s operations. We want to exploit your experience with experimental design, research methods, statistics, and human behavior to help craft even more compelling gameplay experiences for future Valve titles. We’d also expect you to research and weigh in on any and all topics that are relevant to improving the experiences of our customers, partners, and employees.&lt;/div&gt;&lt;/div&gt;&lt;div class="list_title" style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; font-weight: bold; text-align: -webkit-auto;"&gt;Duties:&lt;/div&gt;&lt;ul style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 12px; padding-left: 10px; padding-right: 0px; padding-top: 6px; text-align: -webkit-auto;"&gt;&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Provide relevant insight into human behavior in order to shape gameplay and customer experience.&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Perform statistical analyses on all aspects of Valve’s operations: gameplay, financial, and company data.&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Research compelling new hardware technologies.&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Design experiments to evaluate various gameplay hypotheses and design choices.&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Improve existing playtesting methodologies while incorporating novel techniques to improve best practices.&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Develop innovative ways of acquiring relevant data to answer open questions about all aspects of Valve’s products and business practices.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="list_title" style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; font-weight: bold; text-align: -webkit-auto;"&gt;Requirements:&lt;/div&gt;&lt;ul style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 12px; padding-left: 10px; padding-right: 0px; padding-top: 6px; text-align: -webkit-auto;"&gt;&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Graduate degree in Psychology (or equivalent) field&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Advanced knowledge of statistics&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Familiarity with one or more of the following pieces of data analysis software: SPSS, Systat, Matlab, R, (or equivalent)&lt;/li&gt;
&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Four years experience with:&lt;ul class="sub_list" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;li style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; list-style-image: initial; list-style-position: initial; list-style-type: circle !important; margin-left: 16px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;Experimental design/research methods&lt;/li&gt;
&lt;li style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; list-style-image: initial; list-style-position: initial; list-style-type: circle !important; margin-left: 16px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;Relevant research in cognitive, social, human factors, and related disciplines in psychology&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="list_title" style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; font-weight: bold; text-align: -webkit-auto;"&gt;Recommended:&lt;/div&gt;&lt;ul style="background-color: #d3d6ca; color: #745e4e; font-family: Arial, Helvetica, sans-serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 12px; padding-left: 10px; padding-right: 0px; padding-top: 6px; text-align: -webkit-auto;"&gt;&lt;li style="background-image: url(http://www.valvesoftware.com/images/bullet.png); background-position: 0px 7px; background-repeat: no-repeat no-repeat; list-style-image: initial; list-style-position: initial; list-style-type: none; padding-left: 10px;"&gt;Proficiency in one or more of the following programming languages: C++, SQL, PHP, (or equivalent)&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-7411788517788578130?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/f_1uHsxXWiIOUYpzWWTG5qcSGOM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f_1uHsxXWiIOUYpzWWTG5qcSGOM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/f_1uHsxXWiIOUYpzWWTG5qcSGOM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f_1uHsxXWiIOUYpzWWTG5qcSGOM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/xuhBekUF-as" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7411788517788578130/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7411788517788578130" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7411788517788578130?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7411788517788578130?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/xuhBekUF-as/open-questions-my-two-rules.html" title="Open questions - my two rules" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>2</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/10/open-questions-my-two-rules.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAHRHozeCp7ImA9WhRTEUQ.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-1763212735018169467</id><published>2011-10-26T21:17:00.017-07:00</published><updated>2011-11-01T17:28:55.480-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-01T17:28:55.480-07:00</app:edited><title>Open questions</title><content type="html">&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/-x017tZ7Zu4E/TqjbAWkcVtI/AAAAAAAAAIU/GHmPpuhDnxs/s1600/End_of_the_virtual_world_9.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://4.bp.blogspot.com/-x017tZ7Zu4E/TqjbAWkcVtI/AAAAAAAAAIU/GHmPpuhDnxs/s320/End_of_the_virtual_world_9.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;From the series "&lt;a href="http://shotbyrobert.com/wordpress/?page_id=102"&gt;End of the virtual world&lt;/a&gt;" by Robert Overweg &lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Battlefield, Mass Effect, &lt;a href="http://www.youtube.com/watch?v=1xjCdN_rWCE&amp;amp;hd=1"&gt;Modern Warfare&lt;/a&gt;, &lt;a href="http://www.youtube.com/watch?v=cZUUVV2rjoc&amp;amp;hd=1"&gt;Red Dead&lt;/a&gt;, Crysis, Rage, Forza, GT, Alan Wake...&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;What makes the graphics work? I've played the last three call of duty games on 360, with a projector and a 5.1 system. I found them to be amazing. Then I downloaded MW2 on steam, and the graphics looked mediocre.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Conversely, Mass Effect 2 seemed decent on 360 but way more awesome on PC.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Red Dead pushes less polygons and has more visual defects than Crysis but awed me in a way no other game of this generation did.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Battlefield 3 is a technical jewel but MW seemed to me to have a better atmosphere.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Why? Is my subjective judgment shared by others? Is my memory failing me and have my expectations shifted? Or there is also something technical behind these impressions?&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;MW textures on PC have the low-res quality of a bad port. Is this, coupled with the increase in resolution, the reason the game looks worse to me on PC, makes my brain "see" the polygons more? Or is it because its atmosphere is better suited for a projector and a couch? Or maybe it's because playing the game I was more immersed into it than when I just looked at the graphics on the PC.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Why was it the opposite for ME2? Is its art style, less reliant on gritty texture detail, making better use of the high resolution and antialiasing of the PC?&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Why I enjoyed more ME2 single player graphics than BF3 ones? Are the graphics enhancing the gameplay, or is also the opposite true, game and story do affect the perception of the graphics?&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Is it the aliasing that is killing BF? Or is the inability of deferred lighting to express the subtleness of light transport and materials the issue? Is our industry jumping on the deferred lighting approach too fast, without really understanding what it's losing form precomputed lighting?&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;What about the heavy bloom and flares that BF3 and Crysis2 use? How are they working? How do they alter the perception of the image?&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;From my experience I observed some patterns, but I don't really know much, I've also found very little research...&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;i&gt;Aliasing and other high frequency artifacts quickly tell your brain that it's looking at CG, they are very disturbing. Motionblur at 30fps looks more cinematic and packs more punch than 60fps without blur. We tolerate framerate problems way more if the game looks busy (i.e. A huge explosion) than if they are not connected with game actions. Colour is hard to get right, and ambient lighting and proper occlusion of lighting terms are important to represent volume, rendering the air (haze, fog, scattering, desaturation tricks etc) helps with scale. Crowd variety is achieved more with colour and behavior variation than texture and model. Specular lobes are everywhere, have always fresnel, and we can't recognize errors in the light directions in the specular but we use high-gloss highlights to evaluate shape. Bleeding dark edges (i.e. when dealing with subsampled effects) looks less questionable than having bright halos.&lt;/i&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;There, I think I didn't miss anything, that's pretty much all I know, it fills a few lines of text. I think that's a big challenge for us, there are more studios that know how to do deferred lighting right and fast than there are studios that know what's important to create an immersive, beautiful game. We don't know what to focus on where, what devices are used for what, which artifacts are tolerable and which are disturbing.&lt;br /&gt;
&lt;br /&gt;
We know the (sometimes) the physics but we have very little math to model the psychology. Yes, KSK fits skin specular well. But what parts of it are important? When does it break and breaks the perception of skin being skin? We need to make hacks, and physically reasonable hacks are fundamental in our line of business, physics are fundamental, but physiologically motivated hacks &lt;a href="http://cs.yale.edu/c2/images/uploads/HR18_1.pdf"&gt;would be way better&lt;/a&gt;!&lt;br /&gt;
This also affects all the "tuning" decisions, i.e. more &lt;a href="http://graphics.pixar.com/library/LOD2002/paper.pdf"&gt;LOD&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdocs.cs.ualberta.ca/~xingdong/papers/ISM06.pdf"&gt;switching&lt;/a&gt; but with better detail near the camera, or vice-versa? &lt;a href="http://cs.yale.edu/c2/images/uploads/HR12_2.pdf"&gt;Geometry or textures&lt;/a&gt;? Bigger SSAO radius and more noise or the opposite and so on.&lt;br /&gt;
Moreover linking perception (vision) and psychology with rendering would give us more objective tools for art-direction, like what device is the best to convey in the general audience a given intent, what makes a sense of "scale" or of "fear" and so on...&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Rendering without knowing about perception is crazy, it's like if musicians knew more about sound waves and instruments than harmony and melody. And yet we often chose rendering techniques based on really faint leads about what is needed to look good. There is little research, and the little there is focuses on issues that seldom are directly applicable to modern videogame rendering techniques.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Even worse, we are just not starting to understand the basics, like &lt;a href="http://filmicgames.com/archives/586"&gt;color&lt;/a&gt; and normals, and not only in the industry but even in most publications you will find little regard towards even basic visual perception metrics.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;Videogame rendering today at its best it's a work of iteration, the more you can try and the better feedback you get, the more you inch towards this ill-defined target of visual splendor. But e&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ven artists and art-directors with a great eye for light and colour seldom have much experience about realtime CG artifacts and their impact on perception.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Shifting from art to science has to happen in order for our profession to evolve, we can't rely on art direction for technical problems, it's not only too error-prone but also very inefficient. Scientific studies can be shared and described exactly, while art direction remains subjective and does not result in a shared progress.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;It of course not something that happens only in rendering (or presentation in general, &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.2002&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;animation, audio&lt;/a&gt;), we even make games with very faint leads about what is needed to make fun. And that's why often you have studios investing big amounts of money, and staffed with great talents, producing results that are impressive but still fail, while only very few games really know how to be fun, and really know how to immerse players in their art...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;More to come... Meanwhile you might want to read something (other than the links I've already scattered in the post):&amp;nbsp;&lt;a href="http://virtual.inesc.pt/cge02/pdfs/chalmers.pdf"&gt;Some&lt;/a&gt; &lt;a href="http://www.neurovr.org/emerging/volume5.html"&gt;interesting&lt;/a&gt; &lt;a href="http://www.crcpress.com/product/isbn/9781568814650"&gt;reads&lt;/a&gt; &lt;a href="http://www.physiologicalcomputing.net/?p=1698"&gt;here&lt;/a&gt;. Also &lt;a href="http://graphics.cs.yale.edu/holly/pres.html"&gt;Holly Rushmeier&lt;/a&gt;'s work (some is linked in the post - from the website the EG2001 and EG2003 presentations are very neat)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;Please comment if you know more resources on the topic. A question has been posted on Quora &lt;a href="http://www.quora.com/What-do-we-know-about-the-relation-between-perception-psychology-and-computer-graphics"&gt;here&lt;/a&gt;...&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-1763212735018169467?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3UQIl2AKZ7IzDwbyuZgrnsMqZuM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3UQIl2AKZ7IzDwbyuZgrnsMqZuM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3UQIl2AKZ7IzDwbyuZgrnsMqZuM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3UQIl2AKZ7IzDwbyuZgrnsMqZuM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/-cRJprZX2lU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/1763212735018169467/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=1763212735018169467" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/1763212735018169467?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/1763212735018169467?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/-cRJprZX2lU/open-questions.html" title="Open questions" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-x017tZ7Zu4E/TqjbAWkcVtI/AAAAAAAAAIU/GHmPpuhDnxs/s72-c/End_of_the_virtual_world_9.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/10/open-questions.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUERn8-fyp7ImA9WhRTEUQ.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-2951388119451368685</id><published>2011-10-18T17:52:00.005-07:00</published><updated>2011-11-01T17:36:47.157-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-01T17:36:47.157-07:00</app:edited><title>Rendering 102</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Follow-up to&amp;nbsp;&lt;a href="http://c0de517e.blogspot.com/2011/09/rendering-101.html"&gt;http://c0de517e.blogspot.com/2011/09/rendering-101.html&lt;/a&gt;:&amp;nbsp;a simplified and hopefully clearer version of the "&lt;a href="http://c0de517e.blogspot.com/2008/04/gpu-part-1.html"&gt;how the gpu works&lt;/a&gt;" posts.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Covers GPU computational model and GPU graphics pipeline.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Check it out here:&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://www.scribd.com/doc/69372569/videogame-Rendering-102"&gt;http://www.scribd.com/doc/69372569/videogame-Rendering-102&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As usual, let me know in the comments about mistakes and possible improvements!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-2951388119451368685?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/N2omPhzSRqPCfA35jD85QKs57rk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/N2omPhzSRqPCfA35jD85QKs57rk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/N2omPhzSRqPCfA35jD85QKs57rk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/N2omPhzSRqPCfA35jD85QKs57rk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/9K4Vj3hVU_E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/2951388119451368685/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=2951388119451368685" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2951388119451368685?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2951388119451368685?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/9K4Vj3hVU_E/rendering-102.html" title="Rendering 102" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2011/10/rendering-102.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8CQXk7cSp7ImA9WhdUF0s.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-8359663029894453430</id><published>2011-10-04T14:47:00.001-07:00</published><updated>2011-10-04T14:47:40.709-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-04T14:47:40.709-07:00</app:edited><title>Spent</title><content type="html">&lt;a href="http://www.playspent.org/"&gt;http://www.playspent.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-8359663029894453430?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WGWbbuGU5dFAv2CSJ_Nlp2v30Es/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WGWbbuGU5dFAv2CSJ_Nlp2v30Es/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WGWbbuGU5dFAv2CSJ_Nlp2v30Es/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WGWbbuGU5dFAv2CSJ_Nlp2v30Es/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/xTx9HdmA5yQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/8359663029894453430/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=8359663029894453430" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8359663029894453430?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8359663029894453430?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/xTx9HdmA5yQ/spent.html" title="Spent" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2011/10/spent.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMCSHY_fyp7ImA9WhdUFko.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-8081676578287236269</id><published>2011-10-03T12:12:00.003-07:00</published><updated>2011-10-03T13:07:49.847-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-03T13:07:49.847-07:00</app:edited><title>Don't lie.</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A task is not done when its code gets checked-in. In production, "done" is:&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Checked-In&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Stable (passes automated tests)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In-budget (memory and performance)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Usable (tools, parameters)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Verified (art-directior or&amp;nbsp;designer&amp;nbsp;or lead programmer)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If you ignore the last four, you're living in a dream. A dream in which you will ship the game. Instead, you'll die under the pressure of crunch time and ship a flawed product that does not match the quality standards it should.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;That also means that in production we start with a stable, in-budget product. And that we do have means of verifying that this is true for the entire production (tests).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Yes, it will take twice as much time to finish a task. Yes, it will mean that some tasks can't be declared done until you make more space somewhere else, to fit them in.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Of course you can avoid all this. All it takes, is to lie.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;We are a creative industry. We have to deal with change, we don't plan things up ahead and then waterfall until they are all done (not _most_ of the times at least, there are situations in which that applies).&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;We don't craft a product by following a plan, we make drawings and sketches (prototypes) and then take a canvas and start painting.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;You don't have a person detailing a finger, another one refining an eye, another working on the nose and then hope that everything will stick together just right. Or hope that you will have all the parts done by a given date! And what if it then misses one of the ears? What do you do, take ten artists working on that ear till midnight every day near the deadline?&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Only an idiot would do that, and still many game companies work like that, they don't consider that everything has to fit just right, and that change is not local, every change has to fit with the entire context, every brush stroke has to make a sense in the entire painting.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;You start with a painting, a rough one, and then refine it, and at all time the painting is a painting, it's not a collection of unrelated pieces. You can stop at any moment and it will be still a painting, maybe not that refined, maybe not as intricate and detailed as you wanted, but it's a painting.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A game is such only if it runs. If it crashes or goes out of memory on the target platform, it's not a game, it's some binary that crashes. If it does not hold its performance, it's not a game, we can't burn it to a disc and call it a game, it won't be shipped, it won't pass certification. Iteration should not break this quality, it should go from a "shippable" game to a "shippable" game. Especially during production.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-8081676578287236269?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-IzDDQabjW-oSwon4uQ2lFpAvV0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-IzDDQabjW-oSwon4uQ2lFpAvV0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-IzDDQabjW-oSwon4uQ2lFpAvV0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-IzDDQabjW-oSwon4uQ2lFpAvV0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/nga0PFlxMcw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/8081676578287236269/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=8081676578287236269" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8081676578287236269?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/8081676578287236269?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/nga0PFlxMcw/dont-lie.html" title="Don't lie." /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>2</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/10/dont-lie.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUABRH09fSp7ImA9WhdUFE8.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7327930099938374110</id><published>2011-09-30T16:02:00.000-07:00</published><updated>2011-09-30T16:02:35.365-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-30T16:02:35.365-07:00</app:edited><title>Rendering 101</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://www.scribd.com/doc/66998911/videogame-Rendering-101"&gt;This&lt;/a&gt; is how I explain (videogame) rendering to non-rendering (engineers... even if hopefully it's still understandable for some non-programmers as well).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If you have suggestions on how to make it more clear, post a comment!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-7327930099938374110?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XsL67N2wpm0D4enynPDrbv5gKDU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XsL67N2wpm0D4enynPDrbv5gKDU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XsL67N2wpm0D4enynPDrbv5gKDU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XsL67N2wpm0D4enynPDrbv5gKDU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/s_5BmJbpefc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7327930099938374110/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7327930099938374110" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7327930099938374110?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7327930099938374110?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/s_5BmJbpefc/rendering-101.html" title="Rendering 101" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>4</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/rendering-101.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAGSH0-fSp7ImA9WhdUFE0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-2884323111843035397</id><published>2011-09-28T14:30:00.007-07:00</published><updated>2011-09-30T11:18:49.355-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-30T11:18:49.355-07:00</app:edited><title>Fight Night Champion Rendering @ GDC</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I wrote so much for Fight Night Champion over the years, but not much can be found on the internet. I crafted at least five presentations for it, three mostly internal for the team on Fight Night 4 analysis and pre-production, one on the various prototypes and ideas done to exit pre-production, to share ideas with the other EA teams, and one for GDC after the game was done, which was refined and presented by my (awesome!) colleague Vicky Ferguson when I left EA (you should see the recording of her presentation, and she also presented for FN4 at the previous GDC which was very cool too).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Unfortunately the slides of this last one were not published (a couple could be found &lt;a href="http://chulin28ho.egloos.com/5495308"&gt;here&lt;/a&gt;, but they are pretty useless)... until now.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;At the beginning I thought about writing more detalied blog articles about many of the experiments that were done, but many of them do not really need that much space, some others were rediscovered and published by others (i.e. pre-blurred SSS, bent normals SSAO), and I think FNC was more about the process than the final tech (in fact, the&amp;nbsp;lengthy&amp;nbsp;presentation never goes into the detail of what at the end were the final FNC shaders!), so...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;This is a "director's cut" of the GDC slides, it's way more verbose (not meant for presentation) and with much more material. &lt;a href="http://www.scribd.com/doc/66973213/Fight-Night-Champion-GDC-Presentation"&gt;Enjoy&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-2884323111843035397?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/4z6IF6LksSZK3Lp0xhWQH9ldkRo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4z6IF6LksSZK3Lp0xhWQH9ldkRo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/4z6IF6LksSZK3Lp0xhWQH9ldkRo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4z6IF6LksSZK3Lp0xhWQH9ldkRo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/WRmJWyGT2gQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/2884323111843035397/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=2884323111843035397" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2884323111843035397?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2884323111843035397?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/WRmJWyGT2gQ/fight-night-champion-gdc.html" title="Fight Night Champion Rendering @ GDC" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/fight-night-champion-gdc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEABRXk-eSp7ImA9WhdUEkk.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-492207887513024071</id><published>2011-09-27T20:22:00.003-07:00</published><updated>2011-09-28T14:52:34.751-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-28T14:52:34.751-07:00</app:edited><title>Bad ideas don't require much explanation: Caching Stable Cascaded Shadowmaps</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;Note:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-0p7WCZyTuyI/ToKS-pKJuvI/AAAAAAAAAIE/F4gharbDUxU/s1600/2011-09-26+16.12.07.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-0p7WCZyTuyI/ToKS-pKJuvI/AAAAAAAAAIE/F4gharbDUxU/s320/2011-09-26+16.12.07.jpg" width="236" /&gt;&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/6950833531562942289-492207887513024071?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XH7B3O2ShNQv6UNKektMyLB2nnA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XH7B3O2ShNQv6UNKektMyLB2nnA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XH7B3O2ShNQv6UNKektMyLB2nnA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XH7B3O2ShNQv6UNKektMyLB2nnA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/0V9KCkINbhM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/492207887513024071/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=492207887513024071" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/492207887513024071?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/492207887513024071?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/0V9KCkINbhM/bad-ideas-dont-require-much-explanation.html" title="Bad ideas don't require much explanation: Caching Stable Cascaded Shadowmaps" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-0p7WCZyTuyI/ToKS-pKJuvI/AAAAAAAAAIE/F4gharbDUxU/s72-c/2011-09-26+16.12.07.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/bad-ideas-dont-require-much-explanation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYNSXc5eip7ImA9WhdVFUg.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-2363872499335654433</id><published>2011-09-20T15:16:00.001-07:00</published><updated>2011-09-20T15:19:58.922-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-20T15:19:58.922-07:00</app:edited><title>Mathematica and Spherical Harmonics</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As my &lt;a href="http://c0de517e.blogspot.com/2011/09/mathematica-and-skin-rendering.html"&gt;previous post&lt;/a&gt; about Mathematica seemed to be well-received, I've decided to dig some old code, add some comments and post it here. Unfortunately it's littered with \[symbol] tags as in Mathematica I used some symbols for variables and shortcuts (which you can enter either in that form or as esc-symbol-esc). You can also see a PDF version of the notebook &lt;a href="http://www.scribd.com/doc/65701735/Mathematica-Spherical-Harmonics"&gt;here&lt;/a&gt;, with proper formatting. Enjoy!&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&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/-ciMinaxEm4U/TnkReOa578I/AAAAAAAAAIA/FNshMsWltOM/s1600/sh.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="282" src="http://4.bp.blogspot.com/-ciMinaxEm4U/TnkReOa578I/AAAAAAAAAIA/FNshMsWltOM/s320/sh.jpg" 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;A function and its SH approximation&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Normalization part of spherical harmonics *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shNormalizationCoeffs[l_, m_] :=&amp;nbsp;Sqrt[((2*l + 1)*(l - m)!)/(4*Pi*(l + m)!)]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Evaluates to a function of \[Theta],\[Phi] for a given degree l&amp;nbsp;and order m, it's defined as three different cases for m=0, m&amp;lt;0, and&amp;nbsp;m&amp;gt;0*)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shGetFn[l_, m_] :=&amp;nbsp;Simplify[Piecewise[{{shNormalizationCoeffs[l, 0]*LegendreP[l, 0, Cos[\[Theta]]],&amp;nbsp;m == 0}, {Sqrt[2]*shNormalizationCoeffs[l, m]*Cos[m*\[Phi]]*LegendreP[l, m, Cos[\[Theta]]],&amp;nbsp;m &amp;gt; 0}, {Sqrt[2]*shNormalizationCoeffs[l, -m]*Sin[-m*\[Phi]]*LegendreP[l, -m, Cos[\[Theta]]], m &amp;lt; 0}}]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Indices for a SH of a given degree, applies a function which&amp;nbsp;creates a range from -x to x to every element of the range 0...l,&amp;nbsp;return a list of lists. Note that body&amp;amp; is one of Mathematica's way&amp;nbsp;to express pure function, with parameters #1,#2... fn/@list is the&amp;nbsp;shorthand for Map[fn,list] *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shIndices[l_] := (Range[-#1, #1] &amp;amp;) /@ Range[0, l]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* For each element of the shIndices list, it replaces the&amp;nbsp;corresponding shGetFn *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* This is tricky. MapIndexed takes a&amp;nbsp;function of two parameters: element of the list and index in the&amp;nbsp;list. Our function is itself a function applied to a list, as our&amp;nbsp;elements are lists (shIndices is a list of lists) *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shFunctions[l_] :=&amp;nbsp;MapIndexed[{list,&amp;nbsp;currLevel} \[Function] ((m \[Function]&amp;nbsp;shGetFn[currLevel - 1, m]) /@ list), shIndices[l]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Generates SH coefficients of a given function fn of&amp;nbsp;\[Theta],\[Phi], it needs a list of SH bases obtained from&amp;nbsp;shFunctions,it will perform spherical integration between fn and each&amp;nbsp;of the SH functions *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shGenCoeffs[shfns_, fn_] :=&amp;nbsp;Map[Integrate[#1*fn[\[Theta], \[Phi]]*Sin[\[Theta]], {\[Theta], 0,&amp;nbsp;Pi}, {\[Phi], 0, 2*Pi}] &amp;amp;, shfns]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* From SH coefficients and shFunctions it will generate a function&amp;nbsp;of \[Theta],\[Phi] which is the SH representation of the given&amp;nbsp;coefficients. Note the use of assumptions over \[Theta] and \[Phi]&amp;nbsp;passed as options to Simplify to be able to reduce the function&amp;nbsp;correctly, @@ is the shorthand of Apply[fn,params] *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;angleVarsDomain = {Element[\[Theta], Reals],&amp;nbsp;Element[\[Phi], Reals], \[Theta] &amp;gt;= 0, \[Phi] &amp;gt;= 0, \[Theta] &amp;lt;=&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; Pi, \[Phi] &amp;gt;= 2*Pi};&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shReconstruct[shfns_, shcoeffs_] :=&amp;nbsp;Simplify[Plus @@ (Flatten[shcoeffs]*Flatten[shfns]),&amp;nbsp;Assumptions -&amp;gt; angleVarsDomain]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Let's test what we have so far *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testNumLevels = 2;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shfns = shFunctions[testNumLevels]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFn[\[Theta]_, \[Phi]_] :=&amp;nbsp;Cos[\[Theta]]^10*UnitStep[Cos[\[Theta]]] (* Simple, symmetric around the z-axis *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(*&amp;nbsp;generate coefficients and reconstructed SH function *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFnCoeffs =&amp;nbsp;shGenCoeffs[shfns, testFn]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFnSH = {\[Theta], \[Phi]} \[Function]Evaluate[shReconstruct[shfns, testFnCoeffs]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* plot original and reconstruction *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;SphericalPlot3D[{testFn[\[Theta], \[Phi]], testFnSH[\[Theta], \[Phi]]}, {\[Theta], 0,&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&amp;nbsp; Pi}, {\[Phi], 0, 2*Pi}, Mesh -&amp;gt; False, PlotRange -&amp;gt; Full]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Checks if a given set of coefficients corresponds to zonal&amp;nbsp;harmonics *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shIsZonal[shcoeffs_, l_] :=&amp;nbsp;Plus @@ (Flaten[shIndices[l]]*Flatten[shcoeffs]) == 0&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Some utility functions *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shSymConvolveNormCoeffs[l_] :=&amp;nbsp;MapIndexed[{list, currLevel} \[Function]&amp;nbsp;Table[Sqrt[4*Pi/(2*currLevel + 1)], {Length[list]}], shIndices[l]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shExtractSymCoeffs[shcoeffs_] :=&amp;nbsp;Table[#1[[Ceiling[Length[#1]/2]]], {Length[#1]}] &amp;amp; /@ shcoeffs&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Convolution with a kernel expressed via zonal harmonics, symmetric&amp;nbsp;around the z-axis *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shSymConvolution[shcoeffs_, shsymkerncoeffs_,&amp;nbsp;l_] := (Check[shIsZonal[shsymkerncoeffs], err];&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&amp;nbsp; shSymConvolveNormCoeffs[l]*shcoeffs*shExtractSymCoeffs[shsymkerncoeffs])&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Another test *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFn2[\[Theta]_, \[Phi]_] :=&amp;nbsp;UnitStep[Cos[\[Theta]]*Sin[\[Phi]]] (* asymmetric *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFn2Coeffs =&amp;nbsp;shGenCoeffs[shfns, testFn2]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFn2SH = {\[Theta], \[Phi]} \[Function]Evaluate[shReconstruct[shfns, testFn2Coeffs]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;plotFn2 =&amp;nbsp;SphericalPlot3D[testFn2[\[Theta], \[Phi]], {\[Theta], 0, Pi}, {\[Phi], 0, 2*Pi},&amp;nbsp;Mesh -&amp;gt; False, PlotRange -&amp;gt; Full]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;plotFn2SH =&amp;nbsp;SphericalPlot3D[testFn2SH[\[Theta], \[Phi]], {\[Theta], 0, Pi}, {\[Phi], 0, 2*Pi},&amp;nbsp;Mesh -&amp;gt; False, PlotRange -&amp;gt; Full]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;Show[plotFn2, plotFn2SH]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;(* Test convolution *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;shIsZonal[testFnCoeffs, testNumLevels]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testConvolvedCoeffs =&amp;nbsp;shSymConvolution[testFn2Coeffs, testFnCoeffs, testNumLevels]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;testFnConvolvedSH = {\[Theta], \[Phi]} \[Function]&amp;nbsp;Evaluate[shReconstruct[shfns, testConvolvedCoeffs]]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"&gt;plotConvolvedSH =&amp;nbsp;SphericalPlot3D[testFnConvolvedSH[\[Theta], \[Phi]], {\[Theta], 0, Pi}, {\[Phi], 0,&amp;nbsp;2*Pi}, Mesh -&amp;gt; False, PlotRange -&amp;gt; Full]&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-2363872499335654433?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/glFhDGaPpNFQZyrWvnUTbfSKKVo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/glFhDGaPpNFQZyrWvnUTbfSKKVo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/glFhDGaPpNFQZyrWvnUTbfSKKVo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/glFhDGaPpNFQZyrWvnUTbfSKKVo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/PN1xPpYa8PQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/2363872499335654433/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=2363872499335654433" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2363872499335654433?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/2363872499335654433?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/PN1xPpYa8PQ/mathematica-and-spherical-harmonics.html" title="Mathematica and Spherical Harmonics" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-ciMinaxEm4U/TnkReOa578I/AAAAAAAAAIA/FNshMsWltOM/s72-c/sh.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/mathematica-and-spherical-harmonics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkAGRn04fip7ImA9WhdVFUk.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-5721025470712836644</id><published>2011-09-19T16:58:00.008-07:00</published><updated>2011-09-20T11:52:07.336-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-20T11:52:07.336-07:00</app:edited><title>Raytracing Myths</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I've already blogged about &lt;a href="http://c0de517e.blogspot.com/2008/03/raytracing-vs-rasterization.html"&gt;raytracing and rasterization&lt;/a&gt;, a &lt;a href="http://c0de517e.blogspot.com/2008/03/more-on-raytracing.html"&gt;couple of times&lt;/a&gt;, and I guess I should stop. Still, &lt;a href="http://xkcd.com/386/"&gt;duty calls&lt;/a&gt; when I read statements such as "&lt;a href="http://altdevblogaday.com/2011/09/19/why-i-still-think-ray-tracing-is-the-future/"&gt;rasterization cannot be parallelized nearly as effectively as ray tracing&lt;/a&gt;".&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Let's go!&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Algorithms&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Let's sketch both algorithms in some sort of pseudo-accurate pseudo-code:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;Raytracing (first-hit)&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;for_each pixel px on screen { for_each primitive pr in scene { intersect ray(px) with pr }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;Rasterization&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;for_each primitive pr in scene { for_each pixel px covered by pr { mark px on pr }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Pretty similar right? The inner loops are different, one intersects a ray equation with the&amp;nbsp;analytic&amp;nbsp;description of a primitive, the other in some way walks on the primitive marking pixels covered by the primitive (i.e. for triangles, by scanline interpolation or by walking on the pixels of the bounding box checking the edge equations).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Visible Pixels: there is a fundamental difference here that we will disregard for the future, as it's written raytracing has to walk on all the pixels of the screen, while rasterization walks all the pixels covered by primitives, thus is only part of the screen is covered raytracing has a disadvantage. The same could be said of rasterization if primitives have large parts that off-screen. This is true but not interesting, rasterization could solve the problem by clipping (moving the complexity from pixels to objects at least) and raytracing could subdivide the screen and identify empty tiles, anyhow this does not change the problem in general and does not change the complexity.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Also, some of you might have noticed that the description I've made is overly&amp;nbsp;simplistic. What I've sketched does not deal in any way with depth hiding. Both algorithms need to keep track of which primitive is the closest for every pixel. Fundamentally it's the same operation, but it has a different memory cost due to the ordering of the operations: raytracing can keep a single depth while scanning every primitive of a pixel and understand which primitive is the closest to the camera, rasterization needs to keep a value for each pixel as we will know which is the closest only when the outer loop is done (z-buffer!).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;Raytracing (first-hit)&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;for_each pixel px on screen { for_each primitive pr in scene { intersect ray(px) with pr, keep nearest depth }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;Rasterization&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;zbuffer = list of depths&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;for_each primitive pr in scene { for_each pixel px covered by pr { mark px on pr, store nearest in zbuffer }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Complexity&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;So memory-wise rasterization is worse than raytracing! We have to keep a z-buffer! Not so fast... Let's assume that we have a huge scene to render. Maybe we want even to stream stuff. What could we do with both algorithms?&amp;nbsp;It looks like we would need to have around, in memory, the contents of the inner loop, while we could stream over what's in the outer loop.&amp;nbsp;It's another&amp;nbsp;interesting&amp;nbsp;difference that originates from the same fundamental fact, the two loops are inverted. The z-buffer can be nifty because we can stream primitives through it, no matter how huge the scene is, we can go primitive by primitive and keeping only the z-buffer around we can render a scene. Raytracing on the other hand, has to keep primitives around.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Now we can of course imagine variants for both to be more efficient, z-buffer can be subdivided in tiles (or, for other reasons that are thought still about memory efficiency, we can use a hierarchy), primitives in raytracing can similarly partitioned and&amp;nbsp;aggregated&amp;nbsp;using bounding volumes and so on. It does not really change that we don't have a winner, we have the same computation expressed in a different order, which leds to different&amp;nbsp;trade-offs.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;What about the compute time? It's evident that from what I've sketched, it's identical. But raytracing is O(log(primitives)) &lt;a href="http://dl.acm.org/citation.cfm?id=30319"&gt;right&lt;/a&gt;? At least using spatial subdivision structures and disregarding the complexity of building them (which is often more than linear, thus making from the beginning complexity arguments rather moot)...It might not be obvious how that is not true, so let's make a couple of examples, hopefully these will be enough to generalize to any subdivision structure.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A scene with two group of primitives, one on screen, one off screen. These are bound by a box each, and the two boxes are bound with another box, thus creating a box hierarchy.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;What would the raytracer do? It would for every pixel on screen check the outer box, for each pixel intersecting it it would check then inner boxes, one will fail always and not trigger the check with the inner primitives, the other will not and thus we will end up checking only one of the groups.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Rasterization? We go through all the pixels of the outer box, we see that something is on screen so we go through all the pixels of the inner boxes, one will be on screen, the other won't and we will render only one group of inner primitives.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Other than the tradeoff between "for every pixel on screen" and "for every pixel covered by primitive" - the "visible pixels" problem that I already said that we would disregard, it's the same thing.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;But that is about screen coverage in two of the dimensions.&amp;nbsp;What about depth complexity?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A sparial subdivision structure with a raytracer provides a way of having guarantees on the depth ordering. For each ray, if we find an intersection in a given depth of the subdivision, we don't have to proceed any further, we know that all the primitives in lower depths are hidden for that ray. Or to put it in another way, for all the nodes that are fully covered by previous node's primitives, we don't do any work.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Doesn't that happen also for rasterization? Let's persuade ourselves of this fact. Assume that we have a depth-only hierarchy, our scene is split into different "chunks" along the depth, each chunk is defined by a splitting plane and contains a primitive. Now, let's say that the primitive of the first chunk covers the entire screen. Obviously in a raytracer we would trace that and stop, considering once all the pixels of the first plane, then once over all the pixels of the primitive, and then ending. In a rasterizer, we would rasterize the plane, then the primitive, then the following plane, find it all occluded and end. A bit more work, but constant, no matter how deep the chunk with the all-covering primitive is we stop always analyzing one more plane, so it's not a concern complexity wise.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;What if the primitive does not cover the entire screen though? What if it leaves exactly one pixel not covered? The raytracer would then go and check the following chunks against that single pixel only until a primitive covers it. The rasterizer would rasterize all the pixels in the planes every time it need to check, until the primitive covers it. It seems that we have a fundamental difference here, we could invoke again the "visible pixels" principle, but we would like a way to make the occlusion test resolution independent for the rasterizer to have the same cost.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;To be clear, I'm not advocating the use of BVHs and z-buffer pyramids in your game engine today. I'm just saying you could, so the big algorithmic complexity argument about the doom day when rasterization will not be viable anymore are wrong. By the way, it won't even be a very impractical method good only on the paper (like the constant-time raytracing stufff), it would probably be a good idea in some heavily occluded scenes...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Luckily depth complexity in practice is not even a huge deal for rasterizers, for example on a GPU. How comes? Overdraw should kill us, how do we avoid it? We can because a GPU does not need to rasterize fully covered primitives, if we have a front-to back ordering we can save most of the cost by checking our primitives against a coarse z-buffer, before shading. In a GPU shading is the big cost, and so we just do an early depth test and live with that, but in theory this works in general, we can make the occlusion cost logarithmic on the pixels by subdividing the z-buffer grid in a&amp;nbsp;hierarchy and in fact if we're interested in occlusion culling and not on shading, this is a good idea&amp;nbsp;(&lt;a href="http://www.cs.unc.edu/~zhangh/hom.html"&gt;see HOMs&lt;/a&gt;).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In the real world, if we want to talk outside the theory and useless statements about big-O complexity, both techniques need to deal with primitives and occlusions and they are if not equally good, very close, with both being able to handle scenes of immense complexity and out-of-core rendering. Both can be linear, logN or whatever, it's only that some techniques make more sense in some situations, so in practice most raytracers are logN with N^2 or more subdivision structure build times, rasterizers are mostly linear, both live happily with that on equally complex scenes.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Ironically in some way, raytracing which is said to be less dependent on primitive counts, absolutely needs accelleration structures for all but the simplest scenes, no raytracer goes without one, that's because you need them not only for depth complexity, but also to deal with the screen-space one (I guess you could cull primitives, LOD and tile, but then it would be so very close to a rasterizer not to be really smart, so really no one does that).&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Rasterization on the other hand performs great on a wider range of scenes and needs z-buffer hierarchies, level of detail and other complex occlusion strategies only when the shading costs are&amp;nbsp;negligible and the scenes have a lot of depth complexity. Both can do amazing things.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Parallelism and Concurrency&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Enter the second big topic, &lt;a href="http://blogs.oracle.com/yuanlin/entry/concurrency_vs_parallelism_concurrent_programming"&gt;parallelism and concurrency&lt;/a&gt;. Raytracing is easier to parallize says the myth - because each ray is independent. Is that true?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I can honestly see where this myth comes from, it even has a bit of truth in it. I picture someone in a university, writing a raytracer for fun or for a course and finding that's easy to fork at the ray-generation lever or a parallel_for over some worker threads and it works, because the inner loop is indeed independent, does not rely on shared state. A rasterizer does, for the z-buffer, so it would require some form of syncronization. Not the end of the world, you could have a z-buffer per thread and merge, you could have some a lockless stuff per pixel, tiles or whatever, but still it requires some changes.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;So is it easier? In that sense yes. But let's reason as a more experienced engineer (or scientist) and not as a freshmen. We see two nested loops, we are on a modern CPU architecture, what do we do? Instinctively (at least, I hope) we unroll and parallelize the inner (&lt;a href="http://en.wikipedia.org/wiki/Instruction_level_parallelism"&gt;instruction parallel&lt;/a&gt;), and try to make concurrent the outer (&lt;a href="http://en.wikipedia.org/wiki/Instruction_level_parallelism"&gt;data parallel&lt;/a&gt;). In this respect, how do the two algorithms fare?&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;These two, powerful forms of parallelism are absolutely fundamental to achieve great&amp;nbsp;throughput&amp;nbsp;on modern architectures as it provides them with a lot of coherent computation. Modern CPU execution times are dominated by latencies. Instruction latencies and dependencies and even more nowadays, memory latencies. And this won't change! Latency is hidden by unrolling, by having enough "predictable" computation (and memory access). If we have an operation A1 and a subsequent B1, with B1 dependent on A1 and A1 taking 10 cycles of latency, if we can find nine other instructions between A1 and B1 we're safe, we "hid" the latency. If we can unroll a cycle ten times over data elements 1...10, then we can trivially do A1,A2,A3,... then B1,B2... and we're done.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Now in theory, they are both good. A raytracer inner loop intersect a ray with a number of primitive, a rasterizer walks on a primitive looking for pixels. If the primitives are uniform, both are easy to unroll and play well with SIMD, we can intersect a ray with i.e. four primitives at a time, or in a similar way rasterize four pixels of a scanline (or a 2x2 block...) together.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The outer loop follows the same reasoning we did before, and indeed it's a bit easier on a raytracer. So again a win? Yes if we limit ourselves to a case that does not (as I wrote before) exist: a raytracer without a spatial&amp;nbsp;acceleration&amp;nbsp;structure and shading. And if we don't consider that accessing primitives in the inner loop is way more memory intensive than walking on pixels.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If we write things in "theory", or rather, with a theory based on an&amp;nbsp;over-simplistic&amp;nbsp;model raytracing wins... If we take a realistic renderer on the other hand, things change.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Spatial&amp;nbsp;acceleration&amp;nbsp;breaks uniformity. Shading of different primitives at the same time leads to incoherent memory access. Same for neighboring rays intersecting different groups of primitives. We can have a ray at level zero of the hierarchy and the neighboring one at level ten. A ray might need shading, while the next one might be still traversing. It's a mess!&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;And not an easy one to fight against at all, how do we deal with that? Well it turns out, it's not that simple, and not fully solved yet.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;One of the first approaches was to &lt;a href="http://graphics.stanford.edu/papers/coherentrt/"&gt;collect rays into the spatial structure&lt;/a&gt; cells and then be parallel to all the rays in a given cell. It works if you can generate enough rays, if you have still some coherency, i.e. for a distributed raytracer, less well for a path tracer. And still it deals only with part of the problem.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;For a while the solution seemed to be to organize rays in "&lt;a href="http://software.intel.com/en-us/articles/interactive-ray-tracing/"&gt;packets&lt;/a&gt;" that could walk the structures together, hoping they won't diverge much or trying to reconstruct some coherence by splitting and merging them. Then we found out that this works again for the kind of coherent loads that (we will see) are not really _that_ interesting for a raytracer, it will give you decently fast first-hit, shadows, the sort of stuff a raytracer is still good at. You can get some perfect mirrors on a sphere or so, how &lt;a href="http://www.geeks3d.com/20080612/ray-traced-quake-wars/"&gt;cool&lt;/a&gt; is &lt;a href="http://www.pcper.com/reviews/Graphics-Cards/Caustic-Graphics-and-CausticGL-Ray-Tracing-API"&gt;that&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;More recently, the first approach evolved in more general &lt;a href="http://sglab.kaist.ac.kr/CORR/"&gt;ray reordering&lt;/a&gt; strategies, while the second was turned sideways and experimented with having parallelism on a single ray by &lt;a href="http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=4634618"&gt;growing the width&lt;/a&gt; of the&amp;nbsp;&lt;span class="Apple-style-span" style="color: #0000ee;"&gt;&lt;u&gt;acceleration&lt;/u&gt;&lt;/span&gt;&lt;a href="http://www.uni-ulm.de/fileadmin/website_uni_ulm/iui.inst.100/institut/Papers/QBVH.pdf"&gt;&amp;nbsp;structures&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;All this while on GPUs rasterizers have been&amp;nbsp;executing&amp;nbsp;stuff in parallel, where it matters, over tens and hundreds of computational units, for years now (and &lt;a href="http://graphics.pixar.com/library/Reyes/"&gt;Reyes&lt;/a&gt; have been shading in parallel since the '82).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Ease of use&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Simple algorithms are easy to express in both, and writing a&amp;nbsp;bare-bones&amp;nbsp;triangle rasterizer or sphere raytracer (using the primitives that are easier to map in both) is trivial. Maybe the raytracer will take a few lines less, but hardly anything that we care about.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;For more complex effects, raytracer starts to win. Adding shadows, reflections. An univeristy student can have a lot of fun with a few lines of code, feeling happy. And from here on, if we never consider resource usage, raytracing always wins. You can solve the entire &lt;a href="http://en.wikipedia.org/wiki/Rendering_equation"&gt;rendering equation&lt;/a&gt; (or so) with a path tracer in a &lt;a href="http://kevinbeason.com/smallpt/"&gt;hundred lines of code&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;But when we make programs, in practice and not on paper, no matter what we have to deal with resources, they enter the equation. Then it becomes a matter of performance and how much do we care about it.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;When I started programming, on a commodore 64, I knew only Basic and Assembly, and that was all I knew even when I moved to the Amiga (amos) and the PC (QuickBasic, PowerBasic), until one of my older cousing started university and I grabbed his K&amp;amp;R book. I loved to write graphical effects, and I had to "optimize" code by either tweaking the code to suit better the (to me unknown) logic of the underlying interpreter, or add inline assembly directly via machine code. Hardly easy, even if you might argue that for some things Basic was easier to learn and use than C (and I really liked the QuickBasic PDS IDE at the&amp;nbsp;time...)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I think the complexity argument is rather dumb. Raytracing is less coherent and struggles with performance. Rasterization is more coherent and struggles with algorithms that need more flexibility in the visibility queries. Raytracing needs spatial accelleration structures and complex strategies to gain ray coherency. Rasterization needs fancy algorithms and approximations when it has to deal with global effects and more general visibility queries.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In practice if you've shipped a game, you already knew this. What do GPU use to render all these incredibly complex scenes over thousands of processors? What do we do on the other hand if we have to execute random visibility queries, for example for A.I.? Sometimes there are reasons why things are the way they are. The biggest trade-off between the two is surely that raytracing starts with incoherent visibility queries and research is trying to "find" patterns in them in order to gain performance, rasterization starts with coherent primitive walking and research is trying to find algorithms to compute global, complex illumination out of these fast massive queries we can issue (this is a &lt;a href="http://www.mpi-inf.mpg.de/resources/ImperfectShadowMaps/"&gt;nice example&lt;/a&gt;).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I liken it to programming languages. Dynamic versus Static, Pure versus Imperative. They are all Turing-complete and in theory equally capable at expressing computation. In practice though they start from different endpoints and try to reach the other, pure languages start safe and strive to express side-effects and program order, imperative start with side effects and strive to achieve safety, and so on.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;And if there is something to learn from that (and hopefully there is not :D) is that performance in computer science has been always a stronger drive in the success of a technology than other considerations (we program, unfortunately, in C++ not in Haskell), probably because it's more important to achieve a given amount of quality in practice, than having something that in theory produces something with a higher quality but in practice does not deliver.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Going back to the &lt;a href="http://altdevblogaday.com/2011/09/19/why-i-still-think-ray-tracing-is-the-future/"&gt;article&lt;/a&gt; that "spawned" all this. Is raytracing the future? Sure it is, it's surely "in" the future of rendering. But not because it's easier, or because it has a lower algorithmic complexity, or because it parallelizes better. None of these big global adjectives apply, that's all bullshit. It's in the future because it's a technique which has a set of&amp;nbsp;trade-offs&amp;nbsp;that are orthogonal to rasterization. It's useful, having more options, techniques, points of view is always useful. There will be areas in which rasterization will always make much more sense, and areas in which raytracing will, while most else will be happy to be able to pick and choose depending on the kind of problem they're facing.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I think you can always peek into the future by looking around, looking what other people in other fields with similar problems are doing...&amp;nbsp;In these years, for CG, raytracing and rasterization are influencing each other more and more.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Offline renderers are mixing techniques from both realms, just see what&amp;nbsp;&lt;a href="http://renderman.pixar.com/"&gt;Pixar's Photorealistic Renderman&lt;/a&gt;&amp;nbsp;is capable of doing. It's a Reyes rasterizer, for the first hit. It's parallel, concurrent and distributed. It can do shadowmaps and raytracing. It can cache point clouds and do some sort of screen-space ambient occlusion and so on. Still we lived with rasterization for a long time even in the offline realm especially in some fields that are less concerned about absolute lighting precision.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Only recently we started to see GI and raytracing as useful and productive replacements for some algorithms in the offline realm. I expect everything to be more and more hybrid. I don't think rasterization will ever die. Also, from what I know and I see of the research around raytracing I don't think that we'll see it in realtime, in games for quite some time yet.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-5721025470712836644?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AhtRYoVq9X-BduIKO8dy2FX1MIU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AhtRYoVq9X-BduIKO8dy2FX1MIU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AhtRYoVq9X-BduIKO8dy2FX1MIU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AhtRYoVq9X-BduIKO8dy2FX1MIU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/dMEJ7kd_s8g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/5721025470712836644/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=5721025470712836644" title="22 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/5721025470712836644?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/5721025470712836644?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/dMEJ7kd_s8g/raytracing-myths.html" title="Raytracing Myths" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/raytracing-myths.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ABRXo8eip7ImA9WhRQGU0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-7591560397995875615</id><published>2011-09-08T18:54:00.007-07:00</published><updated>2011-12-14T15:35:54.472-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-14T15:35:54.472-08:00</app:edited><title>Mathematica and Skin Rendering</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Introduction &lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Now, if you've been following my blog for a while, you might have noticed that I hate C++ almost as much as I love rapid prototyping, live-editing languages. &lt;a href="http://en.wikipedia.org/wiki/Mathematica"&gt;Wolfram&lt;/a&gt;'s &lt;a href="http://www.wolfram.com/mathematica/"&gt;Mathematica&lt;/a&gt; is one of the finest of such tools I've found so far.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;It might sound surprising as Mathematica's mostly known as a computer algebra system, performing symbolic manipulations that are arguably not the bread and butter of the realtime rendering engineer, but deep down everything boils down to a Lisp-like language with a twist, as it allows different representations of the parse tree (i.e. plain code, mathematical notation, editable widgets and even inline graphics). All of this is coupled with one of the most powerful mathematical and numerical libraries available, with the symbolical math functionality "helping" the numerical one (automatic algorithm selection, generation of derivatives and so on), and topped with a very good visualization system and amazing documentation.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Sounds cool right? Let's start using it then! &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Preintegrated Skin Shading&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I've been following &lt;a href="http://www.ericpenner.net/portfolio/"&gt;Eric Penner&lt;/a&gt;'s Preintegrated Skin Shading for more than a year now. We were colleagues at EA Canada, but we never ended up on the same project and being both interested in graphics research, we ended up having independently discovering a few of the same ideas while working at our project.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I was pretty amazed when he showed me his "Shader Amortization using Pixel Quad Message Passing" (Now in &lt;a href="http://gpupro2.blogspot.com/"&gt;GPUPro 2&lt;/a&gt;) as I had a similar idea in the back of my mind as well, and I guess he was pretty surprised as well when I presented internally to EA a prototype for Fight Night that sported "preblurred" subsurface scattering (at that time FN still did diffuse lighting with cubemaps, so the prototype was about cubemap biasing, normal preblurring and different normal fetches for each of the RGB channels as in "&lt;a href="http://gl.ict.usc.edu/Research/FaceScanning"&gt;Rapid Acquisition of Specular and Diffuse Normal Maps from &lt;/a&gt;"). He combined that same intuition with gradient estimation (as in "&lt;a href="http://dl.acm.org/citation.cfm?id=1599382&amp;amp;dl=ACM&amp;amp;coll=DL&amp;amp;CFID=38919231&amp;amp;CFTOKEN=89463543"&gt;Curvature-Dependent Local Illumination Approximation for Translucent Materials&lt;/a&gt;", "&lt;a href="https://docs.google.com/viewer?a=v&amp;amp;q=cache:FGYO9jW4gzEJ:www.ijvr.org/paper7.pdf+Curvature-Based+Shading+of+Translucent+Materails,+such+as+Human+Skin&amp;amp;hl=en&amp;amp;gl=ca&amp;amp;pid=bl&amp;amp;srcid=ADGEESje8xQdXnkdhsv3ZSTaKgsULU_YPbvTadAxKEN1Ei5wripWb5lLZCHwmJ_LC8XIYPRlGvSAXb_IjbqC5DIshkbPUkBpoKsaogiP26wE1R46THRCT3LGLsm-zx1UocyHfZ4qWMn3&amp;amp;sig=AHIEtbR9oa_7AshWKkGrW8lgGoavSsrnKQ&amp;amp;pli=1"&gt;Curvature-Dependent Reflectance Function for&amp;nbsp;Interactive Rendering of Subsurface Scattering&lt;/a&gt;", by Kubo et al and "&lt;a href="http://www.arnetminer.org/viewpub.do?pid=236484"&gt;Curvature-Based Shading of Translucent Materails, such as Human Skin&lt;/a&gt;” by Kolchin)&amp;nbsp;and precise integration of Jensen's SSS model to create something fairly amazing, that he recently presented at Siggraph 2011.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;While Eric was preparing his talk I was trying to help by finding a good analytic approximation for his integral. Unfortunately this work came too late and couldn't be included in the Siggraph talk (Eric lists it as "future development" possibility) so I'm writing this now to complement his work and as a primer to show Mathematica's usefulness in our line of business.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mathematica's crash course&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;When you start up Mathematica's interface you'll get prompted to create a new notebook. A notebook is a handy document where you can mix Mathematica's expressions with normal text and graphics, a sort of "active" wordprocessor.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Everything you enter will go in what Mathematica calls a "cell", by default cells are of "input" type, that means ready to accept expressions. Other kind of cells are not "active" and won't be evaluated when asked to process the entire notebook.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;When you want to evaluate the contents of a cell you can press shift-enter in it. That will cause its text to go through the Mathematica kernel, and any output generated by it will be shown underneath, in some output cells grouped together with the input one. Expressions terminated with a&amp;nbsp;semicolon&amp;nbsp;won't generate output (it will be suppressed) which is useful to avoid to spam the notebook with intermediate results which don't require checking.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A nifty thing is that expressions can be entered in various formats, Mathematica supports different notations for the same syntax trees. The cool thing is that you can even ask the interface to convert a given cell in one of the formats, so you can get all your expression in a "programmer's" notation and then have them converted into mathematical formulas ("TraditionalForm") without needing to use complex shortcuts to write everything in the mathematical notation.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Ok let's get started now. We'll need to use the skin diffusion profile of &lt;a href="http://www.eugenedeon.com/papers/EGSR2007skin.pdf"&gt;d'Eon and Luebke&lt;/a&gt; that is expressed as a sum of gaussians with some given coefficients. We start by defining a couple of lists with these coefficients. List literals in Mathematica are entered using curly braces, so we can write and evaluate the following:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;ScatterCoeffs = {0.0064, 0.0484, 0.187, 0.567, 1.99, 7.41}*Sqrt[2]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;ScatterColors = {{0.233, 0.455, 0.649}, {0.1, 0.336, 0.344}, {0.118,&amp;nbsp;0.198, 0}, {0.113, 0.007, 0.007}, {0.358, 0.004, 0}, {0.078, 0,&amp;nbsp;0}}&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Note how the output of the first assignment should already have performed the multiply by 1.414. Using the equal operator in Mathematica forces the evaluation of the expression on the right before assigning it to the variable.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If you squinted you should have noticed already the Sqrt[2] in the previous expression. Function arguments in Mathematica are passed in square brackets, and all Mathematica's built-in functions start with an upper case.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As an exercise, let's now define a Gaussian function manually, instead of relying on Mathematica's internal NormalDistribution:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianFn[var_, x_] := 1/Sqrt[2*Pi*var]*Exp[-(x*x)/(2*var)]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Now, as you evaluate this, you should notice a few things. First of all, it generates no output, the := operator is a delayed assignment, it will evaluate the expression only when needed, and not beforehand (similar to a list quote). Second, that function's input parameters are&amp;nbsp;post-pended&amp;nbsp;with a underscore.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In Mathematica, functions are fundamentally expressions with delayed evaluation, when they are invoked the parameter values are substituted into the expression and then the result is evaluated.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;This concept is important, also because being a computer algebra system, Mathematica is all about expressions (see "FullForm" in the documentation), and in fact we could have literally defined the same GaussianFn by performing a delayed replacement (using ReplaceAll, or its shortcut /. note that in Mathematica most basic functional operators infix notations as well) into an expression, like this:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianExpr =&amp;nbsp;1/Sqrt[2*Pi*var]*Exp[-(x*x)/(2*var)]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianFn[p1_,p2_] := GaussianExpr /. {x-&amp;gt;p1, var-&amp;gt;p2}&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianFn[1,0.5] (* evaluate the function, to prove it works *)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Or as a function object, which won't require a delayed assignment as the function object itself will delay the evaluation of its expression:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianFn[p1_,p2_] = Function[{p1,p2},GaussianExpr/.{x-&amp;gt;p1, var-&amp;gt;p2}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;GaussianFn[1,0.5]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Got that? Probably not, but all should be clear if you as we go, also try things out and have a look at the excellent online documentation that ships with the program.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Let's define now our last helper expression, and then we will delve into Eric's model and how to fit a simplified function to it.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;This is the scattering function, it takes a variable between zero and one and as we don't want to deal with computations in the RGB space which would make visualization of all the functions quite more complex, we pass an index between one and three (lists are one-based in Mathematica) that will decide which channel we're using. We will then need to repeat the fitting for every channel. As I wrote, Mathematica is a lisp-like functional programming environment, so we'll often work with lists and list operations:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;ScatterFn[x_, rgb_] :=&amp;nbsp;Apply[Plus,&amp;nbsp;Table[GaussianFn[var, x], {var, ScatterCoeffs}]*ScatterColors][[rgb]]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In this case the Table function evaluates GaussianFn multiple times generating a list. Each time it will replace the variable "var" with one of the entries in the "ScatterCoeffs" list (note that the other variable, x, will be replaced as it's one of the arguments of ScatterFn, so no "free variable" is left and we should expect to get a list of numbers out of the evaluation). It then multiplies element-wise the list with the ScatterColors one and it applies to the list the "Plus" operator (note that we could have used the infix version "fn @@ expr" as well), thus summing all the elements. We'll then have a single, three-component result (as ScatterColors is a list of three-elements vectors), and we take the "rgb" indexed one out of it (double square brakets is the list indexing operator).&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Integrating Skin Scattering&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The key idea in Eric's work is that the subsurface scattering in the skin depends on a neighborhood of the shaded point, if we don't account for lighting discontinuities caused by shadows (which are handled separately). We can then approximate this neighborhood using the surface curvature, and pre-integrate the scattering on a sphere (circle, really) of the same curvature. It then generate a two-dimensional texture based on the curvature and normal dot light with the results of this precomputation. We are going to try to fit a simple expression that we can compute in realtime to avoid having to use the texture.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Let's now express this two-dimensional function in Mathematica, following the expression that you can find in Eric's paper:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* This is the function defined with integrals, as in the paper *)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseLight[\[Theta]_,r_,rgb_]:=NIntegrate[Clip[Cos[\[Theta]+x], 0,1}]*ScatterFn[Abs[2*r*Sin[x/2]],rgb],{x,-Pi,Pi}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseWeight[r_,rgb_]:=NIntegrate[ScatterFn[Abs[2*r*Sin[x/2]],rgb],{x,-Pi,Pi}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseIntegral[\[Theta]_,r_,rgb_]:=DiffuseLight[\[Theta],r,rgb]/DiffuseWeight[r,rgb]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;This is pretty simple stuff. We're going to generate samples out of these functions (like Eric's precomputed texture) to then compute a fit, so I directly used the numerical integration (NIntegrate) instead of entering it as a mathematical expression and then asking the numerical approximation of it (N[expr] in Mathematica).&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Notice the \[Theta], these were entered as "esc" theta "esc" which is one of the ways of adding symbols in Mathematica's expressions (in this case, the Greek letter theta). These expressions are more readable if pasted in Mathematica and converted into StandardForm.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If you are on a slower computer you can tweak the precision parameters of the NIntegrate or replace it with a NSum, as Eric does in his texture-generator shader:&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* This is a bit faster to evaluate, it's a translation of the code used to generate the lookup table, using an evenly spaced sum instead of NIntegrate *)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseWeight2[r_,rgb_]:=NSum[ScatterFn[Abs[2*r*Sin[x/2]],rgb],{x,-Pi,Pi,2*Pi/20}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseLight2[\[Theta]_,r_,rgb_]:=NSum[Clip[Cos[\[Theta]+x],{0,1}]*ScatterFn[Abs[2*r*Sin[x/2]],rgb],{x,-Pi,Pi,2*Pi/20}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;DiffuseIntegral2[\[Theta]_,r_,rgb_]:=DiffuseLight2[\[Theta],r,rgb]/DiffuseWeight2[r,rgb]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Sampling the function&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Let's generate now a table of data to be used for the numerical fitting. That has to be in the form { {input0, input1...., output}, ... }. We will use the Table function again for that, the expression that will be evaluated at each element of the table is the list literal {angle, radius, DiffuseIntegral[...]} (we could have used the List[...] function as well, instead of the literal) but this time we'll need two ranges, one for the radius and one for the angle.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The Flatten call is needed because Table, when used with two ranges, generates a list of lists (a matrix), while we want a flat list of three-dimensional vectors.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;channel = 1; (* 1=red 2=green 3=blur *)&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;dataThetaRVal&amp;nbsp;= Flatten[Table[{\[Theta], r, DiffuseIntegral[\[Theta], r, channel]}, {\[Theta], 0, Pi, 2*Pi/20}, {r, 0.25, 6, 1/20}], 1];&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Finding a fitting function&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;For the fitting function I also want to check how well it extrapolates. So I will compute the fit over the original sample range, but then plot it over an extended interval to verify how the function looks like outside it.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;To do this we could use Mathematica's function plotting operators (and it might even be a smarter choice) but instead let's still work with a plots that operate on lists of samples, ListPlot3D.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif;"&gt;To plot over an extended range we define an interval table, dataIntervalExt, that's because I want to do these extended plots various times so I "save" the sample inputs and then apply them to different functions.&amp;nbsp;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The first time I use this is to generate a graph of how the lambert&amp;nbsp;lighting&amp;nbsp;model would look like. Using Mathematica's functional programming primitives I define an inline function that maps from x (that will be an element of dataIntervalExt, so a two-dimensional input vector) to a list {first of x, second of x, LambertFn[first of x - that is, the angle]} using the function symbol (in Mathematica it will look like "|-&amp;gt;"), then I map this function to every element of dataIntervalExt using the inline /@ map.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Notice how the cosGraph plot is hidden by closing the expression with a semicolon, then the Show[...] function will combine the two plots into a single output.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;dataIntervalExt = Flatten[Table[{\[Theta], r}, {\[Theta], 0, Pi, 2*Pi/20}, {r, 0, 12, 1/20}], 1];&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;dataGraph = ListPlot3D[dataThetaRVal, InterpolationOrder -&amp;gt; 3]&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;cosGraph = ListPlot3D[(x \[Function] {First[x], Last[x], Clip[Cos[First[x]], {0, 1}]}) /@ dataIntervalExt];&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Show[dataGraph, cosGraph]&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="font-family: Arial,Helvetica,sans-serif; 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/-i_EGMXxuEPA/TmlrDGimCLI/AAAAAAAAAH0/HAPNyx19-2Q/s1600/plots.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-i_EGMXxuEPA/TmlrDGimCLI/AAAAAAAAAH0/HAPNyx19-2Q/s320/plots.jpg" width="249" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;dataGraph and the combined 2d plots&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;In order to find a suitable fitting function, I start looking at a graph of some slices slice, fixing a reasonable radius. If the first argument of Plot is a list of functions instead of a single one, it will overlay the plots of all the functions in the list on the same graph. Show does something similar but with any unrelated plots.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;plotIn2d = Plot[DiffuseIntegral[x, 3, 1], {x, 0, Pi}]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* This will generate a graph with three slices and the Lambert's clamped cos *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Plot[{DiffuseIntegral[x,1,1], DiffuseIntegral[x,3,1], DiffuseIntegral[x,6,1], Max[Cos[x],0]}, {x, 0, Pi}]&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I then make some&amp;nbsp;hypothesis&amp;nbsp;and plot a test function against the slice to visually see if it might fit:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* We have to find a function of cos\[Theta] which could look similar to the DiffuseIntegral*)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Show[Plot[{Max[Cos[x], 0], Max[Cos[x]*0.5 + 0.5, 0]^3}, {x, 0, Pi}], plotIn2d]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Optimizing fitting parameters&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Now we can define a function with a number of free parameters, and ask Mathematica to find a fit, a set of parameters that minimizes the distance between the function and the sample set. NonlinearModelFit is used here, that is a slightly more controllable variant of FindFit. This will take quite some time as the function to fit is quite non linear (due to the Max and Clamps).&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A word on the function I've selected here and why. I'm sure something better can be done, this is not much more than a simple test, but my reasoning here, after visually inspecting the function to approximate, is that the dependency on the radius is rather simple, while the shape that is dependent on the angle is quite complex.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;That's why I started plotting the function in two dimensional graphs that are slices with a fixed radius. Once I've found a possible function that could approximate that with some free parameters, I've modeled the dependency on the radius of these parameters as simple linear equations.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Also I wanted the function to become Lambertian for large radiuses, and I did that by literally having part of the fitting function be a linear interpolation towards the cosine. This constraint is&amp;nbsp;questionable&amp;nbsp; probably for many applications you could just clamp the radius that you will use in a given range, and care only about finding a good fit in that range.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* Let's find the fit now, first we have to define a parametric&amp;nbsp;function, the fitting process will optimize the parameters to&amp;nbsp;minimize the error *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* piecewise linear models... *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* fitFunction[\[Theta]_,r_] :=&amp;nbsp;Max[Cos[\[Theta]] * Min[(a0*r+a1),1] + Max[(a2*r+a3),0],0] *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(*&amp;nbsp;fitFunction[\[Theta]_,r_] := Max[Max[Cos[\[Theta]] * Min[(a0*r+a1),1]&amp;nbsp;+ Max[(a2*r+a3),0],0], Max[Cos[\[Theta]] * Min[(a4*r+a5),1] +&amp;nbsp;Max[(a6*r+a7),0],0]] *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* nonlinear models... *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* fitFunction[\[Theta]_,r_] := (Cos[\[Theta]]*(a0*r+a1) + (a2*r+a3))^3 &amp;nbsp;*)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;fitFunction[\[Theta]_,&amp;nbsp;r_] := (Cos[\[Theta]]*(a0*r + a1) + (a2*r + a3))^3 *&amp;nbsp;Clip[a4*r + a5, {0, 1}] +&amp;nbsp;Max[Cos[\[Theta]], 0] * (1 - Clip[a4*r + a5, {0, 1}])&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;fitting =&amp;nbsp;NonlinearModelFit[dataThetaRVal,&amp;nbsp;fitFunction[\[Theta], r], {a0, a1, a2, a3, a4, a5, a6,&amp;nbsp;a7}, {\[Theta], r}, Method -&amp;gt; NMinimize (*&amp;nbsp;We need to use NMinimize for non-smooth models *)]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;fitParams = fitting["BestFitParameters"]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Plus @@ Abs /@&amp;nbsp;fitting["FitResiduals"] (* Print the sum of residuals *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&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/-430BWv-yqNk/TmpgGepLd4I/AAAAAAAAAH8/XWJ5hOBzFeo/s1600/plotFit.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="236" src="http://2.bp.blogspot.com/-430BWv-yqNk/TmpgGepLd4I/AAAAAAAAAH8/XWJ5hOBzFeo/s320/plotFit.jpg" 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;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Original function and fitted one, plotted at an extended range to show extrapolation to Cos(theta)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;We can now plot the fitted function and overlay it with the original one for a visual comparison. In order to use the fit we've found, we just replace the parameters we got from the NonlinearModelFit into the original fitFunction using the /. operator.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;(* We plot the fit function over dataIntervalExt to check that it&amp;nbsp;extrapolates well *)&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;dataFit = (x \[Function] {First[x], Last[x],&amp;nbsp;fitFunction[First[x], Last[x]] /. fitParams}) /@ dataIntervalExt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;fitGraph =&amp;nbsp;ListPlot3D[dataFit, InterpolationOrder -&amp;gt; 3,&amp;nbsp;ColorFunction -&amp;gt; "SouthwestColors", Mesh -&amp;gt; None];&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Show[fitGraph, cosGraph]&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Show[fitGraph, dataGraph]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;We can do much more, but this should be a good starting point. I've uploaded a PDF of the whole Mathematica notebook on ScribD &lt;a href="http://www.scribd.com/full/64402345?access_key=key-hba2nicyxyxbhm4lo"&gt;here&lt;/a&gt;. Enjoy!&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;P.S. I'd bet everything here could be made ten times faster by applying &lt;a href="http://blog.wolfram.com/2011/12/07/10-tips-for-writing-fast-mathematica-code/"&gt;these suggestions&lt;/a&gt;... Left to the reader :)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;i&gt;P.S. You might want to find some better example of Mathematica's goodness than my lame test code. You could start &lt;a href="http://blog.wolfram.com/"&gt;here&lt;/a&gt; or &lt;a href="http://demonstrations.wolfram.com/"&gt;here&lt;/a&gt;. Also, for Italians only, I've found on Issuu a&lt;a href="http://issuu.com/adpware"&gt;n entire collection of McMicrocomputer&lt;/a&gt; magazines, by ADP! Incredible not only for its nostalgia value but also for all the Mathematica's articles by Francesco Romani that showed me more than ten years ago the power and beauty of this software and of maths in general.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: left;"&gt;&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/6950833531562942289-7591560397995875615?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qv9tCsGFGRAr4zLQgeAYuJPXQwM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qv9tCsGFGRAr4zLQgeAYuJPXQwM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qv9tCsGFGRAr4zLQgeAYuJPXQwM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qv9tCsGFGRAr4zLQgeAYuJPXQwM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/XhcW07L25qc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/7591560397995875615/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=7591560397995875615" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7591560397995875615?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/7591560397995875615?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/XhcW07L25qc/mathematica-and-skin-rendering.html" title="Mathematica and Skin Rendering" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-i_EGMXxuEPA/TmlrDGimCLI/AAAAAAAAAH0/HAPNyx19-2Q/s72-c/plots.jpg" height="72" width="72" /><thr:total>6</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/mathematica-and-skin-rendering.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cBRnc4fyp7ImA9WhdWFUw.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-3723842687162907767</id><published>2011-09-08T11:52:00.007-07:00</published><updated>2011-09-08T12:44:17.937-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-08T12:44:17.937-07:00</app:edited><title>What I've learned from shipping a deferred lighting renderer</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-KMV0mT_SLto/Tmkam-6jOJI/AAAAAAAAAHs/g8xLLzXoBPU/s1600/cave_entrance+l.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-KMV0mT_SLto/Tmkam-6jOJI/AAAAAAAAAHs/g8xLLzXoBPU/s400/cave_entrance+l.jpg" width="220" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;You're going to draw every mesh three times on average (considering shadows), if you don't fuck up the GPU badly, chances are that you're going to be CPU bound.&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Cache-misses in your rendering pipeline are going to kill you.&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Use indirections VERY&amp;nbsp;sparingly. Control where resources can be created and destroyed to be able to avoid to have to reference count everything.&amp;nbsp;Prefer "patching" pointers in place to keeping references around.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Don't iterate multiple times on "drawable" objects collections to isolate which ones to draw in each pass. Store only the draw data needed for a given pass. Scene trees are dumb but by now everyone should be well aware of that.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Parallel rendering is really important.&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Especially if you don't double buffer and add frames of latecy here and there (bad for gameplay and memory), you won't find much to do later in the command buffer generation to keep the cores busy otherwise.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Batching, "sort-by-material" is needed.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;My best bet on how to handle all this is still the old design I've blogged about of having every "drawable" object correspond to a drawcall and represent it as fixed length sort-key whose bits are &amp;nbsp;an encoding of all the state needed for the draw.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;You'll either need to have a robust geometrical pipeline to split/aggregate meshes and generate LODs and occluders...&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;...or you'll have to schedule a sizable chunk of your artist's time for that. And you'd better not think that you can do these&amp;nbsp;optimizations&amp;nbsp;at the very last...&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;On the upside, software occlusion culling is a big win and not that hard!&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Carmack's megatextures (clipmaps) are not (only) attractive to achieve a given art-style, but they have in a deferred setting the big plus of requiring very few material shaders (as you don't need to combine textures, which is most of what material shaders do in a deferred lighting renderer) and less objects (no need of static decals), thus requiring less work on the CPU and making easier to split/merge meshes.&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;A tiled lighting stage (as opposed to the stencil marked volumes) is a good idea&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;...especially if you need shader variations in the lighting stage to render some decent materials, consoles have a one bit hi-stencil that won't help you&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Point, spot and directional lights are not enough. You'll need some kind of ambient lighting devices to create volume.&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;If your game can stream in chunks (regions), don't think about&amp;nbsp;continuous&amp;nbsp;streaming.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Edge-filtering AA can work pretty decently and extremely fast. Not limited only to the final framebuffer...&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;i&gt;PS3 early-z is a bitch, PC Dx9 tools are non-existent&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-3723842687162907767?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xnOAcesrKpL9sUwpseIzDfhDJk8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xnOAcesrKpL9sUwpseIzDfhDJk8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xnOAcesrKpL9sUwpseIzDfhDJk8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xnOAcesrKpL9sUwpseIzDfhDJk8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/d2oNzWbEJ6Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/3723842687162907767/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=3723842687162907767" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3723842687162907767?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3723842687162907767?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/d2oNzWbEJ6Q/what-ive-learned-from-shipping-deferred.html" title="What I've learned from shipping a deferred lighting renderer" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-KMV0mT_SLto/Tmkam-6jOJI/AAAAAAAAAHs/g8xLLzXoBPU/s72-c/cave_entrance+l.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/what-ive-learned-from-shipping-deferred.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEFSH4zfyp7ImA9WhdWFEk.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-4255153064913612351</id><published>2011-09-07T17:58:00.001-07:00</published><updated>2011-09-07T18:00:19.087-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-07T18:00:19.087-07:00</app:edited><title>Back from vacations, Parameter Databases poll results.</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Back after Siggraph and some well-deserved vacations, I have many posts to prepare. For now, here there are the results from my last poll.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;table 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/-i5n10hgY_Ow/TmgQdRVtl9I/AAAAAAAAAHo/akapLuifT6M/s1600/Untitled-1.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-i5n10hgY_Ow/TmgQdRVtl9I/AAAAAAAAAHo/akapLuifT6M/s320/Untitled-1.jpg" width="238" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Coast near my hometown&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The poll was: "Parameter Database systems should use..." and here are the final results. Didn't get too many votes this time (32), maybe people were in vacation as well, or maybe the subject was boring, anyhow:&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Reflection&amp;nbsp;(53%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Code-Generation&amp;nbsp;(28%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Handles/Dynamic Types&amp;nbsp;(18%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Immutable Data (in-game)&amp;nbsp;(18%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Data Inheritance&amp;nbsp;(18%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Schema Inheritance&amp;nbsp;(18%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Relational DB&amp;nbsp;(15%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Live-editing via tool&amp;nbsp;(78%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Live-editing in-game&amp;nbsp;(40%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Serialization via tool&amp;nbsp;(53%)&lt;/span&gt;&lt;/li&gt;
&lt;li style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Serialization in-game (34%)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Predictably I'd say, people prefer to keep editing and serialization in a tool instead of in-game, having the in-game client only to load/listen to the data changes.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;As for the database type, relational systems do not seem to be&amp;nbsp;favored, I guess most parameter systems are still key-values. Low scores are also assigned to dynamic typing, data and schema (class) inheritance.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;What is maybe surprising that reflection wins over code-generation, even if in C++ there is no easy way to &amp;nbsp;implement the former.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I've noticed how often we, as engineers, have a perverse aesthetic sense for which a C++ disgusting macro based reflection system is considered "prettier" than mixing different languages or crafting languages and tools.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;To be fair, reflection could also be done more simply by parsing PDBs or using C++ parsers, but I doubt these are really widespread.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;The good thing about reflection though is that code changes can "break" data, or require data changes, but the opposite is not true. With code-generation data changes can "break" code which is arguably worse.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-4255153064913612351?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/O6PNUsIac_xFG7QrUnpFma73AYg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/O6PNUsIac_xFG7QrUnpFma73AYg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/O6PNUsIac_xFG7QrUnpFma73AYg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/O6PNUsIac_xFG7QrUnpFma73AYg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/TRL4IREdQKU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/4255153064913612351/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=4255153064913612351" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/4255153064913612351?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/4255153064913612351?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/TRL4IREdQKU/back-from-vacations-parameter-databases.html" title="Back from vacations, Parameter Databases poll results." /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-i5n10hgY_Ow/TmgQdRVtl9I/AAAAAAAAAHo/akapLuifT6M/s72-c/Untitled-1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/09/back-from-vacations-parameter-databases.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QDQ3s7eip7ImA9WhdRF00.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-6923955220107567588</id><published>2011-07-30T17:10:00.007-07:00</published><updated>2011-08-07T00:16:12.502-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-07T00:16:12.502-07:00</app:edited><title>If you're asking for crazy overtime, apologize first</title><content type="html">&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Here I'm going to use Team Bondi's emails as they appear in an &lt;a href="http://www.eurogamer.net/articles/2011-07-05-la-noire-the-team-bondi-emails-article"&gt;article on eurogamer&lt;/a&gt;. But if you're been working in this industry for a while chances are that you've seen something very similar at least once. I'm using L.A.Noire developers as an example just because I found these emails todays but we all know excessive overtime is common, other recent examples that went public are the story of &lt;a href="http://www.gamasutra.com/blogs/KeithFuller/20110114/6792/60_Straight_Days_of_Crunch_Really_Please_Explain.php"&gt;Kaos Studios&lt;/a&gt;, the letter from the spouses of &lt;a href="http://www.gamasutra.com/blogs/RockstarSpouse/20100107/4032/Wives_of_Rockstar_San_Diego_employees_have_collected_themselves.php"&gt;Rockstar San Diego&lt;/a&gt; and of course the one that "started" them all, the &lt;a href="http://en.wikipedia.org/wiki/EA_Spouse"&gt;EA_Spouse&lt;/a&gt; blog.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Extract from an email to the team:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;[...]&lt;i&gt;This is an amazing result for 4 hard years and I'm proud of what  we've achieved this far.&amp;nbsp;&lt;u&gt;The game is huge in size and scope and will be a  real breakthrough&lt;/u&gt;.&amp;nbsp;We have almost re-invented the adventure game whilst  including the action elements that people expect in a modern game.&amp;nbsp;Its  these action elements that we really need to tighten up.&amp;nbsp;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;&lt;u&gt;That  said, anyone who has worked on a game or film before knows that to make  a AAA title is going to take a big push at the end to get it complete&lt;/u&gt;.&amp;nbsp;  This is not uncommon within our industry and while it's not ideal, it  is what we need to do to get a polished result to the standard of the  competition. &lt;/i&gt;&lt;i&gt;To achieve this result we're introducing two new working practices, effective immediately:[...] &lt;/i&gt;&lt;i&gt;The hours on Saturday will be compensated through the weekend  working scheme, giving everyone the opportunity to take payment at the  end of the project, or an extended holiday period. &lt;u&gt;As I said this isn't ideal, but it is typical of what it takes to get a game finished.&lt;/u&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Another example:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;[...]T&lt;/i&gt;&lt;i&gt;hat means that everyone is required to keep going until the  milestone ships or your lead informs you that you have done all that you  can for N10 and sub-alpha. Specifically this means in the last two  weeks of the milestone you can expect pretty long days. It's "one in all  in" until we get the Milestone shipped and get the game ready for  testing. &lt;u&gt;We need teamwork&lt;/u&gt; to get the game finished to&amp;nbsp; the quality that  we are after and that means being here to help a tester, a designer, an  artist or programmer who needs your support to get their work finished. &lt;/i&gt;&lt;i&gt;You are not required to work round the clock everyday up until the  milestone ships but for the next six months&lt;u&gt; we will need more from you  than we ever have asked from you &lt;/u&gt;in the past. &lt;u&gt;That's the nature of  getting a AAA title out the door and into the hands of the playing  public&lt;/u&gt;.&amp;nbsp;Getting a result with this game means that the public finally  get to enjoy the fruits of your hard work. It also means that we get to  take a good break later this year and come back refreshed to work on  some exciting new ideas for future projects.[...]&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Again:&lt;/span&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;[...]To complete the project at this time, we require an extension of the  ordinary hours of duty and we are asking people to give more hours.  &lt;u&gt;Putting a product to market of this size, scale and quality is going to  require extra effort from everyone&lt;/u&gt; and while we are asking for it, and  not saying it's easy, the company is perfectly happy to be flexible of  commitments you have outside of the organization[...]&lt;/i&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;So there is a pattern to this. All these emails basically say:&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;We're making a great product&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;We should all be very proud, we're all on the same boat, let's do this&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;We need you to work harder&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;It sucks but this is how AAA games are made.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Now of course in many cases, managers who say this don't actually believe it's true. They know the project is not going in the right direction and they try keep the morale up by minimizing the problems (it's the way AAA games are made) and trying to gather the last energies of the team around the positive aspects of the product (this is a great thing, you've done an amazing job).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Now, while this can resonate well with some employees, unfortunately it's far from ideal for everyone. Remember that in a game company your audience is very varied, and when asking for sacrifices you want to motivate, but also not to piss anyone, especially not to piss your best talents! The problem here is that with this kind of communication you leave the more inquisitive types wondering if this is just a mediocre, stereotyped way of keeping the morale up or if the company does really lack the vision and the ability to make AAA titles in general.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;There are plenty of studies about overtime and its risks I won't get into that discussion&amp;nbsp; so let's even assume that you're not an idiot and you're not pushing your employees past the limit of diminishing returns thus actually hurting the project by asking to work more.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;You need overtime, you believe that it's going to be positive and you need to communicate this decision to the team. You have to remember that you're asking for a sacrifice, even if you're in one of the few countries or companies in the industry that pay for it. You don't own your employees, and surely you don't want to lose your smarter talents &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;One of the worst things to say to your inquisitive audience (especially I might say, engineers) is that "it's not uncommon" for AAA games to require such rough stretches, because you're dealing with people that will not simply accept that fact (that is indeed, and sadly, true today), but ask themselves a few follow-up questions faster than a journalist.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;What else is not uncommon in this industry? Companies that do not generate revenue? That fail to meet their targerts? Massive layoffs and studio closures? And even if crunch is common, how does that relate to good products? Are the best studios, the ones generating most revenue and great games, using cruch? Maybe I should polish my resumee, I hear that [California, Uk, Canada, Germany...] is wonderful this time of the year...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;The fact is, we as an industry have to grow a lot. Crunch is common, but it's a mistake, and many people know this, especially some of the more experienced talents will know that's not the way you make great games.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Personally I've seen great games with zero overtime, bad ones with lots of overtime but also great games done with overtime but more importantly, bad games that made money and great games that didn't... We still have a lot to learn, as an industry, on how to make good games and how to make them in time and how to make money with them...&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Every time you ask for crunch, you as a manager have failed. It can happen and it might be something that you'll need to ask for, but at the very least, you should apologize.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Let me suggest a different, more humble and realistic, communication style:&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;This project was hard, we had to face many hurdles. We should have been better prepared.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Despite the good work done by the team, we're not were we predicted we would be at this time.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;We are apologies for not being able to create a schedule that avoided this, and we will definitely do better next time, we have learned some lessons from this.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;We believe in the product, and this studio needs to deliver a great game in order to go forward.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Let's all help ship this product and make it a huge success. We'll need to work harder, and we'll try our best to compensate you for this extra effort after the end of the project.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;Even better, provide example of what went wrong, of what are you going to do to make things better next time, of why you still strongly believe in the product and you think that this effort will indeed achieve the objective the company has set for it.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;People &lt;b&gt;need&lt;/b&gt; to believe that the future will be better, that there are some problems and not everything went as good as you wanted it to be but you know how to fix things. That there is a &lt;b&gt;reason&lt;/b&gt; to stay and work with you! Just saying "this is great", "we're making something amazing", "let's go team" can be meaningless if not counterproductive if you present no evidence.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-family: Arial,Helvetica,sans-serif;"&gt;With this in mind, let's see how the first email could have been worded better:&lt;/span&gt;&lt;i&gt; &lt;/i&gt;&lt;br /&gt;
&lt;div style="text-align: justify;"&gt;&lt;i&gt;This is an amazing result for 4 hard years and I'm proud of what  we've achieved this far! &lt;u&gt;We wanted to create something amazing and accepted the many risks involved in making an innovative product&lt;/u&gt;. The game is huge in size and scope and will be a  real breakthrough&lt;/i&gt;&lt;i&gt;.&amp;nbsp;We  have almost re-invented the adventure game whilst  including the action  elements that people expect in a modern game.&amp;nbsp;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;Unfortunately, even if the product looks good, &lt;u&gt;we failed to account for everything that creating such an ambitious project entailed, we have learned a lot about how to make such a game during these years&lt;/u&gt;. Now, as the deadline for this game is coming, we still have some issues in our action  elements that we really need to tighten up.&amp;nbsp;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;&lt;u&gt;We know that crunching is bad for everyone and we'll offer some bonus holiday time at the end of the project as a way of partially compensating for this extra effort we're asking you.&lt;/u&gt;&lt;/i&gt;&lt;i&gt;&lt;u&gt;&amp;nbsp;  The studio needs to do to get a polished result to the  standard of the  competition in order to grow and move forward&lt;/u&gt;. To achieve this result we're introducing two new working practices, effective immediately:[...] &lt;i&gt;The hours on Saturday will be compensated through the weekend  working scheme, giving everyone the opportunity to take payment at the  end of the project, or an extended holiday period.&lt;/i&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-6923955220107567588?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/hJGvqGEKI3YpS5y1_YA9EYSideI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/hJGvqGEKI3YpS5y1_YA9EYSideI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/hJGvqGEKI3YpS5y1_YA9EYSideI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/hJGvqGEKI3YpS5y1_YA9EYSideI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/P_0pcenbNWk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/6923955220107567588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=6923955220107567588" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/6923955220107567588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/6923955220107567588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/P_0pcenbNWk/if-youre-asking-for-crazy-overtime.html" title="If you're asking for crazy overtime, apologize first" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>2</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/07/if-youre-asking-for-crazy-overtime.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8HQ38yeCp7ImA9WhdSFE0.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-3844830010623878068</id><published>2011-07-18T19:49:00.005-07:00</published><updated>2011-07-23T00:07:12.190-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-23T00:07:12.190-07:00</app:edited><title>Everyday Carry</title><content type="html">&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;A few weeks ago I was looking around to shop a small utility knife. Went on youtube, searched for some reviews, there are really lots of resources.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;In the end, I didn't buy anything, I went to a local shop even but nothing I saw looked like something a normal, decent human person would really carry without shame. And maybe that's for the better, because I spent already enough money in my past collecting fountain pens and cameras, I don't really need another compulsion.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;In all this search though, I learned quite a bit about knives and steels and blade shapes. And about the average knife-carrying person. One thing that seems to be popular is to create an "&lt;a href="http://www.youtube.com/results?search_query=everyday+carry&amp;amp;aq=f"&gt;everyday carry&lt;/a&gt;" or EDC "system". A collection of things that a person comfortably carries with him everyday.&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Now on the internet most of these are about guns (usually a pair, just to be "safe") and knives (a pair there too) and other "tactical" stuff, I guess these persons really need to compensate for something (Intellect? I bet they also carry a very small penis).&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;But I also found that this EDC stuff is interesting, because when we carry something everyday it really tells a bit about us. It tells who we are and what we need, and who we would like to be and what we think we need (but we don't).&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;Now I'm fully aware that no one will car, but I started this blog for myself and I still keep it that way, so I thought it would be cool to have a snapshot of this aspect of me at thirty. Here it is, my current EDC :)&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; font-family: Arial,Helvetica,sans-serif; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-foC7Ji2mcLk/TiTps0p05yI/AAAAAAAAAHA/4jg7XJfrGzw/s1600/P1020186.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="194" src="http://2.bp.blogspot.com/-foC7Ji2mcLk/TiTps0p05yI/AAAAAAAAAHA/4jg7XJfrGzw/s320/P1020186.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;ul style="font-family: Arial,Helvetica,sans-serif; text-align: justify;"&gt;&lt;li&gt;I usually wear a nice jacket (if the weather permits) and a pair of running shoes. In the picture the jacket is from &lt;a href="http://www.armanicollezioni.com/"&gt;Armani Collezioni&lt;/a&gt; and the shoes are &lt;a href="http://www.reebok.com/CA/brand/men/running/real-flex"&gt;Reebok Realflex&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? I've always liked jackets and casual look, and I love &lt;a href="http://www.fox.com/house/"&gt;House&lt;/a&gt; :D&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Eyeglasses. My current red "Harry Potter" looking ones are from Armani and they are &lt;a href="http://en.wikipedia.org/wiki/Photochromic_lens"&gt;photocromic&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? Because I need them. My eyesight it not bad and I still play sports without glasses. I never tried contacts and I don't care to try them. My father bought me this pair last time I went to Italy. They look a bit silly but I like them, and the photocromic stuff works really well (unlike the early attempts at that tech).&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A cloth bag.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? Because under my sink I have too many plastic ones, so I always try not to carry home more of these.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;An iPad (first gen).&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? It's the single most important gadget I've ever owned. It replaced the big and heavy mess of printed paper and magazines I used to carry around everyday. I use iAnnotatePDF and Reeder everyday.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A &lt;a href="http://rhodiapads.com/"&gt;Rhodia&lt;/a&gt; notebook.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? Writing on the iPad is a pain and I like scribbling and drawing. I also carry another less fancy notepad from some company, I found it in my mail. The Rhodia is cheaper and better (quality paper) than a Moleskine.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Pens and pencils. Currently: a red Sharpie, a red medium point Pilot liquid ink and a &lt;strike&gt;Bic pencil that I stole from EA&lt;/strike&gt; pink &lt;a href="http://davesmechanicalpencils.blogspot.com/2008/04/uni-kuru-toga.html"&gt;Uni KuruToga pencil&lt;/a&gt; a very fine red japanese pen I got from my girlfriend, a big Faber-Castell eraser and a Griffin iPad stylus.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? Because I collect them, and I love writing and drawing. I don't really use them often (as I don't use often the pad) because at home and at work I have more writing instruments and pads and sticky notes and so on. The iPad stylus works decently but it does not make writing on the iPad really enjoyable and even drawing does not feel great. I used to draw a lot on my old winCe phone with a small stylus and a very simple drawing application, somehow the iPad feels worse.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A tin box with various cables.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? The battery on my phone does not last long so I carry its USB cable, I also carry some decent Plantronics phone earbuds that I don't use because I don't really talk much on the phone when I'm around, and at work I have better open can earphones for music and so on.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt; An &lt;a href="http://www.axiomgear.com/products/gear/bags/"&gt;Axiom seat bag&lt;/a&gt; for my &lt;a href="http://www.khsbicycles.com/05_flite_220_07.htm"&gt;bike&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? It fits my EDC camera well and it was cheap :D&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A super-cheap ParkTool &lt;a href="http://www.parktool.com/product/fold-up-hex-wrench-set-aws-10"&gt;hex wrench set&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? You might always need to tune something.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;My 3DS&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? Because I bought it. Because it had 3d and it was cool. So far I never played with it. The best game there is is Zelda and I hate it, I hate Nintendo for making a cheap port and cashing all the money with zero effort. I'll probably sell this sucker.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A Lacie USB key, 64gb. Similar to &lt;a href="http://www.lacie.com/products/product.htm?id=10462"&gt;this one&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? I always need to transfer stuff around and I like to carry some programs and pictures always with me. This USB key is terribly slow so I recently purchased a small pocket harddrive for when I need to transfer bigger amounts of data. The nice thing is that it's all metal, it does not have an usb connector soldered to a board that can easily bent (happens to me all the time with conventional usb keys)&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;My "small" digital camera. A &lt;a href="http://www.dpreview.com/reviews/panasonicdmcg1/"&gt;Panasonic G1&lt;/a&gt; with a &lt;a href="http://www.dpreview.com/lensreviews/panasonic_20_1p7_o20/"&gt;Leica 20mm 1.7&lt;/a&gt;.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? I love photography and this camera is really great (especially paired with that lens, with the standard zoom one is half as good). I have an adapter to mount all my older Leica lenses with it. Unfortunately it's too big to fit my bag so I carry it with my bike, which is bad as really the best camera is the one you always have with you!&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A &lt;a href="http://www.samsung.com/ca/consumer/mobile/mobile-phones/all-phones/GT-I9000HKABMC/index.idx?pagetype=prd_detail"&gt;Samsung Galaxy S&lt;/a&gt; t959 Android phone.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? I don't really mind phones much. I used to when I was a teen but when I relocated to Canada I just bought a very cheap (40$) prepaid one. The problem with that is that prepaid plans are stupidly expensive here, so when Wind came with an incredibly cheap $40 all-unlimited plan I switched. And now I had unlimited internet, so I needed a decent phone to use that. This is a T-Mobile (US) phone that works with the frequencies Wind use, and I found that Android is really better for phones than iOS. I had to &lt;a href="http://c0de517e.blogspot.com/2011/01/ot-owner-of-samsung-galaxy-t959-in.html"&gt;work on it quite a bit&lt;/a&gt; but now I really like it!&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A Leatherman &lt;a href="http://www.leatherman.com/product/Squirt_P4"&gt;Squirt P4&lt;/a&gt; pocket tool&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? It's very cool, with a small knife and pliers it's really the most useful tool of that size I've found.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;A &lt;a href="http://www.tucano.com/"&gt;Tucano&lt;/a&gt; bag.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Why? After I bought my iPad I started carrying way less stuff with me (magazines, papers...) so I bought this bag to replace the small backpack I used to carry before!&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;And of course my wallet, home and bike keys.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6950833531562942289-3844830010623878068?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pR4VuSpTDat04gqE-ReEgn5nJIs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pR4VuSpTDat04gqE-ReEgn5nJIs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pR4VuSpTDat04gqE-ReEgn5nJIs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pR4VuSpTDat04gqE-ReEgn5nJIs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/AuzTWJQqPGk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/3844830010623878068/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=3844830010623878068" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3844830010623878068?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3844830010623878068?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/AuzTWJQqPGk/everyday-carry.html" title="Everyday Carry" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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/-foC7Ji2mcLk/TiTps0p05yI/AAAAAAAAAHA/4jg7XJfrGzw/s72-c/P1020186.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/07/everyday-carry.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUERXo-fyp7ImA9WhdSEkw.&quot;"><id>tag:blogger.com,1999:blog-6950833531562942289.post-3791601781622756632</id><published>2011-07-14T16:53:00.006-07:00</published><updated>2011-07-20T19:43:24.457-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-20T19:43:24.457-07:00</app:edited><title>Querying PDBs</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;We're in the final stages of our game and this means that almost everyone is chasing and fixing crashes, often debugging retail builds from core dumps, having to deal with nasty problems most times without much aid from the debugger.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Sometimes you're just looking at the memory, trying to identify structures: executable regions, virtual tables, floats and so on. From there you might hope to recover the type of the variable you're looking in memory and today we got an email from people trying to do exactly that, chasing a structure from some sparse hints.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;So I thought, how cool would it be if we could execute queries on the debug symbols to find such things!&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Well it turns out it's really, really easy. One great tool that does something similar is &lt;a href="http://gameangst.com/?p=320"&gt;SymbolSort&lt;/a&gt;, and it's written in C#, and it comes with sourcecode! Cool!&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;SymbolSort queries the PDB for global data symbols, here we are interested in global user defined types and their subtypes, it's a pretty similar thing. Also, Microsoft provides a &lt;a href="http://msdn.microsoft.com/en-us/library/x93ctkx8.aspx"&gt;Debugging Interface&lt;/a&gt; wrapped in a COM dll that does pretty much all you need, and it's trivial to call from C# or similar.&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Of course debugging is only a small fraction of what you can do with PDBs, so this is really just an example to show how easy it is, from here you can do many nifty things like code-generating reflection, &lt;i&gt;cross-referencing with profile captures to do coverage analysis &lt;/i&gt;or serialization modules and so on.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;Disclaimer: I wrote this in half an hour. It's probably &lt;i&gt;wrong&lt;/i&gt; and surely ugly. Play with it but don't trust it! It's just meant as an example of how easy it is to query PDBs via msdia.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;In fact the test program I did is a bit more complex and complete than the one I posted here, that is a stripped down version that fits the blog better and IMHO is a better starting point. Also if you really plan to chase structures with this, keep in mind that this version does not recursively search into member structures and inherited stuff.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;P.S. It turned out that this particular bug was caused by bad memory (the actual memory in the hardware - it happens quite often) so this&amp;nbsp;exercise&amp;nbsp;was ultimately useless :)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial,Helvetica,sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;using System;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;using System.Collections.Generic;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;using Dia2Lib; // we need a reference to msdia90.dll in the project&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;namespace Test&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; class Program&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; private static void GetSymbols(IDiaSymbol root, List&amp;lt; IDiaSymbol&amp;gt; symbols, SymTagEnum symTag)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; IDiaEnumSymbols enumSymbols;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; root.findChildren(symTag, null, 0, out enumSymbols);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; uint numSymbols = (uint)enumSymbols.count;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (;;)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; uint numFetched = 1;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; IDiaSymbol diaSymbol;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; enumSymbols.Next(numFetched, out diaSymbol, out numFetched);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (diaSymbol == null || numFetched &amp;lt; &amp;nbsp;1)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; break;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; symbols.Add(diaSymbol);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; private static bool IsMemberPointer(IDiaSymbol s) // Quick'n'dirty based on observation of 1 (one) pointer, I'm sure there are better ways&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return ((s.type != null) &amp;amp;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (s.type.name == null) &amp;amp;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (s.type.type != null) &amp;amp;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (s.type.type.name != null)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; );&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; private static bool IsMemberPrimitive(IDiaSymbol s, ulong length) // I'm not entirely sure about this one too :)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return ((s.type == null) &amp;amp;&amp;amp; s.length == length);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; private static bool SymbolPredicate(IDiaSymbol s)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; { &amp;nbsp; // see the IDiaSymbol documentation here: http://msdn.microsoft.com/en-us/library/w0edf0x4.aspx&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // It's around this size...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (!((s.length &amp;gt; 62) &amp;amp;&amp;amp; (s.length &amp;lt; &amp;nbsp;67)))&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; List&amp;lt; IDiaSymbol&amp;gt; childSymbols = new List&amp;lt; IDiaSymbol&amp;gt;(); // Note: from what I've seen the symbols are arranges in the order they appear in the class/structure&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GetSymbols(s, childSymbols, Dia2Lib.SymTagEnum.SymTagData); // TagData will get us all the member variables, TagNull will get us everything&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // It has to have sub-symbols (fields)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (childSymbols.Count == 0)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // One has to be a matrix&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; bool hasMatrix = false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; foreach (IDiaSymbol subS in childSymbols)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if ((subS.offset &amp;lt; &amp;nbsp;8) &amp;amp;&amp;amp; // It should be one of the first members in memory&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (subS.type != null) &amp;amp;&amp;amp; // It's not a primitive type, so its type has to be a symbol&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (subS.type.name != null) &amp;amp;&amp;amp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (subS.type.name.ToLower().Contains("matrix4")) &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; )&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; hasMatrix = true;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (!hasMatrix) return false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Another one is a pointer to a matrix...&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; bool hasPointer = false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (Int32 i = 0; i &amp;lt; &amp;nbsp;childSymbols.Count; i++)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; IDiaSymbol subS = childSymbols[i];&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (IsMemberPointer(subS)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;&amp;amp; (subS.type.type.name.ToLower().Contains("matrix4"))&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; )&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; { &amp;nbsp; //...followed by a 4 bytes integer&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (i &amp;lt; &amp;nbsp;childSymbols.Count - 2)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (IsMemberPrimitive(childSymbols[i + 1], 4))&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; hasPointer = true;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (!hasPointer) return false;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return true;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; static void Main(string[] args)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; DiaSourceClass diaSource = new DiaSourceClass();&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; diaSource.loadDataFromPdb("game360_release.pdb");&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //diaSource.loadDataForExe(filename, searchPath, null);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; IDiaSession diaSession;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; diaSource.openSession(out diaSession);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; IDiaSymbol globalScope = diaSession.globalScope;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; List&amp;lt; IDiaSymbol&amp;gt; globalSymbols = new List&amp;lt; IDiaSymbol&amp;gt;();&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GetSymbols(globalScope, globalSymbols, Dia2Lib.SymTagEnum.SymTagUDT /* user defined type! */);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; List&amp;lt; IDiaSymbol&amp;gt; matchingSymbols = globalSymbols.FindAll(SymbolPredicate);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; foreach (IDiaSymbol s in matchingSymbols)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(s.name!=null)&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.Console.WriteLine(s.name);&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace; font-size: xx-small;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Arial,Helvetica,sans-serif;"&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/6950833531562942289-3791601781622756632?l=c0de517e.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/I1Jpd6eOi9G9PY42ddgrO3FVylk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/I1Jpd6eOi9G9PY42ddgrO3FVylk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/I1Jpd6eOi9G9PY42ddgrO3FVylk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/I1Jpd6eOi9G9PY42ddgrO3FVylk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/C0de517e/~4/6RW6ek0tIuk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://c0de517e.blogspot.com/feeds/3791601781622756632/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6950833531562942289&amp;postID=3791601781622756632" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3791601781622756632?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6950833531562942289/posts/default/3791601781622756632?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/C0de517e/~3/6RW6ek0tIuk/querying-pdbs.html" title="Querying PDBs" /><author><name>DEADC0DE</name><uri>http://www.blogger.com/profile/01477408942876127202</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>4</thr:total><feedburner:origLink>http://c0de517e.blogspot.com/2011/07/querying-pdbs.html</feedburner:origLink></entry></feed>

