<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7301982</id><updated>2012-02-16T22:22:34.296+01:00</updated><category term='Texture-Compression'/><category term='Geometry-Image'/><category term='Unit-tests'/><category term='Surface-Caching'/><category term='Graph'/><category term='Random-Idea'/><category term='Navigation-Meshes'/><category term='Audio'/><category term='Gameplay'/><category term='Phyiscal-Based-Shading'/><category term='Dithering'/><category term='Intersection-Testing'/><category term='Ptex'/><category term='CSG'/><category term='Behavior-Tree'/><category term='Subdivision-Surfaces'/><category term='HDR'/><category term='Triggers'/><category term='Virtual-Texture'/><category term='Propagation-Volumes'/><category term='Entity-Systems'/><category term='Microfacet'/><category term='BRDF'/><category term='Fluid-Dynamics'/><title type='text'>Sanders' blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>80</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7301982.post-3170772507724586873</id><published>2012-02-07T12:53:00.002+01:00</published><updated>2012-02-08T13:31:49.951+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dithering'/><category scheme='http://www.blogger.com/atom/ns#' term='HDR'/><title type='text'>HDR dithering</title><content type='html'>So I was just busy implementing HDR in my little experimental renderer, adding support to load wavefront .obj/.mtl files and started using the Crytek sponza scene. And at this point I was playing around with the lighting a bit&amp;nbsp;and then I noticed this:&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-tcsRfxm_WOM/TzENSuBXXnI/AAAAAAAAAd8/Y_AW3B6KRhw/s1600/high_contrast_original.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://3.bp.blogspot.com/-tcsRfxm_WOM/TzENSuBXXnI/AAAAAAAAAd8/Y_AW3B6KRhw/s320/high_contrast_original.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;Original HDR screenshot (contrast increased in image to illustrate banding)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Loads of ugly bands in poorly lit areas. And at the moment I'm using really high precision buffers everywhere (16 bit floats), so the first thought that popped up in my head was .. how can I possibly be getting precision artifacts here? So I take a screenshot and start comparing pixels; turns out there's only a difference of 1 between the bands, so it's not a precision problem; my monitor is simply poorly&amp;nbsp;calibrated! (I &lt;i&gt;really&lt;/i&gt; thought I&amp;nbsp;calibrated&amp;nbsp;it properly! Interestingly enough it looks perfectly smooth on my other monitor) So my next thought was.. well most people out there will have poorly calibrated monitors, so is there a way to improve on this? Yes there is! Dithering! I remembered that in the good old days of 4, 16 and 256 color video modes people used to use dithering to simulate smooth crossovers from one color to another, and the higher the resolution, the better it worked. Long story short, I added some dithering to my shader and it worked like a charm:&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-FsnjZgWWq0k/TzENSPGUn8I/AAAAAAAAAd4/AXKk_cwCGfo/s1600/high_contrast_dithered.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://2.bp.blogspot.com/-FsnjZgWWq0k/TzENSPGUn8I/AAAAAAAAAd4/AXKk_cwCGfo/s320/high_contrast_dithered.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;HDR with dithering (contrast increased in image)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
And finally here's the same screenshot without it's contrast increased:&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--ZwMA2Oboi0/TzENTQ1tluI/AAAAAAAAAeI/L2aKoZCnR7U/s1600/result.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="180" src="http://2.bp.blogspot.com/--ZwMA2Oboi0/TzENTQ1tluI/AAAAAAAAAeI/L2aKoZCnR7U/s320/result.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;HDR with dithering (original contrast)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Now when I turn contrast and brightness all the way to the highest levels on my monitor, it still looks nice and smooth.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://twitter.com/#!/renderwonk"&gt;@renderwonk&lt;/a&gt; (&lt;a href="http://www.realtimerendering.com/"&gt;Natty Hoffman&lt;/a&gt;) told me on twitter:&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span style="font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 18px;"&gt;Pixar dither when quantizing. See "Mastering" section of "Color Pipelines..." course &lt;a href="http://www.realtimerendering.com/blog/2011-color-and-imaging-conference-part-ii-courses-a/"&gt;here&lt;/a&gt;&amp;nbsp;instead of adding 0.5 and truncating to quantize, they add rand(0,1) and truncate&lt;/span&gt;&lt;/blockquote&gt;
So I just tried using random noise instead of dithering, and it looks better, although obviously more noisy. (A screenshot wouldn't do it justice I'm afraid) When the noise changes over time it visually blends together. It makes the color transitions much smoother and all kinds of faint details, that where simply a single color before, end up being more visible.&lt;br /&gt;
&lt;br /&gt;
Unlike Pixar I made the noise scale somewhat with the amount of light, this made the noise a bit more visible (especially on a monitor with a very high contrast &amp;amp; brightness, but not &lt;i&gt;too&lt;/i&gt; much) but it also smoothed out the more brighter transitions. Interestingly enough the noise looks similar to the noise that you would see when you're in a poorly lit environment. Although the noise/dithering won't scale the extend of the contrast of your display device, it does extend the perceived color precision.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3170772507724586873?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3170772507724586873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2012/02/hdr-dithering.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3170772507724586873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3170772507724586873'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2012/02/hdr-dithering.html' title='HDR dithering'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-tcsRfxm_WOM/TzENSuBXXnI/AAAAAAAAAd8/Y_AW3B6KRhw/s72-c/high_contrast_original.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7473733294808311627</id><published>2012-01-29T10:42:00.001+01:00</published><updated>2012-01-29T10:42:23.280+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Random-Idea'/><category scheme='http://www.blogger.com/atom/ns#' term='Phyiscal-Based-Shading'/><category scheme='http://www.blogger.com/atom/ns#' term='BRDF'/><category scheme='http://www.blogger.com/atom/ns#' term='Microfacet'/><title type='text'>Physical Based Rendering</title><content type='html'>Lately I've been playing around with &lt;a href="http://simonstechblog.blogspot.com/2011/12/microfacet-brdf.html"&gt;Physical&lt;/a&gt; &lt;a href="http://renderwonk.com/publications/s2010-shading-course/"&gt;Based&lt;/a&gt; &lt;a href="http://seblagarde.wordpress.com/tag/physically-based/"&gt;Rendering&lt;/a&gt;&amp;nbsp;(yes, I'm late to the party).&amp;nbsp;It took me a while to get it working because I kept getting weird results that looked more like caustics than surface roughness. I checked the math again and again, looked up as many source materials I could find to compare them to my implementation (just in case there where some errors in some articles), but couldn't see what could cause these weird artifacts. The thing is, when I rendered the light on a sphere it looked perfect, but when I rendered it from the inside of a box it looked completely wrong! So I started to check all my inputs and they all seemed fine ... until I discovered that my lighting position was inverted. Wut? How the hell? It turned out that the wrong light position caused my half way vector to be, well, something else entitely. And that combination made it all look plausible most of the time and completely threw me off course.&lt;br /&gt;
&lt;br /&gt;
I'm currently using the GGX microfacet distribution, from the&amp;nbsp;&lt;a href="http://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf"&gt;Microfacet Models for Refraction through Rough Surfaces&lt;/a&gt; paper. Here's what it looks like with some random textures and lightwave models borrowed from Doom 3 (don't sue me!) for testing purposes.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/pw0QAkmG0mw/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/pw0QAkmG0mw?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;
&lt;param name="bgcolor" value="#FFFFFF" /&gt;
&lt;embed width="320" height="266"  src="http://www.youtube.com/v/pw0QAkmG0mw?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Some random thoughts about gloss / roughness maps &amp;amp; normal maps&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
While I was working on all this I realized that while roughness maps&amp;nbsp;describe&amp;nbsp;surface detail at the micro level, normal maps describe surface detail at the macro level. This made me think that, when generating normal map mip-maps, that lost normal details at lower resolution could be put in the gloss map instead. Of course this probably would work better with an anisotropic BRDF (directional-roughness) compared to an isotropic BRDF (uniform-roughness). Since both of them seem to be connected, it may imply that there might be a way to combine the two in a single thing. ("anisotropic normal maps"? lol)&lt;br /&gt;
&lt;br /&gt;
This would probably work a lot better (especially with isotropic BRDF's) if you generate normal your maps from heightmaps, and create the gloss and normal maps mip maps from the mip-maps of the heightfield. The roughness would be calculated from all the height variation within a lower resolution mip pixel (compared to the highest resolution mip), while the normal would simply be calculated from the lower resolution mip directly. Maybe some sort of min-max mipmap approach could be used for the roughness. Of course you'd still have to take into account that the further away you are from a gloss map, the smoother it'll look.&amp;nbsp;(disclaimer; I haven't actually tried any of this)&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7473733294808311627?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7473733294808311627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2012/01/physical-based-rendering.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7473733294808311627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7473733294808311627'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2012/01/physical-based-rendering.html' title='Physical Based Rendering'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-9181186136481132686</id><published>2012-01-25T10:15:00.002+01:00</published><updated>2012-01-25T10:24:02.518+01:00</updated><title type='text'>Just a quick update</title><content type='html'>The last couple of months I was entangled in some stuff that I can't really talk about, so I didn't have time to post on my blog, or work on any of my tech experiments. (Not to mention that so many interesting tech stuff happened in those months, Rage was released, Doom 3 source code was released etc.) &amp;nbsp;However now that's all behind me, it's now my intention to blog more regularly again now that I can.&lt;br /&gt;
&lt;br /&gt;
In the meantime, here are some things that I've been messing around with lately.&lt;br /&gt;
&lt;br /&gt;
I created a simple Minecraft renderer, which unfortunately slowed down to a crawl due to the recording software but which is silky smooth without it. (I really need to upgrade my aging machine!!)&amp;nbsp;The light is simply interpolated between the tiles which creates an interesting GI kind of effect. It doesn't correctly take occlusion into account, so that's an area of improvement. Also it's very close to brute force at the moment, with chunks only frustum culling (and of course back-face culling) being used right now to decrease the number of polygons. Transparent blocks are sorted on a chunk level, but are currently incorrectly sorted within the center chunk. The only way to do that is to split the center chunk into 8 pieces and render those&amp;nbsp;separately. In fact, all chunks that lie in a straight line with respect to the center chunk would need splitting. That said, I'm not so sure if I'm going to spend much more time on this though.&lt;br /&gt;
&lt;div style="text-align: -webkit-auto;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="360" src="http://www.youtube.com/embed/EWE-FIsUgBE" width="480"&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Of course like everybody else and their cat, I created my own&amp;nbsp;&lt;a href="https://github.com/LogicalError/doom3.gpl"&gt;Doom 3 source code branch&lt;/a&gt;, with GLSL shader support, where I'm busy replacing the Doom 3 lighting model. Right now it uses a physical correct lighting model, although the lighting isn't yet properly normalized. I also wrote a small C# library to&amp;nbsp;&lt;a href="https://github.com/LogicalError/LWO-library"&gt;load LWO files&lt;/a&gt;, which is still &lt;i&gt;very &lt;/i&gt;rough in it's current form, but my intention is to improve on it as time goes by (any help improving this lib is&amp;nbsp;appreciated!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-9181186136481132686?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/9181186136481132686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2012/01/just-quick-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9181186136481132686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9181186136481132686'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2012/01/just-quick-update.html' title='Just a quick update'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/EWE-FIsUgBE/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5578283518765931506</id><published>2011-08-16T14:09:00.004+02:00</published><updated>2011-08-17T09:03:13.662+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Random-Idea'/><title type='text'>Deferred rendering with virtual texturing</title><content type='html'>Just a random thought.&lt;br /&gt;
&lt;br /&gt;
I had thought about a deferred rendering / virtual texturing approach before where instead of storing the normal, albedo etc. in a g-buffer you'd only store the texture coordinate +&amp;nbsp;texture derivatives (+ z position &amp;amp; surface normal, unless you're storing normals in worldspace which is possible for &lt;i&gt;static&lt;/i&gt; environments with virtual texturing). But I quickly dropped that idea back then because you'd store roughly the same amount of data so it wouldn't gain you much. But this morning I was thinking... If you have a lot of overdraw and/or if you render lots of small triangles (especially if a lot of them are smaller than 2x2 pixels) it might pay to have a really simple shader at the g-buffer phase, and then do the actual texture lookups later on, when you're just rendering a single full-screen triangle. It might work, it might make no difference, it might be worse. I should definitely try it some day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5578283518765931506?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5578283518765931506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/08/deferred-rendering-with-virtual.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5578283518765931506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5578283518765931506'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/08/deferred-rendering-with-virtual.html' title='Deferred rendering with virtual texturing'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1670637879326748696</id><published>2011-08-06T13:45:00.005+02:00</published><updated>2011-08-08T17:00:44.575+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Carmack Quakecon 2011 keynote</title><content type='html'>&lt;br /&gt;
So I saw the QuakeCon 2011 keynote by John Carmack..&lt;br /&gt;
&lt;br /&gt;

&lt;center&gt;
&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/4zgYG-_ha28"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/4zgYG-_ha28" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;/center&gt;
&lt;br /&gt;
... and I figured I'd jot down some notes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
80 degree field of view in Rage,  pages might be loaded for entire 360 degree view?&lt;br /&gt;
Loading full pages that occupied 1 pixel on screen hurt a lot in Rage.&lt;br /&gt;
&lt;br /&gt;
Single 4k x 4k texture wasn't enough.&lt;br /&gt;
Ended up using multiple 4kx4k textures on consoles.&lt;br /&gt;
&lt;br /&gt;
Second buffer of cache, uses just about all memory on console, shared with audio.&lt;br /&gt;
Transcode pipeline comes after cache, so pages are not cached uncompressed.&lt;br /&gt;
&lt;br /&gt;
Blu-ray is worse in latency than DVD.&lt;br /&gt;
Pages are cached on HD on consoles.&lt;br /&gt;
&lt;br /&gt;
Carmack said better solution would've been split page cache in low-detail and high-detail pages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1 thread reading from DVD&lt;br /&gt;
1 thread reading from HD&lt;br /&gt;
"additional threads (plural!) doing analysis of the feedback buffer"&lt;br /&gt;
"a bunch of threads doing transcoding"&lt;br /&gt;
&lt;br /&gt;
HD-photo derivative compression, not using dct based compression.&lt;br /&gt;
30% better compression, requires twice the processing power.&lt;br /&gt;
&lt;br /&gt;
Rage is running on intel hardware?!? (but not at 60hz)&lt;br /&gt;
&lt;br /&gt;
Rage blurry close up, newer titles have more detail up close.&lt;br /&gt;
&lt;br /&gt;
Biggest levels are 128kx128k, dynamic characters are 64kx64k.&lt;br /&gt;
Wasteland are 14 pieces, various sizes from 32kx32k to 128kx128k.&lt;br /&gt;
&lt;br /&gt;
He mentions that "the wasteland doesn't fit into one 256 x 256", &lt;br /&gt;
Did he mean 256k x 256k?&lt;br /&gt;
Considering he specifically said that number I'm assuming that's some sort of maximum.&lt;br /&gt;
256k / 128 = 2k. GPU side page texture is 4k x 4k.&lt;br /&gt;
Are they using more page-tables?&lt;br /&gt;
Are they swapping page-tables (pieces) in and out according to the area/level you're in?&lt;br /&gt;
or maybe it's just not a hard limit, but rather a soft limit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
About 300 - 500mb per 'level'.&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
(My Q4 level conversion is 1.5gb, DXT compressed)&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
Source data giant 256000*256000 texture&lt;br /&gt;
64 gigatexels of source data.&lt;br /&gt;
Terrabyte of source art.&lt;/div&gt;
&lt;br /&gt;
100 gigabytes of texture data (uncompressed) used in Rage.&lt;br /&gt;
&lt;br /&gt;
Large ammount of profiling, removing pieces that aren't visible (roofs etc.)&lt;br /&gt;
(Clearly works better in outdoor levels, compared to my experiments with Q4)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This made me think of .. (not mentioned by carmack)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;OnLive/Gaikai&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;The advantage of making a game purely for OnLive/Gakai is that the whole game runs on their servers and the images &amp;amp;amp;amp; audio are send to the player over the network, the player only sends their controller inputs.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;Obvious latency issues aside, which can be helped somewhat by putting servers all over the world, this has a lot of advantages for publishers and developers.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;Piracy and cheating being impossible being one example, not being constrained by disk space or hardware is another.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;A game like rage could run with full detail, maybe even with dynamic lighting, if it had a good server using an OnLive/Gakai approach. In fact, gameplay could be run on separate severs compared to the actual rendering, which could be done in a more render-farm sort of way.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;The render servers could hold a large chunk of the texture data in memory and keep the rest on SSD.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Oddly enough multi-player / MMO's become more attractive than single player games because if all players play in the same world lighting can be cached into the pages for all players, allowing the render farm to separate rendering lighting from rendering camera views. The same goes for anything else that's shared between the players, like physics etc.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="line-height: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Scary to think about scaling this up to world of warcraft like sizes though, from a technical POV.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1670637879326748696?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1670637879326748696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/08/carmack-quakecon-2011-keynote.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1670637879326748696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1670637879326748696'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/08/carmack-quakecon-2011-keynote.html' title='Carmack Quakecon 2011 keynote'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7107426335336471339</id><published>2011-07-01T11:37:00.001+02:00</published><updated>2011-08-08T16:44:51.076+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual texturing, brute force page VSD</title><content type='html'>So I had a little bit of time between things to try out discovering which of my pages are potentially visible at any given time when moving around in my test scene (imported from quake 4).&lt;br /&gt;
At first I was amazed, my 1.5gb virtual texture file had reduced to about 50mb! I wanted to tell the world!&lt;br /&gt;
&lt;br /&gt;
But no, that was a bug. Crap.&lt;br /&gt;
(Good thing I double checked!!)&lt;br /&gt;
&lt;br /&gt;
When I got it working properly, it only removed 9 pages :(&lt;br /&gt;
It took about 5 minutes to process the entire Quake 4 level, 2 minutes to create the virtual texture file.&lt;br /&gt;
&lt;br /&gt;
That said, in my current implementation I'm reusing the pages across surfaces, although they're still unique on the GPU side of things (so decals can still be added in the virtual texture), so it might be a bigger improvement when all pages are unique. Besides that I used the gathered information to sort all the pages according to locality and it helped reduce latency when loading the pages.&lt;br /&gt;
&lt;br /&gt;
Considering that I'm reusing pages (hell, even the texture coordinates are created carefully as to maximize reusing the pages) I'm actually surprised that I only managed to get rid of 9 pages. I guess a lot of the 'reusing the pages' idea gets wasted when pages are combined into higher MIPs, which automatically makes them less unique. It would be better to store the lower resolution pages, that make up the lower resolution MIPs, separately. That way the virtual texture file could never be larger than the combined source textures. It would also allow more fine sorting (of sub-pages) and allow us to downscale higher resolution pages into a MIP, and hopefully removing the necessity to loading some pages. But it all gets awfully complicated real quick.&lt;br /&gt;
And I'm not sure how much that would help with true unique texturing.&lt;br /&gt;
&lt;br /&gt;
The quake 4 levels are really worst cases for virtual texturing considering that the  texture placement is made to minimize the number of textures in the level, not so much minimizing texture area and not worrying about the source of the texture. So many tiny pieces of geometry are rendered with unique pages, which could all be combined into single surfaces. So I really should try to either combine all the surfaces and re-project the textures onto them, or create geometry from scratch with a more virtual texture friendly texture layout.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7107426335336471339?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7107426335336471339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/07/virtual-texturing-brute-force-page-vsd.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7107426335336471339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7107426335336471339'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/07/virtual-texturing-brute-force-page-vsd.html' title='Virtual texturing, brute force page VSD'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5534239588684173992</id><published>2011-06-09T08:21:00.001+02:00</published><updated>2011-06-09T11:33:54.335+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Game Development Tools source code went up</title><content type='html'>The source code for the book "Game Development Tools" went up,&lt;br /&gt;
and you can find all the source code, including my CSG article, &lt;a href="http://gamedevelopmenttools.com/index_Page348.htm"&gt;here&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5534239588684173992?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5534239588684173992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/06/game-development-tools-source-code-went.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5534239588684173992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5534239588684173992'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/06/game-development-tools-source-code-went.html' title='Game Development Tools source code went up'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7578946557652758584</id><published>2011-06-03T16:38:00.003+02:00</published><updated>2011-06-03T17:17:01.543+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Graph'/><title type='text'>Winforms Graph library</title><content type='html'>For some strange reason I was blocked on all projects I was working on, so I had a little time to work on something else. I've encountered many situations where a simple graph editor would've made my life a lot easier, yet I couldn't find any good and simple libraries to help me out. So I figured I'd make a simple graph library myself and make it open source to (hopefully) help whomever who needs similar tech in the future. &lt;br /&gt;
&lt;center&gt;&lt;br /&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/N-gWbOWY7Rung&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/gWbOWY7Rung&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
There are still a couple of things I want to add to this such as support for different colors of nodes/connections and maybe drop-down thingies. Anyone is welcome to contribute. Anything is open for discussion. I should mention, however, that I'm not interested in making this a super uber-leet library that includes everything including the kitchen sink. I'd rather keep it small, simple &amp; flexible.&lt;br /&gt;
&lt;br /&gt;
MIT license. Git repository can be found &lt;a href="https://github.com/LogicalError/Graph"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Yes, I used my own image as an example. &lt;br /&gt;
It's just my weird sense of humor.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PS.&lt;br /&gt;
I should be getting a copy of the book soon, yay!&lt;br /&gt;
Hopefully that'll mean the CSG code will be online soon too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7578946557652758584?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7578946557652758584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/06/winforms-graph-library.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7578946557652758584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7578946557652758584'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/06/winforms-graph-library.html' title='Winforms Graph library'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-534883128276977954</id><published>2011-05-24T09:16:00.000+02:00</published><updated>2011-08-08T16:45:43.996+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Random-Idea'/><title type='text'>Random thought</title><content type='html'>This morning I suddenly was thinking, would it be possible to have some sort of hive mind server-client architecture working on top of a peer to peer network?&lt;br /&gt;
Meaning that the hive-mind (all or clumps of clients) would act as a sort of referee when it comes to gameplay. I can imagine that it would be pretty complicated, but it would remove the need for dedicated servers and possibly help avoid cheating ... &lt;br /&gt;
&lt;br /&gt;
Just another one of my random thoughts ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-534883128276977954?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/534883128276977954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/05/random-thought.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/534883128276977954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/534883128276977954'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/05/random-thought.html' title='Random thought'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-9077176819799082997</id><published>2011-05-02T13:21:00.003+02:00</published><updated>2011-05-02T14:01:40.833+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Busy busy busy</title><content type='html'>For a long time me &amp; &lt;a href="http://mfbaranow.blogspot.com/"&gt;Matthew&lt;/a&gt; have been working on an article on "real-time constructive solid geometry" (CSG) for the &lt;a href="http://www.amazon.com/Game-Development-Tools-Marwan-Ansari/dp/1568814321/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1302676283&amp;sr=1-1"&gt;Game Development Tools&lt;/a&gt; book. We finished the article somewhere at the end of march, and last week we finished the demo. It's been a really interesting experience, writing an article, but it sure was a lot more work than I thought it would be! It really gives me a renewed respect for authors in general! Anyway, the source is going to be put on the book's website eventually, I'll post a link here when it's up, and eventually put it on git (when I can find time in my way too busy schedule). The article itself is basically a better written version of what I already wrote down on my blog, but with a couple of additional details, improvements and discoveries that we've made along the way!&lt;br /&gt;
&lt;center&gt;&lt;br /&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/N-gVXjmMkQ0&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/PeoevMLW_L8&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
While making the CSG demo I had a bug in my polygon splitting code (obviously fixed now), which looked kinda funny :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-fFAg2MiyOdU/Tb6R9v_wdPI/AAAAAAAAAT0/hk7b9zGIWsM/s1600/polygon-split-bug.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="250" width="320" src="http://3.bp.blogspot.com/-fFAg2MiyOdU/Tb6R9v_wdPI/AAAAAAAAAT0/hk7b9zGIWsM/s320/polygon-split-bug.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Other than that I've been really busy with my regular projects, and a super secret IOS game which I've been working on with my friends at &lt;a href="http://www.limbicsoftware.com/"&gt;Limbic&lt;/a&gt; and &lt;a href="http://www.hiddenelephant.com/"&gt;Hidden Elephant&lt;/a&gt;. Can't wait to show some stuff from the game!&lt;br /&gt;
&lt;br /&gt;
Unfortunately, all this means that I haven't had much time to work on my other experiments :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-9077176819799082997?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/9077176819799082997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/05/busy-busy-busy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9077176819799082997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9077176819799082997'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/05/busy-busy-busy.html' title='Busy busy busy'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-fFAg2MiyOdU/Tb6R9v_wdPI/AAAAAAAAAT0/hk7b9zGIWsM/s72-c/polygon-split-bug.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3853699070582557019</id><published>2011-02-14T20:15:00.002+01:00</published><updated>2011-08-08T16:44:51.017+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>VT progress</title><content type='html'>Last weekend I spend a little more time on my VT experiment and added normal, specular and alpha channels to pages, all of which area only stored when they're actually used. I've also added alpha testing support, since id tech 4 makes heavy use of it, which made me split the geometry into two stages. I'm not entirely sure if it's a good idea to support alpha testing in a real world virtual texturing engine (especially when an engine is using deferred rendering), so I might remove it eventually. &lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-NlDi3siYO4g/TVl9X4Xm3SI/AAAAAAAAATY/R_ybN3yEj7c/s1600/normal_map.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-NlDi3siYO4g/TVl9X4Xm3SI/AAAAAAAAATY/R_ybN3yEj7c/s400/normal_map.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
My short term goal is to render this into a G-buffer and do some simple deferred rendering (just a naive, simple deferred rendering implementation will do for the time being).&lt;br /&gt;
&lt;br /&gt;
I've also spend some time optimizing my import pipeline, and each stage (a separate executable) only takes about a minute (at most) except the stage that creates the virtual texture itself. That final stage doesn't scale very well and it can go from a minute to 30 minutes depending on the size of the virtual texture. This is mostly because of the part that creates the mipmaps for each page, this is mostly because I'm not using simple box filtering but using some more better quality solutions instead. &lt;br /&gt;
&lt;br /&gt;
I'm considering just using pre-mipped source textures for this since it would bring back the vt creation time to basically the time it take to write it to disk, but it would snap all my pages to 128x128 coordinates, which could create a lot of additional wasted texels in the worst case.. It would also be a temporary solution since eventually I want to re-parameterize the geometry and render the textures into this newly created texture space. It won't allow me to re-use as many pages as I am now (which makes it possible to store a 6gb virtual texture in 500mb, uncompressed) but it causes less wasted texel space, simplify geometry and most importantly help with page locality (fewer pages visible at the same time), which would help latency wise.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3853699070582557019?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3853699070582557019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/02/vt-progress.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3853699070582557019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3853699070582557019'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/02/vt-progress.html' title='VT progress'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-NlDi3siYO4g/TVl9X4Xm3SI/AAAAAAAAATY/R_ybN3yEj7c/s72-c/normal_map.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3564180657257249973</id><published>2011-02-01T12:57:00.003+01:00</published><updated>2011-08-08T16:44:51.011+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Infinite virtual textures</title><content type='html'>I've been playing with the thought that the page table of a virtual texture could itself have a higher level indirection table, allowing us to create much bigger virtual textures by dynamically allocating huge virtual texture blocks. This would make geometry streaming simpler with virtual texturing since you wouldn't need to have the entire worlds' page table in memory at once and can help avoid precision issues when page tables get too big.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_QB2O0HdIQjQ/TUfzz04WXoI/AAAAAAAAATE/-z1MKpvxksA/s1600/pagetableblock.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="138" width="400" src="http://3.bp.blogspot.com/_QB2O0HdIQjQ/TUfzz04WXoI/AAAAAAAAATE/-z1MKpvxksA/s400/pagetableblock.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The texturing on geometry would not be able to cross the edges of these higher level blocks, but that would be fine because the dimensions of these blocks would basically still be really big, much bigger than you'd ever want polygons to be. Also, we only really care about the actual texture pages that we store on disk and loading them quickly enough, if page tables have huge empty spaces, it doesn't matter because they don't actually take any space on disk, or any substantial space in memory. So if we have lots and lots of additional page table space, we gain a lot of freedom in how we built and update our virtual texture, and how we place our model/level textures within our virtual texture. We don't need to pack it as tightly anymore and we could consider using other metrics to place our textures in our virtual texture, for example proximity of the geometry on which the texture lies.&lt;br /&gt;
&lt;br /&gt;
Obviously we do not want to have an extra indirection in our pixel/fragment shaders, which would be terribly wasteful, but we could easily use our vertex shaders for that, considering that geometry wouldn't be allowed to cross these higher level blocks. Another way could be that suppose you can load X page table blocks in memory at the same time, and each page table block would have a fixed position within the page table then you wouldn't have to use a vertex shader either. But you'd have to guarantee that no two page table blocks with the same position would ever be loaded, which might be fine if you have enough block positions.&lt;br /&gt;
&lt;br /&gt;
On another note I've been looking at Assimp (I know what you're thinking, but no, that stands for &lt;a href="http://assimp.sourceforge.net/"&gt;Open Asset Import Library&lt;/a&gt;, you pervert) and it's pretty cool. I couldn't get the .net library to compile, which is a shame, but I've been using the C compiled command line tool to convert all the Lightwave files in quake 4 into an easily parsable XML format, which I then parse and use in my, oh so neglected, virtual texture experiment. It really makes everything feel more like an actual level, instead of random geometry with big gaping holes in it ;) Along the way I discovered that somehow my geometry was swizzled across an axis compared to quake 4, so I fixed that. In the process of getting all the geometry in the level I've had to parse all the skin, guide, mtt (material type), and def (entity definition) files (next to all the mtr (material), map and proc files that already was parsing before), which was a big adventure in figuring our how the id-tech 4 technology worked from a data point of view. Certainly gave me renewed respect for it's flexibility, despite the engine's age.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_QB2O0HdIQjQ/TUf03RwnPdI/AAAAAAAAATM/EZ3o1BxIpBk/s1600/screenshot4.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://2.bp.blogspot.com/_QB2O0HdIQjQ/TUf03RwnPdI/AAAAAAAAATM/EZ3o1BxIpBk/s400/screenshot4.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
One of these days I'm going to put support for all the texture and door animations in my little demo (well, it's actually starting to become a little engine of sorts), and put in proper support for texture blending. And brute force page VSD as a pre-process (to determine if a page mip can actually ever be visible). And fast texture compression. And lighting obviously. And physics. And maybe it's not really an engine after all :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3564180657257249973?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3564180657257249973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2011/02/infinite-virtual-textures.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3564180657257249973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3564180657257249973'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2011/02/infinite-virtual-textures.html' title='Infinite virtual textures'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QB2O0HdIQjQ/TUfzz04WXoI/AAAAAAAAATE/-z1MKpvxksA/s72-c/pagetableblock.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6965480266871135206</id><published>2010-12-21T10:37:00.001+01:00</published><updated>2011-08-08T16:46:51.636+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unit-tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Gameplay'/><category scheme='http://www.blogger.com/atom/ns#' term='Triggers'/><title type='text'>Static analysis of gameplay</title><content type='html'>Last night, couldn't really sleep, and my mind somehow landed at Fallout 3 and how complex a game like that is. It must've been an QA nightmare to test a game that has so many ways to play, so many different quests which may or may not be compatible with each other.&lt;br /&gt;
&lt;br /&gt;
So I was thinking, what if game developers had a sort of editor, where they can see all the triggers in the game and their relationships between them, and have some sort of static analysis going on there to make sure you're not accidentally creating impossible situations.&lt;br /&gt;
&lt;br /&gt;
In this editor, every trigger would have some 'hard' prerequisites, some of these would be added automatically from the trigger itself 'trigger will be triggered when you have object X and walk into region Y', and others would be implicit 'you can't get object X unless you finished quest Z', which would mean that all the prerequisites required to complete quest Z are automatically added to the trigger. Less quantifiable rules, I call them soft' prerequisites, could be added manually, for example 'Player must have strength X to reach this trigger'. &lt;br /&gt;
&lt;br /&gt;
The difference between soft and hard prerequisites is that hard prerequisites would be checked at runtime (indirectly or directly) and soft prerequisites would only be used to check for situations where you don't want your average player to get stuck, but a good player might still be able to get through it. Each of these prerequisite rules would be either a boolean true/false 'do you own object X' or a simple comparison 'is your health &gt; Y'. &lt;br /&gt;
&lt;br /&gt;
Another idea I had is that the game's navigation meshes (which presumably are also the exact areas that the player can traverse) are divided into regions, and these regions are defined in such a way that you can get to anywhere from anywhere within a region without crossing a trigger, and the only way to leave a region is through a trigger. Triggers that have a location in the world are then associated with one or two regions (depending if it's a doorway or not).&lt;br /&gt;
Using this information we can then do some sort of flood fill where we start at the players' starting location, and while we go from region to region, we remember the prerequisites that are required to go from one region to the next and add them to the the triggers we encounter.&lt;br /&gt;
We actually have to do that for every possible path taken, skipping identical paths and avoiding loops. This can quickly become pretty complex, but it wouldn't have to be done in real-time or even all the time.&lt;br /&gt;
&lt;br /&gt;
Regions can also be used to detect situations where a player jumps down from region A into region B, which he can't possibly get out anymore (nor finish the game from that location). (because, for example, the prerequisites of region A are in direct conflict with region B)&lt;br /&gt;
&lt;br /&gt;
In the end we'll end up with basically a big expression tree, which can be simplified at every iteration. This expression tree can then be checked for conflicting expressions (for example, to trigger a certain trigger 'apple must be eaten' AND 'apple must've been thrown in bottomless pit'), and be shown to the game designer who can then check if it makes any sense ('you can only finish the game if science = 100'). The game designer could even do a sort of stack trace to see how the current expression tree was created.&lt;br /&gt;
&lt;br /&gt;
I wonder if anyone out there has ever attempted to create something like this, it's basically a gameplay unit test of sorts..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6965480266871135206?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6965480266871135206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/12/static-analysis-of-gameplay.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6965480266871135206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6965480266871135206'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/12/static-analysis-of-gameplay.html' title='Static analysis of gameplay'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6413550048214123040</id><published>2010-11-09T10:17:00.001+01:00</published><updated>2011-08-08T16:44:51.056+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Another virtual texturing thesis!</title><content type='html'>I'm still recovering from an insane amount of deadlines, and in the process I neglected my blog. (so sorry! *cries*)&lt;br /&gt;
&lt;br /&gt;
Anyway.&lt;br /&gt;
&lt;br /&gt;
Some time ago I received an email from Julian Mayer about the thesis he wrote about &lt;a href="http://www.ub.tuwien.ac.at/dipl/2010/AC07808876.pdf"&gt;Virtual Texturing&lt;/a&gt;, but until now I hadn't had any time to actually take a look at it. His thesis is a comprehensive list of all the (publicly known) virtual texturing implementations and their implementation details, combined with his own test implementation and performance testing and heuristics.&lt;br /&gt;
Considering it's size and the amount of details, Julian must've put an insane amount of time and effort into it!&lt;br /&gt;
&lt;br /&gt;
It's well worth the read, if you're interested in virtual texturing you should definitely check it out!&lt;br /&gt;
&lt;br /&gt;
The only criticism I have for his thesis is that he measured his timings in fps instead of ms, ironically he mentions in his thesis that ms is a better metric, which makes me wonder why he didn't just use ms instead .. &lt;br /&gt;
&lt;br /&gt;
Also, he mentions that the borders of the pages need to be stored with the pages, which isn't true. As &lt;a href="http://sandervanrossen.blogspot.com/2010/06/borders-borders-i-dont-need-no-stinkin.html"&gt;I mentioned before&lt;/a&gt; you can create the borders from the pages you already have in memory, at the cost of a little bit of extra bookkeeping and copying of textures fragments.&lt;br /&gt;
&lt;br /&gt;
Another interesting thing he mentioned is the idea to have some sort of PVS for pages, something I've been thinking about as well (I may actually have mentioned something along those lines before). In &lt;a href="http://mrelusive.com/publications/presentations/2010_gtc/GTC_2010_Virtual_Textures.pdf"&gt;J.M.P. van Waveren last presentation&lt;/a&gt; about virtual texturing he mentions that they do some brute force page visibility determinations to determine which MIP levels of which pages can possible be visible to the player, and which ones cannot. &lt;br /&gt;
&lt;br /&gt;
I imagine they do this by rendering the scene in all directions from all points within the area where the player can walk, jump &amp; fall, obviously with a minimum distance between the points. This way you basically know which pages are visible from each point in the map and theoretically, after massaging this data somewhat, you could create a system where you can figure out which pages you'll (potentially) need soon, and which pages can safely be discarded from the cache. For moving &amp; dynamic objects the same concept can be used, except a distance metric should be used to determine which pages are required to properly render the object.&lt;br /&gt;
&lt;br /&gt;
This information can also be used to group pages together in blocks on disk, so that they can be loaded together, decreasing latency. Obviously you'll need to be able to cache more pages because you'll always be loading more pages than you need, but because you can better predict which pages will potentially be visible soon, this doesn't have to be a problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6413550048214123040?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6413550048214123040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/11/another-virtual-texturing-thesis.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6413550048214123040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6413550048214123040'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/11/another-virtual-texturing-thesis.html' title='Another virtual texturing thesis!'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7295603743233006582</id><published>2010-10-01T11:05:00.000+02:00</published><updated>2011-08-08T16:52:06.715+02:00</updated><title type='text'>MD3View online</title><content type='html'>I've set up a repository on codeplex to hold the MD3View source.&lt;br /&gt;
So anyone who needs the source, you can find it &lt;a href="http://md3view.codeplex.com"&gt;here&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7295603743233006582?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7295603743233006582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/10/md3view-online.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7295603743233006582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7295603743233006582'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/10/md3view-online.html' title='MD3View online'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5696508253902537251</id><published>2010-09-29T12:03:00.001+02:00</published><updated>2011-08-08T16:52:06.708+02:00</updated><title type='text'>MD3view file hosting blues</title><content type='html'>Sometime ago I wrote about &lt;a href="http://sandervanrossen.blogspot.com/2010/05/md3view.html"&gt;MD3View&lt;/a&gt;, and old project which I was a part of, and hosted the file.&lt;br /&gt;
Unfortunately it seems that the download stopped working some time ago.&lt;br /&gt;
I received some emails about it, I am aware of it, I just haven't had any time to do anything about it. (Can you say attack of the multiple insane deadlines?)&lt;br /&gt;
&lt;br /&gt;
My plan is to eventually put it up on sourceforge or github or something like that.&lt;br /&gt;
&lt;br /&gt;
I haven't forgotten, its on my to-do list.&lt;br /&gt;
Sorry for the delay.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5696508253902537251?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5696508253902537251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/09/md3view-file-hosting-blues.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5696508253902537251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5696508253902537251'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/09/md3view-file-hosting-blues.html' title='MD3view file hosting blues'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1000614550260193966</id><published>2010-09-23T10:11:00.003+02:00</published><updated>2011-08-08T16:47:22.222+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Mr Elusive strikes again!</title><content type='html'>Mr Elusive, or I should say J.M.P. van Waveren from Id Software, has released &lt;a href="http://mrelusive.com/publications/pubs_bydate.html"&gt;a new presentation about virtual texturing&lt;/a&gt; called "Using Virtual Texturing to Handle Massive Texture Data".&lt;br /&gt;
&lt;br /&gt;
Most of it has been covered in previous presentations, but there are a couple of interesting tidbits which give some hints on how Id Software's virtual texture implementation works.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Their "&lt;b&gt;sparse texture quad tree&lt;/b&gt;" is implemented as a MIP mapped texture, just like everybody else. I wondered about this because they never explicitly mentioned it before, and only mentioned a quad tree.&lt;/li&gt;
&lt;li&gt;The presentation mentions about feedback rendering that "&lt;b&gt;factor 10 smaller is OK&lt;/b&gt;" and "&lt;b&gt;~ .5 msec on CPU for 80 x 60&lt;/b&gt;" which surprises me, because it's definitely not okay in my quake 4 test levels. But I suppose if the artwork has been made to work with virtual texturing it might actually work. &lt;/li&gt;
&lt;li&gt;It also mentions that &lt;br /&gt;
&lt;ul&gt;&lt;il&gt;&lt;b&gt;diffuse + specular + normal + alpha + power = 10 channels&lt;/b&gt; &lt;i&gt;- notice the 10&lt;/i&gt; &lt;ul&gt;&lt;li&gt;&lt;b&gt;128k x 128k x 12 channels = 256 GB&lt;/b&gt; &lt;i&gt;- now where did that 12 come from??&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;53 GB DXT compressed (1 x DXT1 + 2 x DXT5)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;use brute force scene visibility to throw away data&lt;/b&gt; &lt;i&gt;- I was wondering about that, I could only think of brute force solutions, I guess the same goes for Id!&lt;/i&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;down to 20 – 50 GB (uncompressed)&lt;/b&gt; &lt;i&gt;- It says uncompressed but it's still DXT compressed otherwise the numbers simply don't make any sense&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;4 – 10 GB DXT compressed&lt;/b&gt; &lt;i&gt;- this must be simply 'compressed' then.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/il&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;So 128x128x12 texels per page = 192kb per page.&lt;br /&gt;
192kb / 6 = 21.5x compression. (their worst case compression ratio)&lt;br /&gt;
&lt;br /&gt;
(50 GB / 10 GB = 5x compression, which explains why that 50 GB &lt;i&gt;must&lt;/i&gt; be DXT compressed)&lt;br /&gt;
&lt;br /&gt;
It also mentions somewhere "&lt;b&gt;lossy compression is perfectly acceptable&lt;/b&gt;", so I'm guessing there are probably a lot of artifacts in their textures, otherwise they won't be able to achieve such high compression ratios.&lt;br /&gt;
&lt;br /&gt;
They also mention that decompressing costs "&lt;b&gt;1 to 2 milliseconds per page on a single CPU core&lt;/b&gt;", &lt;br /&gt;
which I'm assuming for their entire 12 channel page.&lt;br /&gt;
&lt;br /&gt;
My results are about 3ms per 4 channel texture, which would be 3*3=9ms.&lt;br /&gt;
Of course my compression stuff is rather unoptimized, I chose to focus on compression ratio and image quality, so I'm not at all surprised that they have far better results than my part-time experimental efforts.&lt;br /&gt;
&lt;br /&gt;
Another thing is that they specifically mention read back buffers, so their implementation is not analytical after all.&lt;br /&gt;
Which makes me wonder about this screenshot ...&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s1600/rage.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="224" src="http://3.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s320/rage.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
... which incidentally uses the exact same screenshot as the previous presentation, because the MIP boundaries always lie on the page boundaries, which is completely not how a normal MIP boundary would look like.&lt;br /&gt;
So I'm thinking it's probably just an artificial representation of the pages, not at all representative of their technology.&lt;br /&gt;
&lt;br /&gt;
Afterwards it presents an high level overview of their decompression pipeline, which I haven't had any time yet to look in detail.&lt;br /&gt;
&lt;br /&gt;
Now if you'll excuse me I have to go back to my 2 simultaneous (and impossible) deadlines, thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1000614550260193966?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1000614550260193966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/09/mr-elusive-strikes-again.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1000614550260193966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1000614550260193966'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/09/mr-elusive-strikes-again.html' title='Mr Elusive strikes again!'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s72-c/rage.jpg' height='72' width='72'/><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2370856516626557838</id><published>2010-08-16T11:37:00.001+02:00</published><updated>2011-08-08T16:44:50.981+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual texturing on iPhone</title><content type='html'>Sorry for the lack of updates, I've been on vacation in Illinois for the last 3 weeks, visiting family in laws, and only now starting to recover from jet lag. Before I left me and &lt;a href="http://mfbaranow.blogspot.com/"&gt;Matthew Baranowski&lt;/a&gt; (start blogging already!) submitted a proposal to write an article for a book (not sure if I'm allowed to say anything more about it, so I won't, at least not yet), and while I was on vacation it got accepted! Yesterday (Sunday) was the deadline for the first draft, and I came back last Wednesday.&lt;br /&gt;
If I hadn't taken my laptop with me and worked on the article in my vacation, I would've only had a couple of days to write it! Pfew!&lt;br /&gt;
&lt;br /&gt;
Today we submitted the draft and we should be getting comments on the article eventually.&lt;br /&gt;
&lt;br /&gt;
Anyway.&lt;br /&gt;
&lt;br /&gt;
While I was on vacation &lt;a href="http://kotaku.com/5611523/id-unleashes-rage-on-the-iphone"&gt;John Carmack showed a technical demo&lt;/a&gt; on the iPhone which used virtual texturing.&lt;br /&gt;
It's pretty cool, but I'm actually not surprised that it works. In fact it's something I wanted to try myself, but haven't had the time to do yet.&lt;br /&gt;
&lt;br /&gt;
Why does it work so well on the iPhone? Well from what I've heard they've backed lighting into most surfaces in Rage, leaving only the specular channel to store and render.&lt;br /&gt;
&lt;br /&gt;
IO latency and throughput are less of an issue on the iPhone because of flash memory for 'disk', and that pages don't need to be of as high a resolution compared to consoles.&lt;br /&gt;
&lt;br /&gt;
So if you have pixel shaders, which the iphone does, then it's really not that hard.&lt;br /&gt;
&lt;br /&gt;
The only thing that is more problematic on the iPhone is storage space which is alleviated somewhat by the lower resolution pages. Texture decompression would be more of a problem on the iPhone however, so they're probably not doing that.&lt;br /&gt;
&lt;br /&gt;
I'm still wondering if Id software is subdividing it's geometry at the highest resolution page level though, in which case you wouldn't even need a pixel shader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2370856516626557838?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2370856516626557838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/08/virtual-texturing-on-iphone.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2370856516626557838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2370856516626557838'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/08/virtual-texturing-on-iphone.html' title='Virtual texturing on iPhone'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-391280443714797042</id><published>2010-07-20T10:48:00.000+02:00</published><updated>2011-08-08T16:44:51.022+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>VSD implemented</title><content type='html'>Last Friday I spend an hour or two in massaging my tools pipeline so that all the polygons would be stored on a per area basis, and passing along the id tech 4 portal information along to my test app.&lt;br /&gt;
This morning I implemented portal rendering.&lt;br /&gt;
I don't have any screenshots because it's hard to show what you couldn't see anyway ;)&lt;br /&gt;
I need to implement a multi-camera system first before I can show anything useful.&lt;br /&gt;
&lt;br /&gt;
The next step will be to store area information with the pages as well, so I can try an analytical solution to page VSD.&lt;br /&gt;
The same data can also be used to determine which light potentially casts light on which page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-391280443714797042?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/391280443714797042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/vsd-implemented.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/391280443714797042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/391280443714797042'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/vsd-implemented.html' title='VSD implemented'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8443007146984065966</id><published>2010-07-15T11:19:00.000+02:00</published><updated>2011-08-08T16:44:51.118+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Bounds, Fragments and Updated tools</title><content type='html'>Progress has been slow with my virtual texture experiments because I've come to a point where I can't simply work on things iteratively and need big chunks of time to work on some things.&lt;br /&gt;
&lt;br /&gt;
I've managed to do some things however.&lt;br /&gt;
&lt;br /&gt;
The first thing I did was rewrite the whole layout of my virtual texture file &amp;amp; the way they are loaded so that page definitions are separated from the texture pieces (which I named fragments) that form them.&lt;br /&gt;
&lt;br /&gt;
This will make it possible to eventually support things like procedural and dynamic textures.&lt;br /&gt;
It will also allow me to share fragments between pages, which for the time being, speeds up my virtual page generation &lt;i&gt;a lot&lt;/i&gt;, which is useful when I need to make more modifications in the future.&lt;br /&gt;
It also made it possible to define that a page consists out of more than just a diffuse layer, and my virtual texture file now also contains normal and specular maps, although I don't actually use them yet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another thing I've done is calculate the bounds of each page, by clipping the pages' geometry by the page boundaries, and then calculating it's extends.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_QB2O0HdIQjQ/TD7Evb70O2I/AAAAAAAAAQs/cOC_k3E_27w/s1600/bounds.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="248" src="http://4.bp.blogspot.com/_QB2O0HdIQjQ/TD7Evb70O2I/AAAAAAAAAQs/cOC_k3E_27w/s320/bounds.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Here you can see the bounds being rendered around their pages.&lt;br /&gt;
It shows how doom 3's texture usage is horrible for virtual texturing, and I really should be merging geometry and projecting the textures onto it.&lt;br /&gt;
But not now, because it's a nice worst case situation for testing.&lt;br /&gt;
&lt;br /&gt;
What I really want to do first is start ordering pages in the virtual texture by how close they are together in worldspace, and I want to try to see how better or worse an analytical solution to page visibility would perform.&lt;br /&gt;
&lt;br /&gt;
But before I can do that, I need to implement VSD.&lt;br /&gt;
Right now I'm rendering the entire level each frame, but I really should be using doom 3's portal/area information to do some simple portal rendering instead.&lt;br /&gt;
&lt;br /&gt;
Another thing I should be doing is to do the page assignments in the virtual texture on a per area basis, because this will improve page locality at lower resolution mip map levels.&lt;br /&gt;
Right now a page on one end of the level could sit right next to a page on the other end of the level.&lt;br /&gt;
&lt;br /&gt;
At a lower resolution mip level, the two page bounds would be combined and the bounds would enclose the entire level.&lt;br /&gt;
This is obviously bad because the bounds would become increasingly unusable at lower resolution mips, but it also makes us load a page where it's parts will never be used at the same time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8443007146984065966?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8443007146984065966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/bounds-fragments-and-updated-tools.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8443007146984065966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8443007146984065966'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/bounds-fragments-and-updated-tools.html' title='Bounds, Fragments and Updated tools'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QB2O0HdIQjQ/TD7Evb70O2I/AAAAAAAAAQs/cOC_k3E_27w/s72-c/bounds.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8228142256819708569</id><published>2010-07-08T14:03:00.000+02:00</published><updated>2011-08-08T16:45:44.000+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Random-Idea'/><title type='text'>3rd person story telling</title><content type='html'>Just had an interesting thought about game storytelling ...&lt;br /&gt;
&lt;br /&gt;
First person story telling never seems to work very well, this is because you are in control and you can't be directed to play your part in someone else's story.&lt;br /&gt;
The more control someone tries to assert over you, the less freedom you have.&lt;br /&gt;
&lt;br /&gt;
When you watch a movie, you sympathize with the characters you're seeing on the screen.&lt;br /&gt;
When you play a traditional first person game, you don't sympathize with yourself in the same way, because even though you control your character, you are never truly him or her.&lt;br /&gt;
You don't share that made up history with the character, you are just you put in the shoes of someone else and everybody pretending that you are that other person.&lt;br /&gt;
&lt;br /&gt;
The first person games that have the best stories always have their stories revolve *around* the player, always trying to put the player into the center of the story in a somewhat fake way.&lt;br /&gt;
Half life does this the best because it lets most of it's story be told by other characters, and acted out by other characters.&lt;br /&gt;
&lt;br /&gt;
So I was thinking, perhaps the story shouldn't centered around the player, but around other characters, and the player is simply there to, sort of, witness it.&lt;br /&gt;
Certainly the player would participate in the puzzles and obstacles, but when it comes to the story, the player wouldn't actually be the focal point.&lt;br /&gt;
The player wouldn't be the main character.&lt;br /&gt;
&lt;br /&gt;
This would allow much more interesting characters in the story, or maybe even switching between multiple characters, like they do in series.&lt;br /&gt;
You would simply be the faceless guy/girl who goes along for the ride, so to speak.&lt;br /&gt;
&lt;br /&gt;
Which explains why freeman never speaking in half life works so well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8228142256819708569?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8228142256819708569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/3rd-person-story-telling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8228142256819708569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8228142256819708569'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/07/3rd-person-story-telling.html' title='3rd person story telling'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1241809518359526740</id><published>2010-06-26T20:37:00.000+02:00</published><updated>2011-08-08T16:49:11.160+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><title type='text'>3D TV and dynamic surface caching</title><content type='html'>Just a thought I wanted to share about rendering lighting into a virtual texture (dynamic surface caching).&lt;br /&gt;
&lt;br /&gt;
Compared to deferred rendering, it should be slower in the worst case.&lt;br /&gt;
But the worst case will always be bounded by the size of the page cache texture x the number of lights per page.&lt;br /&gt;
The best case is much better because lighting could theoretically be cached per page, as long as the lights that touch that page don't move or change.&lt;br /&gt;
&lt;br /&gt;
However, unless you're moving *a lot* of lights around on screen, dynamic surface caching might always be faster than deferred rendering when rendering the scene multiple times.&lt;br /&gt;
Which is what you'd need to do when creating 3D for a 3D TV.&lt;br /&gt;
&lt;br /&gt;
This is because when you're done with rendering the lighting into the page cache texture, you only need to render the scene as if you're rendering the geometry with only one texture, period.&lt;br /&gt;
&lt;br /&gt;
Of course I'm simplifying this a little bit, because in the real world you also have post processing.&lt;br /&gt;
&lt;br /&gt;
But it's still an interesting property ..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1241809518359526740?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1241809518359526740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/3d-tv-and-dynamic-surface-caching.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1241809518359526740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1241809518359526740'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/3d-tv-and-dynamic-surface-caching.html' title='3D TV and dynamic surface caching'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1006757361783310629</id><published>2010-06-25T10:20:00.000+02:00</published><updated>2011-08-08T16:44:50.916+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Borders? Borders? I don't need no stinkin' borders (on disk)</title><content type='html'>Anyone who's read any paper about virtual texturing knows that you need to put borders around your pages, otherwise you get ugly seems because of bilinear interpolation.&lt;br /&gt;
This is because your page might be anywhere in your page texture, neighbouring other pages which have completely different colors, and when you sample an interpolated pixel near the border of the page, it interpolates between pixels of unrelated pages.  &lt;br /&gt;
&lt;br /&gt;
Usually the borders are build at preprocessing time, where the first 4 pixel horizontal or vertical lines are duplicated from a neighbouring page to serve as a border in the former page and visa versa.&lt;br /&gt;
&lt;br /&gt;
Today I realized that the pages on disk don't need any borders at all, because you will always have all the information available to you to build those borders at upload time..&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_QB2O0HdIQjQ/TCRVo99TYVI/AAAAAAAAAQU/cymcMuRA8PA/s1600/dual_page.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="160" src="http://1.bp.blogspot.com/_QB2O0HdIQjQ/TCRVo99TYVI/AAAAAAAAAQU/cymcMuRA8PA/s320/dual_page.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
In this case, we've got a polygon crossing two pages, which are both visible, and both loaded from disk.&lt;br /&gt;
Here we can just copy the border pixels from both pages to the other one.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_QB2O0HdIQjQ/TCRVpbnXWMI/AAAAAAAAAQY/40-MuAaJToo/s1600/dual_page_blur.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="160" src="http://2.bp.blogspot.com/_QB2O0HdIQjQ/TCRVpbnXWMI/AAAAAAAAAQY/40-MuAaJToo/s320/dual_page_blur.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
So what about this case?&lt;br /&gt;
Here we've got the same polygon crossing the same two pages, but one isn't loaded yet (or it's visible, in which case we really don't care), and we only have a lower resolution version of that page.&lt;br /&gt;
So what are we going to do now?&lt;br /&gt;
Well, we simply up-sample the lower resolution page, and then just copy border pixels from that page as before.&lt;br /&gt;
&lt;br /&gt;
And when you think about it, this is actually more correct, because if we used a preprocessed border it would have been be a higher resolution border, and we'd actually get a (very subtle) seem here because the neighbouring page is different!&lt;br /&gt;
&lt;br /&gt;
Bottom line:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Borders do not need to be stored, less disk space required.&lt;/li&gt;
&lt;li&gt;The most correct resolution border is always in memory anyway.&lt;/li&gt;
&lt;li&gt;Preprocessing is simplified.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Downsides:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;More bookkeeping / work at runtime (but not much).&lt;/li&gt;
&lt;li&gt;Borders of adjacent pages need to be updated when you load in a higher resolution page.&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/7301982-1006757361783310629?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1006757361783310629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/borders-borders-i-dont-need-no-stinkin.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1006757361783310629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1006757361783310629'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/borders-borders-i-dont-need-no-stinkin.html' title='Borders? Borders? I don&apos;t need no stinkin&apos; borders (on disk)'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QB2O0HdIQjQ/TCRVo99TYVI/AAAAAAAAAQU/cymcMuRA8PA/s72-c/dual_page.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6559709405492950800</id><published>2010-06-19T10:29:00.006+02:00</published><updated>2011-08-08T16:50:42.828+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual texture reflections, random thought</title><content type='html'>A thought popped up in my head this morning..&lt;br /&gt;
&lt;br /&gt;
I'm wondering if the following scheme would work.&lt;br /&gt;
For all reflecting static objects the world would be rendered around it, into a paraboloid environment map.&lt;br /&gt;
&lt;br /&gt;
Actually, only the part of the world facing the camera, so the paraboloid environment map would be aligned with the camera in the opposite direction.&lt;br /&gt;
These maps would be relatively small, maybe virtual texture page sized (128 x 128), and rendered from a specified point within the reflected object.&lt;br /&gt;
&lt;br /&gt;
Instead of storing the colors in the environment map, we store the virtual texture texel coordinates, which are always unique.&lt;br /&gt;
&lt;br /&gt;
Using this, we can then bounce between the environment maps a couple of times using the surface normal of the texel and the destination texel in the environment maps.&lt;br /&gt;
If a texel doesn't have an environment map, it would just use that texel.&lt;br /&gt;
After x bounces, it would just use some default color.&lt;br /&gt;
Obviously the texel coordinates would be an approximation, so some blur would have to be applied afterwards, and more blur would be required at grazing angles..&lt;br /&gt;
&lt;br /&gt;
Would this work/look good enough? I don't know.&lt;br /&gt;
Would it be fast? Probably not, but I think it would beat ray tracing.&lt;br /&gt;
Obviously there would be a lot of cost in the form of vsd, draw calls and fill-rate.&lt;br /&gt;
&lt;br /&gt;
Update:&lt;br /&gt;
Whoops, because of reflections you'd be able to see the back of a reflected object, which would require a second environment map to be rendered in the direction of the reflection.&lt;br /&gt;
Damn you reflection angles! Damn you to heck.&lt;br /&gt;
&lt;br /&gt;
However, it might be possible to make some sort of simplified reflection graph and figure out which environment maps you'd need to render.&lt;br /&gt;
Which one to use and when would be more complicated however.&lt;br /&gt;
And it certainly won't help with performance.&lt;br /&gt;
&lt;br /&gt;
Update 2:&lt;br /&gt;
Maybe objects could be pre-split into several environment maps, and we could then perform back-face / frustum culling etc. on these maps.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6559709405492950800?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6559709405492950800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/virtual-texture-reflections.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6559709405492950800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6559709405492950800'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/virtual-texture-reflections.html' title='Virtual texture reflections, random thought'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2153466584984147249</id><published>2010-06-17T17:04:00.003+02:00</published><updated>2011-08-08T16:47:22.235+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Texture compression II</title><content type='html'>I've made some more progress on the compression code.&lt;br /&gt;
I have &gt;6000 128x128 pages, created from Quake 4 textures that I'm using for testing purposes.&lt;br /&gt;
Right now the average page size is roughly 2kb.&lt;br /&gt;
There's one page of 10kb, and two more that are almost 9kb, other than that none gets higher than 6kb.&lt;br /&gt;
I could get more compression out of this, but not without degrading quality beyond where I would like to go.&lt;br /&gt;
Average decompression time is 8ms, but I haven't made any attempt at optimizing.&lt;br /&gt;
I can compress all the pages combined to 31x their original size.&lt;br /&gt;
&lt;br /&gt;
I'm wondering how id software do their compression though..&lt;br /&gt;
According to their latest presentation (&lt;a href="http://s09.idav.ucdavis.edu/talks/05-JP_id_Tech_5_Challenges.pdf"&gt;id Tech 5 Challenges: From Texture Virtualization to Massive Parallelization&lt;/a&gt;) they compress each page to about 2-6kb, but that's diffuse, normal + specular.&lt;br /&gt;
&lt;br /&gt;
But I'm only compressing diffuse here.&lt;br /&gt;
&lt;br /&gt;
I know they're using DCT, they even have some papers published about older versions of their compression routines, but so far I haven't been able to get it down to these sizes without &lt;i&gt;seriously&lt;/i&gt; degrading quality.&lt;br /&gt;
&lt;br /&gt;
Perhaps, because of all the real-time lighting etc., it's perfectly fine to really compress textures all the way down to the point where the artefacts are really obvious, simply because they won't be as visible in a scene as it would be in a 2d picture.&lt;br /&gt;
&lt;br /&gt;
Perhaps, I'm nitpicking too much when it comes to quality.&lt;br /&gt;
&lt;br /&gt;
I'm also using SSIM for texture quality assessments now.&lt;br /&gt;
It's not perfect, but better than PSNR.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2153466584984147249?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2153466584984147249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/texture-compression-ii.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2153466584984147249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2153466584984147249'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/texture-compression-ii.html' title='Texture compression II'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2310265709603280264</id><published>2010-06-14T10:16:00.004+02:00</published><updated>2011-08-08T16:47:22.240+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Texture compression</title><content type='html'>So the last couple of days I've been playing around with texture compression again, just to see how far I could take it using wavelet compression.&lt;br /&gt;
&lt;br /&gt;
I'm pretty pleased with the results. It's not very fast, but then again I haven't made &lt;i&gt;any&lt;/i&gt; attempt to optimizing this yet.&lt;br /&gt;
I don't think I can get it as fast as DCT, but I can definitely get far more compression for the same quality.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_QB2O0HdIQjQ/TBXiUfchZiI/AAAAAAAAAPw/7cemkAnSGtw/s1600/compressionTool1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="210" src="http://4.bp.blogspot.com/_QB2O0HdIQjQ/TBXiUfchZiI/AAAAAAAAAPw/7cemkAnSGtw/s400/compressionTool1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Just to be able to measure my results more accurately I've created a tool which crawls through my page textures, compresses them, and measures the difference between the compressed/ and the original texture and determines the compressed size.&lt;br /&gt;
&lt;br /&gt;
I should note that the third displayed bitmap in the tool is the exaggerated difference between the two textures.&lt;br /&gt;
&lt;br /&gt;
The cool thing about wavelet compression is that it implicitly has it's mip-map encoded within it.&lt;br /&gt;
With virtual texturing you should always permanently cache your lowest resolution mip-maps, which means that if you use wavelet compression that you already have part of the compressed page in memory.&lt;br /&gt;
&lt;br /&gt;
The idea is to use the mip maps that are already in memory to decompress the higher resolution mip maps, which helps decrease the amount of data that needs to be loaded from disk.&lt;br /&gt;
(Something I'm not yet doing right now)&lt;br /&gt;
&lt;br /&gt;
Of course this will only be useful if the decompression can be made fast enough.&lt;br /&gt;
&lt;br /&gt;
PS.&lt;br /&gt;
Texture page size is 128 x 128, 'diffuse' includes alpha channel here.&lt;br /&gt;
&lt;br /&gt;
PPS.&lt;br /&gt;
Noticed that the textures that compress the worst are simple greyish textures with alpha.&lt;br /&gt;
It seems that these textures are using pre-multiplied alpha and as such have each color multiplied with their alpha.&lt;br /&gt;
This causes lots of variability in the color channels, even in the areas which you can't really see, which hurts compression.&lt;br /&gt;
The best solution would be to pre-multiply the alpha at load time, and not pre-multiply it on disk. For now I'm setting all the alpha==0 pixels to the average color, and this seem to work fairly well.&lt;br /&gt;
&lt;br /&gt;
PPPS.&lt;br /&gt;
After interpolating the average color with the actual pixel color using the alpha as the interpolation factor, the compression ratio for the worst cases halved!&lt;br /&gt;
Obviously this shouldn't be done in production code, but it does show that non pre-multiplied alpha textures compress better than pre-multiplied alpha textures, which means that pre-multiplying the alpha should be done after decompression.&lt;br /&gt;
&lt;br /&gt;
Also, can't help but notice that difference images kind of look like edge detection filters, which might mean sharpening the image with a filter might increase the overall quality of the images (maybe).&lt;br /&gt;
&lt;br /&gt;
I could definitely use some better down/up scaling code for the Co/Cg channels.&lt;br /&gt;
(I'm using YCoCg internally as a color representation)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2310265709603280264?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2310265709603280264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/texture-compression.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2310265709603280264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2310265709603280264'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/texture-compression.html' title='Texture compression'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QB2O0HdIQjQ/TBXiUfchZiI/AAAAAAAAAPw/7cemkAnSGtw/s72-c/compressionTool1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8228700332862099853</id><published>2010-06-02T20:26:00.003+02:00</published><updated>2011-08-08T16:47:22.257+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Some interesting links...</title><content type='html'>I've got 2 interesting links to share, both are useful for virtual texturing.&lt;br /&gt;
&lt;br /&gt;
The first one "&lt;a href="http://iquilezles.org/www/articles/wavelet/wavelet.htm"&gt;Wavelet image compression - Iñigo Quilez&lt;/a&gt;" is a nice article about wavelet compression, which makes me think all the mip maps of a texture page could be compressed together.&lt;br /&gt;
This would mean that lower resolution mips would need to be build up dynamically from several pages, which is not necessarily a bad thing because a lower resolution mip's texture area might not be fully utilized anyway.&lt;br /&gt;
However, you don't want to require too many compressed pages to be in memory at the same time when you look at a very low resolution page, so there needs to be some sort of trade of.&lt;br /&gt;
The very lowest mips should be pre-cached in memory anyway, so that you always have something to display when you can't load in your pages fast enough.&lt;br /&gt;
&lt;br /&gt;
The other link "&lt;a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=572450"&gt;Bump Mapping Unparametrized Surfaces on the GPU - Morten S. Mikkelsen&lt;/a&gt;" is very interesting.&lt;br /&gt;
Bryan McNett actually sums it up:&lt;br /&gt;
&lt;blockquote&gt;The guy who wrote this paper sits five feet away from me. The paper doesn't say so explicitly, but this finally makes normal maps obsolete for games. Implement the paper, and you can replace 2-channel normal maps with 1-channel height maps. You can also throw away all per-vertex tangent/binormal data. Cool stuff, if you ask me!&lt;br /&gt;
&lt;br /&gt;
The primary flaw of the technique is that, since the derivative of the height map is taken with linear-filtering texture sampling hardware, when magnified it looks like "nearest neighbor" filtering. Fixing this requires adding bicubic-filtering to the hardware.&lt;/blockquote&gt;&lt;br /&gt;
This can actually be used as a texture compression of sorts, by rendering the generated normal map into the normal page cache texture. The linear filtering won't be an issue there.&lt;br /&gt;
Of course this requires per pixel position &amp; per pixel normal, something I would need to do lighting into the page cache anyway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8228700332862099853?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8228700332862099853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/some-interesting-links.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8228700332862099853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8228700332862099853'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/06/some-interesting-links.html' title='Some interesting links...'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3800514640852285799</id><published>2010-05-28T11:50:00.000+02:00</published><updated>2011-08-08T16:40:15.988+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Optimizations</title><content type='html'>The &lt;a href="http://sandervanrossen.blogspot.com/2010/05/realtime-csg-part-5.html"&gt;last time&lt;/a&gt; I blogged about realtime CSG, I mentioned that in my test scene if I performed CSG on the entire scene it would take about 80ms.&lt;br /&gt;
(And I should mention again that this algorithm is intended for fast updates, not necessarily doing this faster for the entire CSG tree. Even though that would be a nice bonus)&lt;br /&gt;
&lt;br /&gt;
I also mentioned a couple of things that could be done to improve performance, and that there are a lot of ways to improve performance.&lt;br /&gt;
&lt;br /&gt;
Today I had a simple idea to improve performance.&lt;br /&gt;
By checking the bounds for each left and right branch separately at a higher level, so that we know what operation we're performing, we can handle some common situations in a more simplified, and faster, way.&lt;br /&gt;
&lt;br /&gt;
Here's the updated pseudo code for the CSGBranch.Categorize method.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;void CSGBranch.
       Categorize( categorizationNode,
                   inputPolygons,
                   ..., 
                   inside, 
                   touchInside, 
                   touchOutside, 
                   outside)
{
  switch (Operator)
  {
    case CSGOperator.Addition:
    {
      // Check if the given polygons
      // are possibly touching the 
      // left branch
      if (boundsOfPolygons
            .IsOutside(Left.Bounds))
      {
        // Polygons are not touching 
        // the left branch.

        // Check if the given polygons
        // are possibly touching the
        // right branch
        if (boundsOfPolygons
              .IsOutside(Right.Bounds))
        {
          // Nope, all of them are
          // categorized as 'outside'
          outside.AddRange(
                    inputPolygons);
        } else
        {
          // We only need to check
          // with the right branch
          Right.
            Categorize(...);
        }
      } else
      // Polygons are touching 
      // the left branch.
      // Check if the given polygons
      // are possibly touching the
      // right branch
      if (boundsOfPolygons
            .IsOutside(Right.Bounds))
      {
        // We only need to check
        // with the left branch
        Left.
          Categorize(...);
      } else
      {
        // Polygons are touching
        // both branches 

        // same as before ...
        // (Left || Right)
        LogicalOr(categorizationNode,
                  inputPolygons,
                  ...,  
                  inside, touchInside, 
                  touchOutside, outside, 

                  false,
                  false
                  );
      }
      break;
    }
    case CSGOperator.Common:
    {
      // Check if polygons are outside
      // either left or right branch 
      if (boundsOfPolygons
            .IsOutside(Left.Bounds) ||
          boundsOfPolygons
              .IsOutside(Right.Bounds))
      {
        // Considering that in a
        // 'common' operation we need
        // to find the parts that are
        // shared with both branches, 
        // we know that if the polygons
        // are outside just one branch 
        // that they are categorized as
        // 'outside'
        outside.AddRange(
                  inputPolygons);
      } else
      {
        // Polygons are touching
        // both branches 

        // same as before ...
        // !(!Left || !Right)
        LogicalOr(categorizationNode,
                  inputPolygons,
                  ...,  
                  outside, touchOutside, 
                  touchInside, inside, 
                
                  true, // reverse Left
                  true  // reverse Right
                  );
      }
      break;
    }
    case CSGOperator.Subtraction:
    {
      // Check if the polygons are
      // touching the left branch
      if (boundsOfPolygons
            .IsOutside(Left.Bounds))
      {
        // The right branch removes
        // and the left branch keeps
        // whatever is inside it.
        // If all the polygons are
        // outside the left branch
        // then we know they're all
        // categorized as 'outside'
        // this branch.
        outside.AddRange(
                  inputPolygons);
      } else
      // Polygons are touching 
      // the left branch.
      // Check if the given polygons
      // are possibly touching the
      // right branch
      if (boundsOfPolygons
              .IsOutside(Right.Bounds))
      {
        // If we're only touching the 
        // left branch, we don't need
        // to do a more complicated
        // operation, and just
        // categorize the left branch.
        Left.
          Categorize(...); 
      } else
      {
        // Polygons are touching
        // both branches 

        // same as before ...
        // !(!Left || Right)
        LogicalOr(categorizationNode,
                  inputPolygons,
                  ...,  
                  outside, touchOutside, 
                  touchInside, inside, 

                  true, // reverse Left
                  false
                  );
      }
      break;
    }
  }
}&lt;/pre&gt;&lt;br /&gt;
This alone increased the speed from about 80ms to 25-30ms for the entire test scene.&lt;br /&gt;
&lt;br /&gt;
I'm going to use a much bigger scene in the future, &lt;br /&gt;
because it really is too small to properly test for scalability.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3800514640852285799?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3800514640852285799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/realtime-csg-optimizations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3800514640852285799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3800514640852285799'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/realtime-csg-optimizations.html' title='Realtime CSG - Optimizations'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7957323940068811272</id><published>2010-05-26T19:55:00.010+02:00</published><updated>2011-08-08T16:52:06.719+02:00</updated><title type='text'>MD3View - A short trip down nostalgia lane</title><content type='html'>A long time ago, about 10 years, &lt;a href="http://www.idsoftware.com/games/quake/quake3-arena/"&gt;Quake 3 Arena&lt;/a&gt; was released.&lt;br /&gt;
Within 24 hours &lt;a href="http://mfbaranow.blogspot.com"&gt;Matthew Baranowski&lt;/a&gt; and I had reverse engineered the MD3 model format and created a model viewer that could display all the models in all it's Q3A shaded glory.&lt;br /&gt;
&lt;br /&gt;
Well actually it could've been 24 hours after Q3Test, but anyway..&lt;br /&gt;
&lt;br /&gt;
We named it MD3View and released it with the source, and because open source &lt;i&gt;obviously&lt;/i&gt; equals GPL we slapped the GPL license on top of it. (at least that's we thought at the time, not that we gave it much thought)&lt;br /&gt;
&lt;br /&gt;
Interestingly enough &lt;a href="http://www.ravensoft.com/"&gt;Raven software&lt;/a&gt; found our tool, expanded on it and used it on games such as &lt;a href="http://www.mobygames.com/game/star-trek-voyager-elite-force"&gt;Star Trek: Voyager - Elite force&lt;/a&gt; (We both got a special thanks in the credits because of this) and apparently &lt;a href="http://www.mobygames.com/game/star-wars-jedi-knight-jedi-academy"&gt;Star Wars: Jedi Knight - Jedi Academy&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Not long after Matthew, me and &lt;a href="http://volcore.limbicsoft.com/"&gt;Volker Schoenefeld&lt;/a&gt; went on an awesome road trip, starting at New York (well technically Volker &amp; I flew to NY from Germany and the Netherlands) and we (well Matt) drove all the way to &lt;a href="http://www.siggraph.org/s2000/"&gt;Siggraph 2000&lt;/a&gt; in New Orleans (which was still in one piece at the time) and finally to &lt;a href="http://en.wikipedia.org/wiki/QuakeCon#2000"&gt;Quakecon 2000&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I still remember being nervous as hell talking to a pretty cool Raven guy there, I mean there I was, this young geeky guy actually talking to someone from Raven Software!! &lt;br /&gt;
I politely told him, well mumbled, that MD3View was released under the GPL and that the modified source code &lt;i&gt;should&lt;/i&gt; be released as well, or something or other.&lt;br /&gt;
Some time later we received an NDA through email, and then got a copy of the source code... and unfortunately my memory gets rather fuzzy beyond that.&lt;br /&gt;
But for no particular reason, certainly not because of Raven, the modified source code never got released.&lt;br /&gt;
&lt;br /&gt;
I would've never given this any more thought if someone wouldn't, out of the blue, just asked me if I still had the source code.&lt;br /&gt;
&lt;br /&gt;
Which I didn't.&lt;br /&gt;
I just couldn't find it.&lt;br /&gt;
Not the original (can anyone out there help me with that?) or the version from Raven.&lt;br /&gt;
&lt;br /&gt;
So I figured, what the hell, I'll just politely ask Raven software for it, it's not like it's state of the art technology any more anyway.&lt;br /&gt;
&lt;br /&gt;
Within hours I got an email back from Ste Cork:&lt;br /&gt;
&lt;pre&gt;&lt;i&gt;Wow, you won't believe how hard it was to find this, 
we stopped using SourceSafe years ago (and that was
the only place this was ever stored), and it took a
while to even install the client (doesn't work on
Vista) and find all the databases and various INI 
files etc, then pick out the one this was in. 
Anyway, as you can see from the attachment our
IT guy finally managed it.&lt;/i&gt;&lt;/pre&gt;Whoops, sorry to put your IT guy through that! (so sorry!) &lt;br /&gt;
But thanks a lot for all the effort!&lt;br /&gt;
&lt;br /&gt;
And after a couple of emails back and forth, making sure that the headers contained the proper legal information and converting it to a more modern version of visual studio: &lt;strike&gt;here it is&lt;/strike&gt;.&lt;br /&gt;
Update: Apparently the original hosted file disappeared, so I put it on Codeplex this time, you can find it &lt;a href="http://md3view.codeplex.com/"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It's old, it's outdated, and it's yours, all yours.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update&lt;/b&gt;: Matthew confirmed it, 24 hours after Q3Test, not Quake 3 Arena.&lt;br /&gt;
&lt;b&gt;Update 2&lt;/b&gt;: He also said that we got a cease and desist from &lt;a href="http://www.idsoftware.com/"&gt;Id software&lt;/a&gt; and that we had to take it down,  wait a couple of weeks until Quake 3 Arena was released before we could put it up again.&lt;br /&gt;
I honestly can't remember that... is that a grey hair?&lt;br /&gt;
&lt;b&gt;Update 3&lt;/b&gt;: Wow, this article brought almost 5000 visitors to my blog in a day!?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7957323940068811272?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7957323940068811272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/md3view.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7957323940068811272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7957323940068811272'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/md3view.html' title='MD3View - A short trip down nostalgia lane'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-611842333662125524</id><published>2010-05-21T12:23:00.006+02:00</published><updated>2011-08-08T16:40:16.000+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Part 5</title><content type='html'>In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;part 1&lt;/a&gt; I explained the basics you'll need to know to understand how to perform real-time CSG.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html"&gt;part 2&lt;/a&gt; I described how to build a brush, which is the basic building block of the algorithm I'm describing.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html"&gt;part 3&lt;/a&gt; I wrote about CSG operations.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2010/03/realtime-csg-part-4.html"&gt;part 4&lt;/a&gt; I wrote about cutting a brush with another brush.&lt;br /&gt;
&lt;br /&gt;
When I started on writing about real time CSG, I had my original real time CSG algorithm in mind.&lt;br /&gt;
It's a simple enough algorithm, but a very simplistic subset of CSG.&lt;br /&gt;
I foolishly thought I could just figure our how to generalize it as I went along, it turned out to be a little bit harder than that.&lt;br /&gt;
&lt;br /&gt;
Eventually I managed to get an algorithm to work, but it was complicated and un-intuitive.&lt;br /&gt;
The additive and common operations seemed coherent all right, I could rationalize every piece of it.&lt;br /&gt;
But the subtractive operation, my god, it was frankenstein as code.. &lt;br /&gt;
It just didn't make any sense!&lt;br /&gt;
&lt;br /&gt;
I managed to make it work, but only through trial and error.&lt;br /&gt;
And even though it seemed to work in all my tests, I didn't really trust it.&lt;br /&gt;
It definitely didn't feel right to unleash that piece of code into the wild, &lt;i&gt;imagine what kind of damage that could do in the wrong hands&lt;/i&gt;!&lt;br /&gt;
&lt;br /&gt;
And then, as &lt;a href="http://sandervanrossen.blogspot.com/2010/05/csg-operations.html"&gt;I blogged about before&lt;/a&gt;, I read a post at &lt;a href="http://filmicgames.com/archives/130"&gt;filmic games&lt;/a&gt; and it hit me; not only can CSG operations be seen as logical operations (which makes it so much easier to express), but the subtractive operation is actually a combination of operations!&lt;br /&gt;
That's why it was so hard to get it to work coherently, I was trying to doing multiple things at the same time!&lt;br /&gt;
&lt;br /&gt;
After that figuring out the lean and mean version of my previous algorithm was fairly easy.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Categorization&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
As I mentioned before, the final solution of the entire CSG tree consists of all the polygons of all the brushes MINUS all the pieces of these polygons that we reject.&lt;br /&gt;
&lt;br /&gt;
We don't add any new polygons, at all.&lt;br /&gt;
Ever.&lt;br /&gt;
We just remove parts.&lt;br /&gt;
&lt;br /&gt;
So the heart of this CSG algorithm is the categorization code, this code takes the polygons of a brush, goes through the CSG tree and categorizes each piece of the polygon as being inside, outside, or touching the shape that the entire CSG tree (or sub-tree) represents.&lt;br /&gt;
Well actually we have two types of "touch" categories, inside-touching (plane aligned) and outside-touching (aligned with the reverse of the plane).&lt;br /&gt;
&lt;br /&gt;
We essentially do this for every left / right branch and then swizzle the categorization depending on the CSG operation and the results from the left and right branch.&lt;br /&gt;
&lt;br /&gt;
First the code for the branches in the tree (pseudo code)&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;void CSGBranch.
       Categorize( categorizationNode,
                   inputPolygons,
                   ..., 
                   inside, 
                   touchInside, 
                   touchOutside, 
                   outside)
{
  // Early out, check if the bounding box of
  // the categorizingBrush intersects with 
  // the bounding box of this branch. 
  // If it doesn't, don't bother going any further
  // (This effectively works as a, somewhat
  // unbalanced, bounding volume hierarchy)
  if (boundsOfPolygons
        .IsOutside(this.Bounds))
  {
    // ... add all input polygons to outside
    outside.AddRange(inputPolygons);
    return;
  }

  switch (Operator)
  {
    case CSGOperator.Addition:
    {
      // (Left || Right)
      LogicalOr(categorizationNode,
                inputPolygons,
                ...,  
                inside, touchInside, 
                touchOutside, outside, 

                false,
                false
                );
      break;
    }
    case CSGOperator.Common:
    {
      // !(!Left || !Right)
      LogicalOr(categorizationNode,
                inputPolygons,
                ...,  
                outside, touchOutside, 
                touchInside, inside, 
                
                true, // reverse Left
                true  // reverse Right
                );
      break;
    }
    case CSGOperator.Subtraction:
    {
      // !(!Left || Right)
      LogicalOr(categorizationNode,
                inputPolygons,
                ...,  
                outside, touchOutside, 
                touchInside, inside, 

                true, // reverse Left
                false
                );
      break;
    }
  }
}&lt;/pre&gt;Notice how elegant it is?&lt;br /&gt;
The LogicalOr method &lt;b&gt;is&lt;/b&gt; basically the CSG Addition operator.&lt;br /&gt;
The inside, touchInside, touchOutside, outside parameters are lists to which the polygon pieces are added.&lt;br /&gt;
Notice how the 'not operator' is basically nothing more but a reversal of the parameters!&lt;br /&gt;
The last two parameters are used to tell the LogicalOr method if the left and/or right branch need to have their parameters reversed.&lt;br /&gt;
&lt;br /&gt;
So here's the LogicalOr method:&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;void CSGBranch.
       LogicalOr( categorizationNode,
                  inputPolygons,
                  ..., 
                  inside, 
                  leftTouchInside, 
                  leftTouchOutside, 
                  leftOutside)
{
  //        right
  //        inside | touch-I | touch-O | outside
  // left          |         |         |
  // inside    I   |    I    |    I    |    I
  // touch-I   I   |   tI    |    I    |   tI
  // touch-O   I   |    I    |   tO    |   tO
  // outside   I   |   tI    |   tO    |    O

  ... create some temp lists ...

  // if anything is inside the left branch, 
  // we don't need to check it again for 
  // the right branch. Everything else is put
  // in temporary lists whose contents we'll
  // check against the right branch ...
  if (!inverseLeft)
    Left.
      Categorize(categorizationNode,
                 inputPolygons,
                 ..., 
                 inside, leftTouchInside, 
                 leftTouchOutside, leftOutside);
  else    
     // .. same as above but with parameters
     //    reversed

  if (!inverseRight)
  {
    //        right
    //        inside | touch-I | touch-O | outside
    // left          |         |         |
    // touch-I   I   |   tI    |    I    |   tI
    Right.
      Categorize(categorizationNode,
                 leftTouchInside,
                 ..., 
                 inside, touchInside, 
                 inside, touchInside);

    //        right
    //        inside | touch-I | touch-O | outside
    // left          |         |         |
    // touch-O   I   |    I    |   tO    |   tO
    Right.
      Categorize(categorizationNode,
                 leftTouchOutside,
                 ...,  
                 inside, inside,
                 touchOutside, touchOutside);

    //        right
    //        inside | touch-I | touch-O | outside
    // left          |         |         |
    // outside   I   |   tI    |   tO    |    O
    Right.
      Categorize(categorizationNode,
                 leftOutside,
                 ..., 
                 inside, touchInside, 
                 touchOutside, outside);
  } else
  {
     // .. same as above but with parameters
     //    reversed
  }
}
&lt;/pre&gt;&lt;br /&gt;
Note that if a polygon is touching-inside on one branch, and touching-outside on the other branch, then it means the two branches are touching each other there.&lt;br /&gt;
Which means that any polygon in that area is essentially inside both, and therefore 'inside'.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here's the code that handles the leafs in the tree; the brushes themselves:&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;void CSGBrush.
       Categorize( categorizationNode,
                   inputPolygons,
                   ..., 
                   inside, 
                   touchInside, 
                   touchOutside, 
                   outside)
{
  // Early out, check if the polygons we're 
  // processing belong to the same brush as
  // we're currently checking against
  if (categorizingBrush == this)
  {
    // We're looking for the parts of 
    // 'categorizingBrush' that are visible
    // and at this position in the tree, these
    // polygons are definitely visible ...
    foreach (var polygon in inputPolygons)
      polygon.Visible = true;
    
    // We know all polygons are interesecting
    // with the brush they lie on
    touchInside.AddRange(inputPolygons);
    return;
  }

  // Early out, check if the bounding box of
  // the categorizingBrush intersects with 
  // the bounding box of this brush. 
  // If it doesn't, don't bother going any further
  if (boundsOfPolygons
        .IsOutside(this.Bounds))
  {
    // ... add all input polygons to outside
    outside.AddRange(inputPolygons);
    return;
  }

  ... create some temp lists ...

  this.Split(inputPolygons,
             ...,      
             inside,
             tempTouchingInside,
             tempTouchingOutside,
             outside);

  // We know that the current brush
  // is not the 'categorizingBrush'.
  // We also know that any polygon liying
  // on the surface of this brush cannot 
  // be lying on the surface of 
  // 'categorizingBrush' (well okay, it
  // can, but one overrides the other 
  // depending on order, which is exactly
  // what we want)
  // So we set all the polygons lying on 
  // the surface of this brush to invisible.
  // This solves overlapping polygon problems
  foreach (var polygon in tempTouchingInside)
    polygon.Visible = false;
  foreach (var polygon in tempTouchingOutside)
    polygon.Visible = false;

  touchInside.AddRange(tempTouchingInside);
  touchOutside.AddRange(tempTouchingOutside);
}&lt;/pre&gt;&lt;br /&gt;
And finally here's what we do at the top level:&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;void CSGTree.
       ProcessBrush(categorizationNode,
                    inputPolygons)
{
  .. create temporary lists ...
 
  // Categorize the inputPolygons
  // depending on their location in 
  // the tree ...
  RootNode.
    Categorize(categorizationNode,
               inputPolygons,
               ...,
               // Store results in
               // temporary lists ..
               invisiblePolygons,
               visiblePolygons,
               reversedPolygons,
               invisiblePolygons);

  // We set all polygons that are outside
  // or inside the tree as being invisible ...
  foreach (var polygon in invisiblePolygons)
    polygon.Visible = false;

  // We reverse the order of all the polygons
  // that the tree categorized as having a
  // reversed orientation ...
  foreach (var polygon in reversedPolygons)
    ReverseVertexOrder(polygon);
}
&lt;/pre&gt;&lt;br /&gt;
And that's it!&lt;br /&gt;
After you've build all the geometry, when a brush moves, simply reprocess it and all the brushes it touches.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;The result:&lt;/center&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_QB2O0HdIQjQ/S_ZgWm1ca4I/AAAAAAAAAPk/HU0Qkk9LU3g/s1600/csghouse.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_QB2O0HdIQjQ/S_ZgWm1ca4I/AAAAAAAAAPk/HU0Qkk9LU3g/s320/csghouse.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;center&gt;Points are vertices moved towards the center of the polygon &lt;br /&gt;
to make it easier to see where there are any t-junctions, &lt;br /&gt;
or where multiple vertices lie on the same line&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
Note that I didn't describe the CSGBrush.Split method, I'm going to retroactively modify the previous posts to add more pseudo code (it belongs there), and update the repository as well.&lt;br /&gt;
(but not today)&lt;br /&gt;
I'll post about it when I've done that.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Limitations and Future work&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
When I use this algorithm on my test level which has 234 brushes and 467 nodes, I can generate a mesh with it within about 80ms.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that this algorithm was designed with dynamically updating a handful of brushes in mind, not so much with updating everything all the time.&lt;br /&gt;
&lt;br /&gt;
The resulting mesh has not been optimized yet, there are T-junctions and polygons that should be joined together, but that's a different topic and really deserves a series on it's own.&lt;br /&gt;
If the polygons are optimized per brush, T-junctions should be a rarity considering that the cutting plane that split an edge, would've cut any aligned edges on another brush as well.&lt;br /&gt;
(Of course, there might still be T-junctions because of floating point errors, so don't completely rely on this)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As for performance, there is much room for improvement here:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;All brushes are processed independently, which makes them a prime candidate for parallelization. &lt;br /&gt;
(This is what I did in &lt;a href="http://video.google.com/videoplay?docid=-1907574989981648678#"&gt;my editor&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;This is the big elephant in the room; The algorithm should be rewritten with CPU cache usage in mind, this alone could make it an order of a magnitude faster. Half edges are the biggest problem here. The code would become more complex.&lt;/li&gt;
&lt;li&gt;A higher level bounding volume hierarchy, hashed grid, or sweep &amp;amp; prune phase could theoretically speed things up. Although when I tried it, it only slowed things down.&lt;br /&gt;
I'm guessing that this is because we're already doing some sort of (unbalanced) hierarchical culling while going through the CSG-tree, so perhaps there's not too much to be gained. Perhaps this only becomes a problem when the tree grows very large.&lt;/li&gt;
&lt;li&gt;I'm convinced that it should be possible to figure out some short cuts when going through the tree. Perhaps it's even possible to work from the bottom-up, by starting at the leafs.&lt;br /&gt;
Perhaps that would allow getting rid of all the temporary lists, which is not so much a problem in a language such as C# where allocation is very cheap, but a bigger problem in languages such as C++.&lt;/li&gt;
&lt;li&gt;There are a lot of lower level optimizations that can help a lot with performance too.&lt;br /&gt;
I'm using a lot of methods and enumerations in the example code for clarity and readability, and these hurt performance.&lt;br /&gt;
Once you understand the code, you should consider copying all the planar/vector methods code directly into the methods where they're used.&lt;br /&gt;
Also, you should consider not converting planar side calculations into enums, but using the floating point values instead.&lt;br /&gt;
This should help a lot in the inner loops and could seriously improve performance.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
That's it for now, let me know if I need to explain something in more detail or if you use or improve on my algorithm!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-611842333662125524?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/611842333662125524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/realtime-csg-part-5.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/611842333662125524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/611842333662125524'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/realtime-csg-part-5.html' title='Realtime CSG - Part 5'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QB2O0HdIQjQ/S_ZgWm1ca4I/AAAAAAAAAPk/HU0Qkk9LU3g/s72-c/csghouse.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2461183259530530711</id><published>2010-05-18T16:34:00.001+02:00</published><updated>2011-08-08T16:44:50.988+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Andreas Neu's virtual texturing thesis online</title><content type='html'>A while ago &lt;a href="http://sandervanrossen.blogspot.com/2010/04/virtual-texturing.html"&gt;I mentioned a very interesting thesis&lt;/a&gt; written by Andreas Neu, but back then it wasn't online yet.&lt;br /&gt;
&lt;br /&gt;
Today Andreas send me an email telling me that it's online now, and you can find it &lt;a href="http://www.graphics.rwth-aachen.de/index.php?id=12"&gt;&lt;i&gt;here&lt;/i&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Be sure to check it out if you're in any way interested in virtual texturing technology!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2461183259530530711?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2461183259530530711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/andreas-neus-virtual-texturing-thesis.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2461183259530530711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2461183259530530711'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/andreas-neus-virtual-texturing-thesis.html' title='Andreas Neu&apos;s virtual texturing thesis online'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-9179230043239963976</id><published>2010-05-14T17:16:00.001+02:00</published><updated>2010-05-14T17:16:40.756+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>CSG operations update</title><content type='html'>In my &lt;a href="http://sandervanrossen.blogspot.com/2010/05/csg-operations.html"&gt;last post&lt;/a&gt; I mentioned that I suddenly realized that all popular CSG operations (Addition, Subtraction &amp; common) can be expressed as logical operations.&lt;br /&gt;
Using that knowledge it was trivial to rewrite all operations as a mix of logical OR (the simplest of operations) and logical NOT operations.&lt;br /&gt;
&lt;br /&gt;
To reiterate:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&amp;nbsp;(&amp;nbsp;A&amp;nbsp;||&amp;nbsp;&amp;nbsp;B) = CSG Addition&lt;/li&gt;
&lt;li&gt;!(!A&amp;nbsp;||&amp;nbsp;&amp;nbsp;B) = CSG Subtraction&lt;/li&gt;
&lt;li&gt;!(!A&amp;nbsp;||&amp;nbsp;!B) = CSG Union&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Now the way my CSG code iterated over the CSG tree was basically to tell each child-node in which list to store the polygons that are inside, outside or touching (I actually have 2 categories of touching polygons, depending on the alignment of the plane that touches it).&lt;br /&gt;
&lt;br /&gt;
Performing a logical NOT comes down to just swizzle the lists I'm passing on, so it's essentially free.&lt;br /&gt;
Leaving me with code for just 1 CSG operation that needed to work perfectly!&lt;br /&gt;
&lt;br /&gt;
Although I got everything working with the more complicated code before, it had some really scary parts because of the CSG subtraction operation which was really hard to get right because I flipped the orientation of the polygons to get it working.&lt;br /&gt;
This caused a cascading effect which complicated all the other operations as well.&lt;br /&gt;
&lt;br /&gt;
So when I rewrote it today I found a much more elegant solution which allows me to flip the orientation of the polygons at the very end, again simplifying everything even more.&lt;br /&gt;
&lt;br /&gt;
It's pretty clean and easy to read now, I still need to test it.&lt;br /&gt;
I'm way more confident now about it working in all test cases compared to before because of it's reduced complexity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-9179230043239963976?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/9179230043239963976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/csg-operations-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9179230043239963976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/9179230043239963976'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/csg-operations-update.html' title='CSG operations update'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5096835595802264088</id><published>2010-05-12T12:42:00.040+02:00</published><updated>2011-08-08T16:24:29.341+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>CSG operations</title><content type='html'>Lately I've been posting a lot of random thoughts, and this is one of them.&lt;br /&gt;
Today I read &lt;a href="http://filmicgames.com/archives/130"&gt;a post at filmic games&lt;/a&gt; about CSG, and for one reason or another a thought popped up in my head:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;CSG operations can be expressed more intuitively as logical operations!&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Technically, bitwise operations would work too, at least from a programming pov, but would make less sense (we're not working with bits here, aren't we).&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;A &lt;b&gt;CSG complement&lt;/b&gt; operation would behave like a &lt;b&gt;logical NOT&lt;/b&gt; operation (! in C languages), where the shape becomes "everything outside of the shape" (which is only useful as an intermediate step, not so much as an actual operation).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_QB2O0HdIQjQ/S-qOwd-tOsI/AAAAAAAAAPg/SYK_yow1yGo/s800/CSGlogicalNot.png" /&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;A &lt;b&gt;CSG common&lt;/b&gt; (also known as 'intersection') operation behaves like a &lt;b&gt;logical AND&lt;/b&gt; operation (&amp;amp;&amp;amp; in C languages) because only the parts that are kept are the ones shared between the two shapes.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src=http://lh3.ggpht.com/_QB2O0HdIQjQ/S-qLd03hXbI/AAAAAAAAAN8/kP7es53iaTM/s800/CSGlogicalAnd.png" /&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;A &lt;b&gt;CSG addition&lt;/b&gt; (also known as 'union') operation behaves like a &lt;b&gt;logical OR&lt;/b&gt; operation (|| in C languages) because all the parts of both shapes in this operation are kept afterwards. &lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_QB2O0HdIQjQ/S-qLipiTSYI/AAAAAAAAAOE/CN3OvNRig3Q/s144/CSGlogicalOr.png" /&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;A &lt;b&gt;CSG subtraction&lt;/b&gt; operation would actually be &lt;b&gt;a combination of AND and NOT&lt;/b&gt; (A&amp;amp;&amp;amp;!B).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_QB2O0HdIQjQ/S-qLoiIJAWI/AAAAAAAAAOU/jFFFqI0Uvok/s144/CSGsubtraction.png" /&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;The pictures have shamelessly been taken from &lt;a href="http://en.wikipedia.org/wiki/Logical_connective"&gt;wikipedia on the topic of logical operators&lt;/a&gt; which interestingly enough showed CSG like pictures! &lt;br /&gt;
(They're actually &lt;a href="http://en.wikipedia.org/wiki/Venn_diagrams"&gt;Venn diagrams&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
Which shows that these things are, in fact, the very same thing! &lt;br /&gt;
(Hmm ... I wonder why I never noticed that before)&lt;br /&gt;
&lt;br /&gt;
Note that logical OR (CSG union) operations can also be expressed as !(!A &amp;&amp; !B), and that I've already shown that CSG subtraction can be expressed as (A &amp;&amp; !B), meaning that all popular CSG operations can be implemented using only NOT and AND operations.&lt;br /&gt;
&lt;br /&gt;
Now consider that a NOT operation would effectively not change the mesh at all, but would only invert the classification of triangles being inside or outside, there would effectively only be one kind of mesh modifying operation left..&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Interesting!&lt;/b&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5096835595802264088?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5096835595802264088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/csg-operations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5096835595802264088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5096835595802264088'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/csg-operations.html' title='CSG operations'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_QB2O0HdIQjQ/S-qOwd-tOsI/AAAAAAAAAPg/SYK_yow1yGo/s72-c/CSGlogicalNot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1986938820192280650</id><published>2010-05-11T11:10:00.012+02:00</published><updated>2011-08-08T16:52:30.764+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Intersection-Testing'/><title type='text'>More random thoughts</title><content type='html'>&lt;b&gt;Random thought 1: GJK / backface culling&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
So I was reading another chapter in my "&lt;a href="http://www.gameenginebook.com/"&gt;Game Engine Architecture&lt;/a&gt;" book, written by Jason Gregory (which, incidentally, is a &lt;i&gt;really good&lt;/i&gt; book), about Physics or more specifically, about the &lt;a href="http://mollyrocket.com/forums/viewtopic.php?t=245"&gt;GJK algorithm&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I've seen the algorithm mentioned before but only glaced over it, not realizing how useful it is, but now I do!&lt;br /&gt;
It's &lt;i&gt;very&lt;/i&gt; useful for doing intersection tests for my CSG algorithm.&lt;br /&gt;
&lt;br /&gt;
Part of the GJK algorithm is finding a point furthest along a particular direction within a convex polytope (which is, basically, the same thing as a CSG brush).&lt;br /&gt;
&lt;br /&gt;
Maybe they're already doing this in real life, but I couldn't help but wonder, why aren't they backface culling polygons (and all it's vertices) using this direction vector?&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Update&lt;/i&gt;: Giving this some more thought makes me think that this won't work.&lt;br /&gt;
When you have relatively few points then all the back face culling operations would take more cycles compared to just going through all points. Yet if you have lots and lots of points you end up having more branching and CPU-cache misses. So ignore this idea.&lt;br /&gt;
&lt;br /&gt;
I wonder if storing vertices into 8 octants, where each octant is a particular direction, and then using the signs of the x,y &amp; z components of the direction vector to pick an octant would work.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Random thought 2: CPU Cache &amp; Component entity systems&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Couldn't help but think that &lt;a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/"&gt;component entity systems&lt;/a&gt;, &lt;a href="http://gamesfromwithin.com/data-oriented-design"&gt;data orientated design&lt;/a&gt; (optimize for CPU cache), block based memory allocations, splitting all the work into tasks (for easy multi-threading) would work &lt;i&gt;really&lt;/i&gt; &lt;i&gt;really&lt;/i&gt; well together, if all where designed together.&lt;br /&gt;
&lt;br /&gt;
After all, component entity systems have lots of lists of similar components on which systems work.&lt;br /&gt;
This is exactly what you'd want to be doing with data based design because it's cache friendly, and it also allows you to break things up into small tasks within the system..&lt;br /&gt;
&lt;br /&gt;
Of course entity systems are traditionally only used for the gameplay code, and usually written in a very flexible (and potentially very slow) way, but I'm wondering if the entire engine could be written around these principles..&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Random thought 3: Each VT Page mip should decrease in size&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In 'traditional' virtual texturing a lower resolution mip of a page contains several lower resolution versions of higher resolution pages, so that each page, no matter what mip, has the same size (for example, 128x128)&lt;br /&gt;
&lt;br /&gt;
This is useful because you can more easily mix different pages of different mip levels within the GPU page cache, and this is fine.&lt;br /&gt;
&lt;br /&gt;
I've been wondering though, should we really be doing the same on the disk side?&lt;br /&gt;
&lt;br /&gt;
After all, we could just update the pieces of a lower resolution mip page in the GPU cache, instead of loading the entire mip, which would include an incrementally larger virtual texture area the lower resolution the mip level is.&lt;br /&gt;
&lt;br /&gt;
This would all not be a problem if a virtual texture would just be a texture, but it isn't.&lt;br /&gt;
It's a texture management system, or a texture atlas at best.&lt;br /&gt;
&lt;br /&gt;
There are a lots of seems within the virtual texture where individual mip pages contain pieces of texture that, within the level, can be very far apart.&lt;br /&gt;
&lt;br /&gt;
Only loading the pieces of the mip pages that we need would reduce loading pixels that we're not going to use anyway.&lt;br /&gt;
&lt;br /&gt;
It also makes it easier when compressing the pages, because we can more easily omit channels when they're not being used by a page.&lt;br /&gt;
Before, any used channel would travel up the mip map chain, because one of the higher resolution mips would be using it.&lt;br /&gt;
&lt;br /&gt;
This is all, of course, not an issue for all the pre-cached pages.&lt;br /&gt;
And, in all fairness, the highest resolution pages are always the biggest problem, and this would only optimize loading the lower resolution pages.&lt;br /&gt;
&lt;br /&gt;
All the above issues could also, potentially, be solved by grouping pages within the virtual texture in a more optimal way, but you'd probably end up with a lot of wasted space.&lt;br /&gt;
&lt;br /&gt;
Also compressing pages in 8x8 blocks (or something) and omitting unused channels in those individual blocks would help to avoid the above problems too, and would probably be a good idea anyway.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Random thought 4: Compressing the mip map chain&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I'm also wondering if there are good ways to compress an entire mip map chain together in context, considering that there isn't likely to be too much difference between two mip-map levels.&lt;br /&gt;
&lt;br /&gt;
We're already pre-caching several mip map levels... so, can we leverage that information so that we can decrease the disk size of all the pages that we load on the fly?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1986938820192280650?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1986938820192280650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/more-random-thoughts.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1986938820192280650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1986938820192280650'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/more-random-thoughts.html' title='More random thoughts'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-727246040894672509</id><published>2010-05-06T12:29:00.004+02:00</published><updated>2011-08-08T16:52:53.155+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><category scheme='http://www.blogger.com/atom/ns#' term='Geometry-Image'/><title type='text'>Worldspace shadow-map / virtual texture - another random idea</title><content type='html'>Just a new random, not even a nearly completely thought out idea of mine.&lt;br /&gt;
Which I blame on only having time to dream up these things, but not actually try them $@#!&lt;br /&gt;
Yes, I &lt;i&gt;am&lt;/i&gt; frustrated ;)&lt;br /&gt;
&lt;br /&gt;
Anyway.&lt;br /&gt;
&lt;br /&gt;
Suppose we perform our lighting within our virtual texture cache (aka surface caching), which I've blogged about often, and we store our texel world-space coordinates in the cache, wouldn't we also be able to use this information to do shadow mapping?&lt;br /&gt;
&lt;br /&gt;
The (&lt;b&gt;HUGE&lt;/b&gt;) downside is that we'd need a place to store the texel coordinates even for pages that aren't visible (being able to analytically cull pages and lights would definitely help here... page bounding boxes? bounding volume hierarchies?)&lt;br /&gt;
Would lower resolution mips be enough for lighting? (sometimes?)&lt;br /&gt;
I suppose some sort of preprocessing could help here.. I can imagine that a lot of the geometry that uses a specific page would essentially be flat.&lt;br /&gt;
&lt;br /&gt;
The upside is that we'd only have to render geometry exactly once per frame (or less, with caching), and &lt;i&gt;perhaps&lt;/i&gt; we could be rendering the lighting directly into the cache..&lt;br /&gt;
In which case having the knowledge of all the transparent pages between your texel and the light-source would be &lt;i&gt;interesting&lt;/i&gt;! (&lt;i&gt;Probably&lt;/i&gt; slow as hell though, even &lt;b&gt;IF&lt;/b&gt; you manage to get this to work &lt;i&gt;somehow&lt;/i&gt;)&lt;br /&gt;
&lt;br /&gt;
What about texel world coordinate mip maps? &lt;br /&gt;
Would we need to store min/max coordinates instead of 'just' coordinates?&lt;br /&gt;
Could that be used in a sort of hierarchical z-buffer type of setup somehow?&lt;br /&gt;
For (rough) culling on the CPU side perhaps? &lt;br /&gt;
For both the shadow map and camera?&lt;br /&gt;
That would require us to have the texel coordinates on the CPU side though.. (static geometry only?)&lt;br /&gt;
Preprocessed and stored with the pages? (geometry images?)&lt;br /&gt;
But bandwidth is already an issue... &lt;br /&gt;
Then again, it would probably be very compressible, most of the time.&lt;br /&gt;
At least, for the higher resolution mips..&lt;br /&gt;
&lt;br /&gt;
Argh, too many angles, too many ideas! &lt;br /&gt;
Most of them look extremely impractical to begin with, but it's a lot of fun to think about ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Besides all that, this idea popped in my head:&lt;br /&gt;
If every texel coordinate is unique with virtual texturing, wouldn't we be able to use this, somehow, to eliminate shadow acne? (Assuming you're not using cascaded shadow maps already &amp; this would really be complicated by page mip maps)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-727246040894672509?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/727246040894672509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/worldspace-shadow-map-virtual-texture.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/727246040894672509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/727246040894672509'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/worldspace-shadow-map-virtual-texture.html' title='Worldspace shadow-map / virtual texture - another random idea'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-4444149328414611107</id><published>2010-05-04T08:43:00.005+02:00</published><updated>2011-08-08T16:50:04.061+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Audio'/><category scheme='http://www.blogger.com/atom/ns#' term='Propagation-Volumes'/><title type='text'>Propagation volumes</title><content type='html'>I don't have much time to actually experiment with ideas these days, but I can still find a little time here and there to just let my thoughts go and see where they lead me.&lt;br /&gt;
&lt;br /&gt;
Here's a thought I was playing with yesterday.&lt;br /&gt;
&lt;br /&gt;
Suppose for a minute that we'd have the ultimate computer, memory is so large that it doesn't form any barriers, and CPU and memory speed is high enough to practically do anything we want.&lt;br /&gt;
So 'of course' all assets would consist out of a form of voxels, &lt;br /&gt;
but what about lighting?&lt;br /&gt;
Well all lighting would be performed within very high resolution propagation volumes of course!&lt;br /&gt;
Obviously, the propagation volumes would even handle light reflection, refraction, scattering and absorption.&lt;br /&gt;
&lt;br /&gt;
This led me to the following, more interesting, idea.. what about audio?&lt;br /&gt;
&lt;br /&gt;
Now I should mention that I'm nowhere near an expert on audio, so take this with a grain of salt, but audio is in the frequency domain, right?&lt;br /&gt;
Well, so are the spherical harmonics used in light propagation volumes!&lt;br /&gt;
Hmm.. doesn't that mean it should be possible to perform audio within a propagation volume-esque solution?&lt;br /&gt;
&lt;br /&gt;
Just imagine being able to simulate how audio behaves within a scene, with reflections etc.!&lt;br /&gt;
I have no idea though which x-th order spherical harmonics, or what resolution of the volume would be "enough", nor do I have any idea how good this would sound.&lt;br /&gt;
&lt;br /&gt;
But it sure sounds cool.&lt;br /&gt;
Err.. If you know what I mean.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-4444149328414611107?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/4444149328414611107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/propagation-volumes.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/4444149328414611107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/4444149328414611107'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/05/propagation-volumes.html' title='Propagation volumes'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5904117703804883596</id><published>2010-04-28T15:18:00.012+02:00</published><updated>2011-08-08T16:49:11.174+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><title type='text'>Rendering into virtual texture using indirection table</title><content type='html'>I mentioned an idea in the past where lighting would be performed into the GPU side cache of the virtual texture.&lt;br /&gt;
&lt;br /&gt;
This would have some advantages, such as when you render to the scene, you basically only need to render a single texture, have perfect filtering and being able to render everything using standard anti-aliasing techniques (compared to, for example, deferred rendering).&lt;br /&gt;
Blur pages the right way and you can fake skin subsurface scattering..&lt;br /&gt;
Proper transparency with lighting would be a lot simpler too!&lt;br /&gt;
&lt;br /&gt;
Of course there are downsides as well.. (Can you say post processing?)&lt;br /&gt;
&lt;br /&gt;
One of the bigger fundamental problems with this approach is that you need to, somehow, know the positions of your pixels within your cache texture.&lt;br /&gt;
&lt;br /&gt;
Before I was thinking along the lines of rendering into the cache texture using predefined batches of geometry per page.&lt;br /&gt;
Which requires a lot of preprocessing, costs a lot of memory or complicated schemes and would require you to either render the same batch to different mip levels, or have monolithic batches (where you'd basically be rendering &lt;i&gt;EVERYTHING&lt;/i&gt;) for the highest mip levels (which would be &lt;i&gt;ridiculous&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
But now I realized it might be better to limit each triangle to a single page, and then to render the scene into the cache texture using the indirection table to transform the triangle to the right page with the right size!&lt;br /&gt;
&lt;br /&gt;
It has some annoying issues though, it needs per vertex texture coordinates or a geometry shader, but it should work.&lt;br /&gt;
The caching of pixels-in-page-coordinates wouldn't be as straight forward either.&lt;br /&gt;
&lt;br /&gt;
That said, I consider this surface caching idea just a (fun!) thought experiment.&lt;br /&gt;
For anything serious, I'd use a deferred renderer!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5904117703804883596?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5904117703804883596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/rendering-into-virtual-texture.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5904117703804883596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5904117703804883596'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/rendering-into-virtual-texture.html' title='Rendering into virtual texture using indirection table'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5397736809326692257</id><published>2010-04-21T11:17:00.004+02:00</published><updated>2011-08-08T16:44:51.031+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual Texturing Thesis from Andreas Neu</title><content type='html'>So last Friday I received an email from Andreas Neu who wrote his bachelor thesis about virtual texturing.&lt;br /&gt;
He was advised at the RWTH Aachen university by my good friend &lt;a href="http://volcore.limbicsoft.com/"&gt;Volker Schoenefeld&lt;/a&gt;, and he told him I would probably be interested in his thesis, which I obviously was!&lt;br /&gt;
It cannot be found online (yet?), so I can't provide a link unfortunately.&lt;br /&gt;
Hopefully when or if it'll be placed online, I can provide a link to it here.&lt;br /&gt;
&lt;br /&gt;
In his thesis he investigated which page priority heuristic would be better at choosing which page to load next, by measuring which would have the most positive visual impact.&lt;br /&gt;
&lt;br /&gt;
He tried a couple of variations of what he calls "PixelSum", where he counts the number of visible pixels of a specific page (a technique I mentioned before on the blog), which performed surprisingly well.&lt;br /&gt;
He also provided some tweaks on "PixelSum" which improved it's performance when moving the camera, but which didn't have that much impact while rotating the camera, which is actually the worst case.&lt;br /&gt;
&lt;br /&gt;
Another thing he tried was a "look ahead camera", which basically doubled the rotation and translations of the current frame compared to the previous frame, and used that new transformation for the readback buffer, which he calls a "needbuffer" in his thesis&lt;br /&gt;
This seemed to provide better or same performance in the worst cases, but sometimes slightly worse in the best cases.&lt;br /&gt;
&lt;br /&gt;
The best idea, however, is what he calls "NoiseValues".&lt;br /&gt;
Here he compared his pages to it's lower mipmaps, using a rooted MSE on their luminance, and using that value as a weight to determine which pages would have the most visual difference between miplevels.&lt;br /&gt;
That same weight can then be used to determine which pages would have the biggest visual impact on the scene when loaded.&lt;br /&gt;
&lt;br /&gt;
Personally I'd love to see more stuff like this, and I think there are a lot of interesting possibilities that continue on some of the ideas put forth by Andreas!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
P.S. Still haven't found any time to continue on the whole CSG thing, but don't worry, I'll continue on it when I have some time! (Too much work, too many clients, where's the recession when you need it!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5397736809326692257?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5397736809326692257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/virtual-texturing.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5397736809326692257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5397736809326692257'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/virtual-texturing.html' title='Virtual Texturing Thesis from Andreas Neu'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3530510129423049990</id><published>2010-04-03T11:29:00.002+02:00</published><updated>2011-08-08T16:36:18.221+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Just a tiny update</title><content type='html'>&lt;i&gt;Finally&lt;/i&gt; had some time yesterday to put all the individual generic CSG components that I made together, write a simple 3d view test app, and test it.&lt;br /&gt;
And after fixing a couple of tiny issues, it worked like a charm!&lt;br /&gt;
Now I only need to do a couple of more tests, and then I can write the next part in the CSG series&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3530510129423049990?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3530510129423049990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/just-tiny-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3530510129423049990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3530510129423049990'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/04/just-tiny-update.html' title='Just a tiny update'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-736165151048246084</id><published>2010-03-13T10:34:00.005+01:00</published><updated>2011-08-08T16:40:16.019+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>CSG woes</title><content type='html'>So, as I mentioned before, the algorithm I used in &lt;a href="http://video.google.com/videoplay?docid=-1907574989981648678#"&gt;my editor&lt;/a&gt; used a simplified CSG implementation.&lt;br /&gt;
When I started blogging about CSG I thought, how hard could it be to turn this into a full implementation? &lt;br /&gt;
Easy, right?&lt;br /&gt;
&lt;br /&gt;
Boy was I wrong.&lt;br /&gt;
&lt;br /&gt;
My old implementation only supported subtractive and additive brushes and didn't supporting any grouping of brushes. This made it possible to put all the brushes in a single list and let the brushes BE the CSG operation themselves.&lt;br /&gt;
In a full implementation things get way more complicated, mainly because of the grouping of brushes and the tree like CSG structure which results out of that.&lt;br /&gt;
&lt;br /&gt;
The cool thing about CSG is that, except the brush splitting method, it actually works exactly the same in 3D as it does in 2D.&lt;br /&gt;
So I made a tool to perform CSG in 2D to build an CSG implementation which I could then, once I've got it to work, transfer to a 3D implementation.&lt;br /&gt;
After all, 2D is much much easier to debug and visualize. &lt;br /&gt;
&lt;br /&gt;
Anyway, my theory to get a full real-time CSG implementation working is like this.&lt;br /&gt;
First of all, each brush is processed separately so we can not only perform these operations in parallel, but also update individual brushes without needing to reprocess everything.&lt;br /&gt;
&lt;br /&gt;
Since in any CSG implementation the resulting mesh would only included portions of the original polygons created from the original brushes, no new polygons would be created.&lt;br /&gt;
This means we can use our brushes and operations as a sort of query over the polygons of these same brushes. &lt;br /&gt;
We 'just' pass our polygons through our CSG tree and determine which pieces are visible and which ones are removed.&lt;br /&gt;
&lt;br /&gt;
At a higher level the CSG tree could be simplified on a per brush basis and some space partitioning data structure could be used to avoid unneeded calculations, but I haven't got to that point yet.&lt;br /&gt;
&lt;br /&gt;
Our brush splitting method will tell us which lines are inside/outside or touching and if we make sure that at every stage in our tree we correctly determine if the given polygons is inside/outside or touching then we should end up with the correct polygons. &lt;br /&gt;
&lt;br /&gt;
The inside/outside part is relatively easy, it gets hard with the touching part though.&lt;br /&gt;
&lt;br /&gt;
Take for instance the following simple situation with an additive operation and two brushes:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_QB2O0HdIQjQ/S5tOy8UvSQI/AAAAAAAAAM8/zX9OOOn5FkM/s1600-h/additive_brushes.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_QB2O0HdIQjQ/S5tOy8UvSQI/AAAAAAAAAM8/zX9OOOn5FkM/s1600/additive_brushes.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
In the left situation we want to treat the parts of the polygons that touch as being "inside" this particular branch of the CSG tree, on the right we want to keep the touching polygons.&lt;br /&gt;
&lt;br /&gt;
Well we actually want to remove it for the left brush and keep it for the right brush, but this can be solved by detecting if surfaces on the left and right brush overlap, and then only keeping the polygons that belong to the last brush that overlaps.&lt;br /&gt;
&lt;br /&gt;
We can solve this by taking the relative orientation of the polygons into account;&lt;br /&gt;
If they're opposites, remove them, if they're aligned, keep them.&lt;br /&gt;
&lt;br /&gt;
For subtractive operations it gets more complicated: &lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_QB2O0HdIQjQ/S5tO30gWj_I/AAAAAAAAANA/EmPNZeSAQtY/s1600-h/subtractive_brushes.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_QB2O0HdIQjQ/S5tO30gWj_I/AAAAAAAAANA/EmPNZeSAQtY/s1600/subtractive_brushes.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
In the left situation I'm doing something which may be debatable.&lt;br /&gt;
When the subtractive brush touching another brush on the outside, I keep that polygon part because I want the subtractive brush to be able to override the underlying brush.&lt;br /&gt;
&lt;br /&gt;
In the right situation not only do we keep all the polygons of the subtractive brush that are inside (we remove all the polygons that are outside), but we need to change the orientation of the polygons too!&lt;br /&gt;
&lt;br /&gt;
This brings me to the biggest problem with CSG trees; the number of polygons increase, because of splits, as you go down the tree!&lt;br /&gt;
This works fine as long as you work with a single list of nodes, like in my old algorithm, but when you have a tree like data structure this causes lots of problems.&lt;br /&gt;
&lt;br /&gt;
Suppose I first categorize my polygons in the left branch into inside/outside/touching-inside/touching-outside categories, what happens if I then try to categorize those same polygons in the right branch?&lt;br /&gt;
The original polygons could actually be split into lots of new pieces, and I have no easy way to match them together! (Certainly not in a hierarchy that's x-levels deep)&lt;br /&gt;
&lt;br /&gt;
Even if I find a good way to handle this, imagine what happens a polygon's orientation is changed in the right branch, it would've been categorized wrongly in the left!&lt;br /&gt;
This probably means I have to determine the orientation of a touching polygon at the very last moment, but that would require me to pass along additional information like which plane it was touching.&lt;br /&gt;
&lt;br /&gt;
Right now I 'solve' this by going through the CSG tree and splitting functions several times, but to say that this is inefficient would be an understatement..&lt;br /&gt;
&lt;br /&gt;
I'm playing with some ideas, like building some sort of categorization tree, but they're not fully gestated just yet.&lt;br /&gt;
&lt;br /&gt;
I'm close, but I'm not there just yet.&lt;br /&gt;
&lt;br /&gt;
Edit: &lt;br /&gt;
It's funny how writing things down often helps you find an answer to a problem!&lt;br /&gt;
This is my solution:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;Categorize(branch.Left, ... );

//for each category
foreach(var polygon in myCategory)
{
    Categorize(branch.Right, ... );

    // now, even if the polygon has been split, 
    // we know the category of all polygons
    // in both the left and right branch!
} 
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-736165151048246084?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/736165151048246084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/csg-woes.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/736165151048246084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/736165151048246084'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/csg-woes.html' title='CSG woes'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QB2O0HdIQjQ/S5tOy8UvSQI/AAAAAAAAAM8/zX9OOOn5FkM/s72-c/additive_brushes.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-4995156317070255639</id><published>2010-03-10T21:39:00.002+01:00</published><updated>2011-08-08T16:49:37.908+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subdivision-Surfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='Ptex'/><title type='text'>Ptex</title><content type='html'>Through Google Buzz, Bryan McNett mentioned &lt;a href="http://www.disneyanimation.com/library/ptex/"&gt;Ptex&lt;/a&gt; to me, which I missed somehow.&lt;br /&gt;
&lt;br /&gt;
It's an interesting approach to texture a model without having to use any parameterization.&lt;br /&gt;
Now obviously this has been written with Renderman in mind, but I'm pretty sure it could be used in an art-pipeline which would triangulate the subdivision surfaces somewhere in the art pipeline (or use dx11), and put all the texturing into a virtual texture.&lt;br /&gt;
Obviously it would waste some texture space, but it would sure make the life of artists a lot easier.&lt;br /&gt;
It'll free up time for them to do what they do best; art!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Still working on the next part of my real-time CSG articles but I need my test code to work flawlessly on all my test cases (and there are oh so many of them), and debugging a full CSG implementation takes *a lot* of time I'm afraid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-4995156317070255639?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/4995156317070255639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/ptex.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/4995156317070255639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/4995156317070255639'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/ptex.html' title='Ptex'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1395090427782369887</id><published>2010-03-02T11:29:00.003+01:00</published><updated>2011-08-08T16:40:15.953+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Part 4</title><content type='html'>In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;part 1&lt;/a&gt; I explained the basics you'll need to know to understand how to perform real-time CSG.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html"&gt;part 2&lt;/a&gt; I described how to build a brush, which is the basic building block of the algorithm I'm describing.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html"&gt;part 3&lt;/a&gt; I wrote about CSG operations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As I mentioned in my &lt;a href="http://sandervanrossen.blogspot.com/2010/01/first-post-of-year.html"&gt;first post of the year&lt;/a&gt;; The most important thing to realize is that when you're performing CSG with multiple brushes, no matter which operations you perform, or how you group your brushes, the final mesh you'll end up with will always consist out of (parts of) the original polygons, which where made out of our brushes.&lt;br /&gt;
Only parts of these original polygons are removed, no new polygons need to be created, ever.&lt;br /&gt;
&lt;br /&gt;
So in the end, we basically need to manage which parts will be visible or invisible depending on the situation.&lt;br /&gt;
&lt;br /&gt;
At the end of &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html"&gt;part 3&lt;/a&gt; I said that in the next blog post I would write about how to traverse the operations list.&lt;br /&gt;
Well, before I we get to that part I need to explain how to cut up a brush into the right pieces.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Cutting the brush&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;part 1&lt;/a&gt; I wrote about cutting polygons.&lt;br /&gt;
Cutting a brush is a natural extension to that.&lt;br /&gt;
&lt;br /&gt;
The algorithm is pretty straight forward; for every brush you intersect with, cut each polygon of your brush with the planes of the intersecting brush.&lt;br /&gt;
&lt;br /&gt;
All the pieces that are on the outside of the polygon are classified as "outside".&lt;br /&gt;
At the end, if there's anything left of the original polygon, then that's either "inside" or "touching-inside" or "touching-outside".&lt;br /&gt;
&lt;br /&gt;
The polygon is "touching" when all the points of the polygon lie on one of the planes of the intersecting brush.&lt;br /&gt;
By comparing the normal of the polygon and the touching plane you can determine if it's "touching-inside" (normals are pointing in the same direction) or "touching-outside" (normals point in opposite directions).&lt;br /&gt;
You can use a dot product between the normals for this.&lt;br /&gt;
If the result of the dot product is positive, they're pointing in the same direction, if it's negative they're opposites.&lt;br /&gt;
Obviously if it's not touching, it's "inside".&lt;br /&gt;
&lt;br /&gt;
Depending on the situation you'd need to discard your polygon pieces if it's inside/touching-inside/touching-outside or 'just' outside.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Next time&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
That's all I have time for today, the &lt;a href="http://sandervanrossen.blogspot.com/2010/05/realtime-csg-part-5.html"&gt;next time&lt;/a&gt; I'll go through the algorithm for general CSG.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1395090427782369887?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1395090427782369887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/realtime-csg-part-4.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1395090427782369887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1395090427782369887'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/03/realtime-csg-part-4.html' title='Realtime CSG - Part 4'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6222553761683758586</id><published>2010-02-04T10:09:00.000+01:00</published><updated>2011-08-08T16:47:22.250+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>"Efficient Irradiance Normal Mapping"</title><content type='html'>Quote:&lt;br /&gt;
"Irradiance normal mapping is a method to combine two popular techniques, light mapping and normal mapping, and is used in games such as Half-Life 2 or Halo 3. This combination allows using low-resolution light caching on surfaces with only a few coefficients which are evaluated by normal maps to render spatial high-frequency changes in the lighting."&lt;br /&gt;
&lt;br /&gt;
Now that sounds like it might work in combination with the virtual texturing surface caching idea!&lt;br /&gt;
Not sure about it's performance though, which is rather crucial.&lt;br /&gt;
&lt;br /&gt;
You can find the paper &lt;a href="http://www.cg.tuwien.ac.at/research/publications/2010/Habel-2010-EIN/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6222553761683758586?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cg.tuwien.ac.at/research/publications/2010/Habel-2010-EIN/' title='&quot;Efficient Irradiance Normal Mapping&quot;'/><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6222553761683758586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/02/efficient-irradiance-normal-mapping.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6222553761683758586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6222553761683758586'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/02/efficient-irradiance-normal-mapping.html' title='&quot;Efficient Irradiance Normal Mapping&quot;'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3568686214631344046</id><published>2010-02-01T10:54:00.000+01:00</published><updated>2011-08-08T16:45:43.990+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Random-Idea'/><title type='text'>Random thought</title><content type='html'>Just had a random thought concerning game component object systems.&lt;br /&gt;
&lt;br /&gt;
If the system is optimized to quickly add and remove components, then an event system could be realized by adding and removing components.&lt;br /&gt;
So instead of having a complex event system to send events between components, you would add a specialized component that performs or represents the event.&lt;br /&gt;
The component would then be removed when the event is processed.&lt;br /&gt;
Not entirely sure how flexible it would be, but it would sure be easier to optimize for cache and multiple threads.&lt;br /&gt;
&lt;br /&gt;
Yes, this blog has been neglected lately, I'm going to give it some attention again soon (I hope).&lt;br /&gt;
Real life has simply thrown several projects my way which is taking all my time at the moment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3568686214631344046?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3568686214631344046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/02/random-thought.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3568686214631344046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3568686214631344046'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/02/random-thought.html' title='Random thought'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8124171302431656319</id><published>2010-01-18T09:56:00.000+01:00</published><updated>2010-01-18T09:56:25.689+01:00</updated><title type='text'>615 bits should be enough for everyone</title><content type='html'>Here's &lt;a href="http://www.wolframalpha.com/input/?i=ceil(log2(volume+of+the+observable+universe+/+planck+volume))"&gt;the proof&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8124171302431656319?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8124171302431656319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/01/615-bits-should-be-enough-for-everyone.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8124171302431656319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8124171302431656319'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/01/615-bits-should-be-enough-for-everyone.html' title='615 bits should be enough for everyone'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1320478212286386186</id><published>2010-01-04T15:49:00.002+01:00</published><updated>2011-08-08T16:40:15.949+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>First post of the year</title><content type='html'>Happy new year!&lt;br /&gt;
Let's all hope this decade will lead us all towards a better path compared to the last one.&lt;br /&gt;
&lt;br /&gt;
Lately most of my time, that I haven't spend with my family, has gone to my secret project&amp;trade;, but between all this I managed to sneak in some time for my other projects.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Real-time CSG&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
It's not full proof yet (there are some issues with duplicates), and only 2d (the basics are the same), but I've managed to come up with an algorithm that can perform CSG on each brush individually with a full CSG-tree implementation.&lt;br /&gt;
&lt;br /&gt;
My old algorithm just added brushes together in a list.&lt;br /&gt;
Subtractive brushes where basically inverted and would work automatically.&lt;br /&gt;
The adding of subtractive brushes and additive brushes only differed when it came to brushes touching each other.&lt;br /&gt;
&lt;br /&gt;
I'll explain the new algorithm it in detail eventually, when I finish it, but the basic thinking behind it is that with any CSG operation you perform on any mesh, that the resulting mesh will ALWAYS have the same polygons or with some pieces of these polygons removed.&lt;br /&gt;
&lt;br /&gt;
This means that you never ever have to create new polygons, you just need to figure out which parts will need to be visible, and which polygons need their vertex order inverted.&lt;br /&gt;
&lt;br /&gt;
If you consider a CSG-tree to be a sort of iterative query, where for every polygon you go trough the query and determine which parts of it are inside, outside or touching, then eventually you'll end up with all the parts that are visible.&lt;br /&gt;
&lt;br /&gt;
Update: Figured out that if you give each node an index and pass the index of the node the current polygon belongs along with you while you traverse the CSG-tree.&lt;br /&gt;
Then you can compare this index with the current brush you're splitting with, which makes it possible to decide which overlapping polygon must be discarded, and which one must be kept!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Surface caching&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Spherical harmonics won't work for storing specular highlights in a surface cache, I'm hoping the "half-life 2 basis" explained in the "&lt;a href="http://www.valvesoftware.com/publications/2004/GDC2004_Half-Life2_Shading.pdf"&gt;half-life 2 shading paper&lt;/a&gt;" might do the trick.&lt;br /&gt;
I'm afraid it won't be accurate enough though.&lt;br /&gt;
&lt;br /&gt;
There are also some really annoying inefficiencies in the whole virtual texture/surface cache idea, like having to render the geometry position into a buffer, which would require anything that moves to re-render it's position.&lt;br /&gt;
This could perhaps be done only once, when rigid bodies are concerned, by transforming the light instead of the world-positions of the texels.&lt;br /&gt;
This won't help when skinned characters are concerned though, they will need their positions rendered into the page cache and lighting re-calculated every frame.&lt;br /&gt;
I wonder if there's a way around this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1320478212286386186?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1320478212286386186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2010/01/first-post-of-year.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1320478212286386186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1320478212286386186'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2010/01/first-post-of-year.html' title='First post of the year'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8220369194353697237</id><published>2009-12-13T16:08:00.008+01:00</published><updated>2011-08-08T16:49:11.189+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Just a quick update</title><content type='html'>&lt;b&gt;Deferred Virtual Texture Shading&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I've &lt;a href="http://sandervanrossen.blogspot.com/search/label/surface%20caching"&gt;blogged about this idea before&lt;/a&gt;, using a virtual texture cache as a sort of g-buffer, and this has some advantages (I'm not going to re-iterate these again, just read my older posts if you want to know more).&lt;br /&gt;
&lt;br /&gt;
Frankly it's simply a dynamic form of &lt;a href="http://en.wikipedia.org/wiki/Surface_caching"&gt;surface caching&lt;/a&gt;, so I decided I'll start calling this idea "dynamic surface caching" instead of "deferred virtual texture shading", which is a horrible name for it anyway.&lt;br /&gt;
&lt;br /&gt;
Anyway, today &lt;a href="http://solid-angle.blogspot.com/2009/12/screen-space-spherical-harmonic.html"&gt;I read a blog post&lt;/a&gt; about an idea where a &lt;a href="http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html"&gt;light pre-pass renderer&lt;/a&gt; is implemented using spherical harmonics.&lt;br /&gt;
This made me realize that with my dynamic surface caching idea, the lighting of the surfaces could be stored as SH coefficients as well, de-coupling it from the view direction, which would make the cache idea more useful.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Realtime CSG&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
When I implemented &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;the realtime CSG algorithm I've been blogging about&lt;/a&gt;, I was mainly concerned with getting it to work, getting it stable and making it perform fast, not so much with code readability (it was a prototype anyway).&lt;br /&gt;
Since I needed to explain it in a coherent way (or at least I &lt;i&gt;try&lt;/i&gt; to) I needed to figure out all the peculiar details I put in code a year ago, and figure out how to communicate all this in an effective way.&lt;br /&gt;
&lt;br /&gt;
This actually gave me some new insights and ideas.&lt;br /&gt;
My original implementation only had additive and subtractive brushes, no 'common' brushes, and the CSG operation was tied with the brush, making a complete CSG hierarchy impossible.&lt;br /&gt;
&lt;br /&gt;
It worked really well for it's purpose (seriously, you probably wouldn't want to directly expose this kind of functionality in an editor anyway), but I have some ideas on how to generalize it, possibly make it more efficient, and definitely make it more readable and accessible.&lt;br /&gt;
So I need to do some tests and get some code working before I can continue with the blog posts about it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Unfortunately this is a very busy time for me at the moment.&lt;br /&gt;
Clients with lot's of deadlines (meaning I need to do some work at home as well), a top secret project I'm working on with some friends of mine, preparing for Christmas, wife wanting me to do all kinds of home improvement stuff, and my daughter obviously wanting some attention between all this as well ..&lt;br /&gt;
&lt;br /&gt;
But I &lt;i&gt;should&lt;/i&gt; have more time to code around Christmas itself!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8220369194353697237?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8220369194353697237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/just-quick-update.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8220369194353697237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8220369194353697237'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/just-quick-update.html' title='Just a quick update'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2175361373816426222</id><published>2009-12-07T10:49:00.008+01:00</published><updated>2011-08-08T16:40:15.971+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Part 3</title><content type='html'>In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;part 1&lt;/a&gt; I explained the basics you'll need to know to understand how to perform real-time CSG.&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html"&gt;part 2&lt;/a&gt; I described how to build a brush, which is the basic building block of the algorithm I'm describing.&lt;br /&gt;
&lt;br /&gt;
This time I'll start explaining some parts of my CSG algorithm.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;CSG Operations&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Now that we've created our brushes, we want to build larger meshes with them.&lt;br /&gt;
We do that by performing certain operations between them, these are similar &lt;br /&gt;
to regular algebra because their order matters greatly and you really want &lt;br /&gt;
to be able to group them together.&lt;br /&gt;
&lt;br /&gt;
Formally there are 3 types of CSG operations:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Addition, sometimes called 'Union' or 'Merge'.&lt;/li&gt;
&lt;li&gt;Subtraction, sometimes called 'Difference'.&lt;/li&gt;
&lt;li&gt;Common, sometimes called 'Intersection' or, confusingly 'Union'.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
At each operation we determine which pieces of each mesh is inside, outside or is touches the other mesh. (Something I'll be blogging about eventually)&lt;br /&gt;
(A brush 'touches' another brush when one of it's polygons lies exactly on the plane of the other brush)&lt;br /&gt;
Depending on the type of operation these polygon pieces are either discarded or kept.&lt;br /&gt;
&lt;br /&gt;
Since you almost never would want to perform a 'common' CSG operation on anything but a small number of brushes, you really need to group brushes together.&lt;br /&gt;
This is also, to a lesser degree, true for subtractive brushes.&lt;br /&gt;
This means you'll need some sort of tree structure so you can determine what operation to perform on and with which brushes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Divide and conquer&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
So do we need to perform those operations on all brushes for each brush?&lt;br /&gt;
Fortunately not!&lt;br /&gt;
&lt;br /&gt;
The trick is that for each brush, using some sort of bounding volume hierarchy, you determine which brushes intersect or touch your brush, and then put them into a list (let's call it an operations list) which is also sorted by the order in which they appear in your CSG tree.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So now that you have a list of operations to perform on each brush, on a per brush granularity.&lt;br /&gt;
This means that when a brush is added, deleted, moved or is modified, only that brush and the brushes it touches need to be rebuild, this is the part that makes this algorithm real-time.&lt;br /&gt;
This also makes it easier to perform each brush update in parallel, which will make this algorithm faster and faster the more cores a CPU has!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Early outs&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Keep in mind that you can drastically shorten your operations list by having some intelligent early-outs.&lt;br /&gt;
For example, if the brush your working on is inside another additive brush, which is further on in your CSG-tree, then you know that you can just discard the entire brush (because anything you do will be deleted further on in the tree anyway). &lt;br /&gt;
In the reverse you can also just ignore the smaller brush when processing the larger brush because it'll never have any effect on this brush.&lt;br /&gt;
There are many cases like this, but be careful with this, I've tried a lot of early-outs which seemed to work most of the time but then broke down on a rare situation!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;User interface limitations&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In my editor I never implemented the CSG-grouping of brushes because it's really hard from an user-interface point of view.&lt;br /&gt;
&lt;br /&gt;
In an editor you really want to group brushes semantically (for example all the brushes that form a 'door' or 'window') instead based on operation (artists aren't programmers after all, nor should we burden them with technicalities; they need to focus on their art, not their editor!).&lt;br /&gt;
If you try to implement this sort of functionality in an editor, you'll get an extra level of complexity which will really make your editor harder to use and understand.&lt;br /&gt;
That said, it shouldn't be too hard to implement because from the algorithms' point of view, it only effects the building of that operations list I was talking about earlier.&lt;br /&gt;
&lt;br /&gt;
Nothing is stopping you from implementing a full implementation and not necessarily exposing all the functionality (all the time) in your editor, if you're building something which doesn't require an editor this is not so much of a problem obviously.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Processing a brush&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To process each brush, we need to traverse the operations list.&lt;br /&gt;
Both parts of it.&lt;br /&gt;
&lt;br /&gt;
The thing is, all the brushes that are ahead of our brush in the hierarchy, need to be handled differently than the brushes that come after it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Which is exactly what I'll be blogging about &lt;a href="http://sandervanrossen.blogspot.com/2010/03/realtime-csg-part-4.html"&gt;next time&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2175361373816426222?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2175361373816426222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2175361373816426222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2175361373816426222'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html' title='Realtime CSG - Part 3'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1095264308774982004</id><published>2009-12-02T09:55:00.017+01:00</published><updated>2011-08-08T16:40:15.940+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Part 2</title><content type='html'>This is part 2, you can find &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;part 1 here&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;Last time&lt;/a&gt; I told a bit about numerical stability, and the importance of consistency when dealing with geometry.&lt;br /&gt;
I also mentioned that in my CSG algorithm I represent my geometry in &lt;a href="http://www.flipcode.com/archives/The_Half-Edge_Data_Structure.shtml"&gt;half-edges&lt;/a&gt; and described an algorithm that cuts a polygon using another &lt;a href="http://en.wikipedia.org/wiki/Plane_(geometry)"&gt;plane&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Now I'm going to explain how to build the geometry of a brush, which is the most basic primitive in my CSG algorithm. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Brushes&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
A brush is a &lt;a href="http://en.wikipedia.org/wiki/Convex_polytope"&gt;Convex Polytope&lt;/a&gt;, which is essentially a list of planes.&lt;br /&gt;
You create geometry from a brush by calculating all the intersections (which will be our vertices) of these planes, and creating our half-edges and polygons from these.&lt;br /&gt;
&lt;br /&gt;
But before we begin, a word of advise.&lt;br /&gt;
You have to make sure that your data is clean otherwise you'll run into all kinds of wonderfully weird bugs.&lt;br /&gt;
What you really need to check for, and you should write some code to do this, that you don't have any duplicate planes, or planes that are -almost- the same.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So how do we build geometry and half-edges from this set of planes? &lt;br /&gt;
There are two methods that I know of.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The "standard" way&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The first one is the most commonly used in game engines:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;You create a big polygon by &lt;a href="http://en.wikipedia.org/wiki/Projection_(linear_algebra)"&gt;projecting&lt;/a&gt; an axis-aligned rectangle onto each plane, which is aligned by the most major axis of the &lt;a href="http://en.wikipedia.org/wiki/Surface_normal"&gt;normal&lt;/a&gt; of the plane.&lt;/li&gt;
&lt;li&gt;You then cut this polygon up, using the polygon split method i described in &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html"&gt;my previous post&lt;/a&gt;, using all the other planes in your brush.&lt;/li&gt;
&lt;li&gt;You then merge all the half-edges and turn it into a proper mesh.&lt;/li&gt;
&lt;/ul&gt;Now the problem I have with this method is that first of all, it works the best when your brush is at the center in worldspace, the moment your brush is placed beyond the size of your axis-aligned rectangle it'll fall apart.&lt;br /&gt;
You can of course make that rectangle really large, but the problem with that is that when you mix numbers that are both very large and very small that your floating point errors will end up getting worse. &lt;br /&gt;
Another problem is that at the end you need to start to merge your vertices, which means comparing coordinates which is dangerous because floating point calculations are not exact, and you might end up either merging vertices that shouldn't be merged, or end up not merging vertices that should.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The "precise" way&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The above method might very well be good enough for some applications, but I prefer a different, more complicated method.&lt;br /&gt;
It's a complicated SOB, so if I'm too fuzzy about some details, please let me know.&lt;br /&gt;
Keep in mind that you need to understand half-edges before you can comprehend this algorithm!&lt;br /&gt;
&lt;br /&gt;
In the first step we calculate all the intersections of all the planes, and we make sure those intersections also lie on the inside or on all the other planes, because some planes also intersect somewhere outside the brush.&lt;br /&gt;
&lt;br /&gt;
So at this moment you might be thinking "How can we possibly create polygons out of that??", "And how can that possibly be more accurate than the above method?" or "Maybe I should get some coffee..."&lt;br /&gt;
Now, I can't help you with the coffee, but bear with me, all will be revealed.&lt;br /&gt;
(Good thing I didn't accidentally write down "&lt;i&gt;bare with me, all will be revealed&lt;/i&gt;"!)&lt;br /&gt;
&lt;br /&gt;
Let's go over what information we have at every intersection:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;We have the location of the intersection&lt;/li&gt;
&lt;li&gt;We know which planes intersect at each vertex&lt;/li&gt;
&lt;li&gt;We know that each plane will create 1 polygon&lt;/li&gt;
&lt;li&gt;We know that where two planes intersect, we'll have an edge&lt;/li&gt;
&lt;li&gt;We know that each edge will have two vertices&lt;/li&gt;
&lt;/ul&gt;(Well actually a plane may actually only intersect at 0, 1 or 2 vertices, in which case you should just drop the plane.)&lt;br /&gt;
&lt;br /&gt;
So now if you visualize this, you'll have multiple edges (defined by a pair of planes) ending at your vertex.&lt;br /&gt;
So, at this moment in time we only know one side of the edge.&lt;br /&gt;
Hmm... that sounds familiar.. that almost sounds like.. a half-edge!&lt;br /&gt;
&lt;br /&gt;
Now look at this picture:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_QB2O0HdIQjQ/SxdpFS16_eI/AAAAAAAAALQ/5L_HW9paMn8/s1600/HalfEdges.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_QB2O0HdIQjQ/SxdpFS16_eI/AAAAAAAAALQ/5L_HW9paMn8/s1600/HalfEdges.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
The green arrows are the half-edges we can build for every vertex.&lt;br /&gt;
The Red arrows are the half-edges that we know would be build for other vertices, but we don't know them yet.&lt;br /&gt;
However, we know that the edge formed by a pair of red/green arrows would share the same pair of planes (A/B , B/C and A/C in this case), so we can use that information to link both sides together!&lt;br /&gt;
&lt;br /&gt;
The next issue is then, how to put the half-edges in order?&lt;br /&gt;
If you look at the picture, what do we know about our edges:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;We now know both half-edges on each full-edge&lt;/li&gt;
&lt;li&gt;We know that we'll have two full-edges on each plane (let's call them E &amp; F)&lt;/li&gt;
&lt;li&gt;We know that E will go to F -OR- F will go to E.&lt;/li&gt;
&lt;li&gt;We know both full-edges on a plane share one vertex, but only one of these full-edges will be on that plane/polygon, so either E or F will not have this vertex.&lt;/li&gt;
&lt;li&gt;We know that the order of half-edges or vertices in a polygons are consistent (clockwise or anti-clockwise)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
So if we check the orientation of E going to F and F going to E, one of them will have the 'correct' orientation (which depends on how you define the order of your polygons).&lt;br /&gt;
After that it's a just matter of setting a pointer from one to the other.&lt;br /&gt;
&lt;br /&gt;
Theoretically you could probably get away with only checking the orientation of 2 edges, and then using that information to iteratively build the edges around the edges with known orientation, it would probably be pretty complex and I haven't tried this.&lt;br /&gt;
It would, however, be more accurate.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that if you can't find 2 full-edges on the same plane, then you're dealing with a plane that only intersects at an edge and needs to be dropped.&lt;br /&gt;
&lt;br /&gt;
Once you've done that, the mesh will be done.&lt;br /&gt;
&lt;br /&gt;
In &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-3.html"&gt;part 3&lt;/a&gt; I'll start explaining the CSG algorithm itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1095264308774982004?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1095264308774982004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1095264308774982004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1095264308774982004'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html' title='Realtime CSG - Part 2'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QB2O0HdIQjQ/SxdpFS16_eI/AAAAAAAAALQ/5L_HW9paMn8/s72-c/HalfEdges.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3754186769732188577</id><published>2009-12-01T08:12:00.022+01:00</published><updated>2011-08-08T16:40:15.979+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSG'/><title type='text'>Realtime CSG - Part 1</title><content type='html'>Yesterday I got an email asking if I could explain my &lt;a href="http://video.google.com/videoplay?docid=-1907574989981648678#"&gt;real-time CSG algorithm&lt;/a&gt;.&lt;br /&gt;
So I figured I might as well blog about it.&lt;br /&gt;
&lt;br /&gt;
(CSG stands for &lt;a href="http://en.wikipedia.org/wiki/Constructive_solid_geometry"&gt;Constructive Solid Geometry&lt;/a&gt; by the way)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I'm doing this from memory, so hopefully i'm not missing anything, please don't hesitate to tell me if something isn't clear to you.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;About Numerical Stability&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Before I begin, I need to stress that with these kinds of things you &lt;br /&gt;
really have to worry about floating point errors.&lt;br /&gt;
As you might know, floating point numbers have limited precision and &lt;br /&gt;
cannot possible hold a number with infinite precision.&lt;br /&gt;
If you divide 1 by 3, you won't get 0.3333333 with 3's into infinity, &lt;br /&gt;
instead you'll just get 0.333333343 (single precision).&lt;br /&gt;
&lt;br /&gt;
Above all, consistency is more important than accuracy with geometry&lt;br /&gt;
on a computer. Otherwise you always end up with coordinates that are&lt;br /&gt;
almost the same, but never quite the same.&lt;br /&gt;
You'll need to use 'epsilon values', which is a small bias&lt;br /&gt;
(for example 0.01), when comparing coordinates or distances.&lt;br /&gt;
This is because you cannot assume that two calculations that are &lt;br /&gt;
equal from a mathematical sense, will produce the same result.&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
a/b does not (necessarily) give the same result as  a * (1/b)&lt;br /&gt;
a*(b*c) does not (necessarily) give the same result as (a*b)*c&lt;br /&gt;
etc.&lt;br /&gt;
&lt;br /&gt;
So, for example, when you determine the distance of a point to a &lt;a href="http://en.wikipedia.org/wiki/Plane_(geometry)"&gt;plane&lt;/a&gt; you need to define for yourself that a point will be:&lt;ul&gt;&lt;li&gt;on the negative side of a plane when it's distance is &amp;lt; -epsilon.&lt;/li&gt;
&lt;li&gt;on the positive side if it's distance is &amp;gt; epsilon.&lt;/li&gt;
&lt;li&gt;on the plane itself if it's distance is between &amp;gt;= -epsilon and &amp;lt;= epsilon.&lt;/li&gt;
&lt;/ul&gt;Make sure that you don't mix up, for example, &amp;gt; with &amp;gt;=, or you'll get all kinds of weird hard to track down bugs!&lt;br /&gt;
Be &lt;u&gt;consistent&lt;/u&gt;!  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Half-edges&lt;/b&gt;  &lt;br /&gt;
&lt;br /&gt;
I use a half-edge data structure to represent my geometry, you can find &lt;a href="http://www.flipcode.com/archives/The_Half-Edge_Data_Structure.shtml"&gt;a basic explanation of the half-edge data structure here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
For my CSG algorithm you'll need a couple of basic methods.&lt;br /&gt;
&lt;br /&gt;
First of all you'll need a &lt;a href="http://github.com/LogicalError/Realtime-CSG/blob/master/HalfEdge.cs"&gt;method to create a pair of half-edges (with a new vertex) in between two other half-edges&lt;/a&gt;, which essentially splits a full edge in two and inserts the new vertex in between.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Polygon cutting&lt;/b&gt;  &lt;br /&gt;
&lt;br /&gt;
Another thing you'll need is a &lt;a href="http://github.com/LogicalError/Realtime-CSG/blob/master/Polygon.cs"&gt;method to cut a polygon with a plane&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It works like this:&lt;br /&gt;
You cut a polygon by looping trough all your vertices, and for every vertex determine if it's on the positive side (outside), the negative side (inside) or -on- the plane you're currently cutting with. (using epsilon values like I mentioned before)&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;If all vertices are on the plane, then you've got a duplicate plane and you'll need to remove that plane (quite frankly, you should've detected that before you start cutting)&lt;/li&gt;
&lt;li&gt;If all your vertices are on the 'outside' or are on the plane then you need to treat the entire polygon as being cut.&lt;/li&gt;
&lt;li&gt;If all your vertices are on the 'inside' or are on the plane then your entire polygon wasn't cut by the plane.&lt;/li&gt;
&lt;li&gt;In all other situations you'll need to cut your polygon into two pieces.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
You do this by finding the two vertices where the polygon was intersected by the plane.&lt;br /&gt;
If the vertices you find just happen to lie on the cutting plane you won't need to calculate any intersection, but often you'll need to calculate the intersection point of an edge with the cutting plane, and then use the half-edge insert method I mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The big advantage of half-edges here is that when you split the half-edge, you automatically do it for both polygons on both sides of the edge.&lt;br /&gt;
And since you won't be calculating an intersection when a point is already on the plane, you won't be splitting it twice and everything will be nice and consistent!&lt;br /&gt;
&lt;br /&gt;
When you have an edge to split, you may have an edge that goes from the inside to the outside, or an edge that goes from the outside to the inside.&lt;br /&gt;
Now what is -really- important is that you always calculate the intersection point in the same direction.&lt;br /&gt;
What this means is that if you do:&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;myNewVertex = myCuttingPlane.Intersect(myInsideVertex, myOutsideVertex);&lt;/pre&gt;&lt;br /&gt;
Then you don't mix it with:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;myNewVertex = myCuttingPlane.Intersect(myOutsideVertex, myInsideVertex);&lt;/pre&gt;&lt;br /&gt;
When you calculate your intersection point, stick with one direction!&lt;br /&gt;
Otherwise you'll end up with some vertices that are biased towards one side of the plane, and other vertices that are biased at the other side of the plane.&lt;br /&gt;
So make sure you're, once again, consistent here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In the &lt;a href="http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-2.html"&gt;part 2&lt;/a&gt; I'll explain how to build geometry from &lt;br /&gt;
brushes (&lt;a href="http://en.wikipedia.org/wiki/Convex_polytope"&gt;convex polytopes&lt;/a&gt;), which are the building blocks of my CSG algorithm.&lt;br /&gt;
&lt;br /&gt;
Update:&lt;br /&gt;
Created a &lt;a href="http://github.com/LogicalError/Realtime-CSG"&gt;repository&lt;/a&gt; for the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3754186769732188577?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3754186769732188577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3754186769732188577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3754186769732188577'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/12/realtime-csg-part-1.html' title='Realtime CSG - Part 1'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6209101921642832760</id><published>2009-11-25T09:35:00.000+01:00</published><updated>2011-08-08T16:44:51.051+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 16</title><content type='html'>The last couple of days I've been cleaning up some parts of my code and preparing for when I can add variable sized compressed pages, which may or may not include normal and specular maps.&lt;br /&gt;
&lt;br /&gt;
Unfortunately my code wasn't build with that in mind, and now it'll take some serious refactoring work to make my mip generating code work with it.&lt;br /&gt;
&lt;br /&gt;
What really annoys me is that if only one tiny sub-page in a higher mip page has a normal map, then the entire mip page will need a normal map too.&lt;br /&gt;
Sure, it'll compress nicely, but I can imagine that this will complicate rendering, that you may or may not have a normal map at a texel basis.&lt;br /&gt;
I suppose this will have to be handled either at a per mesh level, or just give everything a default normal map.&lt;br /&gt;
I'm probably going for option no. 2 because it'll be safer and simpler.&lt;br /&gt;
&lt;br /&gt;
Besides, I need to reserve the texture for it anyway. &lt;br /&gt;
&lt;br /&gt;
Also tweaked my algorithm to combine polygons a bit, and I'm now using fewer pages for the same geometry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6209101921642832760?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6209101921642832760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_25.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6209101921642832760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6209101921642832760'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_25.html' title='Adventures in virtual texture space, part 16'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1060170084742907238</id><published>2009-11-18T08:17:00.000+01:00</published><updated>2011-08-08T16:44:50.919+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 15</title><content type='html'>For the last couple of weeks I've been working at a client in Utrecht, a city in the middle of the Netherlands, but I live in Capelle aan den Ijssel, which is a small city which has grown into the much larger city of Rotterdam.&lt;br /&gt;
The problem is that traffic between those two city is horrible.&lt;br /&gt;
If there wasn't any traffic it would take me 45 minutes, but it actually takes me 2 to 3 hours.&lt;br /&gt;
Well, it would take me 2 to 3 hours if I didn't get up at 6, eat my breakfast in the car, and drive like mad to avoid the rush!&lt;br /&gt;
So for the last couple of weeks I've been in a constant state of tiredness.&lt;br /&gt;
&lt;br /&gt;
Anyway.&lt;br /&gt;
Since my last update I've written a idtech-4 shader parser so I can get more correct textures.&lt;br /&gt;
Before I would just take the name of the shader and let the importer kinda guess which textures it would need.&lt;br /&gt;
Fortunately most of the time the shaders and their textures had predictable names, but not always.&lt;br /&gt;
Parsing the shaders also allows me to get back the normal and specular maps, which should be useful when I start to implement lighting. &lt;br /&gt;
&lt;br /&gt;
Other than that I downloaded the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=255fc5f1-15af-4fe7-be4d-263a2621144b&amp;displaylang=en"&gt;beta of Visual Studio 2010&lt;/a&gt;, and man, those profiling tools rock!&lt;br /&gt;
I haven't tried them on C++ code yet, so I'm not sure how or if they're any good there, but for managed code they're awesome!&lt;br /&gt;
Can't wait for it to come out of beta.&lt;br /&gt;
&lt;br /&gt;
I also optimized my code a bit, and now it oscillates between 3-5ms per frame (300-200fps).&lt;br /&gt;
It takes about 2ms for the whole readback part, which is more than I would like.&lt;br /&gt;
(And I'm pretty sure this could be done a lot faster in C/C++ where you can do all kinds of smart pointer tricks etc.)&lt;br /&gt;
This makes me think that the analytical solution that I've been thinking about could be a lot faster. &lt;br /&gt;
&lt;br /&gt;
Other than that it also takes about 2ms to render everything, but I expected that since I'm not doing anything remotely smart, at the moment, when it comes to rendering geometry.. I'm basically just drawing the entire level in one draw call right now.&lt;br /&gt;
The fact that the vertex count is way above 200k certainly doesn't help ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1060170084742907238?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1060170084742907238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_18.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1060170084742907238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1060170084742907238'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_18.html' title='Adventures in virtual texture space, part 15'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2219163443788731987</id><published>2009-11-09T14:18:00.002+01:00</published><updated>2011-08-08T16:44:50.964+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 14</title><content type='html'>This is just an update to show my progress.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/N-gVXjmMkQ0&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/nN5l7_BRVEs&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;/div&gt;&lt;div&gt;Texture coordinates are now generated correctly, and popping of pages is extremely rare now and basically only happens if you travel trough a wall.&lt;br /&gt;
&lt;br /&gt;
Note that I haven't put the texture compression code in yet, so IO performance will actually get better in the future.&lt;br /&gt;
&lt;br /&gt;
Also, the frame rate in the video is rather chaotic, this is due to the screen recorder competing with the application for resources.&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/7301982-2219163443788731987?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2219163443788731987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_09.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2219163443788731987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2219163443788731987'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space_09.html' title='Adventures in virtual texture space, part 14'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-660385259646097485</id><published>2009-11-06T09:10:00.001+01:00</published><updated>2011-08-08T16:44:51.071+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 13</title><content type='html'>Since my last post I've been working on cleaning up my tool set and breaking it up into several different pieces instead of one huge monolithic tool which did all the processing.&lt;br /&gt;
I really needed to do this because my processing time jumped up from 10 seconds per level to more than 20 minutes, which is clearly unacceptable.&lt;br /&gt;
&lt;br /&gt;
Splitting it up into multiple pieces allows me to skip the processing steps that go before whichever part I'm modifying.&lt;br /&gt;
It also allows me to cache and pre process some content, such as the textures, for easy processing.&lt;br /&gt;
I'm not completely done with this yet, but hopefully it won't take much longer.&lt;br /&gt;
&lt;br /&gt;
Other than that I've implemented my own disk cache code, and what a difference it makes!&lt;br /&gt;
Right now you wouldn't be able to tell if the level was textured normally or virtual textured, other than if you pass through a wall you have one or two frames of lower resolution pages.&lt;br /&gt;
&lt;br /&gt;
I've pre cached all the smallest MIP-levels, so they're always in memory, this is to ensure that no matter what you always have at least a lower resolution version of your page in memory.&lt;br /&gt;
These cached pages cannot be unloaded as well.&lt;br /&gt;
&lt;br /&gt;
All in all right now I'm allocating a whopping 500 Mb of page cache memory, but this should decrease a lot when I put the new texture compression code in which I mentioned in my previous posts, the idea is to store compressed textures in the cache and decompress them on demand.&lt;br /&gt;
&lt;br /&gt;
After a while, hiccups appear in the application, and I'm not entirely sure what's causing them.&lt;br /&gt;
It might have to do with certain areas in the map which have lots and lots of different pages visible, which can probably only be fixed by improving my tool set.&lt;br /&gt;
&lt;br /&gt;
I've also noticed that the TextPrinter I'm using from &lt;a href="http://www.opentk.com/"&gt;OpenTK&lt;/a&gt; has some pretty horrendous memory leaks, which makes my memory consumption grow rather rapidly.&lt;br /&gt;
I'm currently using an older version though, so this might already been fixed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-660385259646097485?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/660385259646097485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/660385259646097485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/660385259646097485'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/11/adventures-in-virtual-texture-space.html' title='Adventures in virtual texture space, part 13'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1543794427762709568</id><published>2009-10-28T10:32:00.019+01:00</published><updated>2011-08-08T16:47:22.227+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Adventures in virtual texture space, part 12</title><content type='html'>So the &lt;a href="http://sandervanrossen.blogspot.com/2009/10/ive-been-working-on-implementing.html"&gt;last time&lt;/a&gt; I mentioned that I managed to compress my textures to about 6Kb, and theorizing that it's about the same compression ratio that Id software has.&lt;br /&gt;
Obviously Id software, next to simply being awesome, have many more resources compared to me to get their texture compression just perfect.&lt;br /&gt;
So I was quite happy with myself that, using their published papers, I was able to get it the same results.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, as Brian Karis mentioned in the comments, I was wrong.&lt;br /&gt;
&lt;br /&gt;
6Kb wasn't per texture but for all the different material channels, diffuse/bump/specular, combined.&lt;br /&gt;
&lt;br /&gt;
To get the same compression ratio I would need to get it down to 2Kb.&lt;br /&gt;
&lt;br /&gt;
Of course I could just crank up the compression ratio, but I didn't really like the results if I did.&lt;br /&gt;
That being said, if I convert the results to dxt5 after decompression I'd lose some more quality anyway, so in the end cranking up the compression ratio might be acceptable.&lt;br /&gt;
But I really wanted to see how far I could go without decreasing the quality.&lt;br /&gt;
&lt;br /&gt;
So I started to experiment with &lt;a href="http://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform"&gt;Burrows Wheeler transformations&lt;/a&gt;, which do some clever stuff to change the order of bytes so that when you perform RLE (&lt;a href="http://en.wikipedia.org/wiki/Run-length_encoding"&gt;Run Length Encoding&lt;/a&gt;) on them, the compression ratio ends up being better.&lt;br /&gt;
And look at that, it worked like a charm!&lt;br /&gt;
&lt;br /&gt;
The file size got down to 2Kb.&lt;br /&gt;
&lt;br /&gt;
But it's slow. &lt;b&gt;REALLY &lt;/b&gt;slow.&lt;br /&gt;
&lt;br /&gt;
The algorithm scales horribly, and on a 64Kb buffer it took seconds to finish.&lt;br /&gt;
Decompression took &gt;10ms, which is a lot faster than compression, but still not good enough.&lt;br /&gt;
&lt;br /&gt;
Sometime later, after trying all kinds of things, I tried doing RLE both before &amp; after the transformation, just to see what would happen.&lt;br /&gt;
The reasoning was that if I first decrease the size of the buffer, by compressing it a little with RLE, then the Burrows Wheeler process would be faster.&lt;br /&gt;
After that I would then do another RLE over the resulting buffer to increase my compression ratio somewhat.&lt;br /&gt;
I expected this to be a little faster, and probably have somewhat worse compression overall.&lt;br /&gt;
&lt;br /&gt;
To my surprise now the total compression process was &lt;b&gt;MUCH FASTER&lt;/b&gt; only taking 14ms.&lt;br /&gt;
Decompression only took 3.2ms overall, and the file got about 100 bytes &lt;b&gt;SMALLER&lt;/b&gt;, which is somewhat counter-intuitive.&lt;br /&gt;
&lt;br /&gt;
Result: &lt;b&gt;1899 bytes&lt;/b&gt; for an 128x128 RGBA texture. &lt;br /&gt;
(the alpha channel is a solid color though)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1543794427762709568?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1543794427762709568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_28.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1543794427762709568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1543794427762709568'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_28.html' title='Adventures in virtual texture space, part 12'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1590288408380955235</id><published>2009-10-23T16:27:00.004+02:00</published><updated>2011-08-08T16:47:22.230+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Adventures in virtual texture space, part 11</title><content type='html'>I've been working on implementing the texture compression ideas from the &amp;nbsp;"&lt;a href="http://softwarecommunity.intel.com/UserFiles/en-us/Image/1221/Real-Time%20Texture%20Streaming%20&amp;amp;%20Decompression.pdf"&gt;Real-Time Texture Streaming &amp;amp; Decompression&lt;/a&gt;" paper in my virtual texture implementation.&lt;br /&gt;
I couldn't just use the code and port it this time because this paper only has the decompression code, and I figured it would probably be easier to write everything from scratch then to try to figure out how the compression side would look to perfectly work with the given decompression code.&lt;br /&gt;
It's not implemented into my VT demo (yet), but I have some results.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_QB2O0HdIQjQ/SuG3IUh7vEI/AAAAAAAAAJo/rhrjWOupnt8/s1600-h/compression.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_QB2O0HdIQjQ/SuG3IUh7vEI/AAAAAAAAAJo/rhrjWOupnt8/s320/compression.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Right now I can decompress an 128x128 texture in 2.5ms, and it ends up about 5-6kb, and that includes an alpha channel.&lt;br /&gt;
I don't think i can get it much smaller, at least i don't know how to do that without seriously degrading performance, and the quality is already less than i would like.&lt;br /&gt;
Eventually i'll see how much of a difference it makes when i turn this into a YCoCg/DXT5 texture, in which case there might not be much difference in quality when comparing the original and the compressed one (since DXT5 already reduces the quality)&lt;br /&gt;
The speed can probably be increased several times considering this is written in plain vanilla C#. Languages like C or C++ are much better at this sort of thing because you can do all kinds of pointer tricks that you cannot do easily in a managed language, although i might try C++/CLI eventually.&lt;br /&gt;
&lt;br /&gt;
Like the paper I'm converting my RGB(A) texture into YCoCg(A), separate the channels, and then downsample the Co and Cg channels (which actually makes no real visual impact).&lt;br /&gt;
I then splice the buffers up into 8x8 blocks and pass them trough an DCT converter and quantize it all.&lt;br /&gt;
Unlike the paper I'm not doing run-length and&amp;nbsp;Huffman&amp;nbsp;encoding on a block basis, but i'm doing this over all blocks. Eventually it might make sense to do the encoding on a block basis, to make it easier to&amp;nbsp;multi thread&amp;nbsp;the decompression, but I'm not so sure it's a good idea to have a Huffman header on a per block basis, I'm think it would be more efficient on a per texture basis.&lt;br /&gt;
&lt;br /&gt;
In the "&lt;a href="http://s09.idav.ucdavis.edu/talks/05-JP_id_Tech_5_Challenges.pdf"&gt;From Texture Virtualization to Massive Parallelization&lt;/a&gt;" paper they mention they have "diffuse, specular, bump and cover/alpha" channels for their tiles, and that they have "Typically 2-6kB input, 40kB output".&lt;br /&gt;
Which makes me wonder if they have this 2-6Kb input per 'texture', or for all those channels combined.&lt;br /&gt;
I can't imagine that it's for all the channels combined, because 40Kb is a 128x128 texture with 2.5 bytes per texel, and they use 128x128 tile sizes as an example in the same PDF.&lt;br /&gt;
So it seems to me they have 2-6Kb per tile, which is about the same I have right now.&lt;br /&gt;
The lower limit of 2Kb is probably for grey textures that only have 1 channel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1590288408380955235?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1590288408380955235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/ive-been-working-on-implementing.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1590288408380955235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1590288408380955235'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/ive-been-working-on-implementing.html' title='Adventures in virtual texture space, part 11'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QB2O0HdIQjQ/SuG3IUh7vEI/AAAAAAAAAJo/rhrjWOupnt8/s72-c/compression.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-994711182184827313</id><published>2009-10-13T09:04:00.006+02:00</published><updated>2009-10-13T15:16:11.661+02:00</updated><title type='text'>The birdmen cometh</title><content type='html'>So yesterday my parents came back from France, from their second home i mentioned before in a &lt;a href="http://sandervanrossen.blogspot.com/2009_07_01_archive.html"&gt;previous post&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
While they where in France my brother and his family visited them and he helped them cut down a couple of trees.&lt;br /&gt;
&lt;br /&gt;
So my parents showed me a video of my brother perched up in a tree, &lt;br /&gt;
sawing off the branches.&lt;br /&gt;
&lt;br /&gt;
A little while later his 3 year old son comes out of the house, &lt;br /&gt;
barely awake, just woken up.&lt;br /&gt;
&lt;br /&gt;
He looks up, and sees his father sitting there in the tree, &lt;br /&gt;
which he obviously didn't expect to see.&lt;br /&gt;
Somewhat puzzled, he then says (roughly translated from dutch): &lt;br /&gt;
"Daddy, surely you're not a bird!?"&lt;br /&gt;
&lt;br /&gt;
Classic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-994711182184827313?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/994711182184827313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/birdmen-cometh.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/994711182184827313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/994711182184827313'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/birdmen-cometh.html' title='The birdmen cometh'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5815117863200521519</id><published>2009-10-12T21:43:00.011+02:00</published><updated>2011-08-08T16:47:22.245+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Texture-Compression'/><title type='text'>Adventures in virtual texture space, part 10B</title><content type='html'>Like I promised in my &lt;a href="http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_12.html"&gt;last post&lt;/a&gt;, here are some images.&lt;br /&gt;
On the left you can see the original texture, the other two are the result of YCoCg/DXT5 compression.&lt;br /&gt;
The middle one is with the simplification used in the &lt;br /&gt;
"&lt;a href="http://cache-www.intel.com/cd/00/00/32/43/324337_324337.pdf" style="color: #666699;"&gt;Real-Time DXT Compression&lt;/a&gt;" paper I talked about, the right one is without it.&lt;br /&gt;
&lt;br /&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: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_QB2O0HdIQjQ/StTH3s7ADTI/AAAAAAAAAJQ/TMzqhyypzRU/s1600-h/compare1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_QB2O0HdIQjQ/StTH3s7ADTI/AAAAAAAAAJQ/TMzqhyypzRU/s320/compare1.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="" style="clear: both; text-align: center;"&gt;Here you can see that there's an orange border around&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;all the yellow edges. In the middle one there are also some&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;bright&amp;nbsp;green blocks.&lt;br /&gt;
&lt;/div&gt;&lt;br /&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: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_QB2O0HdIQjQ/StTH6aOfC_I/AAAAAAAAAJY/xCilIN_1C-g/s1600-h/compare2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_QB2O0HdIQjQ/StTH6aOfC_I/AAAAAAAAAJY/xCilIN_1C-g/s320/compare2.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="" style="clear: both; text-align: center;"&gt;Everything is blocky after compression, has a&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;washed out red appearance, and in the middle&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;there are some purple smudges here and there.&lt;br /&gt;
&lt;/div&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: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_QB2O0HdIQjQ/StTH9CXksEI/AAAAAAAAAJg/7qjkCb1faYg/s1600-h/compare3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_QB2O0HdIQjQ/StTH9CXksEI/AAAAAAAAAJg/7qjkCb1faYg/s320/compare3.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="" style="clear: both; text-align: center;"&gt;In the middle image there's a red glow around&amp;nbsp;the&amp;nbsp;top&amp;nbsp;of&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;the yellow stripes,&amp;nbsp;while the black stripes have a redish glow.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;The right one isn't that much better, but the glow is more yellow,&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;which makes more sense since there's no red in the original.&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&amp;nbsp;When you look at the yellow stripes from some distance,&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;the middle one&amp;nbsp;looks green, unlike the left and right&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&amp;nbsp;one which remain yellow.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
I'm pretty sure these artifacts would be far less visible on higher resolution textures, but here all these artifacts are rather visible. &lt;br /&gt;
&lt;br /&gt;
Update: Updated images with higher resolution versions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-5815117863200521519?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5815117863200521519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_1397.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5815117863200521519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5815117863200521519'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_1397.html' title='Adventures in virtual texture space, part 10B'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QB2O0HdIQjQ/StTH3s7ADTI/AAAAAAAAAJQ/TMzqhyypzRU/s72-c/compare1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2563905811647089042</id><published>2009-10-12T13:51:00.012+02:00</published><updated>2011-08-08T16:44:50.992+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 10</title><content type='html'>&lt;b&gt;Texture compression&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Yesterday night I managed to spend some time on my virtual texture project.&lt;br /&gt;
I got sick of just fiddling around with all the stuff I already build, especially since it didn't really produce that much results.&lt;br /&gt;
So I figured it would be better to implement YCoCG/DXT5 compression.&lt;br /&gt;
Since time is a problem for me, I simply copied the code from the excellent&lt;br /&gt;
"&lt;a href="http://developer.nvidia.com/object/real-time-ycocg-dxt-compression.html"&gt;Real-Time YCoCg/DXT5 Compression&lt;/a&gt;" paper and converted the C code into C# (since that's the programming language I'm using right now).&lt;br /&gt;
&lt;br /&gt;
Conversion was pretty trivial, but unfortunately there seemed to be some inconsistencies between all the papers on this subject, so it took me more time than I would've liked to find the right combination of compression and decompression code.&lt;br /&gt;
It also turned out that somewhere in my image conversion chain my red and blue channels where reversed somehow? Still not sure exactly where it went wrong, didn't have much time, so i simply swapped them, which worked.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Unfortunately the quality was a big let down. &lt;br /&gt;
I'm guessing Id software simply uses higher resolution textures for Rage, so it's less obvious, but with some of the quake 4 textures the artifacts get really ugly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I noticed that in the "&lt;a href="http://cache-www.intel.com/cd/00/00/32/43/324337_324337.pdf"&gt;Real-Time DXT Compression&lt;/a&gt;" paper (the prequel to the former paper) at the top of page 12 they mentioned that a line of code from 'EmitColorIndices' can be simplified from:&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;result = ( !b3 &amp;amp; b4 ) | ( b2 &amp;amp; b5 ) | 
         ( ( ( b0 &amp;amp; b3 ) | 
             ( b1 &amp;amp; b2 ) ) &amp;lt;&amp;lt; 1 );
&lt;/pre&gt;to&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;result = ( b2 &amp;amp; b5 ) | 
         ( ( ( b0 &amp;amp; b3 ) | 
             ( b1 &amp;amp; b2 ) ) &amp;lt;&amp;lt; 1 );
&lt;/pre&gt;mentioning that &lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;Evaluating the above expression reveals that the sub expression ( !b3 &amp;amp; b4 ) can be omitted because it does not significantly contribute to the final result.&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
Well maybe it's just me, but I &lt;b&gt;DO&lt;/b&gt; see significant differences, and replacing their 'improved' version with the 'unimproved' version increased quality a lot for me, especially with anything yellow. (I'll try to post some images later on)&lt;br /&gt;
&lt;br /&gt;
(Don't get me wrong though, other than this little thing, it's an excellent paper and very valuable resource!)&lt;br /&gt;
&lt;br /&gt;
Anyway, with YCoCg/DXT5 compression my page tiles shrunk 4x and performance increased a lot, so I'm quite happy about that.&lt;br /&gt;
I had a couple of frustratingly moments in the past where I thought I fixed my page loading performance, but it turned out the be caching, so I replaced everything with uncached memory mapping, and everything still ran rather smoothly.&lt;br /&gt;
Even though reducing the size of my pages on disk helps with locality and therefore latency, I honestly thought that throughput wasn't really part of my performance problems, at least not yet.&lt;br /&gt;
Apparently I was wrong.&lt;br /&gt;
&lt;br /&gt;
I haven't tried the more advanced "&lt;a href="http://softwarecommunity.intel.com/UserFiles/en-us/Image/1221/Real-Time%20Texture%20Streaming%20&amp;amp;%20Decompression.pdf"&gt;Real-Time Texture Streaming &amp;amp; Decompression&lt;/a&gt;" stuff yet, but that should increase my performance even more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that I've mentioned all these papers, I should also mention "&lt;a href="http://software.intel.com/en-us/articles/geospatial-texture-streaming-from-slow-storage-devices/"&gt;Geospatial Texture Streaming From Slow Storage Devices&lt;/a&gt;" which is another paper written by Id Software, the latest one if I'm not mistaken.&lt;br /&gt;
Even though it's, oddly enough, about the older megatexture/clipmapping technology rather than virtual texture technology, which makes me wonder if they're mixing megatexure for terrain with virtual texturing for everything else, there is some rather interesting stuff in there, so well worth the read.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;Possible analytical solution&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Other than that, I have this vague idea concerning virtual texturing. I could have a hashed grid for each mip-level, and then store which pages are potentially visible from within each hashed-grid cell. I can then use this to sort my pages in my virtual texture file, and perhaps also use this at runtime to determine which pages are (potentially) visible when.&lt;br /&gt;
&lt;br /&gt;
It would avoid having to do a read-back, and it would actually work with transparent textures.&lt;br /&gt;
Another thing would be that it would allow me to 'look ahead' to determine which pages might be visible in the future when i move in the direction i'm facing (or something similar). &lt;br /&gt;
I would need to load more pages though, most of which, i'm guessing should, be cached on the CPU side.. Hopefully this would be offset by the better (theoretical) locality of it all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2563905811647089042?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2563905811647089042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_12.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2563905811647089042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2563905811647089042'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space_12.html' title='Adventures in virtual texture space, part 10'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-612203714453625950</id><published>2009-10-07T16:30:00.007+02:00</published><updated>2011-08-08T16:44:51.047+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Somebody beat me to it!</title><content type='html'>I was planning to, eventually, try to optimize some parts of virtual texturing using OpenCL.&lt;br /&gt;
&lt;br /&gt;
But now it seems someone has done this pioneering work before me! &lt;br /&gt;
(using CUDA)&lt;br /&gt;
&lt;br /&gt;
Check out this post from &lt;a href="http://charles.hollemeersch.net/Article/29/virtual-texturing-using-cuda"&gt;Charles-Fredrik Hollemeersch&lt;/a&gt;.&lt;br /&gt;
Perhaps some of you may recognize the name as the guy behind &lt;a href="http://www.tenebrae2.com/"&gt;Tenebrae&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
According to their  &lt;a href="http://multimedialab.elis.ugent.be/gpu/media/pdf/2009.09%20-%20GTC%202009%20-%20Charles-Frederik%20Hollemeersch%20et%20al.%20-%20Accelerating%20Virtual%20Texturing%20Using%20CUDA.pdf"&gt;Poster&lt;/a&gt; they seemed to have presented their results at the &lt;a href="http://www.nvidia.com/object/gpu_technology_conference.html"&gt;GPU Technology Conference&lt;/a&gt; in San Jose, California.&lt;br /&gt;
&lt;br /&gt;
A chapter about this can be found in the upcoming book&lt;br /&gt;
"&lt;a href="http://gpupro.blogspot.com/2009/10/virtual-texturing-using-cuda.html"&gt;GPU Pro: Advanced Rendering Techniques&lt;/a&gt;"&lt;br /&gt;
&lt;br /&gt;
Awesome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-612203714453625950?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://gpupro.blogspot.com/2009/10/virtual-texturing-using-cuda.html' title='Somebody beat me to it!'/><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/612203714453625950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/somebody-beat-me-to-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/612203714453625950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/612203714453625950'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/somebody-beat-me-to-it.html' title='Somebody beat me to it!'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8196778800369553033</id><published>2009-10-02T22:39:00.003+02:00</published><updated>2011-08-08T16:44:51.099+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 9</title><content type='html'>Awesome, I discovered that if I use bigger page sizes, my level would display much more smoothly.&lt;br /&gt;
Not because bigger page sizes are better, but because the code i was using to update my indirection table was god awfully slow!&lt;br /&gt;
(and the bigger the page size, the smaller the indirection table)&lt;br /&gt;
&lt;br /&gt;
In the &lt;a href="http://ati.amd.com/developer/SIGGRAPH08/Chapter02-Mittring-Advanced_Virtual_Texture_Topics.pdf"&gt;crytek paper&lt;/a&gt; they mention a trick where they basically render their page changes into the indirection table instead of uploading a texture.&lt;br /&gt;
Sounds like the next step for me!&lt;br /&gt;
&lt;br /&gt;
Now if only I had some time to actually do this.. hmmm&lt;br /&gt;
&lt;br /&gt;
Oh and defrag your harddisk when working on virtual texture tech!&lt;br /&gt;
It helps! &lt;br /&gt;
&lt;b&gt;A LOT&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8196778800369553033?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8196778800369553033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8196778800369553033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8196778800369553033'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/10/adventures-in-virtual-texture-space.html' title='Adventures in virtual texture space, part 9'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1015838565416234116</id><published>2009-09-29T10:44:00.000+02:00</published><updated>2009-09-29T10:44:22.422+02:00</updated><title type='text'>Adventures in virtual texture space, part 8</title><content type='html'>So yesterday I had a little bit of time to try a couple of small things.&lt;br /&gt;
&lt;br /&gt;
I changed the page sorting, first sorting the pages from high mipmap level to low mipmap level, then from more to less visible (by counting how many samples I find for each page in the readback buffer).&lt;br /&gt;
&lt;br /&gt;
I also &lt;i&gt;decreased&lt;/i&gt; the amount of pages I store in my GPU side page-cache, because I suspect that OpenGL updates the entire texture even when I only update a small part of it, and a smaller texture would upload faster.&lt;br /&gt;
&lt;br /&gt;
Next to that i fixed a small bug where a buffer wasn't reset properly.&lt;br /&gt;
&lt;br /&gt;
Oh, and I defragmented my system :)&lt;br /&gt;
&lt;br /&gt;
And lo and behold... my virtual texture app worked flawlessly!?&lt;br /&gt;
No popping at all!&lt;br /&gt;
&lt;br /&gt;
So naturally I wanted to figure out which of my changes was responsible for this!&lt;br /&gt;
.. and then my wife pulled me away from my computer ;)&lt;br /&gt;
&lt;br /&gt;
I guess I'll have to look at it next time I have time, but I'm really happy at the current results!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1015838565416234116?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1015838565416234116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_29.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1015838565416234116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1015838565416234116'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_29.html' title='Adventures in virtual texture space, part 8'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-3108307636601363913</id><published>2009-09-28T09:58:00.004+02:00</published><updated>2011-08-08T16:44:51.006+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 7</title><content type='html'>Yesterday I spend a little time on my VT project, fiddled with priorities and got a good speedup by rewriting my threading code.&lt;br /&gt;
I wasn't lock-free data structures before, and now that I am things are much better.&lt;br /&gt;
&lt;br /&gt;
That said, I did notice that in my profiler i'm now spending *a lot* of cycles in my lock-free data structure.&lt;br /&gt;
I'm assuming this is because the IO thread is often waiting for things to load.&lt;br /&gt;
&lt;br /&gt;
I've now capped my IO thread queue to x items, assuming that before the thread would ever load the last texture in the queue it would've already been supplemented with new items anyway.&lt;br /&gt;
This way the response time is increased, and i don't run the risk of infinitely growing my queue.&lt;br /&gt;
&lt;br /&gt;
This is still a part that i'm experimenting with, and i still need to try a lot of the stuff that's been suggested to me in the comment section of last couple of posts.&lt;br /&gt;
&lt;br /&gt;
Once again, my test data is far from optimal.&lt;br /&gt;
In a perfect situation you'd have roughly 1:1 pixel to virtual page texel ratio, but i sometimes need 32x more than that.&lt;br /&gt;
This is because of lots of textures 'stamped' onto the geometry, and lots of tiny slivers of geometry that use their own unique textures.&lt;br /&gt;
&lt;br /&gt;
This makes me believe that there are two ways to building virtual texture content.&lt;br /&gt;
&lt;br /&gt;
One is that you build your virtual texture as a big texture-atlas, where although the textures themselves are only stored once (subdivided into pages), the pages themselves would actually be used many times in the indirection table.&lt;br /&gt;
UV coordinates would be calculated to take maximum advantage of this.&lt;br /&gt;
It might be somewhat tricky to do with multiple mip-levels, but it would speed up file IO and would remove some of the pressure on the page cache.&lt;br /&gt;
The UV coordinates would require more area, and the more uniquely textured area you have, the less efficient this would become.&lt;br /&gt;
This technique would be very close to regular, non virtual, texturing approaches, but would basically give you automatic texture management.&lt;br /&gt;
&lt;br /&gt;
The other approach is to uv-unwrap all the geometry, avoiding overlapping unless the geometry truly lies on the same plane in world space.&lt;br /&gt;
The new UV coordinates would have to be aligned as much as possible with the original UV coordinate axis, to avoid the texturing looking different.&lt;br /&gt;
After this the original UV coordinates, and the textures belonging to each piece of geometry, would need to be rendered into the virtual texture.&lt;br /&gt;
&lt;br /&gt;
This would more easily remove all the stamping problems I'm having, since the 'stamp' textures would be rendered on top of the original geometry (it would require some sorting though, somehow), and improve page locality.&lt;br /&gt;
Texel density would also be uniform across the geometry, which can also be a bad thing, lo-res textures could potentially use much more memory (like cube-maps which are processed as regular textures).&lt;br /&gt;
It would also be harder to re-use identical pages with this technique, since the chance that 2 pages are identical would probably be much smaller.&lt;br /&gt;
&lt;br /&gt;
Also I tried rendering all my textures transparently, just to see how it looked, and I realized that using the readback approach to discover which pages has a serious defect: it can't look beyond the first surface, and since you might not have a page loaded yet, this won't even work with texture masks.&lt;br /&gt;
This is clearly a situation where an analytical approach would be superior.&lt;br /&gt;
&lt;br /&gt;
Alas, I won't be able to spend as much time on virtual textures as the last couple of weeks.&lt;br /&gt;
I'm going to work at a client for the next two months, instead of at home, so the little time i can find will be fragmented at best.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-3108307636601363913?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/3108307636601363913/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_28.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3108307636601363913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/3108307636601363913'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_28.html' title='Adventures in virtual texture space, part 7'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1795659362233630962</id><published>2009-09-23T10:12:00.002+02:00</published><updated>2011-08-08T16:44:50.954+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 6 B</title><content type='html'>&lt;div&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/N-gVXjmMkQ0&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/N-gVXjmMkQ0&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;/div&gt;&lt;div&gt;As promised in my last post, here's a video of what i got so far.&lt;br /&gt;
&lt;br /&gt;
Random thought:&lt;br /&gt;
I'm wondering if it would be useful to have automatically generated page 'samples' spread around the level, each containing a list which pages are near it. That way it would be relatively simple to 'look ahead' and determine which pages could potentially be required in the near future.&lt;br /&gt;
&lt;br /&gt;
The samples would contain all the pages for a specific miplevel in all directions and limited to the distance to the sample where a miplevel would be used.&lt;br /&gt;
&lt;br /&gt;
Since this would only be possible for static pages / geometry, pages for dynamic objects would have to be handled differently.&lt;br /&gt;
&lt;br /&gt;
Potentially, this could remove the need to do a readback completely..&lt;br /&gt;
&lt;br /&gt;
But would this approach be faster? It &lt;i&gt;could&lt;/i&gt; be more accurate though.&lt;br /&gt;
&lt;br /&gt;
Maybe navigation meshes, if they're accurate enough, could be used to simplify the process of creating the samples.&lt;br /&gt;
The same information could be used to determine which pages could never be visible.&lt;br /&gt;
It would look pretty horrible when some pages are missing but turn out to be visible after all though.&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/7301982-1795659362233630962?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1795659362233630962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_23.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1795659362233630962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1795659362233630962'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_23.html' title='Adventures in virtual texture space, part 6 B'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-6574100148476479747</id><published>2009-09-22T13:49:00.005+02:00</published><updated>2011-08-08T16:44:51.066+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 6</title><content type='html'>Yesterday I was working on my virtual texture code, and there's only one bug left (that i know of).&lt;br /&gt;
&lt;br /&gt;
I haven't had much time to look at it, but it fails to load some pages when the page-cache is full for some reason, so it probably has to do with the code that kicks out unused pages when the cache is full.&lt;br /&gt;
&lt;br /&gt;
That aside i'm having some problems with loading my pages from disk. &lt;br /&gt;
&lt;br /&gt;
If I schedule pages to be loaded right when i discover i need them, and just keep adding them to the list, i end up with an ever increasing list if i move around fast enough, because the disk IO simply can't keep up.&lt;br /&gt;
&lt;br /&gt;
So i tried a couple of things, one of them being counting how many times i have a reference to each page in my readback buffer, and giving the pages with the highest ammount of references the highest priority.&lt;br /&gt;
&lt;br /&gt;
After all, the more visible it is, the more imporant it is to load!&lt;br /&gt;
That helped somewhat, but still caused a lot of pages to be loaded and uploaded which aren't visible, yet might actually kick out pages that would be more likely to be visible soon.&lt;br /&gt;
&lt;br /&gt;
The next thing i tried was to remove all the pages from my scheduler that aren't visible in the current frame, but that caused pages to not get loaded at all while you move your camera.&lt;br /&gt;
&lt;br /&gt;
A couple of things that i'm going to try:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;A CPU side disk cache, i only have one on the GPU at the moment.&lt;/li&gt;
&lt;li&gt;Compression, hoping that'll decrease all these problems simply because loading would be faster and the list wouldn't grow as quickly.&lt;/li&gt;
&lt;li&gt;Using adjacency information. By pre-calculating a bounding box of all the texel area in world-space, i can sort all the pages by how close they are to each other, and perhaps do some analysis on what is likely to be visible soon, and what would be unlikely to be visible soon.&lt;/li&gt;
&lt;li&gt;The source material I'm working with is pretty horrible because it has a lot of decal textures which take up extra pages on the screen, and there are simply too many different pages on the screen at the same time. Building my own CSG preprocessor would allow me to optimize this more easily, as apposed to trying to fix a relatively arbitrary list of triangles with all kinds of materials.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
My good friend &lt;a href="http://volcore.limbicsoft.com/"&gt;Volker&lt;/a&gt; suggested a couple of things i could try:&lt;ul&gt;&lt;li&gt;If you know if a page is to be loaded for the current frame, it may be wise to put the higher and lower mip levels of that page in the queue too. (but only if there is nothing else)&lt;/li&gt;
&lt;li&gt;Kick out pages by random instead of last used or least frequently used caching schemes, apparently the worst case is better, so that's worth a shot.&lt;br /&gt;
(Obviously no pages should be kicked out that's visible in the current frame)&lt;/li&gt;
&lt;li&gt;Using memory mapped IO.&lt;br /&gt;
Volker: "in my tests, mmap io made a difference from 10mb/s to 500mb/s. (using the disk cache)"&lt;br /&gt;
My biggest problem is latency though.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
So does anyone out there have any good ideas on how to determine which pages should be loaded &amp; which pages should be kicked out?&lt;br /&gt;
&lt;br /&gt;
I'm going to see if I can upload a new video of my test level tonight.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-6574100148476479747?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/6574100148476479747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_22.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6574100148476479747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/6574100148476479747'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space_22.html' title='Adventures in virtual texture space, part 6'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-927170231130203057</id><published>2009-09-17T13:48:00.004+02:00</published><updated>2011-08-08T16:50:23.865+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Adventures in virtual texture space, part 5</title><content type='html'>Today I've spend some time improving my tools and they're much simpler and faster than before, it only takes about 20 seconds to convert a quake4 level into a 16384x16384 virtual texture file and a separate geometry file.&lt;br\&gt;
&lt;br\&gt;
I'm quite happy with the tool as it is, there are only a handful of things i still want to do such as trying to rotate an allocated texture space to see if it'll fit better and forcing a texel density to some sane (maximum) limit. &lt;br/&gt;
&lt;br/&gt;
Before i used 128x128 pages, and used texture-arrays (which are basically 3d textures where the z direction alway uses near filtering) with a depth of 512 layers.&lt;br/&gt;
&lt;br/&gt;
This worked out pretty well because you never have any bleeding artifacts between pages.&lt;br/&gt;
It is possible to have visible seams between 2 pages that are rendered next to each other if they have a strong enough contrast right on the edge between them, the seam looks as if it's an aliased edge. &lt;br/&gt;
However i would consider it extremely rare, i only managed to see such a seam when i purposely made some handmade pages to see if it would happen at all, i couldn't find one when i looked at it in more real-life artwork.&lt;br/&gt;
&lt;br/&gt;
So today i tried using smaller pages, but this caused some problems.&lt;br/&gt;
First of all, since i make the pages smaller (say 64x64 or 32x32) it uses less texture space, therefore i need more pages for the same amount of texels.&lt;br/&gt;
In theory, smaller pages should be able to match what i render on screen more precisely.&lt;br/&gt;
However, since my texture-array has a hard limit of 512 layers, even when the width/height is 4x smaller, i had no choice but to create a version of my texture cache that works with a giant 2d texture.&lt;br/&gt;
I haven't bothered to put borders around my pages (yet), so there are plenty of artifacts rendering it like that.&lt;br/&gt;
&lt;br/&gt;
But when i started rendering lots of other artifacts started popping up, which apparently where more likely to happen with smaller pages somehow.&lt;br/&gt;
So i fixed a couple of these artifacts, some which helped improved performance, and i still have a couple of mysterious ones left.&lt;br/&gt;
&lt;br/&gt;
Eventually i'll probably build something where i can record and replay a certain path trough my test level and i would use it to compare all the different parameters that can be used to build and render a virtual texture and see which ones are more efficient compared to the other.&lt;br/&gt;
This will also help to measure performance improvements, or the reverse, when i'll try to implement stuff like texture compression.&lt;br/&gt;
&lt;br/&gt;
Unfortuneatly i probably won't have too much time working on this in the near future, so i'm kinda unsure if i should start on a CSG preprocessor for the level at this moment, because it'll take a couple of days to build and test.&lt;br/&gt;
&lt;br/&gt;
On the upside I actually managed to get into NVIDIA's "GPU Computing Registered Developer Program"!&lt;br/&gt;
Which means i have access to OpenCL, which i would like to experiment with, to see if i can use it to optimize virtual texturing.&lt;br/&gt;
I can imagine that determining which pages are currently visible, could be done more efficiently trough OpenCL.&lt;br/&gt;
It could be done mostly on the GPU, saving CPU time, and would reduce the amount of data to be downloaded back to the CPU.&lt;br/&gt;
Another thing it could help with would be to improve texture decompression speed.&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-927170231130203057?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/927170231130203057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/927170231130203057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/927170231130203057'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/adventures-in-virtual-texture-space.html' title='Adventures in virtual texture space, part 5'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1152966984839383774</id><published>2009-09-15T12:02:00.008+02:00</published><updated>2011-08-08T16:44:50.923+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual Texturing part 4; importing madness</title><content type='html'>&lt;div&gt;
So after rewriting the code to load the pages in the background on a secondary thread, i started to write some code to import a Quake 4 level (.proc files) and modify the geometry so it could be displayed using a virtual texture, which would be automatically created from the textures in the level.
&lt;/div&gt;
&lt;div&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_QB2O0HdIQjQ/Sq9ohGVC6XI/AAAAAAAAAH4/k-toOrqrGZ0/s1600-h/textured.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 247px;" src="http://4.bp.blogspot.com/_QB2O0HdIQjQ/Sq9ohGVC6XI/AAAAAAAAAH4/k-toOrqrGZ0/s320/textured.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5381634997574887794" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
The red in the screenshot above are textures that i couldn't automatically discover without hacking. The black areas are supposed to be transparent, but i'm not handling that at the moment.&lt;br/&gt;
&lt;br/&gt;
Here's a screenshot where every color is a different page, which shows that i have way too many different pages on screen at the same time:&lt;/div&gt;
&lt;div&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_QB2O0HdIQjQ/Sq9oqM0XR6I/AAAAAAAAAIA/Js5xzuwdXBI/s1600-h/tiles.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 247px;" src="http://1.bp.blogspot.com/_QB2O0HdIQjQ/Sq9oqM0XR6I/AAAAAAAAAIA/Js5xzuwdXBI/s320/tiles.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5381635153935681442" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
There are a couple of things that I've learned about converting existing (Quake 4, but the same will apply to other sources as well) geometry to take advantage of virtual textures:&lt;br\&gt;
&lt;ul&gt;
&lt;li&gt;Quake 4 uses a z prepass to take care of occlusion, so it's geometry is optimized for number of triangles and not so much for using as little geometry area as possible, which means a lot of wasted texel space.&lt;/li&gt;
&lt;li&gt;Quake 4 has a lot of transparent textures that are placed upon other textures, which again leads to wasted texel space, as you can see in my screenshots i'm actually not handling transparency.&lt;/li&gt;
&lt;li&gt;Since Quake 4 has separate geometry for each type of shader, you might end up with lots of patches of geometry that each have completely different pages. If this was build with virtual textures in mind, it would've been continuous. This is bad because it means more pages need to be loaded into memory.&lt;/li&gt;
&lt;li&gt;Sometimes large textures are assigned to a relatively small area. If you don't take that into account you'll be assigning large areas of texture space to something which is tiny.&lt;/li&gt;
&lt;li&gt;Without parsing materials (which i'm not doing), discovering the right textures is sometimes impossible.&lt;/li&gt;
&lt;/ul&gt;
These problems are causing me some headaches with my test-scene because i'm loading waaaay more pages than i would need to in a scene that would've been build with virtual textures in mind.&lt;br/&gt;
I could solve this by building my own quake4 map CSG code, which i might do eventually as i &lt;a href="http://video.google.com/videoplay?docid=-1907574989981648678#"&gt;already have some experience with CSG&lt;/a&gt;.&lt;br/&gt;
&lt;br/&gt;
However, if you would be building geometry from scratch this would all be easier, as long as you try to keep texel density at a sane level and keep surface area to a minimum. (aka don't assign texel space to something which is never visible)&lt;br/&gt;
Sounds rather straightforward, i know, but if you don't think about this up front you might end up with some nasty surprises later on.&lt;br/&gt;
&lt;br/&gt;
Also, allocated texture space should be aligned to page boundaries, if you don't you might end up loading 4 pages when 1 would've been sufficient.&lt;br/&gt;
&lt;br/&gt;
One mistake i made trough this whole process was thinking about a virtual texture as a giant texture, and processing it as such.&lt;br/&gt;
The problem with this is that you cannot handle unused pages easily.&lt;br/&gt;
&lt;br/&gt;
Update: scratch that, fixing existing geometry (automatically), to be able to be used with virtual texturing -efficiently-, is hard enough to be considered a dead-end.&lt;br/&gt;
I'm going to rebuild the geometry with my own CSG process instead.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1152966984839383774?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1152966984839383774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/virtual-texturing-part-4-importing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1152966984839383774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1152966984839383774'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/virtual-texturing-part-4-importing.html' title='Virtual Texturing part 4; importing madness'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QB2O0HdIQjQ/Sq9ohGVC6XI/AAAAAAAAAH4/k-toOrqrGZ0/s72-c/textured.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1326877465446766580</id><published>2009-09-07T14:33:00.008+02:00</published><updated>2011-08-08T16:44:50.932+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual Texturing part 3</title><content type='html'>My virtual texture implementation now reads pages from disk.&lt;br/&gt;&lt;br/&gt;
I'm doing it the completely naive way, reading and uploading a page to the video card *just* before i need it, and i'm absolutely surprised how little performance penalty i'm seeing; only 0.1 - 0.2ms!&lt;br/&gt;&lt;br/&gt;
I'm guessing that this has to do, at least in part, because of disk caching since i'm using the regular .net disk functions at the moment (and i -just- generated my virtual texture disk file, so it's fresh in the cache).&lt;br/&gt;
Update: Confirmed, after a reboot i get horrible spikes of +/- 30ms when i move the camera around on the virtual texture!&lt;br/&gt;&lt;br/&gt;
Unfortunately .net won't get any memory mapped IO until .net 4.0 comes out, so i won't be able to try this unless i port everything over to C++.&lt;br/&gt;&lt;br/&gt;
I really should 'acquire' some more interesting test scenes.. a flat polygon is simply too ..erhm.. simple.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1326877465446766580?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1326877465446766580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/virtual-texturing-part-3.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1326877465446766580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1326877465446766580'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/09/virtual-texturing-part-3.html' title='Virtual Texturing part 3'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7282451206614444742</id><published>2009-08-19T19:33:00.012+02:00</published><updated>2011-08-08T16:44:51.092+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual Texturing part 2</title><content type='html'>&lt;div&gt;
A picture, or well in this case a movie, is worth more than a thousand words:&lt;br/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/YCZl16JMF08&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/YCZl16JMF08&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br/&gt;
On top of the screen you can see (pages A/B) how many pages are used (A), and how many there are in memory (B). &lt;br/&gt;
The FPS / Ms should really be ignored..&lt;br/&gt;
&lt;br/&gt;
Internally the OpenGL library for C# i'm working with (OpenTK, and i don't have the source-code) or a broken driver is forcing my app to sync to my monitor's refresh rate (60hz), and my recording software is seriously interfering with the timing of that syncing.&lt;br/&gt;
&lt;br/&gt;
Update: putting a timer around the rendering code (and not relying on OpenTK's timer which is always synchronized to the monitors' refresh rate) showed that i was actually rendering around 4000-5000fps (0.2-0.3ms) instead of just 60fps ;)&lt;br/&gt;
&lt;br/&gt;
Other than that there hasn't been any real performance optimalisations yet and i'm doing some things the quick &amp;amp; dirty way (readbacks are not async, page uploads are not async either, and should probably be spread out over multiple frames etc. etc.).&lt;br/&gt;
I'm basically just doing whatever i can to get things working like i want instead of trying to use the most optimal OpenGL api mechanisms at the moment.&lt;br/&gt;
&lt;br/&gt;
Next to that there are still some artifacts there, i mean next to the usual video compression artifacts, which i'm trying to track down at the moment.&lt;br/&gt;
Just look at 0:30 to 0:32 in the bottom-left corner of the video.&lt;br/&gt;
It's weird that the page loading artifacts are there, because at the moment i'm uploading all the required pages before i use them.&lt;br/&gt;
&lt;br/&gt;
The virtual texture is a mere 8192x8192 at the moment and completely in memory (no reading from disk at the moment).&lt;br/&gt;
Any larger texture would have to be loaded from disk, my system would probably not like loading a 16384x16384 texture in memory ;)&lt;br/&gt;
&lt;br/&gt;
Filtering is trilinear, Bilinear would obviously be faster and would stress the system less as there are fewer pages to be required to be used per frame.&lt;br/&gt;
Seams between pages are more visible with bilinear filtering, but surprisingly hard to spot using trilinear filtering.. in fact, i haven't been able to spot a single one so far!&lt;br/&gt;
&lt;br/&gt;
Next steps would be to fix all the artifacts, start reading back from disk, and optimizing everything.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7282451206614444742?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7282451206614444742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/virtual-texturing-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7282451206614444742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7282451206614444742'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/virtual-texturing-part-2.html' title='Virtual Texturing part 2'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2313600334748158853</id><published>2009-08-14T16:06:00.012+02:00</published><updated>2011-08-08T16:44:50.977+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Virtual Texturing part 1.</title><content type='html'>&lt;div&gt;
Yay! I finally managed to liberate a little time for me to work on virtual texturing!&lt;br/&gt;&lt;br/&gt;
Thinking it would help me avoid worrying about additional borders i used a texture-array instead of a large texture for my physical page-cache texture.&lt;br/&gt;&lt;br/&gt;
(Edit: My test textures just happen to be a 'best case' and with alternating border colors between pages an aliased edge is actually visible, so additional page-borders are still necessary) &lt;br/&gt;&lt;br/&gt;
Each layer in the texture-array (255 max) is a single page, each page is 128x128, which would give me a cache of 255 x 128 x 128 pixels.&lt;br/&gt;&lt;br/&gt;

Right now the 'virtual texture' is small enough that it fits completely in video memory, so it's not exactly 'virtual', there's no readback yet either.&lt;br/&gt;&lt;br/&gt;
There's already a page lookup table however.&lt;br/&gt;&lt;br/&gt;

The next step would be to readback which pages are visible, upload them and update the page lookup table.&lt;br/&gt;&lt;br/&gt;

Here's a short video showing the blending between the pages&lt;br/&gt;&lt;br/&gt;
Yes Yes no fancy graphics or even interesting geometry, I'm on a tight time schedule here people! ;)
&lt;/div&gt;
&lt;div&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ONYt4hbitFE&amp;fmt=18&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/ONYt4hbitFE&amp;fmt=18&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br/&gt;
While working on this i did realize that the rage screenshot in my last post has something odd in it.. &lt;br/&gt;&lt;br/&gt;
Before i only noticed that all the pages where just nice and square and that they had a nice locality to them.&lt;br/&gt;&lt;br/&gt;
What i failed to notice, and what i notice now, that it's just plain weird that there's just no blending or any transitions between what i assumed where mip-maps!?&lt;br/&gt;&lt;br/&gt;
Maybe they're showing pages at the highest resolution? And the ones in the back are bigger because some pages just happen to have a larger geometric area assigned to them? And it just, by chance, looks like some sort of weird rough mipmapping?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2313600334748158853?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2313600334748158853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/virtual-texturing-part-1.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2313600334748158853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2313600334748158853'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/virtual-texturing-part-1.html' title='Virtual Texturing part 1.'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-2973617243240075057</id><published>2009-08-07T09:24:00.008+02:00</published><updated>2011-08-08T16:44:50.997+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><title type='text'>Rage</title><content type='html'>I was just reading a new &lt;a href="http://s09.idav.ucdavis.edu/talks/05-JP_id_Tech_5_Challenges.pdf"&gt;pdf&lt;/a&gt; about Rage, which i'm sure you know is the new game from id software, and i noticed something interesting in one of the screenshots:
&lt;br/&gt;&lt;br/&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s1600-h/rage.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 224px;" src="http://2.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s320/rage.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5367119652520267394" /&gt;&lt;/a&gt;
&lt;br/&gt;
Notice how the texturing is nicely aligned? &lt;br/&gt;&lt;br/&gt;
Seems to me that it would be possible to build a rough bounding volume tree with which you could determine which pages are potentially visible.&lt;br/&gt;
(Something I'm thinking about with my Deferred Virtual Texture Shading stuff)&lt;br/&gt;&lt;br/&gt;
Interestingly they're still reading back from the gpu which pages are visible at which LOD.&lt;br/&gt; 
I wonder if that could be done more efficiently on the cpu avoiding the readback completely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-2973617243240075057?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/2973617243240075057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/rage.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2973617243240075057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/2973617243240075057'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/08/rage.html' title='Rage'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QB2O0HdIQjQ/SnvW40N9DoI/AAAAAAAAAFs/330UqWehq0w/s72-c/rage.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7145556406010933917</id><published>2009-07-26T21:04:00.006+02:00</published><updated>2009-07-26T21:17:35.949+02:00</updated><title type='text'>Time Allocation Failure Exception</title><content type='html'>The plan was like this.&lt;br/&gt;&lt;br/&gt;
My parents have a second house in clermont-ferrand which they bought from the money they had left when they moved to a smaller home when my brother and i started living on our own.&lt;br/&gt;
I was going to spend two weeks there together with my parents, my wife and my daughter.&lt;br/&gt;
After those two weeks i would go home (i have a job after all), and my wife and daughter would stay there with my parents and go home with them another two weeks after that.&lt;br/&gt;
Two heavingly, having breakfast, lunch &amp; diner behind your computer coding weeks.
The week before we would go my wife was complaining that i was spending too much time behind my computer and suggested i would simply do some more work in those two weeks instead.&lt;br/&gt;
Perfect.&lt;br/&gt;
In theory..&lt;br/&gt;&lt;br/&gt;
Ofcourse i didn't get almost any time to program when i was there, and then the day before i was supposed to go home alone we got a call.&lt;br/&gt;
My aunt got a 'cerebral infarct' (mild one, but still very scary and serious stuff obviously).&lt;br/&gt;
So the next day we all went home.&lt;br/&gt;
Together.&lt;br/&gt;
&lt;br/&gt;
Sigh.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7145556406010933917?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7145556406010933917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/07/time-allocation-failure-exception.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7145556406010933917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7145556406010933917'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/07/time-allocation-failure-exception.html' title='Time Allocation Failure Exception'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-5204612661210364823</id><published>2009-06-30T09:46:00.005+02:00</published><updated>2011-08-08T16:49:11.168+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><title type='text'>Deferred Virtual Texture Shading 4</title><content type='html'>Reading a post at &lt;a href="http://gameangst.com/?p=167"&gt;gameangst&lt;/a&gt; made me realize yet some more advantages to my "Deferred Virtual Texture Shading" (*sigh* i really need to think of a better name for this!) idea:&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;It's possible to exclude/include objects from the influence of lights, this makes it easier to make sure that you won't have light bleeding through walls when a light doesn't actually cast any shadows.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;Some time soon i'm going to try this idea out.&lt;/div&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/7301982-5204612661210364823?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/5204612661210364823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-4.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5204612661210364823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/5204612661210364823'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-4.html' title='Deferred Virtual Texture Shading 4'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1734200953161443195</id><published>2009-06-18T09:38:00.007+02:00</published><updated>2011-08-08T16:49:11.164+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><title type='text'>Deferred Virtual Texture Shading 3</title><content type='html'>Just realized another good property of my "Deferred Virtual Texture Shading" idea:  &lt;ul&gt;&lt;li&gt;Anti-aliasing is not a problem with this technique because all the shading occurs in texture space, and the rendering is 'simply' just rendering geometry with one (or two) textures ;)&lt;/li&gt;
&lt;li&gt;Update: Also, if we render our lights in texture space, we can't use proxy meshes to only render light to the pixels that are visible to both the light and the camera. To reduce this disadvantage we could have some sort of octtree/hashed grid/whatever to determine which texture-pages are 'hit' by the light and only redraw those. If we also take page-mipping into account, and only redraw the part of the mip that holds the page we're touching we actually get the "the smaller the light is, the less pixels we process" advantage of deferred lighting back.&lt;/li&gt;
&lt;li&gt;Update 2: Another interesting property is that smoothing the lighting over a surface to make it look as if it's more curved than it actually is would be much easier in texture-space..&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;I really need to allocate some time and try to implement this technique ...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1734200953161443195?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1734200953161443195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-3.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1734200953161443195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1734200953161443195'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-3.html' title='Deferred Virtual Texture Shading 3'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7273113977076909705</id><published>2009-06-17T09:33:00.003+02:00</published><updated>2011-08-08T16:53:27.064+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Fluid-Dynamics'/><title type='text'>Fluid dynamics experimentation</title><content type='html'>&lt;div&gt;
Here is an experiment in fluid dynamics i'm working on:
&lt;/div&gt;&lt;div&gt;
&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/xVuhYhb7biI&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/xVuhYhb7biI&amp;amp;fmt=18&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7273113977076909705?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7273113977076909705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/fluid-dynamics-experimentation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7273113977076909705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7273113977076909705'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/fluid-dynamics-experimentation.html' title='Fluid dynamics experimentation'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7147844482579292717</id><published>2009-06-10T10:11:00.007+02:00</published><updated>2011-08-08T16:49:11.179+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><title type='text'>Deferred Virtual Texture Shading 2</title><content type='html'>&lt;div&gt;I just read a &lt;a href="http://enterthesingularity.blogspot.com/2009/06/deferred-rendering-w-msaa-msaa-z.html"&gt;post on EntherTheSingularity&lt;/a&gt; about some variations on a new technique that's roughly based on deferred rendering.&lt;/div&gt;&lt;div&gt;Basically they can work with transparent surfaces and can let you render the lighting at a lower resolution (saving fillrate), which works because lighting is usually rather low frequency anyway.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;This made me realize a couple of things a&lt;span class="Apple-style-span"&gt;bout my "&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;Deferred Virtual Texture Shading&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;"&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt; idea that i mentioned in a &lt;span class="Apple-style-span"&gt;&lt;a href="http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading.html"&gt;Previous post&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;The &lt;i&gt;good&lt;/i&gt;:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Since we're rendering in texture space we can render lighting at a lower resolution. We could still combine it with albedo at a higher resolution (probably at render time). &lt;i&gt;Yay!&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;The &lt;i&gt;bad&lt;/i&gt;:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Rendering in texture space can cause light leaks, which would be &lt;b&gt;&lt;i&gt;bad&lt;/i&gt;&lt;/b&gt;. So texturing geometry (or filtering) would have to take edges into account. &lt;span class="Apple-style-span" style="font-style: italic; "&gt;Ouch ...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&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/7301982-7147844482579292717?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7147844482579292717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7147844482579292717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7147844482579292717'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading-2.html' title='Deferred Virtual Texture Shading 2'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-7578635290662923323</id><published>2009-06-09T14:30:00.028+02:00</published><updated>2011-08-08T16:51:43.164+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Behavior-Tree'/><category scheme='http://www.blogger.com/atom/ns#' term='Navigation-Meshes'/><title type='text'>Behavior Tree &amp; Navigation Meshes</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Arial;font-size:medium;"&gt;&lt;b&gt;Behavior Tree&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:Arial;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Today i've been busy implementing a behavior tree in C#, which was suprisingly easy!&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;(In case you don't know what a behavior tree is, read &lt;a href="http://aigamedev.com/insider/presentations/behavior-trees/"&gt;this&lt;/a&gt; &lt;b&gt;NOW&lt;/b&gt;!)&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Update: Apparently i the link i provided is in a part of that website which requires (free) registration..&lt;/div&gt;&lt;div&gt;However, the same article is also available (oddly enough) in the publicly accessible part of the website, but split in 3 parts (go figure).&lt;/div&gt;&lt;div&gt;Here &lt;a href="http://aigamedev.com/open/article/behavior-trees-part1/"&gt;are&lt;/a&gt; &lt;a href="http://aigamedev.com/open/article/behavior-trees-part2/"&gt;the&lt;/a&gt; &lt;a href="http://aigamedev.com/open/article/behavior-trees-part3/"&gt;links&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;One of the more complicated parts of the tree is that you don't run the entire tree each frame (which is a good thing!), so it has to be split into small pieces.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;I realized that i could probably abuse the whole enumerator/yield construction in C#, and came up with the following solution:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre class="brush: csharp"&gt;public class Sequence : IBehaviorTransform
{
public IEnumerable&amp;lt;BehaviorResult&amp;gt; Process()
{
   foreach (var node in Children)
   {
       foreach (BehaviorResult result 
                in node.Execute())
       {
           switch (result)
           {
               case BehaviorResult.Success:
                   // If child-node executes
                   // successfully, continue 
                   // to the next node
                   goto NextChild;

               case BehaviorResult.Failure:
                   // Notify parent that 
                   // we've failed ..
                   yield return 
                       BehaviorResult.Failure;
                   // Exit the function
                   yield break;

               case BehaviorResult.Running:
                   // Notify parent that
                   // we're still running
                   yield return 
                       BehaviorResult.Running;
                   // Continue the loop
                   continue;
           }
       }
       NextChild:
       ;
   }
   // Finally, if all nodes are processed
   // without failing we return success
   yield return BehaviorResult.Success;
}
}
&lt;/pre&gt;&lt;br /&gt;
&lt;div&gt;Every IBehaviorTransform implementation would return an IEnumerable of BehaviourResult, and as i enumerate my enumerable once each frame, it'll just &lt;i&gt;magically&lt;/i&gt; work ;)&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;span class="Apple-style-span"  style=" font-weight: bold; font-family:Arial;"&gt;Navigation Meshes&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;Another rough idea of mine is about navigation meshes (Look &lt;a href="http://www.ai-blog.net/archives/000152.html"&gt;here&lt;/a&gt; if you don't know what those are).&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;I haven't played with them yet, but it seems to me that it should be possible to simply perform A* on the traversable edges (that are wide enough for the current entity) to find a path.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;One problem with navigation algorithms is that they're relatively expensive and either need to be stored and/or re-calculated every x frames.. &lt;/div&gt;&lt;div&gt;So you really want to only calculate a rough high level path, and use some more refined (maybe completely different) algorithm at a lower level.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;Suddenly i realized that quite often you'd end up with long paths in any navigation mesh where several connected cells/nodes form a chain.&lt;/div&gt;&lt;div&gt;Which means that you could basically just skip the whole chain during the high level path finding, and only check the nodes/cells where you need to make a decision!&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;You'd probably need to store some basic stuff like the minimum portal size so you can tell in advance if an entity will actually fit through that chain. And you'd need to be able to update the chain in case it's obstructed.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;Maybe information about obstructions could be stored at an entity level?&lt;/div&gt;&lt;div&gt;(probably too memory heavy though)&lt;/div&gt;&lt;div&gt;Entities would then expect a pathway to be clear, but when they arrive it's blocked (useful for planning an ambush?), and then will either try to remove the obstruction (if possible and doesn't require too much time and energy) or try another route instead...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-7578635290662923323?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/7578635290662923323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/behavior-tree-navigation-meshes.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7578635290662923323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/7578635290662923323'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/behavior-tree-navigation-meshes.html' title='Behavior Tree &amp; Navigation Meshes'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8620301856642395300</id><published>2009-06-08T16:11:00.020+02:00</published><updated>2011-08-08T16:52:53.162+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtual-Texture'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface-Caching'/><category scheme='http://www.blogger.com/atom/ns#' term='Geometry-Image'/><title type='text'>Deferred Virtual Texture Shading</title><content type='html'>For some time now i've had this, admittingly pretty vague, idea about a combination of deferred shading and virtual textures (aka "mega-texture").&lt;div&gt;&lt;br /&gt;
&lt;div&gt;It hit me that most of the attributes stored into a G-buffer during deferred shading are already present in a virtual-texture, so if you combine the two you'd only need to store the virtual-texture coordinates, which would require smaller G-buffers.&lt;/div&gt;&lt;div&gt;Ofcourse that's not entirely true, since a pixel in a G-buffer almost never exactly match a texel on a texture; that's what filtering is for.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;But what if we would use our virtual-texture cache as the G-buffer itself?&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;The problems:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;We'd need to fill some of the attributes of the virtual texture at runtime, like coordinates/normals of the texels. However, For static geometry this could be pre-baked, for dynamic geometry this could be cached. (Interestingly enough this sounds a lot like geometry images)&lt;/li&gt;
&lt;li&gt;Another big problem is how can we (efficiently) render the lights into this "virtual G-buffer"? &lt;/li&gt;
&lt;/ol&gt;I'm not sure how the last problem could easily be done without losing all the benefits of deferred shading. It would definitely help to have some sort of hierarchy where virtual texture pages are matched with chunks of geometry.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;That way we'd only calculate the light for lights who's radius touches those chunks of geometry and their respective virtual texture pages.&lt;/div&gt;&lt;div&gt;It would also make it possible to move the paging algorithm completely to the cpu side, that way we won't need a nasty readback from the gpu to discover what virtual texture pages to upload.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;But if (a BIG if) these problems would be solved, it would give us some interesting properties:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Lighting calculations can be cached.&lt;/li&gt;
&lt;li&gt;A virtual texture would be able to contain a lot more data, at a much higher quality, compared to G-buffer (which would potentially create a disk space problem)&lt;/li&gt;
&lt;li&gt;Rendering the geometry would simply be a matter of rendering the geometry with a single texture.&lt;/li&gt;
&lt;li&gt;Transparent surfaces wouldn't need to be rendered in a separate pass. (depth peeling?)&lt;/li&gt;
&lt;li&gt;All shadows and lighting would automatically be filtered. (so you'd better have a high-res virtual texture!)&lt;/li&gt;
&lt;li&gt;Filters and blurs can be applied on lit surfaces (although there would be some difficulties at cache-page boundaries), which could be useful for subsurface scattering effects.&lt;/li&gt;
&lt;li&gt;If you ignore all  the caching, all the calculations would be relatively constant, scaling nicely with the amount of geometry and lights.&lt;/li&gt;
&lt;/ul&gt;The questions are, is it possible? and, is it fast enough?&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/7301982-8620301856642395300?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8620301856642395300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8620301856642395300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8620301856642395300'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2009/06/deferred-virtual-texture-shading.html' title='Deferred Virtual Texture Shading'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-8186273451013204148</id><published>2008-07-06T11:31:00.002+02:00</published><updated>2009-04-21T21:11:28.013+02:00</updated><title type='text'>My 92 year old grandfather plays with Wii</title><content type='html'>Yesterday my grandfather played Wii sports tennis, i kid you not. :)&lt;div&gt;
My parents, both over 60, are considering buying one themselves.. my mother played hours on end!
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Update: My parents actually bought one now ;)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-8186273451013204148?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/8186273451013204148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2008/07/92-year-old-grandfather-plays-with-wii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8186273451013204148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/8186273451013204148'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2008/07/92-year-old-grandfather-plays-with-wii.html' title='My 92 year old grandfather plays with Wii'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7301982.post-1496721121504733794</id><published>2008-06-30T22:32:00.005+02:00</published><updated>2011-08-08T16:53:50.364+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entity-Systems'/><title type='text'>Component Object Systems</title><content type='html'>Lately I've been thinking a lot about component object systems.
If you don't know what that is, read the following links:&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="color:#551A8B;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;Entity Systems are the future of MMOG development&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.gamearchitect.net/Articles/GameObjects1.html"&gt;Game Object Structure: Inheritance vs. Aggregation&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.drizzle.com/~scottb/gdc/game-objects_files/frame.htm"&gt;A Data-Driven Game Object System&lt;/a&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;I've implemented the basics of this system in C#.&lt;/div&gt;&lt;div&gt;Still trying to figure out how to do messaging most effectively...&lt;/div&gt;&lt;div&gt;and wondering how to make this all work in a multi-threaded environment&lt;/div&gt;&lt;div&gt;(each component = job in worker thread?) and still keep everything predictable.

&lt;/div&gt;&lt;div&gt;I just have this gut feeling that component object systems could be mixed with finite state machines, where an object would remove/deactivate or add/activate components based on which state they're in ...&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;But it would complicate the hell out of any user-interface around it...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7301982-1496721121504733794?l=sandervanrossen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sandervanrossen.blogspot.com/feeds/1496721121504733794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sandervanrossen.blogspot.com/2008/06/component-object-systems.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1496721121504733794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7301982/posts/default/1496721121504733794'/><link rel='alternate' type='text/html' href='http://sandervanrossen.blogspot.com/2008/06/component-object-systems.html' title='Component Object Systems'/><author><name>Sander van Rossen</name><uri>https://profiles.google.com/115320162438581803860</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-lChGYLMOtog/AAAAAAAAAAI/AAAAAAAAAdw/POZkmrp54qs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry></feed>
