<?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-9153918266310828368</id><updated>2011-11-17T23:51:36.164-08:00</updated><category term='C++'/><category term='Bullet'/><category term='Procedural City'/><category term='Voronoi'/><category term='SlimDX'/><category term='PhysX'/><category term='Tessellation'/><category term='Unity'/><category term='Perlin Noise'/><category term='DirectX 10'/><category term='HLSL'/><category term='Compute Shader'/><category term='DirectX 11'/><category term='JavaScript'/><category term='XNA'/><title type='text'>ReCreation Studios</title><subtitle type='html'>Following my adventures in various graphics projects. These mainly consist of procedural development, image processing, and physics.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>59</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-17076011501223665</id><published>2011-09-25T22:26:00.000-07:00</published><updated>2011-09-25T22:25:12.775-07:00</updated><title type='text'>Unity GPU Noise (Part 4)</title><content type='html'>Well, I'm a stubborn individual, so I continued working on the Android version of GPU Noise.  I have actually been successful and made a little progress.  Not without encountering more issues, of course.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, I must say that GLSL &lt;b&gt;hates &lt;/b&gt;conditional branches (including &lt;i&gt;for &lt;/i&gt;loops).  The main reason why my example scene wasn't running on Android was because I used an if-else tree in my shader (&lt;a href="http://recreationstudios.blogspot.com/2011/08/unity-gpu-noise-part-2.html"&gt;previously a switch statement&lt;/a&gt;) to select the noise type based upon a variable that was set on the Material by the C# side.  While this works perfectly fine on Windows and DirectX, it's not the case for Android.  I had to separate each noise type into its own shader/material and then have logic on the C# side to select the correct Material.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is where things start to get strange.  The basic Perlin noise function worked fine (as well as Voronoi), but none of my summations (like fBm) worked.  They are simply &lt;i&gt;for &lt;/i&gt;loops that call the Perlin function repeatedly.  For testing, instead of having it take a variable for the number of times to loop, I hard-coded it to 4 octaves.  This didn't work either.  However, if I manually unrolled the for loop to have the code repeated 4 times, it finally worked.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, a little aside about my implementation.  In order to speed up the noise functions, I precompute some values and store them in various textures which the noise functions then sample from.  I wanted the noise functions to be accessible in both a vertex shader and pixel shader, so I used the &lt;a href="http://msdn.microsoft.com/en-us/library/bb509680(v=vs.85).aspx"&gt;tex2Dlod &lt;/a&gt;function to sample the textures.  This is because tex2Dlod is the only permitted function for sampling from a vertex shader. (Automatic mip-mapping doesn't work in a vertex shader, so the developer must specify the mip-map level to use.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thinking that using tex2Dlod was somehow causing my &lt;i&gt;for &lt;/i&gt;loop problems, I decided to look into a different implementation.  I found a &lt;a href="https://github.com/ashima/webgl-noise/wiki"&gt;GLSL implementation of Perlin noise&lt;/a&gt; that didn't use any arrays or texture lookups (amazing!), thus making it highly cross-platform.  I promptly ported it over to Cg in Unity.  I was dismayed to discover that it yielded really terrible looking visual artifacts.  The problem was even worse when using any summation.  I quickly made a &lt;a href="http://re-creationstudios.com/webgl/noise/"&gt;test scene in WebGL&lt;/a&gt; to test the shader in its original GLSL.  Here, as you can see, it all worked perfectly.  Going back to the Cg port, I went over line by line to see where it was failing.  I first tried replacing the optimized "hacks" he used in place of modulus.  That didn't fix it.  Then, I looked at his inverse square root function.   If I replaced his function with a call to &lt;a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb509643(v=vs.85).aspx"&gt;rsqrt&lt;/a&gt;, the artifacts disappeared!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Armed with a new implementation, I tried running my test scene on Android again.  And again, my summations failed.  I happened to discover that the summations only worked when given certain octaves (&lt;i&gt;for &lt;/i&gt;loop counter).  This is the strangest thing of all.  If I gave it 1, it worked.  If I gave it 2 through 8, it failed.  If I gave it 9 or greater, it worked.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I must say, I'm entirely perplexed.  I have all of my noise functions working on an Android device now, but only with certain ranges on the summations.  Why doesn't it work with 4 octaves when it works with 10?  Does anyone have any insight into this strange issue?&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/9153918266310828368-17076011501223665?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/17076011501223665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=17076011501223665' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/17076011501223665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/17076011501223665'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2011/09/unity-gpu-noise-part-4.html' title='Unity GPU Noise (Part 4)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8152382916779113647</id><published>2011-09-15T11:29:00.000-07:00</published><updated>2011-09-15T14:47:10.255-07:00</updated><title type='text'>Unity GPU Noise (Part 3)</title><content type='html'>As I mentioned &lt;a href="http://recreationstudios.blogspot.com/2011/08/unity-gpu-noise-part-2.html"&gt;previously&lt;/a&gt;, I had updated my GPU Noise to hopefully get it working on Macs.  One of my friends tried the web player build on his Mac, and I was saddened to see that it still came out as a black, non-displaced sphere.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As I was investigating, I found the &lt;a href="http://unity3d.com/support/documentation/ScriptReference/Shader-isSupported.html"&gt;Shader.isSupported&lt;/a&gt; API which looked like it might be helpful.  I noticed in the documentation, however, that it will return true if any of the Fallback shaders will work.  In my noise shader, I had given it a fallback of "VertexLit", thus why only a flat, black sphere was rendered on the Mac.  I didn't want the API to always return true (since VertexLit obviously was working), so I commented out the Fallback statement.  Bad move!  Not only did the web player fail to load on a Mac, it completely locked the entire OS requiring a reboot!  Since my friend's Mac is a dual-boot with Windows 7 on it, I had him try it out on the Windows side.  Everything worked perfectly!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to help me with debugging possible hardware issues, I wrote a simple little Unity web player that listed the hardware specs according to how Unity sees the machine.  It's been pretty interesting and helpful.  You can run it &lt;a href="http://re-creationstudios.com/unity/info/"&gt;over here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Using that app, I was able to see that the Mac only runs OpenGL 2.1!  For comparison, when I forced my Windows build to run in OpenGL mode (using&lt;a href="http://unity3d.com/support/documentation/Manual/Command%20Line%20Arguments.html"&gt; -force-opengl&lt;/a&gt;), it reported that it was running OpenGL 4.1.  My hatred for Apple increases daily.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Deciding to switch gears for a bit, I started looking into deploying the GPU Noise on my EVO 3D to see how it ran.  (No, I don't have a personal Android license for Unity yet, but I do have one from work.  I;m not going to publish anything from it, just use it to test my stuff after work.)  So, I got everything setup and sent my package over to my phone, where I was greeted with the "Powered by Unity" splashscreen.  That was it; it never made it beyond that point.  I hooked up &lt;a href="http://developer.android.com/guide/developing/tools/adb.html#logcat"&gt;logcat &lt;/a&gt;and added some debug lines to see what errors were occurring.  That wasn't helpful at all.  It showed Unity loading, timing out, and then reloading.  My level file was never loaded, none of my scripts were ever executed.  If I switched my Material to be something else (I used a particle material), it would load properly and run.  So, it was an issue with my noise Material, but I have no idea what, due to the lack of errors.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As it stands now, I'm not quite sure how to proceed.  Do I release this on the Unity Asset Store as it is now and put a disclaimer that it only works on Windows currently, or do I invest more time and effort to get it working on Mac/Android first?  Opinions?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8152382916779113647?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8152382916779113647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8152382916779113647' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8152382916779113647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8152382916779113647'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2011/09/unity-gpu-noise-part-3.html' title='Unity GPU Noise (Part 3)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4589967077238544214</id><published>2011-09-12T09:34:00.000-07:00</published><updated>2011-09-12T12:22:51.336-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unity'/><title type='text'>Procedural Primitives (Unity Asset Store)</title><content type='html'>&lt;a href="http://4.bp.blogspot.com/-v_cl7zyKqNM/Tm5UDoFRJKI/AAAAAAAAF8M/uvDx0n3IW8E/s1600/screen1.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 163px;" src="http://4.bp.blogspot.com/-v_cl7zyKqNM/Tm5UDoFRJKI/AAAAAAAAF8M/uvDx0n3IW8E/s400/screen1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5651547003672405154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I've released my first package, Procedural Primitives, on the Unity Asset Store.   &lt;a href="http://u3d.as/content/re-creation-studios/procedural-primitives/1XM"&gt;Check it out here&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's based on the code I wrote to generate primitives in XNA.  You can read about that code and download it on my old blog post &lt;a href="http://recreationstudios.blogspot.com/2009/04/boxes-cylinders-and-spheres-oh-my.html"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Basically, it allows you to create your own primitive 3D shapes (planes, cylinders, cones, and boxes) in Unity.  Sure, Unity already has all  of these as built-in primitives, but you can't change the resolution of these shapes at all.  Plus, they provide no ability to create just the Mesh object and not a full GameObject.   Procedural Primitives lets you pick the quality you want and gives you the option to create only the Mesh or the a full GameObject containing MeshFilter, MeshRenderer, and Collider components.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Procedural Primitives allows you to create the shapes either in the Unity Editor by way of a custom editor window, or you can call the methods in script.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To create them in the editor, you choose GameObject --&amp;gt; Create Other --&amp;gt; Procedural Primitive from the menu:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-Z3RhFXBoWoU/Tm5USuWlpMI/AAAAAAAAF8U/0btpyulpCyo/s1600/screen4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 339px;" src="http://4.bp.blogspot.com/-Z3RhFXBoWoU/Tm5USuWlpMI/AAAAAAAAF8U/0btpyulpCyo/s400/screen4.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5651547263053702338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A new window will pop up that will allow you to tweak several parameters (depending upon the chosen shape) and then create a new primitive shape.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-Oc0rr3j5-yY/Tm5VbGfZMdI/AAAAAAAAF8g/BQ0PXsvdgZQ/s1600/screen5.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 203px;" src="http://2.bp.blogspot.com/-Oc0rr3j5-yY/Tm5VbGfZMdI/AAAAAAAAF8g/BQ0PXsvdgZQ/s400/screen5.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5651548506483667410" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To create a new shape in script, you simply call one of the static methods on the Primitive class along with the desired parameters:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-F_YoB4iBGk4/Tm5a54j0QxI/AAAAAAAAF8s/uC7O5D5hwEs/s1600/screen6.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 139px;" src="http://4.bp.blogspot.com/-F_YoB4iBGk4/Tm5a54j0QxI/AAAAAAAAF8s/uC7O5D5hwEs/s400/screen6.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5651554532878205714" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All money I get from the sales of Procedural Primitives will help fund my purchase of an Android license of Unity.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm currently preparing my noise package release.  It should be coming out sometime in the next week.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4589967077238544214?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4589967077238544214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4589967077238544214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4589967077238544214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4589967077238544214'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2011/09/procedural-primitives-unity-asset-store.html' title='Procedural Primitives (Unity Asset Store)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-v_cl7zyKqNM/Tm5UDoFRJKI/AAAAAAAAF8M/uvDx0n3IW8E/s72-c/screen1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3416555373079770164</id><published>2011-08-18T22:44:00.000-07:00</published><updated>2011-08-19T00:38:35.591-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unity'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>Unity GPU Noise (Part 2)</title><content type='html'>Sheesh!  Yet another 5 months have passed by!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I was creating the demo of GPU Noise in Unity, I kept getting a "&lt;span class="Apple-style-span" style="color: rgb(17, 17, 17); font-family: Helvetica, Arial, sans-serif; font-size: 13px; line-height: 15px; background-color: rgb(254, 254, 254); "&gt;function 'tex2Dlod' not supported in this profile&lt;/span&gt;" error.  I couldn't figure out why except that it was an OpenGL issue.  So, I simply forced my shaders to exclude OpenGL and OpenGL ES renderers (&lt;i&gt;#pragma exclude_renderers opengl gles&lt;/i&gt;).  Obviously this is not the best solution, so I decided to dive into it again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It turns out that the error goes away if you instead force the shader to compile to GLSL (&lt;i&gt;#pragma glsl&lt;/i&gt;).  I have no idea why this fixes the problem, since it was an OpenGL issue in the first place, but whatever.  Forcing the shaders to compile to GLSL brought up two other issues that I had to fix.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1)  &lt;b&gt;GLSL doesn't support default parameters&lt;/b&gt; (Cg and HLSL do).   This means that I had to go duplicate all of my shader functions that used them, which were a lot.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2) &lt;b&gt;GLSL doesn't support the switch statement&lt;/b&gt;.  I had to go manually unroll my switch statements to be if-else trees.  This one really confused me because all of the GLSL documentation seems to indicate that switch is indeed in the language, so this might just be a Unity issue.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can check out the updated demo here:&lt;/div&gt;&lt;div&gt;&lt;a href="http://re-creationstudios.com/unity/noise/"&gt;http://re-creationstudios.com/unity/noise/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hopefully it works on Mac now, but I haven't been able to test it out yet.  Feel free to let me know!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3416555373079770164?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3416555373079770164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3416555373079770164' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3416555373079770164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3416555373079770164'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2011/08/unity-gpu-noise-part-2.html' title='Unity GPU Noise (Part 2)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-1735444662782975352</id><published>2011-03-08T13:55:00.001-08:00</published><updated>2011-07-13T15:00:31.660-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unity'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>Unity GPU Noise &amp; Unity Issues</title><content type='html'>It's amazing how much time keeps slipping by without any posts.  Another 5 months have somehow passed since my last post.  That means that I have only written 2 posts in the past year!  I need to get back to my good update schedule.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;GPU Noise in Unity&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First, I'd like to show a simple demo I made of various types of noise on the GPU in Unity.  You can check out the live demo on the web by clicking on the image below.  You need to have a Shader Model 3.0 GPU in order to run the demo.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://re-creationstudios.com/unity/noise/"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/-hpkESpl8vWE/TXavIQlzvAI/AAAAAAAAFlA/lDE24WNJ7Ds/s400/noise.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5581841344599669762" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see, there are 9 different types of noise in the demo and they are all implemented in Cg shaders on the GPU.&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Perlin_noise"&gt;Perlin&lt;/a&gt;&lt;/i&gt; - "Standard" Perlin Noise (1 octave)&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Fractional_Brownian_motion"&gt;fBm&lt;/a&gt;&lt;/i&gt; - fractional Brownian motion summation of Perlin Noise (8 octaves)&lt;/li&gt;&lt;li&gt;&lt;i&gt;Turbulence&lt;/i&gt; - fBm variation that sums the absolute value of the noise result (8 octaves)&lt;/li&gt;&lt;li&gt;&lt;i&gt;Ridged&lt;/i&gt; - fBm variation from the book "Texturing and Modeling: A Procedural Approach" that performs a special ridge function on the noise result (8 octaves)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Voronoi_diagram"&gt;&lt;i&gt;Voronoi&lt;/i&gt;&lt;/a&gt; (F1) - A "noise" type that uses a field of random 3D points and determines the distance to the closest point&lt;/li&gt;&lt;li&gt;&lt;i&gt;F2&lt;/i&gt; - Voronoi that determines the distance to the &lt;i&gt;second &lt;/i&gt;closest point&lt;/li&gt;&lt;li&gt;&lt;i&gt;F2 - F1&lt;/i&gt; - Voronoi that determines the difference between the first and second closest points&lt;/li&gt;&lt;li&gt;&lt;i&gt;(F1 + F2) / 2&lt;/i&gt; - Voronoi that averages the distance between the two closest points&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://www.gamedev.net/blog/73/entry-1832259-gpu-terrain-generation-cell-noise-rivers-crater/"&gt;Crater&lt;/a&gt;&lt;/i&gt; - Voronoi variation that makes crater-like structures &lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;Have fun messing around with the sliders and seeing how the noise can be manipulated on the fly!&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;Unity Issues&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After completing the GPU noise demo in Unity (it's actually been done since November), I started proceeding with implementing a procedural planet generator in Unity.  It quickly introduced me to some of the issues and limitations that Unity has.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://answers.unity3d.com/questions/29948/disable-frustum-culling"&gt;Cannot disable/control view frustum culling&lt;/a&gt;&lt;/i&gt;.&lt;br /&gt;This is the worst issue I ran into.  The way I implement the planet is to have a small cube that is "blown out" to form a sphere and then offset with noise all on the GPU (à la displacement mapping).  Unity has a camera system that determines which objects are inside each camera's view frustum and automatically culls (doesn't draw) any objects that are outside of the view frustum.  The problem is, while the small cube is not in the view frustum, the final displaced planet &lt;b&gt;is&lt;/b&gt; in the frustum.  This causes the planet to suddenly stop rendering if the camera is pointed a certain direction.&lt;br /&gt;&lt;br /&gt;I tried several fixes such as blowing the cube up to be the same size of the planet and forcing the view angle to be the maximum value (179 degrees) when Unity does the frustum check.  Neither of these got rid of the problem entirely and just reduced how much it happened.  In order to fix it, game developers should have control over which objects should be culled, or be able to disable frustum culling entirely.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://answers.unity3d.com/questions/30420/run-script-in-edit-mode-when-paused"&gt;Cannot run editor scripts when paused&lt;/a&gt;&lt;/i&gt;.&lt;br /&gt;This problem stems from another problem in Unity.  Unity doesn't send the View matrix (by design) or Projection matrix (current bug) to the shaders, so you need a script to send them manually.  Because of this, you need to have this script continually updating the shader variables even when the game is paused.  If they are not updated then the objects render in the same place on the screen no matter where you move the camera.  This is a horrible problem with no real fix.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://answers.unity3d.com/questions/30357/create-a-custom-collider"&gt;Cannot create a custom collider&lt;/a&gt;&lt;/i&gt;.&lt;br /&gt;Unity provides no simple way to create your own physics collider object.  You can inherit from their built-in Collider class, but you cannot override any methods inside of it.  As you can see from the link, I came up with a work-around for what I specifically was trying to accomplish: make a spherical planet collider.  It is very similar to what I did in Bullet in the past.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;&lt;a href="http://forum.unity3d.com/threads/66153-Writing-depth-value-in-fragment-program"&gt;Cannot write depth in pixel shader&lt;/a&gt;&lt;/i&gt;. (&lt;a href="http://www.ogre3d.org/forums/viewtopic.php?p=274238"&gt;Also explained here&lt;/a&gt;.)&lt;br /&gt;I tried implementing a logarithmic depth buffer, but I was greeted with a Cg compilation error when trying to write to the depth register.  This is actually a bug in the Cg compiler.  It's been fixed in the compiler, but Unity is still using an old version of the compiler which has the bug. I need to test the latest releases of Unity to see if this is still a problem.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-1735444662782975352?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/1735444662782975352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=1735444662782975352' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1735444662782975352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1735444662782975352'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2011/03/unity-gpu-noise-unity-issues.html' title='Unity GPU Noise &amp; Unity Issues'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-hpkESpl8vWE/TXavIQlzvAI/AAAAAAAAFlA/lDE24WNJ7Ds/s72-c/noise.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8699083988602433584</id><published>2010-11-15T20:48:00.000-08:00</published><updated>2011-04-05T22:28:50.968-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unity'/><category scheme='http://www.blogger.com/atom/ns#' term='Bullet'/><title type='text'>Update &amp; Unity</title><content type='html'>Wow!  I can't really believe it's been 7 months (exactly!) since I last posted an entry here.  I wish I had something to show, but sadly I do not.  To be honest, I have been all over the place with my development.  I experimented with a number of different things, but nothing for an extended period of time.  I'm hoping to change that soon though.  More on that later, first a list of the things I was working on:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Shadow Mapping&lt;/span&gt;&lt;br /&gt;I had actually never done any shadow mapping programming before, so it was more of a learning experience in understanding the concept and what is required.  I implemented a simple demo in SlimDX/DirectX 11 and posted a video of it on YouTube, but it really is nothing exciting.  Standard, run of the mill, shadow mapping.  No fancy tricks in the implementation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Parallel City Generation&lt;/span&gt;&lt;br /&gt;I pulled out the old procedural city generator code I blogged about before and updated and refactored the road generator to be able to run in parallel.  This allowed me to draw the roads as they were being created.  I thought it was pretty cool looking.  My goal was to parallelize it to the point where I could implement it as a compute shader, but I couldn't seem to get it to that point.  So, I kind of gave up on it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Bullet Physics&lt;/span&gt;&lt;br /&gt;I decided to go back and start messing around with physics again, and I used XNA and BulletSharp this time.  I was working on an idea that I've had brewing in the back of my brain for quite awhile.  I made some decent progress and was quite happy.  However, I started thinking about how I was essentially writing my own game engine (terrain, lighting, shadowing, physics integration).  Plus, looking at the target platforms for XNA (Xbox 360, Windows Desktop, Windows Phone), I started wondering if that was best for me.  So, that led me to the next item.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Unity&lt;/span&gt;&lt;br /&gt;For several months Unity had been looking appealing to me.  Two of the biggest pulls for me were C# scripting (via the Mono Framework) and PhysX integration.  The wide array of supported platforms was also a huge plus (Mac, Windows, iPhone, iPad, Web).  When they announced support for Android as well, I was "sold" in a manner of speaking (as I have an Android phone myself).  So, I installed the free version of Unity and tried to see if I could implement the functionality I had already implemented via BulletSharp and XNA inside of Unity scripting itself.  One weekend later, I had accomplished that and more! &lt;br /&gt;&lt;br /&gt;I'll be honest, Unity is far from the perfect engine.  It severely limits you due to the wide range of hardware specs that it runs on.  Don't expect to be doing any tessellation or compute shaders here.  Heck, it doesn't even support geometry shaders!  However, it does seem to be a very well organized engine with good documentation on their webpage and a component based system that I love.  I like it enough to at least fiddle around with it some more over the next couple of months.&lt;br /&gt;&lt;br /&gt;An added bonus is that my prototypes can be deployed to my server which means you (the reader) can run them in your browser without installing the them.  Expect to see a Perlin Noise example soon.  :-)  That really has become my "Hello World" program for testing different graphics APIs.&lt;br /&gt;&lt;br /&gt;A final note I'd like to leave here is regarding some other "big" game engines.  I was slightly surprised last week to hear not just one, but two game engines have essentially "imploded".  Both Torque and Gamebryo are closing up shop and looking for buyers.  That leaves Unity looking even stronger.&lt;br /&gt;&lt;br /&gt;Until next time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8699083988602433584?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8699083988602433584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8699083988602433584' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8699083988602433584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8699083988602433584'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/11/update-unity.html' title='Update &amp; Unity'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7761763113749210841</id><published>2010-04-15T22:36:00.000-07:00</published><updated>2010-04-16T00:50:41.470-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Bullet'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Spherical Terrain Physics</title><content type='html'>For quite a long while I have been trying to figure out how exactly to do collision detection on my procedurally generated, tessellated, spherical terrain.&lt;br /&gt;&lt;br /&gt;The problem lies with the fact that terrain itself doesn't really exist until the GPU.  I generate a simple spherical mesh on the CPU and then send it to the GPU to draw.  Once there it is tessellated based upon the distance to the camera and then it is displaced via a summation of Perlin Noise.&lt;br /&gt;&lt;br /&gt;Obviously this makes it very hard to do collision detection on the CPU side.  Many physics engines support a special heightmap object for terrain, but they all assume the terrain is on a plane (usually the XZ) with one axis being the displacement axis (usually the Y).  Of course that wouldn't work for spherical terrain.  Most physics engines also have a generic triangle mesh object.  However these are usually meant to be static meshes and therefore are hard to tessellate.  It would require destroying and recreating a mesh on the fly, which would be rather slow and wasteful.&lt;br /&gt;&lt;br /&gt;What I really needed was the ability to create a collision shape that was defined by an equation (the Perlin sum in my case).  In the past I have always used PhysX, but since it is closed source I decided to try this out in another physics engine.  I hopped onto the Bullet forums and posed the question.  I was told that it should be possible if I created a new shape object that inherited from the base concave object and overrode its ProcessAllTriangles() method to use the equation.&lt;br /&gt;&lt;br /&gt;So, I went and did exactly that.  Lo and behold it worked!&lt;br /&gt;&lt;br /&gt;First, I created a shape called btSphericalTerrainShape which inherits from btConcaveShape.  It takes 3 parameters to setup:  The center point of the terrain, the radius of the terrain (including the maximum offset of the terrain) which is used for the bounding box, and a function pointer that points to a function that defines the terrain's equation.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;btSphericalTerrainShape(&lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; center, btScalar radius, btVector3 (*calcVertex)(&lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; position, &lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; center));&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The function pointer passes along 2 parameters:  the current point being evaluated (usually one of the corners of the other object's bounding box), and the center point of the terrain.  This allows the terrain to be defined by practically any method desired.&lt;br /&gt;&lt;br /&gt;For example, if you wanted to define the terrain as a simple sphere with a radius of 50, you would use the following method:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;btVector3 calculateTerrainVertex(&lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; position, &lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; center)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; (position - center).normalized() * 50.0f;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If you wanted to define the terrain as a sphere with a radius of 50 that was offset by 8 octaves of Perlin Noise, you would use this method:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;btVector3 calculateTerrainVertex(&lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; position, &lt;span style="color: blue;"&gt;const&lt;/span&gt; btVector3&amp;amp; center)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; btVector3 normalized = (position - center).normalized();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;double&lt;/span&gt; result = PerlinNoise::fBm(normalized.x(), normalized.y(), normalized.z(), 8);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; normalized * btScalar(50.0f + result * 10.0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now, for the details on the ProcessAllTriangles() method.  It takes an axis aligned bounding box (AABB) for the other shape being tested and a callback that is called for each triangle that collides with that bounding box.&lt;br /&gt;&lt;br /&gt;These are the steps done in the method:&lt;br /&gt;&lt;br /&gt;1) Calculate the 8 corners of the AABB&lt;br /&gt;2) Calculate the midpoint of each of the 6 sides of the AABB&lt;br /&gt;3) Calculate the position of the vertex on the terrain by calling the calculateTerrainVertex function pointer&lt;br /&gt;4) Determine which of the corners of the AABB are colliding with the terrain by checking if the bounding box corners are closer to the center point than the respective terrain vertices&lt;br /&gt;5) Find which 3 sides of the AABB are closest to the terrain in order to prevent extraneous triangle processing&lt;br /&gt;6) Use the callback to process each triangle that collides&lt;br /&gt;&lt;br /&gt;For the actual implementation details, be sure to download the source code for the btSphericalTerrainShape.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.re-creationstudios.com/shared/btSphericalTerrainShape.h"&gt;btSphericalTerrainShape.h&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.re-creationstudios.com/shared/btSphericalTerrainShape.cpp"&gt;btSphericalTerrainShape.cpp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7761763113749210841?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7761763113749210841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7761763113749210841' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7761763113749210841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7761763113749210841'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/04/spherical-terrain-physics.html' title='Spherical Terrain Physics'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8213312985228414542</id><published>2010-04-08T22:24:00.000-07:00</published><updated>2010-04-09T00:14:41.090-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Compute Shader'/><title type='text'>Sobel Filter Compute Shader</title><content type='html'>Thanks to Josh Petrie, I now have the Compute Shader working with the swap chain backbuffer.  I decided a good first test is to use a Compute Shader to run a Sobel Filter on an image and display the result in the backbuffer.&lt;br /&gt;&lt;br /&gt;It was all very easy to get set up.  First you create a DirectX 11 swap chain, just like normal.  The only difference is the Usage property of the swap chain has an additional flag set which is (Usage)1024 and it represents UnorderedAccess.  This allows the backbuffer to be used as an output UAV in the Compute Shader.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;RenderForm&lt;/span&gt; form = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;RenderForm&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;&amp;quot;SlimDX - Sobel Filter Compute Shader&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;form.ClientSize = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Size&lt;/span&gt;(1024, 1024);&lt;/pre&gt;&lt;br /&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;SwapChainDescription&lt;/span&gt; swapChainDesc = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;SwapChainDescription&lt;/span&gt;()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BufferCount = 1,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Flags = &lt;span style="color: #2b91af;"&gt;SwapChainFlags&lt;/span&gt;.None,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IsWindowed = &lt;span style="color: blue;"&gt;true&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ModeDescription = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ModeDescription&lt;/span&gt;(form.ClientSize.Width, form.ClientSize.Height, &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Rational&lt;/span&gt;(60, 1), &lt;span style="color: #2b91af;"&gt;Format&lt;/span&gt;.R8G8B8A8_UNorm),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; OutputHandle = form.Handle,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SampleDescription = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;SampleDescription&lt;/span&gt;(1, 0),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SwapEffect = &lt;span style="color: #2b91af;"&gt;SwapEffect&lt;/span&gt;.Discard,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;//(Usage)1024 = Usage.UnorderedAccess&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Usage = &lt;span style="color: #2b91af;"&gt;Usage&lt;/span&gt;.RenderTargetOutput | (&lt;span style="color: #2b91af;"&gt;Usage&lt;/span&gt;)1024 &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;};&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Device&lt;/span&gt; device;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;SwapChain&lt;/span&gt; swapChain;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Device&lt;/span&gt;.CreateWithSwapChain(&lt;span style="color: blue;"&gt;null&lt;/span&gt;, &lt;span style="color: #2b91af;"&gt;DriverType&lt;/span&gt;.Hardware, &lt;span style="color: #2b91af;"&gt;DeviceCreationFlags&lt;/span&gt;.Debug, swapChainDesc, &lt;span style="color: blue;"&gt;out&lt;/span&gt; device, &lt;span style="color: blue;"&gt;out&lt;/span&gt; swapChain);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The rest of the setup is standard stuff.  You grab the backbuffer texture, load the image to run the filter on, and load/compile the Compute Shader.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt; backBuffer = &lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt;.FromSwapChain&amp;lt;&lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt;&amp;gt;(swapChain, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;RenderTargetView&lt;/span&gt; renderView = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;RenderTargetView&lt;/span&gt;(device, backBuffer);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt; flower = &lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt;.FromFile(device, &lt;span style="color: #a31515;"&gt;&amp;quot;flower.jpg&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;ShaderResourceView&lt;/span&gt; resourceView = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ShaderResourceView&lt;/span&gt;(device, flower);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;ComputeShader&lt;/span&gt; compute = &lt;span style="color: #2b91af;"&gt;Helper&lt;/span&gt;.LoadComputeShader(device, &lt;span style="color: #a31515;"&gt;&amp;quot;Sobel.hlsl&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;UnorderedAccessView&lt;/span&gt; computeResult = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;UnorderedAccessView&lt;/span&gt;(device, backBuffer);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The "render" loop doesn't contain any actual rendering.  It sets up the render target and viewport like normal, but then it sets the Compute Shader and runs it.  After the Compute Shader is ran, the swap chain is told to present the backbuffer, which now contains the Compute Shader output.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;device.ImmediateContext.OutputMerger.SetTargets(renderView);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;device.ImmediateContext.Rasterizer.SetViewports(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Viewport&lt;/span&gt;(0, 0, form.ClientSize.Width, form.ClientSize.Height, 0.0f, 1.0f));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;MessagePump&lt;/span&gt;.Run(form, () =&amp;gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.ClearRenderTargetView(renderView, &lt;span style="color: #2b91af;"&gt;Color&lt;/span&gt;.Black);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.ComputeShader.Set(compute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.ComputeShader.SetShaderResource(resourceView, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.ComputeShader.SetUnorderedAccessView(computeResult, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.ComputeShader.SetConstantBuffer(constantBuffer, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; device.ImmediateContext.Dispatch(32, 32, 1);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; swapChain.Present(0, &lt;span style="color: #2b91af;"&gt;PresentFlags&lt;/span&gt;.None);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;});&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;That's it for the CPU side, now let's look at the GPU side.  It's a standard Sobel Filter that only has an input texture and an output texture.  The output can either be the Sobel result alone, or it can be the Sobel result laid over the input texture.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Texture2D&lt;float4&gt; Input : register(t0);&lt;br /&gt;RWTexture2D&lt;float4&gt; Output : register(u0);&lt;br /&gt;&lt;br /&gt;[numthreads(32, 32, 1)]&lt;br /&gt;void main( uint3 threadID : SV_DispatchThreadID )&lt;br /&gt;{&lt;br /&gt;    float threshold = 0.20f;&lt;br /&gt;    bool overlay = true;&lt;br /&gt;    &lt;br /&gt;    // Sample neighbor pixels&lt;br /&gt;    // 00 01 02&lt;br /&gt;    // 10 __ 12&lt;br /&gt;    // 20 21 22&lt;br /&gt;    float s00 = Input[threadID.xy + float2(-1, -1)].r;&lt;br /&gt;    float s01 = Input[threadID.xy + float2( 0, -1)].r;&lt;br /&gt;    float s02 = Input[threadID.xy + float2( 1, -1)].r;&lt;br /&gt;    float s10 = Input[threadID.xy + float2(-1,  0)].r;&lt;br /&gt;    float s12 = Input[threadID.xy + float2( 1,  0)].r;&lt;br /&gt;    float s20 = Input[threadID.xy + float2(-1,  1)].r;&lt;br /&gt;    float s21 = Input[threadID.xy + float2( 0,  1)].r;&lt;br /&gt;    float s22 = Input[threadID.xy + float2( 1,  1)].r;&lt;br /&gt;&lt;br /&gt;    float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;&lt;br /&gt;    float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;&lt;br /&gt;&lt;br /&gt;    float edgeSqr = (sobelX * sobelX + sobelY * sobelY);&lt;br /&gt;    float result = 1.0 - (edgeSqr &gt; threshold * threshold); //white background, black lines&lt;br /&gt;    Output[threadID.xy] = result;&lt;br /&gt;    if (overlay &amp;&amp; result != 0.0)&lt;br /&gt;    Output[threadID.xy] = Input[threadID.xy];       &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That's it!  I already improved the code so that the threshold float and overlay boolean are in a constant buffer that is set on the CPU side, but I figured I'd keep the code posted here as simple as I could.&lt;br /&gt;&lt;br /&gt;Here was my input image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/S77C_gLguGI/AAAAAAAAFeI/gzdFbr1Z_cA/s1600/flower.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/S77C_gLguGI/AAAAAAAAFeI/gzdFbr1Z_cA/s400/flower.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5458014194645383266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And here is the the output image (input + Sobel result overlay):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/S77DYn8VkFI/AAAAAAAAFeQ/i9oSo1_n_gc/s1600/flower_sobel.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/S77DYn8VkFI/AAAAAAAAFeQ/i9oSo1_n_gc/s400/flower_sobel.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5458014626225950802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Nothing too spectacular, but the main focus was the Compute Shader + backbuffer, not the actual Sobel Filter.  Enjoy!&lt;br /&gt;&lt;br /&gt;By the way, you may have noticed that my C# code snippets now use the same syntax highlighting as Visual Studio.  I installed the &lt;a href="http://copysourceashtml.codeplex.com/"&gt;CopySourceAsHtml&lt;/a&gt; add-on and it seems to work pretty well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8213312985228414542?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8213312985228414542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8213312985228414542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8213312985228414542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8213312985228414542'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/04/sobel-filter-compute-shader.html' title='Sobel Filter Compute Shader'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hGl_uKJzpS0/S77C_gLguGI/AAAAAAAAFeI/gzdFbr1Z_cA/s72-c/flower.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8743921497041649126</id><published>2010-04-07T09:19:00.000-07:00</published><updated>2010-04-07T10:40:40.484-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Compute Shader'/><title type='text'>SlimDX Issue</title><content type='html'>In my previous post I mentioned how my next goal was to use the Compute Shader to write directly to the backbuffer.  Unfortunately, it appears that this is not currently possible using SlimDX.&lt;br /&gt;&lt;br /&gt;In order to write to the backbuffer, the swap chain needs to be created with an unordered access usage flag.  This means that that resource can then be used as a UAV output in a Compute Shader.  There are a &lt;a href="http://forum.beyond3d.com/showthread.php?t=55330"&gt;couple&lt;/a&gt; &lt;a href="http://users.skynet.be/fquake/"&gt;examples&lt;/a&gt; floating around online where people have done this using the DXGI_USAGE_UNORDERED_ACCESS flag in C++ code.&lt;br /&gt;&lt;br /&gt;In SlimDX, that enumeration has been wrapped into the Usage enumeration in the DXGI namespace.  However, it is missing an UnorderedAccess option.  It contains all of the other ones defined in the original C++ code though.  I believe it was just a mistake and accidentally missed during the update to DX11. (At least I hope it wasn't intentional!)&lt;br /&gt;&lt;br /&gt;I posted an &lt;a href="http://code.google.com/p/slimdx/issues/detail?id=648"&gt;issue&lt;/a&gt; on the SlimDX Google Code page, so hopefully this gets resolved.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8743921497041649126?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8743921497041649126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8743921497041649126' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8743921497041649126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8743921497041649126'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/04/slimdx-issue.html' title='SlimDX Issue'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2714175079958963375</id><published>2010-04-04T22:23:00.000-07:00</published><updated>2010-04-18T18:08:36.543-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Compute Shader'/><title type='text'>Simple Compute Shader Example</title><content type='html'>The other big side of DirectX 11 is the Compute Shader.  I thought I would write up a very simple example along the same lines as my tessellation example.&lt;br /&gt;&lt;br /&gt;First let me say that the Compute Shader is awesome!  It opens up so many possibilities.  My mind is just reeling with new ideas to try out.  Also I must mention that SlimDX really does a great job of minimalizing the code necessary to use the Compute Shader.  &lt;br /&gt;&lt;br /&gt;This example shows how to create a Compute Shader and then use it to launch threads that simply output the thread ID to a texture.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Device&lt;/span&gt; device = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Device&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;DriverType&lt;/span&gt;.Hardware, &lt;span style="color: #2b91af;"&gt;DeviceCreationFlags&lt;/span&gt;.Debug, &lt;span style="color: #2b91af;"&gt;FeatureLevel&lt;/span&gt;.Level_11_0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;ComputeShader&lt;/span&gt; compute = &lt;span style="color: #2b91af;"&gt;Helper&lt;/span&gt;.LoadComputeShader(device, &lt;span style="color: #a31515;"&gt;&amp;quot;SimpleCompute.hlsl&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt; uavTexture;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;UnorderedAccessView&lt;/span&gt; computeResult = &lt;span style="color: #2b91af;"&gt;Helper&lt;/span&gt;.CreateUnorderedAccessView(device, 1024, 1024, &lt;span style="color: #2b91af;"&gt;Format&lt;/span&gt;.R8G8B8A8_UNorm, &lt;span style="color: blue;"&gt;out&lt;/span&gt; uavTexture);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;device.ImmediateContext.ComputeShader.Set(compute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;device.ImmediateContext.ComputeShader.SetUnorderedAccessView(computeResult, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;device.ImmediateContext.Dispatch(32, 32, 1);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Texture2D&lt;/span&gt;.ToFile(device.ImmediateContext, uavTexture, &lt;span style="color: #2b91af;"&gt;ImageFileFormat&lt;/span&gt;.Png, &lt;span style="color: #a31515;"&gt;&amp;quot;uav.png&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Believe it or not, but that is the entirety of my CPU code.&lt;br /&gt;&lt;br /&gt;Here is what is going on in the code:&lt;br /&gt;1) Create a feature level 11 Device, in order to use Compute Shader 5.0&lt;br /&gt;2) Load/Compile the HLSL code into a ComputeShader object.&lt;br /&gt;3) Create a 1024x1024 UnorderedAccesdView (UAV) object which will be used to store the output.&lt;br /&gt;4) Set the ComputeShader and UAV on the device.&lt;br /&gt;5) Run the Compute Shader by calling Dispatch (32x32x1 thread groups are dispatched).&lt;br /&gt;6) Save the output texture out to disk.&lt;br /&gt;&lt;br /&gt;My HLSL code is even simpler:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;RWTexture2D&amp;lt;float4&gt; Output;&lt;br /&gt;&lt;br /&gt;[numthreads(32, 32, 1)]&lt;br /&gt;void main( uint3 threadID : SV_DispatchThreadID )&lt;br /&gt;{&lt;br /&gt;    Output[threadID.xy] = float4(threadID.xy / 1024.0f, 0, 1);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see a RWTexture2D object is used to store the output (this is the UAV).  The shader is setup to run 32x32x1 threads.  This means that since the CPU is launching 32x32x1 thread groups, then there are 1024x1024x1 separate threads being run.  This equates to 1 thread per pixel in the output UAV.  So, in the UAV, the color is just set based upon the thread ID.&lt;br /&gt;&lt;br /&gt;This code results in the following output image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/S7l5JcLDytI/AAAAAAAAFdw/kalnv_r9bpc/s1600/uav.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/S7l5JcLDytI/AAAAAAAAFdw/kalnv_r9bpc/s400/uav.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5456525626624428754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Quite simple, eh?  But not that interesting.  We could easily do something like that with a pixel shader (although we would have to rasterize a full-screen quad to do it).&lt;br /&gt;&lt;br /&gt;We should try to do something that shows the power of the compute shader; something you couldn't do in a pixel shader before.  How about drawing some primitives like lines and circles?&lt;br /&gt;&lt;br /&gt;For drawing lines, let's use the &lt;a href="http://en.wikipedia.org/wiki/Digital_Differential_Analyzer_(graphics_algorithm)"&gt;Digital Differential Analyzer&lt;/a&gt; algorithm.  It translates to HLSL very easily.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;void Plot(int x, int y)&lt;br /&gt;{&lt;br /&gt;   Output[uint2(x, y)] = float4(0, 0, 1, 1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void DrawLine(float2 start, float2 end)&lt;br /&gt;{&lt;br /&gt;    float dydx = (end.y - start.y) / (end.x - start.x);&lt;br /&gt;    float y = start.y;&lt;br /&gt;    for (int x = start.x; x &lt;= end.x; x++) &lt;br /&gt;    {&lt;br /&gt;        Plot(x, round(y));&lt;br /&gt;        y = y + dydx;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For drawing circles let's use the &lt;a href="http://en.wikipedia.org/wiki/Midpoint_circle_algorithm"&gt;Midpoint Circle&lt;/a&gt; algorithm.  For brevity I won't list it here now.&lt;br /&gt;&lt;br /&gt;Then, in my Compute Shader main function, I simply add this code:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;if (threadID.x == 1023 &amp;&amp; threadID.y == 1023)&lt;br /&gt;{&lt;br /&gt;   DrawLine(float2(0, 0), float2(1024, 1024));&lt;br /&gt;   DrawLine(float2(0, 1023), float2(1023, 0));&lt;br /&gt;     &lt;br /&gt;   DrawCircle(512, 512, 250);&lt;br /&gt;   DrawCircle(0, 512, 250);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The if check is just done to prevent the lines and circles from being drawn for every thread.  This code results in the following image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/S7l76R2AahI/AAAAAAAAFd8/4S4GUGn0cdY/s1600/uav2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/S7l76R2AahI/AAAAAAAAFd8/4S4GUGn0cdY/s400/uav2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5456528664688618002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I must admit it seems quite odd writing a shader that draws primitives.  It's like some strange recursive loop.  But it definitely helps to illustrate the features of the Compute Shader and how powerful it is.&lt;br /&gt;&lt;br /&gt;You may download the source code to this example here:&lt;br /&gt;&lt;a href="http://www.re-creationstudios.com/shared/ComputeShader11.zip"&gt;ComputeShader11.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My next goal is to setup a standard DX11 Swap Chain and use the Compute Shader to write directly to the backbuffer.  Well that's all for now.&lt;br /&gt;&lt;br /&gt;FYI:  This is my 50th blog post!  I never thought I would continue on this long.  I think I should crack open a beer to celebrate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2714175079958963375?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2714175079958963375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2714175079958963375' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2714175079958963375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2714175079958963375'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/04/simple-compute-shader-example.html' title='Simple Compute Shader Example'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/S7l5JcLDytI/AAAAAAAAFdw/kalnv_r9bpc/s72-c/uav.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3037097832308371268</id><published>2010-03-09T13:29:00.000-08:00</published><updated>2010-04-04T23:20:26.827-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Tessellation'/><title type='text'>Watertight Adaptive Tessellation</title><content type='html'>The next obvious step for tessellation is to make it adaptive based upon the distance to the camera.  It is important to keep the tessellated mesh watertight in order to prevent cracks from appearing between separate quads.&lt;br /&gt;&lt;br /&gt;There are five different ways (that I can think of) to address this problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1) Do absolutely nothing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the longest time with my original LOD algorithm this is the path I followed.  If you are okay with having nasty cracks in your mesh, then this is definitely the way to go.  But that is no longer acceptable to me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2) Cheap fix (force all edges to be 1)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If all quad edges are not subdivided at all, then there will be no cracks and it will be fast.  The problem is there will be no detail at the edges, and this quickly becomes very obvious and ugly.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3) Expensive fix (force all edges to be 64)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is the flip-side to the previous option.  All quad edges are subdivided to the maximum level.  This ensures that the best detail will be used at each edge.  However this is too expensive to do for all quads.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4) Be smart about it (use adjacency information)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is the method that Jack Hoxley uses and describes &lt;a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=531164"&gt;here&lt;/a&gt;. Basically he builds a vertex buffer that contains the 4 vertices of the quad plus another 8 vertices representing the 4 adjacent quads.  In the hull shader, he calculates the midpoint of each quad and then calculates the distance (and thus a tessellation factor) from the midpoint to the camera.  He chooses the minimum factor for each edge in order to have the quads match.&lt;br /&gt;&lt;br /&gt;This is a pretty good solution, but it requires building a large vertex buffer containing adjacency information, as well as the additional midpoint calculation in the hull shader.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5) Do it right (calc factors from each vertex)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The next question is, can we do efficient watertight adaptive tessellation without adjacency information or the midpoint calculation?  The answer is yes!  If we calculate the tessellation factors from the vertices themselves, then we can guarantee that the surrounding quads will use the same factors (because they are using the same vertices). &lt;br /&gt;&lt;br /&gt;The basic algorithm is this:&lt;br /&gt;- Calculate the tessellation factor based on camera distance for each of the 4 vertices&lt;br /&gt;&lt;code&gt;&lt;br /&gt;float distanceRange = maxDistance - minDistance;&lt;br /&gt;float vertex0 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[0].position) - minDistance) / distanceRange))));&lt;br /&gt;float vertex1 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[1].position) - minDistance) / distanceRange))));&lt;br /&gt;float vertex2 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[2].position) - minDistance) / distanceRange))));&lt;br /&gt;float vertex3 = lerp(minLOD, maxLOD, (1.0f - (saturate((distance(cameraPosition, op[3].position) - minDistance) / distanceRange))));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;- Use the minimum value for each edge factor (pair of vertices)&lt;br /&gt;&lt;code&gt;&lt;br /&gt;output.edges[0] = min(vertex0, vertex3);&lt;br /&gt;output.edges[1] = min(vertex0, vertex1);&lt;br /&gt;output.edges[2] = min(vertex1, vertex2);&lt;br /&gt;output.edges[3] = min(vertex2, vertex3);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;- Use the overall minimum value for the inside tessellation factor&lt;br /&gt;&lt;code&gt;&lt;br /&gt;float minTess = min(output.edges[1], output.edges[3]);&lt;br /&gt;output.inside[0] = minTess;&lt;br /&gt;output.inside[1] = minTess;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Note: I originally thought the inside factor should be the &lt;span style="font-style:italic;"&gt;maximum&lt;/span&gt; of the 4 vertices, but I after viewing it in action, I felt that the minimum was better.&lt;br /&gt;&lt;br /&gt;That's it!  Simple, fast, and easy watertight adaptive tessellation.&lt;br /&gt;&lt;br /&gt;Check out the video of it in action: (I recorded the video at 1280x720, so be sure to view it at 720 to see the little details.)&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/5SG1nUEdpM4&amp;hl=en_US&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/5SG1nUEdpM4&amp;hl=en_US&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 class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3037097832308371268?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3037097832308371268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3037097832308371268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3037097832308371268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3037097832308371268'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/03/watertight-adaptive-tessellation.html' title='Watertight Adaptive Tessellation'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5025732725138194040</id><published>2010-03-04T00:39:00.000-08:00</published><updated>2010-04-04T23:27:59.236-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Tessellation'/><title type='text'>Cube to Sphere Tessellation</title><content type='html'>My previous tessellation example was just a 2D, screen-space quad.  My latest example steps into the world of 3D.  &lt;br /&gt;&lt;br /&gt;No code to share, just a pretty little video.  It shows a cube being tessellated on the fly to form a sphere.  What's being done is each quad is being tessellated and then the vertex position is normalized.&lt;br /&gt;&lt;br /&gt;I was lazy and instead of making an entire cube with 6 sides, I only built a vertex/index buffer for 3 sides.  You can only tell when I move the camera around at the end of the video.&lt;br /&gt;&lt;br /&gt;I was getting about 1500 fps for the cube and about 900 fps for the fully tessellated sphere. 63*63*3*2 = 23,814 triangles!&lt;br /&gt;&lt;br /&gt;Here ya go:&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/m73UVyKkyGQ&amp;hl=en_US&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/m73UVyKkyGQ&amp;hl=en_US&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 class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5025732725138194040?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5025732725138194040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5025732725138194040' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5025732725138194040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5025732725138194040'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/03/cube-to-sphere-tessellation.html' title='Cube to Sphere Tessellation'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4983048493965796803</id><published>2010-03-01T22:11:00.000-08:00</published><updated>2010-04-04T23:31:05.099-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='Tessellation'/><title type='text'>Simple Tessellation Example</title><content type='html'>I have finally got my computer all setup with the Radeon 5450 and started doing some DirectX 11 development.  Obviously the first thing I tried out was the tessellation. &lt;br /&gt; &lt;br /&gt;There are some nice sample projects included in the DirectX SDK that cover tessellation, but I felt that they were a little too ... complex.  Don't get me wrong, I feel that they are great samples of doing things like model subdivision, detail tessellation, and bezier curves. I just felt that there should be a very simple demonstration of tessellation in the most basic sense.  I decided to write one myself and share it here.&lt;br /&gt;&lt;br /&gt;I should note that this was written using SlimDX.  I love having the power of DirectX in C#!&lt;br /&gt;&lt;br /&gt;As I stated, this is pretty much the most basic example of tessellation I could think of.  It has one single quad with vertices defined in screen-space, which allows us to skip any transformation.  The shader then tessellates the quad by using hard-coded tessellation factors.  That's it!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/S4ysssjVg6I/AAAAAAAAFac/_HBoa4KBcig/s1600-h/sdx_tessellation2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 313px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/S4ysssjVg6I/AAAAAAAAFac/_HBoa4KBcig/s400/sdx_tessellation2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5443915933457679266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The main application code isn't that important.  It just creates the vertex buffer consisting of 4 vertices.  It then draws using the new "4 control point patch" primitive.  All the rest of the magic happens in the HLSL code.&lt;br /&gt;&lt;br /&gt;The vertex shader isn't that impressive.  It is simply a pass-through shader and passes the vertex position through to the hull shader.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;VS_OUTPUT VS( VS_INPUT input )&lt;br /&gt;{&lt;br /&gt; VS_OUTPUT output;&lt;br /&gt; &lt;br /&gt; output.position = input.position;&lt;br /&gt; &lt;br /&gt; return output;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The hull shader constant fuction simply sets the hard-coded tessellation factors for the edges and inside.  Currently I have it hard-coded to a factor of 32.  You may manually change this value to be anywhere from 1-64.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;HS_CONSTANT_OUTPUT HSConstant( InputPatch&amp;lt;VS_OUTPUT, 4&gt; ip, uint pid : SV_PrimitiveID )&lt;br /&gt;{&lt;br /&gt; HS_CONSTANT_OUTPUT output;&lt;br /&gt; &lt;br /&gt; float edge = 32.0f;&lt;br /&gt; float inside = 32.0f;&lt;br /&gt;&lt;br /&gt; output.edges[0] = edge;&lt;br /&gt; output.edges[1] = edge;&lt;br /&gt; output.edges[2] = edge;&lt;br /&gt; output.edges[3] = edge;&lt;br /&gt;&lt;br /&gt; output.inside[0] = inside;&lt;br /&gt; output.inside[1] = inside;&lt;br /&gt;&lt;br /&gt; return output;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The hull shader itself does not perform a basis change, and therefore it passes through all 4 of the input points to the output.  As you can see from the attributes, it is operating on the quad domain and it uses the standard clockwise winding.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[domain("quad")]&lt;br /&gt;[partitioning("integer")]&lt;br /&gt;[outputtopology("triangle_cw")]&lt;br /&gt;[outputcontrolpoints(4)]&lt;br /&gt;[patchconstantfunc("HSConstant")]&lt;br /&gt;HS_OUTPUT HS( InputPatch&amp;lt;VS_OUTPUT, 4&gt; ip, uint cpid : SV_OutputControlPointID, uint pid : SV_PrimitiveID )&lt;br /&gt;{&lt;br /&gt;    HS_OUTPUT Output;&lt;br /&gt;    Output.position = ip[cpid].position;&lt;br /&gt;    return Output;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Before explaining the domain shader, let me first explain the orientation of the UV coordinates coming from the tessellator.&lt;br /&gt;&lt;br /&gt;Let's assume your vertices are defined in this manner:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   u&lt;br /&gt; 0-----1&lt;br /&gt;v|     |&lt;br /&gt; |     |&lt;br /&gt; 3-----2&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;The U dimension ranges from [0-1] in the direction of vertex 0 to vertex 1.&lt;br /&gt;The V dimension ranges from [0-1] in the direction of vertex 0 to vertex 3.&lt;br /&gt;&lt;br /&gt;I specifically state this now because I had wrongly assumed that it was oriented such that the U and V coordinates were reversed, like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  WRONG!&lt;br /&gt; 1-----2&lt;br /&gt; |     |&lt;br /&gt;v|     |&lt;br /&gt; 0-----3&lt;br /&gt;   u&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, about the domain shader itself.  This is normally where the samples got rather complex calculating bezier curves and such.  This is the simplest algorithm I could come up with.  It uses three linear interpolations to calculate the vertex position.  I visualize it as sliding two lines along the the quad and marking where they intersect as the vertex.&lt;br /&gt;&lt;br /&gt;The first lerp finds the "midpoint" between vertex 0 and 1 by a factor of U.&lt;br /&gt;The second lerp finds the "midpoint" between vertex 3 and 2 by a factor of U.&lt;br /&gt;The third lerp finds the "midpoint" between the first and second calulated midpoints by a factor of V.&lt;br /&gt;&lt;br /&gt;This is rather hard to "draw" a diagram for, but hopefully this makes some sense:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  lerp1&lt;br /&gt; 0--|--1&lt;br /&gt; |  _  | lerp3&lt;br /&gt; |     |&lt;br /&gt; 3--|--2&lt;br /&gt;  lerp2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The color of the vertex is set based upon the tessellation UV coordinates.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[domain("quad")]&lt;br /&gt;DS_OUTPUT DS( HS_CONSTANT_OUTPUT input, float2 UV : SV_DomainLocation, const OutputPatch&amp;lt;HS_OUTPUT, 4&gt; patch )&lt;br /&gt;{&lt;br /&gt;    DS_OUTPUT Output;&lt;br /&gt;    &lt;br /&gt;    float3 topMidpoint = lerp(patch[0].position, patch[1].position, UV.x);&lt;br /&gt;    float3 bottomMidpoint = lerp(patch[3].position, patch[2].position, UV.x);&lt;br /&gt;    &lt;br /&gt;    Output.position = float4(lerp(topMidpoint, bottomMidpoint, UV.y), 1);&lt;br /&gt;    Output.color = float4(UV.yx, 1-UV.x, 1);&lt;br /&gt;    &lt;br /&gt;    return Output;    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The pixel shader just writes out the color.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;float4 PS( DS_OUTPUT input ) : SV_Target&lt;br /&gt;{&lt;br /&gt; return input.color;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;There you have it!  Hopefully this simple example of tessellating a single quad will be useful to other people and help to illustrate how the tessellator works.&lt;br /&gt;&lt;br /&gt;You can download the full source to this example here:  &lt;a href="http://re-creationstudios.com/shared/Tessellation.zip"&gt;Tessellation.zip&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4983048493965796803?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4983048493965796803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4983048493965796803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4983048493965796803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4983048493965796803'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/03/simple-tessellation-example.html' title='Simple Tessellation Example'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hGl_uKJzpS0/S4ysssjVg6I/AAAAAAAAFac/_HBoa4KBcig/s72-c/sdx_tessellation2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8408173827720891346</id><published>2010-02-19T15:20:00.000-08:00</published><updated>2010-04-04T23:35:46.790-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><title type='text'>Quick Update</title><content type='html'>&lt;span style="font-weight:bold;"&gt;DirectX 11&lt;/span&gt;&lt;br /&gt;I attended GameFest 2010.  I can't say much except that I want to work with DX11 even more than before, if that was possible.  As a result, I just bought a Radeon 5450 from newegg.  Sure, it is a rather weak card, but it is only $35!  Plus, it is much faster than the reference rasterizer and it only consumes 19 watts at full usage!&lt;br /&gt;&lt;br /&gt;Here is the card I bought:&lt;br /&gt;&lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16814131339"&gt;http://www.newegg.com/Product/Product.aspx?Item=N82E16814131339&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It should hold me over until the Nvidia 400 series cards come out in a month or two.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;SlimDX&lt;/span&gt;&lt;br /&gt;Talk about perfect timing!  The latest version of SlimDX was just released today.  The D3D11 wrapper should be even more stable than what it already was.&lt;br /&gt;&lt;br /&gt;You can download it from here:&lt;br /&gt;&lt;a href="http://slimdx.org/download.php"&gt;http://slimdx.org/download.php&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8408173827720891346?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8408173827720891346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8408173827720891346' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8408173827720891346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8408173827720891346'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2010/02/quick-update.html' title='Quick Update'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-65553778474730695</id><published>2009-12-27T01:12:00.000-08:00</published><updated>2010-04-04T23:33:49.651-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Procedural City'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Procedural Cities in XNA</title><content type='html'>It's been quite a while since I've talked about any development I've been doing.  To be honest I have been quite busy with work and flight lessons, so I don't have much time to work on my hobby projects.&lt;br /&gt;&lt;br /&gt;Lately I have been working on a procedural city generator in C#/XNA.  I'm basing my work on the &lt;a href="http://pcity.sourceforge.net/"&gt;Metropolis&lt;/a&gt; project, which was in turn based upon a research paper presented at SIGGRAPH 2001. &lt;br /&gt;&lt;br /&gt;I began with the procedural road map generator.  It takes a heightmap and generates a road network from it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SzcmQbTE3DI/AAAAAAAAFXM/vpJQSG9Krmo/s1600-h/map1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SzcmQbTE3DI/AAAAAAAAFXM/vpJQSG9Krmo/s400/map1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419842740211211314" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Zooming in you can begin to see the subdivisions between streets where buildings will be built.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SzcmhQfMEII/AAAAAAAAFXU/x56-I4206lY/s1600-h/map2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SzcmhQfMEII/AAAAAAAAFXU/x56-I4206lY/s400/map2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419843029367001218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Zooming in even further makes the building lots even clearer.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/Szcm7bHNQrI/AAAAAAAAFXc/K9VzVaNsnw0/s1600-h/map3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/Szcm7bHNQrI/AAAAAAAAFXc/K9VzVaNsnw0/s400/map3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419843478895805106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, I began work on the 3D building creation. Here you can see many simple buildings all using the same texturing.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcneIs3oYI/AAAAAAAAFXk/OoieeLch7rs/s1600-h/city1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcneIs3oYI/AAAAAAAAFXk/OoieeLch7rs/s400/city1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419844075248918914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I then added more texture variety.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcntghxXlI/AAAAAAAAFXs/9WJKc58rTt4/s1600-h/city2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcntghxXlI/AAAAAAAAFXs/9WJKc58rTt4/s400/city2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419844339342859858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I finally added in the terrain with road texturing.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcoCRdCYAI/AAAAAAAAFX0/Sl51N1FTL10/s1600-h/city3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SzcoCRdCYAI/AAAAAAAAFX0/Sl51N1FTL10/s400/city3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419844696073723906" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Zoomed out view showing the vast number of buildings generated.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SzcoT6ifzXI/AAAAAAAAFX8/3cKlAuKqSDw/s1600-h/city4.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SzcoT6ifzXI/AAAAAAAAFX8/3cKlAuKqSDw/s400/city4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419844999160253810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And the final image showing "Central Park" (this city was generated from a heightmap of Manhattan).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SzcorfGRvhI/AAAAAAAAFYE/DYrAgR0vmgQ/s1600-h/city5.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SzcorfGRvhI/AAAAAAAAFYE/DYrAgR0vmgQ/s400/city5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5419845404110994962" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I want to eventually release the source code for this, but first I need to clean up the code some more.  I also need to tweak the renderer to run faster.  Right now it is just brute forcing it, and doesn't utilize any form of level of detail or frustum culling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-65553778474730695?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/65553778474730695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=65553778474730695' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/65553778474730695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/65553778474730695'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/12/procedural-cities-in-xna.html' title='Procedural Cities in XNA'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hGl_uKJzpS0/SzcmQbTE3DI/AAAAAAAAFXM/vpJQSG9Krmo/s72-c/map1.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-6253087042717191879</id><published>2009-10-10T18:15:00.000-07:00</published><updated>2010-04-04T23:35:12.380-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><title type='text'>SlimDX August 2009 Release</title><content type='html'>A new version of SlimDX is now available.  This version wraps the latest DirectX SDK release (August 2009, thus the name).  This means that things like DirectX 11 and Direct2D are now officially supported (previous releases were beta).&lt;br /&gt;&lt;br /&gt;You can download the installer here:&lt;br /&gt;&lt;a href="http://code.google.com/p/slimdx/"&gt;http://code.google.com/p/slimdx/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You can also read a little more about this release at the GameDev.net forums:&lt;br /&gt;&lt;a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=549927"&gt;http://www.gamedev.net/community/forums/topic.asp?topic_id=549927&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm looking forward to trying it out.  Unfortunately, I still don't have DX11 hardware, so I'll probably hold off on things like tessellation or the compute shader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-6253087042717191879?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/6253087042717191879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=6253087042717191879' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6253087042717191879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6253087042717191879'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/10/slimdx-august-2009-release.html' title='SlimDX August 2009 Release'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-6511148031468522012</id><published>2009-10-03T19:05:00.000-07:00</published><updated>2010-04-04T23:36:21.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='Tessellation'/><title type='text'>Disappointment</title><content type='html'>Since I have never used the Geometry Shader, I've been reading tutorials on how to use it to generate silhouettes and stencil shadows via the adjacency information being passed through the index buffer.&lt;br /&gt;&lt;br /&gt;From my posts in the past, it is pretty obvious that I am really excited about tessellation and I want to make use of it ASAP.  So, a natural thing that came to my mind was combining the two together to tessellate a mesh and then generate silhouettes.&lt;br /&gt;&lt;br /&gt;No can do.  I was completely and utterly disappointed to find out that you can &lt;span style="font-weight:bold;"&gt;NOT&lt;/span&gt; use adjacency information alongside the tessellator.&lt;br /&gt;&lt;br /&gt;I quote from the official DirectX 11 docs: "A geometry shader that expects primitives with adjacency (for example, 6 vertices per triangle) is not valid when tessellation is active (this results in undefined behavior, which the debug layer will complain about)."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-6511148031468522012?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/6511148031468522012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=6511148031468522012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6511148031468522012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6511148031468522012'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/10/disappointment.html' title='Disappointment'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2019798279274112769</id><published>2009-09-24T19:50:00.000-07:00</published><updated>2010-04-04T23:36:57.439-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><title type='text'>DirectX 11 GPUs have arrived!</title><content type='html'>The Radeon HD 5870 is now out in the wild and available for purchase.  I'm still unsure if I want to buy it or wait for the 5850 coming out next month.  The 5850 is $120 less than the 5870 and the specs aren't that much lower.&lt;br /&gt;&lt;br /&gt;On the Nvidia side of things, it's not looking very good.  The latest rumors are that they are having incredibly low yields from their chips and as a result have delayed the launch of their DX11 GPUs to the third quarter of 2010.  I wonder how this generation will play out if Nvidia's cards don't show up until almost a year after ATI's.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update&lt;/span&gt;:&lt;br /&gt;Apparently the news of the Nvidia delay is just FUD.  They have officially announced that the 300 series will still debut in December.  Read about it &lt;a href="http://www.brightsideofnews.com/news/2009/9/25/nvidia-says-gt300-on-schedule-for-q4-20092c-yields-are-fine.aspx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2019798279274112769?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2019798279274112769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2019798279274112769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2019798279274112769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2019798279274112769'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/09/directx-11-gpus-have-arrived.html' title='DirectX 11 GPUs have arrived!'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8540779350157218172</id><published>2009-09-13T21:25:00.000-07:00</published><updated>2011-08-19T17:24:31.854-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>Perlin Noise in DirectX 10 (Shader Model 4.0)</title><content type='html'>This is somewhat similar to the classic problem of &lt;a href="http://www.sixside.com/fast_good_cheap.asp"&gt;Good, Cheap, and Fast&lt;/a&gt; where you can only have two of them at the same time.&lt;br /&gt;&lt;br /&gt;I implemented Perlin Noise entirely on the GPU, meaning no textures are precomputed and no parameters are set on the GPU.  The shader is simply loaded and ran.  It is a very clean solution and it is incredibly simple to add to any project.&lt;br /&gt;&lt;br /&gt;Unfortunately, it is slow.  Mind you, it is still much faster than the CPU implementation, but it is slow compared to my original precomputed texture implementation.&lt;br /&gt;&lt;br /&gt;I always run my tests using 12 octaves of 3D fBm Perlin Noise summations at a resolution of 1024x1024.  It yields much more stable results than just 1 calculation of Perlin Noise.  My original implementation ran at about 85 fps.  At first, my new simple implementation was running at about 3 fps!  Even though the documentation states that HLSL automatically marks all global variables as &lt;span style="font-style:italic;"&gt;const&lt;/span&gt;, if I put the &lt;span style="font-style:italic;"&gt;const &lt;/span&gt;keyword before my permutation array my frame-rate jumped up to 19 fps.&lt;br /&gt;&lt;br /&gt;I added a gradient lookup table and changed the gradient calculation functions to just index into the table.  However, this basically had no impact on the speed. I then reduced the permutation array from 512 to 256 and performed a modulus operation on any indexing into the array.  This gave my about a 30% speed increase and got it up to about 25 fps.&lt;br /&gt;&lt;br /&gt;I tried various other tweaks, and I was able to get it to go a bit faster, but it was always at the expense of the quality of the noise (wouldn't work with negative values, would look blocky, etc).  The fastest I was able to get it and still maintain the high quality Perlin Noise was 25 fps.&lt;br /&gt;&lt;br /&gt;I must say that I'm rather disappointed with these results.  I had thought that constant memory indexing would be faster than texture lookups, however the texture lookup version was over 3 times faster than the memory indexing version.  Perhaps I'm just missing something or I'm implementing the memory indexing incorrectly, but I don't know what I could possibly do to speed it up anymore AND keep the same quality.&lt;br /&gt;&lt;br /&gt;For the time being, it looks like texture lookups are the way to go.  I've decided to upload 2 versions of the noise code.  The first version is a direct port of Ken Perlin's Java code to HLSL(19 fps).  The second includes the tweaks to the gradients and permutation array (25 fps).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.re-creationstudios.com/shared/noise.fxh"&gt;First Version&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.re-creationstudios.com/shared/noise2.fxh"&gt;Tweaked Version&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As I have said, the major advantage to this implementation is the simplicity.  All you have to do is include the header in your HLSL code and you can call the noise() and fBm() functions.  That's it!  You don't have to do anything else.  So if you just want to drag and drop some Perlin Noise into a shader, this is the best way to do it, if you don't care about speed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8540779350157218172?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8540779350157218172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8540779350157218172' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8540779350157218172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8540779350157218172'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/09/simple-vs-fast.html' title='Perlin Noise in DirectX 10 (Shader Model 4.0)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7647347927123356296</id><published>2009-09-09T17:41:00.001-07:00</published><updated>2010-04-04T23:38:13.248-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 11'/><title type='text'>Soon ... Very Soon</title><content type='html'>The August DirectX SDK was released today (shh, don't tell them it's September).  This brings with it the first official release of DirectX 11!&lt;br /&gt;&lt;br /&gt;You can download it in all of it's glory here:&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;FamilyID=b66e14b8-8505-4b17-bf80-edb2df5abad4"&gt;August DirectX SDK&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Note:&lt;/span&gt; In order to run the DX11 samples on Vista, you need a patch.  Unfortunately, that patch is not yet available, but when it is it should be available &lt;a href="http://support.microsoft.com/kb/971644"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In very related news, it looks like the first DirectX 11 GPUs will be available this month.  The Radeon HD 5850 will be $300, the Radeon HD 5870 will be $400, and the Radeon HD 5870x2 will be $600.&lt;br /&gt;&lt;a href="http://www.theinquirer.net/inquirer/news/1532355/radeon-58xx-pricing-leaked"&gt;Read more here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7647347927123356296?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7647347927123356296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7647347927123356296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7647347927123356296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7647347927123356296'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/09/soon-very-soon.html' title='Soon ... Very Soon'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2044811842129499290</id><published>2009-09-08T07:20:00.000-07:00</published><updated>2011-08-19T17:14:14.731-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>Byte Order Mark - The Invisible Enemy</title><content type='html'>Alternate Title:&lt;br /&gt;&lt;b&gt;&lt;i&gt;EF BB BF - The Three Bytes of Doom&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Last night I decided to whip out a quick SlimDX / DirectX 10 project implementing Perlin Noise using Shader Model 4.0.  In my &lt;span style="font-style:italic;"&gt;Perlin Noise on the GPU&lt;/span&gt; article, I mentioned how much easier it would be to implement Perlin Noise using SM4.0+ vs SM3.0.  I had done a quick port of Ken Perlin's Java example implementation in FX Composer a couple months back, so I thought I would be able to implement the stand-alone version in less than an hour.&lt;br /&gt;&lt;br /&gt;I wanted to test it first in a pixel shader, so I made my own custom vertex as well as a class that would build a fullscreen quad vertex buffer.  I took the Perlin Noise HLSL code and put it into a header file, and made a simple two-technique shader that included the header.&lt;br /&gt;&lt;br /&gt;I fired up the code, but I quickly got an exception (E_FAIL: An undetermined error occurred (-2147467259)) at the point where I was trying to set the InputLayout of the vertex buffer to the shader signature.  Not a very useful exception.&lt;br /&gt;&lt;br /&gt;At first, I thought it might have been a problem with my custom vertex format.  After looking it over and comparing against other custom vertex formats I've made in the past, I determined the issue wasn't there.&lt;br /&gt;&lt;br /&gt;Next I looked at how I was creating the vertex buffer and index buffer for the fullscreen quad.  That all appeared in order too.&lt;br /&gt;&lt;br /&gt;After determining that the issue was not in my custom vertex format or my fullscreen quad, I slowly stepped through the code keeping a close eye on all of the variables.  I didn't think there was a problem with my shader because no errors were being output from the compiler, and it was spitting out a valid Effect.  However, when stepping through and watching the variables, I saw that even though it created an Effect and the IsValid property was true, it said the TechniqueCount was zero!  In fact, all of the counts were saying zero.  It was as if the compiler was seeing it as an empty file.&lt;br /&gt;&lt;br /&gt;So, I next looked at my shader in detail.  I thought maybe something funky was happening with the included header file, so I inlined all of the header code.  I still got the exception.  I thought it might be some random issue in one of my noise functions, so I changed them to all return 1.0.  Exception.  I triple checked all of my input and output structures.  I looked over my technique description.  I changed my vertex shader to be a simple pass-through and the pixel shader to just return white.  Exception.&lt;br /&gt;&lt;br /&gt;What the heck was going on?  I had other shaders that were compiling just fine.  So, just as a "stupid" test, I copied one of the my other working shaders and pasted all of the code into my fx file, overwriting everything in it.  &lt;span style="font-style:italic;"&gt;I still got the exception!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now I knew something was really messed up somewhere.  Here I had two fx files with the &lt;span style="font-weight:bold;"&gt;exact&lt;/span&gt; same HLSL code in them, but one was compiling while the other was not.&lt;br /&gt;&lt;br /&gt;I opened both files up using the Binary Editor in Visual Studio to see byte by byte.  The file that was not compiling had three extra bytes at the beginning - EF BB BF.  I deleted these three bytes, and everything worked!&lt;br /&gt;&lt;br /&gt;It turns out that that byte sequence is the Byte Order Mark.  It is specifying that the file is UTF-8 encoded.  Apparently this is the default for all files created in Visual Studio 2008.  Unfortunately, the FX compiler in DirectX can't read UTF-8 files and just dies and returns an empty Effect.&lt;br /&gt;&lt;br /&gt;I did a quick Google search after fixing the problem and I saw that several other people had the same problem and eventually came to the same solution.  I really wish the compiler would return an error in a situation like this.&lt;br /&gt;&lt;br /&gt;What I find very interesting is the fact that I have been programming shaders for over two and a half years, and I have never run into this problem before.&lt;br /&gt;&lt;br /&gt;Hopefully this post helps someone else if they encounter this same problem.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2044811842129499290?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2044811842129499290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2044811842129499290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2044811842129499290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2044811842129499290'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/09/byte-order-mark-invisible-enemy.html' title='Byte Order Mark - The Invisible Enemy'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8518782883495352518</id><published>2009-08-25T08:40:00.003-07:00</published><updated>2010-04-04T23:39:08.205-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='PhysX'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>Teaser</title><content type='html'>I'm not yet ready to fully talk about what I'm working on, but I wanted to give a little preview to whet everyone's appetite.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SpQGJJ3N_5I/AAAAAAAAFOo/20fd3hFyVzU/s1600-h/physx_slimdx.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SpQGJJ3N_5I/AAAAAAAAFOo/20fd3hFyVzU/s400/physx_slimdx.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5373927009695956882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Yep!  3001 boxes in 1 PhysX scene and still maintaining 29.81 frames per second.  The really awesome part is the fact that this is all in C#!&lt;br /&gt;&lt;br /&gt;I'll talk more about it later.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8518782883495352518?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8518782883495352518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8518782883495352518' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8518782883495352518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8518782883495352518'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/08/teaser.html' title='Teaser'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/SpQGJJ3N_5I/AAAAAAAAFOo/20fd3hFyVzU/s72-c/physx_slimdx.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2045644628874213906</id><published>2009-07-29T11:34:00.000-07:00</published><updated>2011-08-19T17:12:56.242-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><title type='text'>Infinite Depth Buffer</title><content type='html'>I've been planning out how I'm going to rewrite my planet algorithm once DirectX 11 is out.  I've decided to focus on problems I have now that will still be a problem in DX11.  One such problem that I've always been having in the past is the depth buffer.&lt;br /&gt;&lt;br /&gt;My planet is Earth-sized so in order to keep it visible as you fly away from it, I pushed the far clipping plane way out.  Obviously this destroyed the precision of my depth buffer and I had big problems with Z-fighting (far off mountains were being drawn in front of closer ones).&lt;br /&gt;&lt;br /&gt;Rant:  Why the heck are most GPUs these days still stuck with a 24-bit depth buffer?  The Xbox 360 and my GeForce 9800M GT both only support up to a 24-bit depth buffer. DX11 level GPUs will have 64-bit floating point (double) support in shaders, so why not a 64-bit depth buffer?&lt;br /&gt;&lt;br /&gt;In the videos and screenshots I have posted in the past, I did two different things to try and fix my problem with the depth buffer.  First, I had a "sliding" far clipping plane that would have a minimum value, but as you flew away from the planet, it would extend out in order to continually show the planet.  My second solution was to just disable the depth buffer.  Both of these solutions only worked because I was drawing only 1 planet and there were no other objects being rendered.  Obviously I want to keep my depth buffer around, keep the high precision for any near objects, but continue to draw far off planets (not have them clipped by the far clipping plane).&lt;br /&gt;&lt;br /&gt;In order to fully understand my problem, I read about how exactly the depth buffer works and how a position is transfomed and then clipped.  I found &lt;a href="http://www.mvps.org/directx/articles/linear_z/linearz.htm"&gt;this article&lt;/a&gt; very informative about the inner workings of the GPU in terms of the depth buffer.  I did not change my depth buffer to be linear like he does though.  The article helped me to understand the relationship between the Z component and W component of the transformed vertex position.&lt;br /&gt;&lt;br /&gt;Between the vertex shader and the pixel shader, the Z component is divided by W in order to "normalize" the depth (range 0-1).  If the Z value is greater than 1 then it is clipped.  So, I needed to make it so that the normalized Z value never exceeded 1.   This was a very simple thing to fix, once I understood it.  In my vertex shader I check the Z value to see if it is greater than the far clipping plane value (which I pass into the shader).  If it is greater, then I simply set the W component equal to the Z component.  This means that the Z / W calculation thus becomes Z / Z = 1.  Now I can have good depth buffer precision for things close to the camera, but I will continue to draw things even if they are an infinite (theoretically) distance away!&lt;br /&gt;&lt;br /&gt;Obviously this solution isn't perfect and there are some "gotchas".  If I am drawing a planet and a moon, and the moon is behind the planet, and I am flying away from the planet, AND the moon is being drawn after the planet in the C# code, then the moon will suddenly pop in front of the planet once the planet exceeds the far clipping plane.  That means I'll have to have a manager of large objects  in the "local system" to make sure they are drawn in back to front order.  That should be really easy to implement.&lt;br /&gt;&lt;br /&gt;Hopefully this all makes sense and it helps someone else struggling with the same problem.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Update&lt;/b&gt;:  I would now strongly encourage people to use a Logarithmic Depth Buffer to solve all of your depth buffer precision issues.  You can read about it here:&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.gamasutra.com/blogs/BranoKemen/20090812/2725/Logarithmic_Depth_Buffer.php"&gt;http://www.gamasutra.com/blogs/BranoKemen/20090812/2725/Logarithmic_Depth_Buffer.php&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2045644628874213906?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2045644628874213906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2045644628874213906' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2045644628874213906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2045644628874213906'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/07/infinite-depth-buffer.html' title='Infinite Depth Buffer'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3530746992899644593</id><published>2009-07-01T12:39:00.000-07:00</published><updated>2011-08-19T17:08:44.923-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><category scheme='http://www.blogger.com/atom/ns#' term='SlimDX'/><category scheme='http://www.blogger.com/atom/ns#' term='PhysX'/><title type='text'>Perlin Noise in JavaScript</title><content type='html'>I apologize for not having any update for the month of June, but I was gone on vacation for a majority of it.&lt;br /&gt;&lt;br /&gt;I saw tons of places on the road trip.  Illinois, Indiana, Michigan, Ontario, New York, Vermont, New Hampshire, Maine, Massachusetts, New Jersey, Delaware, Maryland, Virginia, Pennsylvania, West Virginia, and Ohio (in that order)!  I had never been to the New England area of the country, so it was great being able to see it all.&lt;br /&gt;&lt;br /&gt;In terms of development, I haven't really done any since I wrote that Perlin Noise article.  I've been tossing around the idea in my head to go try out &lt;a href="http://slimdx.org/"&gt;SlimDX&lt;/a&gt; again.  I know, I know, I just can't make up my mind on things, right?  It would just be very convenient to be writing C# again, and I found the great &lt;a href="http://physxdotnet.codeplex.com/"&gt;PhysX.Net&lt;/a&gt; wrapper that should allow me to continue to use PhysX with my C# development.  Plus SlimDX already is supporting DirectX 11, which is awesome!  (Tessellation, here I come!)&lt;br /&gt;&lt;br /&gt;By the way, I was curious about JavaScript so I developed a simple little webpage that implements Perlin Noise in JavaScript.&lt;br /&gt;&lt;br /&gt;You can find it here:&lt;br /&gt;&lt;a href="http://re-creationstudios.com/noise/"&gt;http://re-creationstudios.com/noise/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I used a Canvas element to display the result, so it won't work in Internet Explorer.&lt;br /&gt;&lt;br /&gt;Be sure to check out the source code since I implemented several different types of summation as well (fBm, turbulence, and ridged multifractal).  Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3530746992899644593?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3530746992899644593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3530746992899644593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3530746992899644593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3530746992899644593'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/07/back-from-vacation.html' title='Perlin Noise in JavaScript'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-92122481694645728</id><published>2009-05-31T09:53:00.001-07:00</published><updated>2010-04-04T23:34:10.278-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>Perlin Noise on the GPU</title><content type='html'>I've written a tutorial on how to implement Perlin Noise in both a pixel shader and a vertex shader.  The tutorial is available over at Ziggyware.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ziggyware.com/readarticle.php?article_id=246"&gt;http://www.ziggyware.com/readarticle.php?article_id=246&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Check it out! I welcome any feedback.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;UPDATE&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.ziggyware.com/news.php?readmore=1125"&gt;http://www.ziggyware.com/news.php?readmore=1125&lt;/a&gt;&lt;br /&gt;I found out I have won first place in the Ziggyware contest!  I'm very happy that my first XNA tutorial was such a success.  Perhaps I will write up more in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-92122481694645728?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/92122481694645728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=92122481694645728' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/92122481694645728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/92122481694645728'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/05/perlin-noise-on-gpu.html' title='Perlin Noise on the GPU'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-133042166049020874</id><published>2009-05-29T10:37:00.000-07:00</published><updated>2010-04-04T23:32:13.012-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>PhysX Planet</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SiAd84Ta_7I/AAAAAAAAE00/UQQi0ZWa_JQ/s1600-h/physx4.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SiAd84Ta_7I/AAAAAAAAE00/UQQi0ZWa_JQ/s400/physx4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341302089804611506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Creating planetary gravity with a force field was much easier than I was expecting.  Especially after finding this thread on the official PhysX forum.&lt;br /&gt;&lt;a href="http://developer.nvidia.com/forums/index.php?showtopic=3201&amp;pid=9249&amp;st=0&amp;#entry9249"&gt;http://developer.nvidia.com/forums/index.php?showtopic=3201&amp;pid=9249&amp;st=0&amp;#entry9249&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After doing that, I got curious and I removed the sphere "planet" but I kept the gravity force field.  As expected, all of the shapes grouped together to form their own planet.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAeQ_EL5CI/AAAAAAAAE08/w3kcUmiSJ98/s1600-h/physx5.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAeQ_EL5CI/AAAAAAAAE08/w3kcUmiSJ98/s400/physx5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341302435217138722" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After I kept watching it, the planet started pulsing back and forth and eventually tore itself apart in a vortex that alternated back and forth.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SiAemVgW0dI/AAAAAAAAE1E/SmSpD67Ex2w/s1600-h/physx6.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SiAemVgW0dI/AAAAAAAAE1E/SmSpD67Ex2w/s400/physx6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341302802018128338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The debris vortex started stabilizing and turned into a spinning ring.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAe3LmGeWI/AAAAAAAAE1M/ywK9L8McRcw/s1600-h/physx7.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAe3LmGeWI/AAAAAAAAE1M/ywK9L8McRcw/s400/physx7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341303091415644514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The ring kept expanding and getting bigger and bigger.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SiAfBFF87gI/AAAAAAAAE1U/UjXaP-mhXFU/s1600-h/physx8.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SiAfBFF87gI/AAAAAAAAE1U/UjXaP-mhXFU/s400/physx8.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341303261468880386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I added some more cubes to the center, which formed a cool looking planet with a ring.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAfPFdWJTI/AAAAAAAAE1c/sfSmf8ss5i0/s1600-h/physx9.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SiAfPFdWJTI/AAAAAAAAE1c/sfSmf8ss5i0/s400/physx9.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341303502085170482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The planet at the center eventually started breaking apart and forming a ring as well, but what was most interesting was that the inner ring was rotating in the opposite direction of the outer ring.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SiAfUiz9RjI/AAAAAAAAE1k/aOOkppAKdBI/s1600-h/physx10.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SiAfUiz9RjI/AAAAAAAAE1k/aOOkppAKdBI/s400/physx10.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341303595863983666" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-133042166049020874?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/133042166049020874/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=133042166049020874' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/133042166049020874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/133042166049020874'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/05/physx-planet.html' title='PhysX Planet'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/SiAd84Ta_7I/AAAAAAAAE00/UQQi0ZWa_JQ/s72-c/physx4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5421887342371412649</id><published>2009-05-28T11:17:00.001-07:00</published><updated>2010-04-04T23:30:25.681-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>PhysX and DirectX 10</title><content type='html'>For the past week or so, I've been working on getting PhysX working in DirectX 10.  I ported over my Shape3D class from my previous blog post to C++ in order to draw the boxes and spheres (no cylinders because PhysX doesn't have a cylinder shape).&lt;br /&gt;&lt;br /&gt;I set up a simple scene with a ground plane (not rendered), normal Earth gravity, two boxes and a sphere.  The space bar spawns new boxes at the origin and the Alt key spawns new spheres.  &lt;br /&gt;&lt;br /&gt;In my first implementation, the application would slow down to 20fps when I added about 75 shapes.  I tracked down this slowdown to the creation of the vertex input layout each frame.  Once I moved that out of the render loop, I could then have 1000 shapes in the scene and still maintain 30fps.  I'm still trying to figure out if I can speed up the rendering even more because without rendering, the PhysX engine was able to handle 2000 shapes and maintain 60fps.  I doubt I can speed it up much more though.&lt;br /&gt;&lt;br /&gt;Here are some screenshots.  Pretty simple, but the debug info helps to illustrate the speeds.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sh7XtagaPJI/AAAAAAAAE0c/esq86suRCp4/s1600-h/physx1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sh7XtagaPJI/AAAAAAAAE0c/esq86suRCp4/s400/physx1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5340943383317331090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/Sh7X9RwI42I/AAAAAAAAE0k/aWD0vp4xPks/s1600-h/physx2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/Sh7X9RwI42I/AAAAAAAAE0k/aWD0vp4xPks/s400/physx2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5340943655845290850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/Sh7YCnMERPI/AAAAAAAAE0s/3DcOSKgVtQE/s1600-h/physx3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/Sh7YCnMERPI/AAAAAAAAE0s/3DcOSKgVtQE/s400/physx3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5340943747498919154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I have decided to share the Visual Studio 2008 project and source code to hopefully provide a nice starting point for others.  I'm not using an official license or anything, but I'll state that is it free for whatever use you desire, be it commercial, hobby, or education.&lt;br /&gt;&lt;br /&gt;Download the zip file: &lt;a href="http://re-creationstudios.com/shared/PhysXDX10.zip"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, I'm going to work on using static triangle meshes in PhysX to have a displaced sphere making up a planet, as well as using force fields to simulate planetary gravity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5421887342371412649?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5421887342371412649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5421887342371412649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5421887342371412649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5421887342371412649'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/05/physx-and-directx-10.html' title='PhysX and DirectX 10'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/Sh7XtagaPJI/AAAAAAAAE0c/esq86suRCp4/s72-c/physx1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5663387604397472081</id><published>2009-04-19T11:46:00.000-07:00</published><updated>2010-04-04T23:33:38.006-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Boxes, Cylinders, and Spheres (Oh My!)</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/Set2UIvP26I/AAAAAAAAExk/gJAEYxXL8Cc/s1600-h/shapes_wireframe.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/Set2UIvP26I/AAAAAAAAExk/gJAEYxXL8Cc/s400/shapes_wireframe.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5326481072610859938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After deciding to use PhysX in combination with DirectX 11 last week, I thought about how I would go about drawing simple 3D shapes.  In the samples and lessons, PhysX uses GLUT with has some shape drawing functions built-in.  While DX9 has similar functions, neither DX10 nor XNA do.  I believe it is safe to assume that DX11 will not have them either.  I can understand why they were removed.  They don't really make sense anymore in a programmable pipeline system.  What is the vertex format of the shape created?&lt;br /&gt;&lt;br /&gt;While most people these days get around it by creating a mesh in a 3D modeling application and then importing it into their game, I prefer to have my simple 3D shapes constructed programatically.  This allows me to easily change the detail of the mesh without worrying about exporting/importing an entire new model.&lt;br /&gt;&lt;br /&gt;Instead of implementing it in DX10 and C++ first, I decided to implement it in XNA.  This allowed me to focus on the algorithms themselves and not have to worry about any C++ issues getting in the way.&lt;br /&gt;&lt;br /&gt;My initial implementation was a static class that had static methods in it that built the shapes and returned the vertex buffer and index buffer.  This worked well, but I thought it still placed too much burden on the user to remember how many vertices they had just created and how many triangles they were going to draw.&lt;br /&gt;&lt;br /&gt;In order to make things simpler, I changed it to be a normal, instantiated class that contained the static methods that created an instance of the class.  This allowed me to store the vertex count, triangle count, as well as the buffers in instance properties in the class.  I even threw in a Draw method to make it incredibly simple to use the generated shape.&lt;br /&gt;&lt;br /&gt;Because this is such a basic, fundamental class that can benefit several people ( have seen various people requesting something like this), I have decided to share it with the public.&lt;br /&gt;&lt;br /&gt;You may download the C# file from here:&lt;br /&gt;&lt;a href="http://re-creationstudios.com/shared/Shape3D.cs"&gt;http://re-creationstudios.com/shared/Shape3D.cs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You can also download the entire test project here:&lt;br /&gt;&lt;a href="http://re-creationstudios.com/shared/ShapeTest.zip"&gt;http://re-creationstudios.com/shared/ShapeTest.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To use, simply create a shape using one of the static methods:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Shape3D sphere = Shape3D.CreateSphere(GraphicsDevice, 1, 12, 12);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To draw, in your Effect block, call the Draw method on the shape:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sphere.Draw(GraphicsDevice);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Create methods are made to follow the same structure as the DX9 shape drawing functions.  You can read more about those here:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb172976(VS.85).aspx"&gt;http://msdn.microsoft.com/en-us/library/bb172976(VS.85).aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/Set21Az6gwI/AAAAAAAAExs/uEkKdN3khc8/s1600-h/shapes_solid.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/Set21Az6gwI/AAAAAAAAExs/uEkKdN3khc8/s400/shapes_solid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5326481637418631938" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5663387604397472081?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5663387604397472081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5663387604397472081' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5663387604397472081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5663387604397472081'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/04/boxes-cylinders-and-spheres-oh-my.html' title='Boxes, Cylinders, and Spheres (Oh My!)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_hGl_uKJzpS0/Set2UIvP26I/AAAAAAAAExk/gJAEYxXL8Cc/s72-c/shapes_wireframe.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7946780627497536001</id><published>2009-04-12T12:55:00.000-07:00</published><updated>2010-04-04T23:33:27.243-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='PhysX'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Tactical RPG</title><content type='html'>I've been engrossed with learning about DX11 lately.  I've looked at slide presentations, listened to audio recordings of speeches, and read various articles discussing the new features being introduced.  I believe it's a great understatement to say that I'm excited about DX11.  I've finally come to the conclusion that once I have a DX11 GPU, I'm going to rewrite my procedural planet code using DX11.&lt;br /&gt;&lt;br /&gt;In the meantime, I've decided to take about 1 month to implement a prototype for a tactical RPG I've been thinking about. I started about 2 weeks ago, and I plan to finish it by the end of April.  One of my main goals is to have it completely mouse driven so that it can be played on a tablet.&lt;br /&gt;&lt;br /&gt;I believe it is coming along rather well.  I have a really nice 2D camera set up that behaves similar to Google Maps.  You can use the mouse to drag around the view and you can zoom in and out using the scroll wheel.  I have basic movement and attacking implemented as well.  I even have one of my graphic designer friends making up some art for me.  Overall, it should shape up to be a pretty decent prototype.  Maybe I will even release it to the public, source and all.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;PhysX&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;New content for Banjo-Kazooie: Nuts &amp; Bolts was released last week.  As a result, I pulled out the game again and played it some more.  I wasted several hours just messing around with the vehicle editor to make various contraptions.  I started thinking about how much fun it was to just tinker around like that without really following any goals, and then I started wondering about how hard it would be to implement a similar system myself.&lt;br /&gt;&lt;br /&gt;Almost 4 years ago, I had implemented a "domino simulator" using what was then known as the NovodeX physics engine.  It is now known as PhysX, is owned by Nvidia, and has hardware acceleration.  So, I downloaded the SDK and played around with some of the samples.  &lt;br /&gt;&lt;br /&gt;First, the good.  I was simply astounded by how many samples were provided in the SDK.  There are 37 samples and 89 "lessons", all with documentation.  It is amazing.  Plus, the hardware acceleration really helps speed the physics engine up.  One of the samples was getting about 40fps in software mode and 130fps in hardware mode.  That was on a 9800M GT.&lt;br /&gt;&lt;br /&gt;The bad is more about C++ than PhysX.  I decided to create a C++ project from scratch and then add all of the libraries and code necessary to get the first lesson from the SDK working.  It was horrific.  It took me 3 hours to get everything to compile and run.  In the end, here is what was in my project:&lt;br /&gt;&lt;br /&gt;5 include directories&lt;br /&gt;3 static libraries&lt;br /&gt; - added to both the project and VS itself&lt;br /&gt; - had to add one directly to solution to get to compile&lt;br /&gt;12 include files (separate from the include directories)&lt;br /&gt;8 cpp files&lt;br /&gt;1 dll&lt;br /&gt;&lt;br /&gt;Remember, all of that was to run the FIRST lesson, which is just three shapes on a plane.  In C#, it would have been 3-4 DLLs and one CS file.  As I said, this is more of a complaint about C++ and not PhysX.  I forgot how tedious it was to setup a project for the first time.  I do plan to stick with PhysX though, because once I do port my procedural planet code over to C++/DX11, then I will want a nice physics engine to go along with it, and it might was well be the only one with hardware acceleration.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7946780627497536001?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7946780627497536001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7946780627497536001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7946780627497536001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7946780627497536001'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/04/tactical-rpg.html' title='Tactical RPG'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-1131099003939679462</id><published>2009-03-18T23:23:00.000-07:00</published><updated>2010-04-04T23:33:12.528-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Voronoi'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><title type='text'>Craters</title><content type='html'>Another quick update.  I have been working on adding craters to the procedural moon.  I implemented a Voronoi diagram shader in HLSL and then I tweak it with quite a few different parameters to generate conical pits that are distorted slightly with fBm noise.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmnrGSYII/AAAAAAAAEqk/2NcJ1ivHtMk/s1600-h/screenshot_633730149444987250.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmnrGSYII/AAAAAAAAEqk/2NcJ1ivHtMk/s400/screenshot_633730149444987250.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5314782604532277378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmnHYkXpI/AAAAAAAAEqc/5NiwNLKnRLA/s1600-h/screenshot_633730148917177250.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmnHYkXpI/AAAAAAAAEqc/5NiwNLKnRLA/s400/screenshot_633730148917177250.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5314782594945277586" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmm8dJ6uI/AAAAAAAAEqU/4_wOvGBZRPM/s1600-h/screenshot_633730145382897250.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmm8dJ6uI/AAAAAAAAEqU/4_wOvGBZRPM/s400/screenshot_633730145382897250.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5314782592011725538" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/ScHmmlzxFOI/AAAAAAAAEqM/KUTGvlrkGwk/s1600-h/screenshot_633730144191097250.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/ScHmmlzxFOI/AAAAAAAAEqM/KUTGvlrkGwk/s400/screenshot_633730144191097250.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5314782585932551394" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I tried for quite a while to get rims around the edges of the craters, but I couldn't get it to work.  I tried using a colormap to alter the Voronoi results, but I was having issues with the it.  I will continue to tinker around with it because I think having rims would add quite a bit.&lt;br /&gt;&lt;br /&gt;Interesting fact: If I add even more fBm noise to the crater distortions, it forms pretty cool canyons:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/ScHo20VExxI/AAAAAAAAEqs/1OmQc-LnC8E/s1600-h/screenshot_633730133103237250.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/ScHo20VExxI/AAAAAAAAEqs/1OmQc-LnC8E/s400/screenshot_633730133103237250.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5314785063731513106" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-1131099003939679462?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/1131099003939679462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=1131099003939679462' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1131099003939679462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1131099003939679462'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/03/craters.html' title='Craters'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/ScHmnrGSYII/AAAAAAAAEqk/2NcJ1ivHtMk/s72-c/screenshot_633730149444987250.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4379064930682462869</id><published>2009-03-03T22:14:00.000-08:00</published><updated>2010-04-04T23:32:54.861-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>That's No Moon ...</title><content type='html'>Quick update.  First, I switched to more "moon-like" textures.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sa4cmIfH-nI/AAAAAAAAEoc/-j82Tr1Ti9E/s1600-h/screenshot_633716335233050000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sa4cmIfH-nI/AAAAAAAAEoc/-j82Tr1Ti9E/s400/screenshot_633716335233050000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5309212452155030130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then, I tweaked some of the parameters to my existing noise function.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sa4c2LxT5qI/AAAAAAAAEok/e6AksskdaUA/s1600-h/screenshot_633716350965900000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/Sa4c2LxT5qI/AAAAAAAAEok/e6AksskdaUA/s400/screenshot_633716350965900000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5309212727914522274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finally, I started messing around with sums of two different noises.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/Sa4dNPOIHhI/AAAAAAAAEos/jiyho6f4gzI/s1600-h/screenshot_633717145869190000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/Sa4dNPOIHhI/AAAAAAAAEos/jiyho6f4gzI/s400/screenshot_633717145869190000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5309213123977682450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's a detail shot showing the "better" noise at the surface.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/Sa4debv_RTI/AAAAAAAAEo0/NiTbHfeTc_o/s1600-h/screenshot_633717147640710000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/Sa4debv_RTI/AAAAAAAAEo0/NiTbHfeTc_o/s400/screenshot_633717147640710000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5309213419398710578" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There's a lot more work to do!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4379064930682462869?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4379064930682462869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4379064930682462869' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4379064930682462869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4379064930682462869'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/03/thats-no-moon.html' title='That&apos;s No Moon ...'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hGl_uKJzpS0/Sa4cmIfH-nI/AAAAAAAAEoc/-j82Tr1Ti9E/s72-c/screenshot_633716335233050000.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5626810400965411290</id><published>2009-02-19T23:29:00.000-08:00</published><updated>2010-04-04T23:42:07.530-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Fixed Lighting + Higher Res</title><content type='html'>As I mentioned in my previous post, I was getting some strange vertical lines appearing in my deferred lighting result.  After I turned down the ambient light to make the lighting a bit more realistic, the lines became even more pronounced. &lt;br /&gt;&lt;br /&gt;Casting that problem aside for a bit, I decided to increase the resolution because 800x600 just wasn't cutting it anymore.  I went with a widescreen resolution because both my laptop and my desktop have widescreen screens.  I settled on 1280x720 because 1920x1200 would just be overkill right now, in my mind.&lt;br /&gt;&lt;br /&gt;The problem with increasing the resolution was that the lines got even worse!  Now I was getting horizontal lines as well as vertical lines, so it looked like a big checkerboard mess.  I spent several days trying to figure out what was going wrong.  At first I thought it was a bad driver/GPU in my laptop.  So, I went to test it on my desktop, but I found out that my power supply was dead.  Luckily my brother let me remote into his PC and run the app.  I got the exact same results, so I knew it wasn't my GPU.  I then installed FX Composer to have a better debugging IDE.  I soon discovered that I was using wrong texel offsets to sample neighbors in the world position texture.  This removed the lines from FX Composer, but they were still appearing in XNA.  I was messing around with my sampler filters when I finally fixed the problem by switching them from Point to Linear. While it does get rid of the lines, it comes at a cost.  I am now getting about 18fps average.  Obviously the change in resolution also figures into that as well.&lt;br /&gt;&lt;br /&gt;I have some interesting new screenshots to share.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SZ5fSps77nI/AAAAAAAAEnQ/g5orMF9GyQc/s1600-h/screenshot_633706820613754000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SZ5fSps77nI/AAAAAAAAEnQ/g5orMF9GyQc/s400/screenshot_633706820613754000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5304782185125637746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5ffHOIHqI/AAAAAAAAEnY/UOeqeanXSBw/s1600-h/screenshot_633706821899854000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5ffHOIHqI/AAAAAAAAEnY/UOeqeanXSBw/s400/screenshot_633706821899854000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5304782399207906978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5frUvLc_I/AAAAAAAAEng/uWii2u2Puls/s1600-h/screenshot_633706822814114000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5frUvLc_I/AAAAAAAAEng/uWii2u2Puls/s400/screenshot_633706822814114000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5304782608994628594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5fzF4UR_I/AAAAAAAAEno/YyBJarON4z0/s1600-h/screenshot_633706823310614000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SZ5fzF4UR_I/AAAAAAAAEno/YyBJarON4z0/s400/screenshot_633706823310614000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5304782742445377522" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5626810400965411290?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5626810400965411290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5626810400965411290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5626810400965411290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5626810400965411290'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/02/fixed-lighting-higher-res.html' title='Fixed Lighting + Higher Res'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hGl_uKJzpS0/SZ5fSps77nI/AAAAAAAAEnQ/g5orMF9GyQc/s72-c/screenshot_633706820613754000.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8869593152781277313</id><published>2009-02-08T17:55:00.000-08:00</published><updated>2010-04-04T23:42:25.360-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Deferred Lighting</title><content type='html'>This weekend I implemented a lighting system like the one I talked about in my last two blog posts.  I'm calling it deferred lighting because it doesn't do any lighting calculation until I have render targets for the scene.  I have one render pass that has two targets: one containing the diffuse color of the scene, and the other containing the world position of each pixel.  In a second render pass, I calculate the normal of each pixel by sampling it's neighboring pixel world positions.  I then simply do a standard lighting calculation using the normal and the diffuse color of the scene.&lt;br /&gt;&lt;br /&gt;It also has much better performance compared to the brute force 32 noise calculations method.  At low altitudes I was getting 16fps with the noise method and 33fps with the deferred method.  At high altitudes I was getting 12fps and 30fps, respectively.  As you can see, I was getting at least double the framerate all the time.&lt;br /&gt;&lt;br /&gt;Now for some pretty pictures.  They are not much different from my previous lighting pictures, the important thing is that they are being rendered much faster now.  I also fixed a slight bug I had in the previous lighting that made the light direction the same for every side of the planet (there was no dark side).  There are some strange vertical lines that are appearing which you can see in some of the screenshots below.  I'm not sure why they are there, but I will continue to investigate them.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SY-P7XdPDlI/AAAAAAAAElU/haYTnNZIa-g/s1600-h/screenshot_633697120860460000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SY-P7XdPDlI/AAAAAAAAElU/haYTnNZIa-g/s400/screenshot_633697120860460000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300613536510053970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SY-QPSjh9wI/AAAAAAAAElc/XvHhxikWE0s/s1600-h/screenshot_633697121969750000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SY-QPSjh9wI/AAAAAAAAElc/XvHhxikWE0s/s400/screenshot_633697121969750000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300613878791665410" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SY-QXVsQH7I/AAAAAAAAElk/HANxU-XqM7Q/s1600-h/screenshot_633697122316720000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SY-QXVsQH7I/AAAAAAAAElk/HANxU-XqM7Q/s400/screenshot_633697122316720000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300614017072504754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SY-QfvyRj1I/AAAAAAAAEls/5_CFz5Fv0m4/s1600-h/screenshot_633697122704560000.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SY-QfvyRj1I/AAAAAAAAEls/5_CFz5Fv0m4/s400/screenshot_633697122704560000.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300614161516040018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the last picture you can see the detailed designs that are being generated for the terrain itself.  Just to show a difference between the lit vs diffuse renderings, here is the diffuse texture alone for the last picture.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SY-RDnRDTJI/AAAAAAAAEl0/3AElfSrodCg/s1600-h/diffuse.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SY-RDnRDTJI/AAAAAAAAEl0/3AElfSrodCg/s400/diffuse.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300614777704500370" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8869593152781277313?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8869593152781277313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8869593152781277313' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8869593152781277313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8869593152781277313'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/02/deferred-lighting.html' title='Deferred Lighting'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hGl_uKJzpS0/SY-P7XdPDlI/AAAAAAAAElU/haYTnNZIa-g/s72-c/screenshot_633697120860460000.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3998049239768628434</id><published>2009-02-05T13:06:00.000-08:00</published><updated>2010-04-04T23:42:36.179-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Per Pixel Normal Calculation</title><content type='html'>Sorry, still no actual code or pretty pictures!&lt;br /&gt;&lt;br /&gt;I just wanted to write up a quick note related to my second topic in my previous post.   I did some Googling to see if any other people have implemented a similar system and indeed some people have.  In fact I found an article by Microsoft that describes exactly what I was talking about.&lt;br /&gt;&lt;a href=" http://msdn.microsoft.com/en-us/library/cc308054(VS.85).aspx"&gt;&lt;br /&gt;http://msdn.microsoft.com/en-us/library/cc308054(VS.85).aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the article, they are creating procedural materials dynamically, so they have to calculate normals dynamically as well.&lt;br /&gt;&lt;br /&gt;From the article:&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;One solution is to run the shader multiple times and compute the difference in height at each sample point. If we calculated the height one pixel to the right of the currently rasterized pixel and one pixel above the currently rasterized pixel, we could compute tangent and bitangent vectors to the central pixel. Doing a cross product on these would give us the normal for that point.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;What I found funny is how they start talking about the ddX and ddY functions in HLSL but in the end they still use the render target + second pass method.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style:italic;"&gt;The solution that this sample uses by default is to render the perturbed heights of the objects in the scene into an off-screen render target. That render target is then read back in on another pass. For each pixel on the screen, its right and top neighbors are sampled. Tangent and bitangent vectors are created from the neighbors to the central pixel. A cross product between these will give the normal.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;I now feel very confident about this method of doing things and I will proceed to implement lighting in this manner.  I will probably branch off of my existing planet codebase so I can easily compare the differences between the brute-force noise calculation vs the "deferred" style.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3998049239768628434?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3998049239768628434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3998049239768628434' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3998049239768628434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3998049239768628434'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/02/per-pixel-normal-calculation.html' title='Per Pixel Normal Calculation'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8719030838596922476</id><published>2009-02-03T11:43:00.000-08:00</published><updated>2010-04-18T22:35:05.402-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Hello 2009!</title><content type='html'>I just realized that I never wrote an entry for January.  It's the first month that I have not had an update since I started this dev blog.  To be honest, I didn't have much to report.  I haven't really written any code but I have been thinking about a lot.&lt;br /&gt;&lt;br /&gt;At first I was thinking about physics.  I thought it would be nice to actually have collision detection with my terrain and possibly throw balls around or maybe even drive a car.  However there was a big problem with this.  How do I detect collision with a mesh that is deformed entirely on the GPU?  Obviously I would have to have some way of sending the physics data to the GPU, do the collision detection there, and then somehow pass the resultant data back to the CPU.  &lt;br /&gt;&lt;br /&gt;Getting the data to the GPU is the easy part, I think.  If I only use bounding spheres for all of the objects, then I can simply pass one normal Color texture to the GPU containing the position of each sphere in the RGB and the radius of the sphere in the Alpha.  It may even be possible to set a constant memory buffer (ie array) with the data, which would be even easier.  &lt;br /&gt;&lt;br /&gt;Once I have this data, I can run through each object in the vertex shader to see if it collides with the current vertex.  The problem I ran into then is I don't know how to get the data back to the CPU.  I would obviously want to write the data to a render target.  Unfortunately, the collision data is in the vertex shader.  Pixel shaders cannot index into memory in XNA/DX9/SM3.0. [In DX10/SM4.0 they can index into constant memory, in DX11/SM5.0 both the vertex and pixel shaders can read and write to dynamic resources.]  I have no idea how I would pass the data from the vertex shader to the pixel shader.&lt;br /&gt;&lt;br /&gt;That means I must somehow do the collision detection in the pixel shader.  However, this means that I will be doing the checks for every object, for every pixel.  That will be massive overkill.  I couldn't come up with a good solution, so I pretty much gave up on physics for now.  It should be a cinch in DirectX 11 and Shader Model 5.0!&lt;br /&gt;&lt;br /&gt;The next thing I was thinking about was mainly efficiencies.  Currently I am calculating the normal in the pixel shader by doing 32 noise calculations per pixel.  This is quite a strain on the GPU.  I was reading an article about deferred rendering and I had a thought.  If I only output the height of each pixel to a render target, then I could have another pass that reads the neighboring pixels in the render target into order to calculate the normal.  This means it would one pass that does 8 noise calculations per pixel and then a second pass that does 4 texture lookups per pixel.  I imagine that would be a much faster way of doing things.&lt;br /&gt;&lt;br /&gt;I have yet to actually implement anything though.  So everything here is just speculation.  Sorry for no pretty pictures.  I will try to get something worth showing off sometime soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8719030838596922476?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8719030838596922476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8719030838596922476' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8719030838596922476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8719030838596922476'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2009/02/hello-2009.html' title='Hello 2009!'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4460548120334945389</id><published>2008-12-22T00:42:00.000-08:00</published><updated>2010-04-04T23:45:17.127-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>Starfields &amp; Nebulas</title><content type='html'>Instead of focusing on craters (which I implied I was going to do last time), I decided to look into generating starfields and distant (ie 2D) nebulas.&lt;br /&gt;&lt;br /&gt;I started on simple starfields and I had a working solution in less than an hour by simply drawing star sprites in random positions.&lt;br /&gt;&lt;br /&gt;This yields the following result:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hGl_uKJzpS0/SU9VRM5DmhI/AAAAAAAAEgY/6-ar9ics2Oc/s1600-h/stars.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_hGl_uKJzpS0/SU9VRM5DmhI/AAAAAAAAEgY/6-ar9ics2Oc/s400/stars.png" alt="" id="BLOGGER_PHOTO_ID_5282534641935555090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, in order to make the stars more interesting, I looked into implementing nebula clouds.  I knew that some summation of Perlin Noise would be the best solution.  So, I decided to implement a Perlin Noise function in C#.  I have a really fast implementation in HLSL, but I wanted the full power of breakpoints and variable watches.  I ended up using a standard fBm summation with an exponential filter applied to it.&lt;br /&gt;&lt;br /&gt;This helped to produce this nebula cloud image:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SU9WoJHNNOI/AAAAAAAAEgg/xU5RIUQoAf8/s1600-h/nebula.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SU9WoJHNNOI/AAAAAAAAEgg/xU5RIUQoAf8/s400/nebula.png" alt="" id="BLOGGER_PHOTO_ID_5282536135569781986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I still need to blend these two results together and construct them into a decent cubemap.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;World of Warcraft + 360 Controller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;All of that work done on the starfields and nebulas was done a couple weeks ago.  My co-workers recently pressured me into playing World of Warcraft again.  (About 6 months ago, I got up to level 18, and then quit.)  As I was playing I kept thinking about how bad the controls were.  I was moving my hands all over the keyboard to use all of my skills.  It was fine for just grinding along and completing quests, but grouping and duels I always performed horribly.  I desparately wanted to play with a game controller, however World of Warcraft didn't support them.  There were a couple of applications that other people had written to allow gamepads, but I didn't care for them either.  One was very ackward and built up macro commands that you had to then "submit" by pulling the right trigger.  Another one seemed decent, but it had a subscription fee of $20 a year.&lt;br /&gt;&lt;br /&gt;I decided that if I wanted something done right, I had to do it myself.  So, I threw together a quick XNA application that read the 360 controller input.  It would then use the Win32 function SendInput to place keyboard and mouse input events into the Windows input queue.  I mapped out all of the controls and I was then able to play World of Warcraft using a 360 controller!  I can target enemies, target allies, use all 12 skills on the current action bar, switch action bars, loot corpses, and even move the camera with full analog control using the 360 controller!  It has completely changed the game for me and I even won my first duel last night.&lt;br /&gt;&lt;br /&gt;I have now taken the app and added in mappings for Call of Duty 4 for my brother.  I'm planning on converting the project to be more generalized so that the input mapping can be defined in XML and easily changed without recompiling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4460548120334945389?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4460548120334945389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4460548120334945389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4460548120334945389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4460548120334945389'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/12/starfields-nebulas.html' title='Starfields &amp; Nebulas'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_hGl_uKJzpS0/SU9VRM5DmhI/AAAAAAAAEgY/6-ar9ics2Oc/s72-c/stars.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3404797958040947596</id><published>2008-12-04T23:53:00.000-08:00</published><updated>2010-04-05T00:08:03.052-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>Lighting Revisited (AKA I'm Back!)</title><content type='html'>So, after almost 3 months of being sidetracked with various other projects I came up with, I finally decided to come back to C# and XNA with welcome arms.&lt;br /&gt;&lt;br /&gt;And I have come back in a big way, in my opinion.  After discussing it with one of my friends, I decided that it would be best to procedurally generate a moon instead of a planet.  This greatly simplifies many things; no atmosphere, no fog, no water, no vegetation, etc.  However, this meant that I needed to figure out how to properly do two things: generate craters and have realistic lighting.&lt;br /&gt;&lt;br /&gt;You may recall that I had a previous blog entry about my attempts with realistic lighting.  [&lt;a href="http://recreationstudios.blogspot.com/2008/07/do-you-see-light.html"&gt;http://recreationstudios.blogspot.com/2008/07/do-you-see-light.html&lt;/a&gt;] In the end, I determined that it would be too difficult to do now, and easy to do in the future once I had geometry shader support.  So, I had settled with simple spherical lighting across the entire planet.&lt;br /&gt;&lt;br /&gt;So, it took me quite a bit of effort to even start looking at alternative ways to render realistic lighting.  In the past I was trying to calculate the other two vertices of the triangle in the vertex shader.  It was with a great facepalm that I realized that what I was trying to find was the tangent of the surface and then I could use that to adjust the spherical normal.  Well, as you may remember from your math classes, a tangent is calculated by taking the derivative of the original function.  So, I looked into quite a few articles about how to find the derivative of a Perlin Noise function.&lt;br /&gt;&lt;br /&gt;This article was very informative, but I wasn't quite sure on what speeds would be on the GPU:&lt;br /&gt;&lt;a href="http://rgba.scenesp.org/iq/computer/articles/morenoise/morenoise.htm"&gt;http://rgba.scenesp.org/iq/computer/articles/morenoise/morenoise.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Finally, I found an article by Ken Perlin himself that shows how to approximate the derivative:&lt;br /&gt;&lt;a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch05.html"&gt;http://http.developer.nvidia.com/GPUGems/gpugems_ch05.html&lt;/a&gt;  (Section 5.6)&lt;br /&gt;&lt;br /&gt;With this little nugget of knowlege I went into my shader and wrote a function to do exactly that.&lt;br /&gt;&lt;br /&gt;float3 NoiseDerivative(float3 position, float e)&lt;br /&gt;{&lt;br /&gt;      //calculate the height values using Perlin Noise&lt;br /&gt;      float F0 = ridgedmf(position*noiseScale, 8);&lt;br /&gt;      float Fx = ridgedmf(float3(position.x+e, position.y, position.z)*noiseScale, 8);&lt;br /&gt;      float Fy = ridgedmf(float3(position.x, position.y+e, position.z)*noiseScale, 8);&lt;br /&gt;      float Fz = ridgedmf(float3(position.x, position.y, position.z+e)*noiseScale, 8);&lt;br /&gt;    float3 dF = float3(Fx-F0, Fy-F0, Fz-F0) / e;&lt;br /&gt;&lt;br /&gt;      //calculate the actual normal&lt;br /&gt;    return normalize(position - dF);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Then I simply added a call to this function in my pixel shader:&lt;br /&gt;   input.Normal = NoiseDerivative(input.Normal, 0.000001);&lt;br /&gt;&lt;br /&gt;Lo and behold, it worked!&lt;br /&gt;&lt;br /&gt;Check out the pics:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/STjiaeajk-I/AAAAAAAAD_Q/lGYb2fiPP0U/s1600-h/screenshot_633640314480390000.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/STjiaeajk-I/AAAAAAAAD_Q/lGYb2fiPP0U/s400/screenshot_633640314480390000.png" alt="" id="BLOGGER_PHOTO_ID_5276215907933459426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/STjis9AcQhI/AAAAAAAAD_Y/5J1pSE5BFWs/s1600-h/screenshot_633640314863860000.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/STjis9AcQhI/AAAAAAAAD_Y/5J1pSE5BFWs/s400/screenshot_633640314863860000.png" alt="" id="BLOGGER_PHOTO_ID_5276216225383072274" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3404797958040947596?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3404797958040947596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3404797958040947596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3404797958040947596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3404797958040947596'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/12/lighting-revisited-aka-im-back.html' title='Lighting Revisited (AKA I&apos;m Back!)'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hGl_uKJzpS0/STjiaeajk-I/AAAAAAAAD_Q/lGYb2fiPP0U/s72-c/screenshot_633640314480390000.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2076204196758449613</id><published>2008-11-07T12:52:00.000-08:00</published><updated>2010-04-18T22:35:24.266-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>Sidetracked</title><content type='html'>Wow, it has been awhile and I haven't really had time to work on my graphics projects.  I have been really busy at work.  When I do finally make it home, I usually get sidetracked with other things.  I finally got to level 60 in Mass Effect.  I am over halfway through the excellent novel Prey by Michael Crichton (I  can't believe he's dead now).  I have also been piecing together ideas for my own novel (I've always wanted to write a novel).&lt;br /&gt;&lt;br /&gt;In terms of the DirectX 10 work, I did manage to get multiple render targets working.  However, I got sidetracked by a bright idea I came up with involving using "strokes" generated in the geometry shader to do some NPR post processing.   I was having a hell of a time trying to get multiple vertex buffers working.  As I was investigating though, I found out that it wouldn't work anyway because the buffer size is limited to 16-bits (65,536 vertices).  I needed more than that ... alot more.  It would be a rather long explanation to explain why, so I'll just say that I was trying to essentially use the vertex shader as a pixel shader.&lt;br /&gt;&lt;br /&gt;XNA 3.0 is out now, and I'm really surprised that I have not yet downloaded it.  It sounds like they added in some nice features though (new Media classes, ClickOnce deployment, etc.).&lt;br /&gt;&lt;br /&gt;I am really missing C#, so I may just go back to XNA and just wait for it (or some other C# graphics library) to get Geometry Shader support.&lt;br /&gt;&lt;br /&gt;I was also reading about some of the features that are going to be in C# 4.0, and I am really excited.  They are finally adding in optional parameters.  Plus they are adding a dynamic type, which could prove useful in some cases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2076204196758449613?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2076204196758449613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2076204196758449613' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2076204196758449613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2076204196758449613'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/11/sidetracked.html' title='Sidetracked'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-6891763258977855355</id><published>2008-10-07T23:22:00.000-07:00</published><updated>2010-04-18T22:35:57.952-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>It's getting close</title><content type='html'>I've been continuing my work in DirectX 10, and it has been relatively slow progress, but progress nonetheless.  I managed to render the simple character model that comes with the DirectX SDK using the first pass of my pencil shader.  The first pass applies 6 different pencil textures based upon how lit that part of the model is.  It is currently using the given texture coordinates of the model, so it doesn't look as good as it potentially could.  That's an improvement for another time though.&lt;br /&gt;&lt;br /&gt;I have been busy working on getting the second pass of the pencil shader working.  It's pretty much just a Sobel filter that is applied to the normal map of the scene.  In order to get the Sobel filter working though, I had to first figure out how to do post-processing image filters in DirectX 10.  Obviously the first step was to render a full-screen textured quad.  In XNA, I "cheated" and just used a SpriteBatch.  It's not the most efficient way, but it allowed for the fastest development.&lt;br /&gt;&lt;br /&gt;There ARE sprites in DX10, but I figured I might as well do it the "proper" way this time.  So, I set up my own vertex format (with Position and Texure Coords), created my own vertex buffer (with the 4 vertices positioned in clipspace), and my own index buffer.  I then wrote a simple shader that simply passed the vertices through the vertex shader, and applied the texture in the pixel shader.  I fired up the app for the first time and Vista completely froze!  Ctrl-Alt-Del didn't work, the mouse didn't move, nothing.  So I shut it down and restarted and I got the Blue Screen of Death!  I booted back into Safe mode and it said that my video card driver had gotten screwed up.  I was able to boot back into Windows regularly the next time without changing anything.&lt;br /&gt;&lt;br /&gt;I set a breakpoint in my code and stepped through the Update/Render loop about a dozen times without any errors, so I just let it run free again.  The exact same problems occurred again, thus causing a reboot.  I had no idea what I was doing wrong to screw up my computer, so I looked at several of the DX tutorials line by line.  I realized that I had forgotten to tell the video card what my vertex input layout was.  I added in the 3 lines of code to do it, and bam, everything worked!  So I now have full screen textured quads working in DX10.  An added bonus is since I positioned the vertices in clipspace, then it works on any resolution without requiring any updates or changes, plus there are no matrix multiplications that are needed to be done.&lt;br /&gt;&lt;br /&gt;The next task I have to work on is to get mutiple render targets working in DX10.  I need this because as I mentioned earlier, my goal is to render a normal map of the scene, and then pass that normal map into the Sobel filter shader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-6891763258977855355?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/6891763258977855355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=6891763258977855355' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6891763258977855355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6891763258977855355'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/10/its-getting-close.html' title='It&apos;s getting close'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4075665854077682133</id><published>2008-09-26T12:48:00.000-07:00</published><updated>2010-04-18T22:36:32.493-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='DirectX 10'/><title type='text'>DirectX 10</title><content type='html'>I've decided to finally start dabbling with DirectX 10.  The main reason behind it is that I want to work with Geometry Shaders.  There is no official C# wrapper around DX10, but I did manage to find two third-party ones.  One had not been updated since April 2006, so I threw that one out the window.  The other, SlimDX, has been in very active development and a new version was just released this month.  I downloaded it and played with some of the samples and was rather impressed.  However, SlimDX also provides a wrapper around DX9 and it is very clear that that was the priority of the project.  There are quite a few things missing from the DX10 wrapper that would have been very useful.&lt;br /&gt;&lt;br /&gt;So, instead of fighting through a third-party C# wrapper, I figured I might as well go back to the straight C++ version.  This has the advantage of having tons of official samples and tutorials from Microsoft.  However, this has the major disadvantage that I have not worked in C++ directly for almost 4 years.  It is rather rough going back to C++ from C#.  There were so many helpful things built into C# that aided in rapid development.  I mean, C++ doesn't even have a string type, you have to use char arrays.  (Edit: I forgot that it &lt;span style="font-weight: bold;"&gt;does&lt;/span&gt; support strings, but you have to include the header for it first. Doh!) I feel like I'm stepping back into the dark ages!  :-P&lt;br /&gt;&lt;br /&gt;I'm hoping to have just the basic C++ code to draw a model using a shader, and then all of the rest of my work will be in HLSL.  We shall see!&lt;br /&gt;&lt;br /&gt;(Edit: I found a really helpful C++ tutorial for getting me back up to speed.  &lt;a href="http://www.cplusplus.com/doc/tutorial/"&gt;http://www.cplusplus.com/doc/tutorial/&lt;/a&gt; )&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4075665854077682133?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4075665854077682133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4075665854077682133' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4075665854077682133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4075665854077682133'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/09/ive-decided-to-finally-start-dabbling.html' title='DirectX 10'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8649393174744412068</id><published>2008-09-14T01:05:00.000-07:00</published><updated>2010-04-18T22:37:19.496-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><title type='text'>Switching Gears</title><content type='html'>So I was chatting with one of my friends about what was up next on the todo list for my procedural planet.  I explained that I was working on fog and that after that I would focus on water.  He suggested that I get HDR and Depth of Field put in next.  I then mentioned how I want to get Atmospheric Scattering in as well.&lt;br /&gt;&lt;br /&gt;With all of these features laid out, the project seems rather daunting.  That is easily several months worth of work right there.  (I still do have a full time job!)  I started thinking about how to make it easier, yet still make it stand out.  I mean no matter how many awesome looking things I put in, I will never even come close to the level of Crysis.  I am only one guy!  So, I decided I should focus more on something that would be feasible for a team of one to accomplish in a lifetime.&lt;br /&gt;&lt;br /&gt;Time for a personal history lesson!&lt;br /&gt;&lt;br /&gt;Back when I first started fiddling around with XNA (over 2 years ago now), I also started looking into shaders for the first time.  I have always been interested in Non-Photorealistic Rendering (cel shading, painterly rendering, hatching, etc),  so I thought that might be a good subject to test with shaders.  In my research, I came across a great paper about doing real-time pencil sketch rendering.  &lt;a href="http://cg.postech.ac.kr/research/pencil_rendering/"&gt;http://cg.postech.ac.kr/research/pencil_rendering/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In January 2007, I began work on my own pencil shader.  I actually started with 4 separate shaders that would require all models to be rendered 4 times.  Fairly quickly I realised that I could speed things up greatly by having 1 shader with 4 passes.  I tinkered around with it, and other things, for several months before I found out about using multiple render targets.  Using this, I was able to get it down to 3 passes.  Not long after that, I demoed the shader in a job interview and I actually got a job as an XNA Game Developer!  That job lasted until the company got bought out by a larger company.  Toward the end of my employment there, I started getting into procedural generatation, and that's how I came to have the procedural planet that I have today.&lt;br /&gt;&lt;br /&gt;As you know, I have a new laptop now, and during the transfer of files from my old laptop, I saw my old pencil shader again.  It had gone untouched since the day I demoed it in my job interview. Yesterday I finally decided to take all of the code and update it to XNA 2.0 and clean up what I could.  I realized that I had learned quite a bit over the last year about both XNA and C#, so I was able to make the code much cleaner.  Not only that, but I was also able to get the shader down to 2 passes!  This gave me a 100fps speed boost.  (On my GeForce 9800 GT,  the 4  pass = 470fps,  3 pass = 480fps, 2 pass = 580fps.)&lt;br /&gt;&lt;br /&gt;This has really given me a desire to work on NPR stuff again.  So, currently my next goal is to have a procedural planet that is rendered using my pencil shader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8649393174744412068?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8649393174744412068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8649393174744412068' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8649393174744412068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8649393174744412068'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/09/switching-gears.html' title='Switching Gears'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3105277731693364232</id><published>2008-09-02T21:47:00.000-07:00</published><updated>2010-04-18T22:38:10.425-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='HLSL'/><title type='text'>Procedural Texturing</title><content type='html'>Well I am now producing what in my opinion are decent procedural textures for the planetary terrain.  They are generated per pixel every frame.  This has the advantage of allowing infinite resolution as well as eliminating any texture coordinate warpings around a sphere, since the textures are actually 3D.&lt;br /&gt;&lt;br /&gt;As I mentioned before, this does require a significant performance hit.  I have managed to simplify the texture generation to the point of having reasonable framerates while maintaining decent texture quality.  What I am doing is calculating 4 separate textures using 2 octaves of turbulence noise at different scales for each one.  These 4 textures represent sand, grass, rock, and snow.  They are then blended together based upon the terrain height to generate a final texture.&lt;br /&gt;&lt;br /&gt;I am getting anywhere between 25-50 frames per second depending upon how many pixels of the terrain are taking up the viewport.  The average for normal travel is 35 frames per second.&lt;br /&gt;&lt;br /&gt;Here are some screenshots of the results.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4ZGiOwXTI/AAAAAAAAD1Q/_1N8grogr3w/s1600-h/screenshot_633559021775571043.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4ZGiOwXTI/AAAAAAAAD1Q/_1N8grogr3w/s400/screenshot_633559021775571043.png" alt="" id="BLOGGER_PHOTO_ID_5241654616364440882" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4ZRamtO4I/AAAAAAAAD1Y/u1KHgUVFV8s/s1600-h/screenshot_633559024006521043.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4ZRamtO4I/AAAAAAAAD1Y/u1KHgUVFV8s/s400/screenshot_633559024006521043.png" alt="" id="BLOGGER_PHOTO_ID_5241654803295976322" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4Zcx-XfsI/AAAAAAAAD1g/zoXxPe4FMbo/s1600-h/screenshot_633559888068550000.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4Zcx-XfsI/AAAAAAAAD1g/zoXxPe4FMbo/s400/screenshot_633559888068550000.png" alt="" id="BLOGGER_PHOTO_ID_5241654998547791554" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3105277731693364232?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3105277731693364232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3105277731693364232' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3105277731693364232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3105277731693364232'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/09/procedural-texturing.html' title='Procedural Texturing'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hGl_uKJzpS0/SL4ZGiOwXTI/AAAAAAAAD1Q/_1N8grogr3w/s72-c/screenshot_633559021775571043.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7793310124462247973</id><published>2008-09-01T12:05:00.000-07:00</published><updated>2010-04-04T23:52:58.534-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Perlin Noise'/><title type='text'>New Laptop, New Opportunities</title><content type='html'>It's been awhile since I've written an update.  As expected I got slightly side-tracked by Too Human, but what was an even worse offender was Mass Effect.  I picked it up at a sale at Toys R Us, and I became addicted to it.  I am currently working on my third playthrough of the game.&lt;br /&gt;&lt;br /&gt;I finally received my new laptop 3 days ago.  I haven't had much time to do programming on it because I had to first install all of my desired applications, transfer all of my files from my old laptop, and then prepare my old laptop for my sister.&lt;br /&gt;&lt;br /&gt;I did manage to run a "benchmark" on the new laptop though.  In the past, I wrote an XNA app that generates a texture using Perlin Noise in a pixel shader.  This is usually a good evaluator of a GPU's performance.  Here are some specs:&lt;br /&gt;&lt;br /&gt;Generating 12 octaves of 1024x1024 3D fractional Brownian motion Perlin Noise:&lt;br /&gt;8600 GT ~20 frames per second&lt;br /&gt;9800 GT ~80 frames per second&lt;br /&gt;&lt;br /&gt;Yep!  My new laptop's GPU is 4 times faster than my desktop!  Just to put a little perspective on it, these results mean that my new GPU was performing over 1 &lt;span style="font-weight: bold;"&gt;billion&lt;/span&gt; perlin noise calculations a second!&lt;br /&gt;&lt;br /&gt;I also started fiddling around briefly with generating procedural textures for the planetary terrain.  My idea was to use 4 different noise calculations per pixel and then blend the results together based on the planetary height of the pixel.  As expected though, there was a severe penalty for doing a noise calculation per pixel.  I never did get up to 4 calculations.  Here are my initial findings, on my 9800 GT of course!&lt;br /&gt;&lt;br /&gt;~120 fps using 4 existing textures&lt;br /&gt;~40 fps using 1 8-octave ridged multifractal per pixel&lt;br /&gt;~30 fps using 2 8-octave ridged multifractals per pixel&lt;br /&gt;&lt;br /&gt;The performance hit is not linear though, so I expect that if I did 4 noise calcs, I would be getting about 20fps. However, that is on a 9800 GT, which is one of the best cards on the market now.  Sure there are about half a dozen better cards, but how many people really have them?&lt;br /&gt;&lt;br /&gt;I do have some ideas to potentially speed it up though.  I could reduce the number of octaves, but then increase the scale.  I could also try to make a fancy gradient so that I don't have to use as many different noise calcs.&lt;br /&gt;&lt;br /&gt;Here are some screenshots showing different simple gradients using just 1 noise calc.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SLxCVK3PfbI/AAAAAAAAD1A/nSyuGhur5M0/s1600-h/screenshot_633558672610121043.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SLxCVK3PfbI/AAAAAAAAD1A/nSyuGhur5M0/s400/screenshot_633558672610121043.png" alt="" id="BLOGGER_PHOTO_ID_5241136997813157298" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hGl_uKJzpS0/SLxBk9g-0wI/AAAAAAAAD04/rgXmF70DPLw/s1600-h/screenshot_633558672309191043.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_hGl_uKJzpS0/SLxBk9g-0wI/AAAAAAAAD04/rgXmF70DPLw/s400/screenshot_633558672309191043.png" alt="" id="BLOGGER_PHOTO_ID_5241136169596408578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hGl_uKJzpS0/SLxCkHgnqMI/AAAAAAAAD1I/ySpal6nGsKY/s1600-h/screenshot_633558673372751043.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_hGl_uKJzpS0/SLxCkHgnqMI/AAAAAAAAD1I/ySpal6nGsKY/s400/screenshot_633558673372751043.png" alt="" id="BLOGGER_PHOTO_ID_5241137254611003586" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7793310124462247973?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7793310124462247973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7793310124462247973' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7793310124462247973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7793310124462247973'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/09/new-laptop-new-opportunities.html' title='New Laptop, New Opportunities'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hGl_uKJzpS0/SLxCVK3PfbI/AAAAAAAAD1A/nSyuGhur5M0/s72-c/screenshot_633558672610121043.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2836227185993247825</id><published>2008-08-17T11:04:00.000-07:00</published><updated>2008-08-18T12:03:45.005-07:00</updated><title type='text'>Relaxing</title><content type='html'>I decided that since I had accomplished so much by pretty much working non-stop for almost a month, I was going to take a break for a bit.  So, I have not worked on my procedural planet for this past week.  Of course, I could never really break myself away from it, so I have been reading books and websites to research the next phase.  I even put together an HLSL project to do some experimentation.  So, don't worry, progress is still being made, just at a much slower rate now.  I'm guessing I will start working on it again this week.  After I get my new laptop (sometime after the 28th) I'm hoping to really pick up the pace again.  Although, I do have a word of warning: I may get distracted with DirectX 10 and Geometry Shaders.  We shall see. (Not to mention that Too Human comes out on Tuesday, Tales of Vesperia next week, Infinite Undiscovery the week after, and Spore the week after that!  Too many good games coming out so soon.)&lt;br /&gt;&lt;br /&gt;Until next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2836227185993247825?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2836227185993247825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2836227185993247825' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2836227185993247825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2836227185993247825'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/relaxing.html' title='Relaxing'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-1051084279781211661</id><published>2008-08-10T11:34:00.000-07:00</published><updated>2010-04-18T22:38:58.722-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Success!</title><content type='html'>I have completed the items on my to-do list!&lt;br /&gt;&lt;br /&gt;I finally stopped the terrain from disappearing  (for the most part ... I still had two instances where it happened).  I discovered that I had a key subtraction backwards.  How it even worked at all before, I will never know.&lt;br /&gt;&lt;br /&gt;I got each terrain level to move at its own stepping distance by storing and updating a world matrix for each level.  Luckily my CPU was hardly being used at all so I could easily spare the CPU cycles to do these extra calculations.&lt;br /&gt;&lt;br /&gt;I fixed the gap between separate levels by simply making the square mesh slightly larger.  Previously, the mesh would extend from (-1, -1) to (1, 1), but I updated it so that the range is (-1.25, -1.25) to (1.25, 1.25).&lt;br /&gt;&lt;br /&gt;Now for what you've been waiting for:  a new video.  In fact this time I have two new videos for your enjoyment.  One showing off the new terrain, and another showing it in wireframe mode.&lt;br /&gt;&lt;br /&gt;Normal Terrain:&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Y-1wCFku3s0&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Y-1wCFku3s0&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Wireframe:&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/erUGvmMeDcQ&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/erUGvmMeDcQ&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;On a separate note I just ordered a new laptop, so I will finally be able to do development on my laptop again.  My current laptop only has a GeForce 6100, so it couldn't handle my shaders anymore (no unified pipeline).  My new laptop has a GeForce 9800 GT which is about 20 times faster than my current GPU.  It will be awesome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-1051084279781211661?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/1051084279781211661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=1051084279781211661' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1051084279781211661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1051084279781211661'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/success.html' title='Success!'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7684360747230774502</id><published>2008-08-08T08:21:00.000-07:00</published><updated>2010-04-18T22:39:33.047-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Huh?</title><content type='html'>Well I beat Braid last night.  I think it took me about 6 hours total to beat it.  It's a very good game and I highly recommend it.  That is, if you enjoy "action puzzle" type games (think along the lines of Portal).  There are 60 puzzles in the game and I was able to do 59 of them myself.  I couldn't figure out one of them and I tried it for an hour.  I finally looked online and I learned about a dynamic of the game that I wasn't even aware of.&lt;br /&gt;&lt;br /&gt;I had read a posting on the XNA forums about how matrix transformations can cause slight errors over time, so I added code after my transformations to renormalize the vectors and even recalculate the cross products in order to maintain orthogonality.   However, when I fired up the program, the terrain was disappearing even &lt;span style="font-style: italic;"&gt;more&lt;/span&gt;!  The angle between the two vectors is still randomly coming up as NaN and Pi.&lt;br /&gt;&lt;br /&gt;Sigh, well I guess I know what I'm working on this weekend.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7684360747230774502?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7684360747230774502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7684360747230774502' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7684360747230774502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7684360747230774502'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/huh.html' title='Huh?'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-8774806952735278760</id><published>2008-08-07T10:01:00.000-07:00</published><updated>2010-04-18T22:39:50.368-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>To-Do List</title><content type='html'>Here is a list of things that I want to get working before I create the next video:&lt;br /&gt;&lt;br /&gt;- Fix disappearing terrain&lt;br /&gt;- Make each level move at it's own step size (right now they all move at the smallest step size)&lt;br /&gt;- Fix gaps between changing detail levels (you can see the gaps in the last screenshot I posted)&lt;br /&gt;&lt;br /&gt;As for the disappearing terrain, in my previous post you will see that I've narrowed the problem down to the angle calculation.  I've read the documentation on acos() and it says that NaN is returned as a result if the input parameter is &lt; -1 or &gt; +1.  I'm passing in the dot product of what &lt;span style="font-style: italic;"&gt;should &lt;/span&gt;be two normal vectors, thus the input should never exceed 1.  Apparently I'm not sending in true normal vectors, so I'm going to add more normalization calculations, just to make sure they are coming out normal.  That should remove the NaN results, but hopefully it fixes the Pi results as well. (I'm crossing my fingers tightly.)&lt;br /&gt;&lt;br /&gt;I'll give it a try when I get home.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-8774806952735278760?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/8774806952735278760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=8774806952735278760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8774806952735278760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/8774806952735278760'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/to-do-list.html' title='To-Do List'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5378390278460131702</id><published>2008-08-06T23:17:00.000-07:00</published><updated>2010-04-18T22:42:47.143-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>No real progress</title><content type='html'>I have been busy playing Braid, which is a great game that just got released on the Xbox Live Arcade.  Therefore, I haven't really put much time into the procedural planet.&lt;br /&gt;&lt;br /&gt;I did put in some code that would always display the calculated angle between the camera and the terrain mesh in order to see if that was causing the disappearing errors.  I actually believe it is, although I'm not quite sure why.&lt;br /&gt;&lt;br /&gt;First, I was surprised to see that probably a quarter of the time, the result was NaN.  Even more surprising is that my terrain works perfectly even when the result is NaN. &lt;br /&gt;&lt;br /&gt;The errors occur when the result suddenly comes back as pi randomly.  I should never be getting an angle that big back.   Heck I shouldn't ever be getting pi/2.&lt;br /&gt;&lt;br /&gt;I will continue to investigate this problem (when I have time between Braid of course).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5378390278460131702?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5378390278460131702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5378390278460131702' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5378390278460131702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5378390278460131702'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/no-real-progress.html' title='No real progress'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2328802104392599325</id><published>2008-08-04T22:01:00.000-07:00</published><updated>2010-04-18T22:42:54.991-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Nothing is easy</title><content type='html'>I thought that my camera was moving way too slowly after I increased the size to 6.5 million meters, so I increased its default speed.  I also have a couple of keys that act as multipliers in order to get really high speeds.  Unfortunately I realized that my terrain couldn't keep up with me because I was moving too fast.  This is because the terrain would only move a maximum of 1 step each loop.  So, if I traveled 3 steps' distance in one update loop, the terrain would fall 2 steps behind.&lt;br /&gt;&lt;br /&gt;I wrote a solution to this by calculating the number of steps the camera has moved and then rotate the terrain the appropriate number of steps.  This worked great and the terrain always kept up with the camera.  BUT!  Yes, the big dreaded but.  The terrain randomly disappears.  It will be fine for quite a while and then flash on and off like crazy.  Even worse, sometimes it completely disappears and doesn't return, no matter which way I turn or move.&lt;br /&gt;&lt;br /&gt;I have no idea what is causing this problem and I have tried debugging the code for awhile now. So either I find a fix to this bug, or I'll have to  limit the speed to be slow enough that the terrain can keep up.&lt;br /&gt;&lt;br /&gt;I feel bad for not having any media for so long, so here is a screenshot to appease the horde.  I desperately need to get better texturing on the terrain, but that will come after I get the terrain working to my satisfaction.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_hGl_uKJzpS0/SJfe25rwyEI/AAAAAAAADzI/pHLgZOPb1cE/s1600-h/screenshot_633534840388750000.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_hGl_uKJzpS0/SJfe25rwyEI/AAAAAAAADzI/pHLgZOPb1cE/s400/screenshot_633534840388750000.png" alt="" id="BLOGGER_PHOTO_ID_5230894526992795714" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2328802104392599325?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2328802104392599325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2328802104392599325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2328802104392599325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2328802104392599325'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/nothing-is-easy.html' title='Nothing is easy'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_hGl_uKJzpS0/SJfe25rwyEI/AAAAAAAADzI/pHLgZOPb1cE/s72-c/screenshot_633534840388750000.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2062303421283177183</id><published>2008-08-02T23:46:00.000-07:00</published><updated>2010-04-18T22:43:06.785-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Everything revolves around the camera</title><content type='html'>Well I fixed the problems I was having with the camera.  First, let me explain &lt;span style="font-style: italic;"&gt;why&lt;/span&gt; I was having trouble.  I had my planet centered at the origin (0,0,0) and I gave it a radius of about 6.5 million meters.  I initialized the camera position to be right at ground level of the planet (6.5 million meters plus the height of the tallest mountain [I use 100,000 meters]).  My camera always looks at a spot 1 meter in front of its position.  Once you are dealing with positions up in the millions (about 6.6 million), the accuracy is lost and so it doesn't always register that 1 meter difference.&lt;br /&gt;&lt;br /&gt;I found an article online where someone was having similar issues with having the sun at the origin and having the camera out at Earth's distance (about 150 billion meters = 1 AU).  He fixed the problem by always making the camera situated at the origin and just positioning all objects based on the camera position.  I thought I would give that a try.&lt;br /&gt;&lt;br /&gt;I didn't have translation code for my planet yet, so I had to first write that and get it debugged.  Once I had that working, it was pretty simple to switch the coordinates around (I added 2 lines of code and commented 1 out).  Now my camera works perfectly even when dealing with a planet with a radius of 6.5 million.&lt;br /&gt;&lt;br /&gt;I also managed to tweak the Z-fighting occuring with the depth buffer.  So it looks alot better than what it did, but it's still not perfect and there are still triangles fighting with each other on the horizon.  As soon as I have that fixed, I'll post some more screenshots.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2062303421283177183?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2062303421283177183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2062303421283177183' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2062303421283177183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2062303421283177183'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/08/everything-revolves-around-camera.html' title='Everything revolves around the camera'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-3369881524734525409</id><published>2008-07-31T22:28:00.000-07:00</published><updated>2010-04-18T22:43:14.641-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Planets are Too Big!</title><content type='html'>Last night I decided to increase the scale of the planet to Earth's size.  The original size of the radius was 60,000 meters.  Earth's radius is about 6.5 million meters.  So, I had to make my planet over 100 times larger.&lt;br /&gt;&lt;br /&gt;Unfortunately, all sorts of problems arose from attempting to do this.  First, my depth buffer went to crap.  If I wanted to be able to see anything from even a low altitude, I had to extend the far clipping plane back to at least 1 million meters.  This resulted in all sorts of errors with triangles that were fighting over their depths because the range was trying to be stretched over such a long distance. &lt;br /&gt;&lt;br /&gt;The second problem that occurred was that my camera was rotating in "steps".  If I moved the mouse up, instead of smoothly rotating the view upwards, it would snap every Pi/4 or so.  This snapping problem was alleviated by shrinking the size of the planet.  Shrunk in half it was still too bad to use, shrunk by 4x was much better, but the problem was completely gone if I shrunk by 10x.&lt;br /&gt;&lt;br /&gt;I really need to fix all of these problems so that I can have Earth-sized planets.  There are &lt;span style="font-style: italic;"&gt;many&lt;/span&gt; other planets that are even larger than Earth so this is very important.  I have found some articles online where people have found solutions to these problems.  I'm just unsure of how feasible these solutions are for XNA (they are all OpenGL solutions).&lt;br /&gt;&lt;br /&gt;On a side note, I switched my Perlin noise function from fBm to ridged multifractal and it looks &lt;span style="font-style: italic;"&gt;much&lt;/span&gt; better.  I am very impressed with the terrain results.  I would post screenshots, but with the depth issues and such, I figured I would wait.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-3369881524734525409?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/3369881524734525409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=3369881524734525409' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3369881524734525409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/3369881524734525409'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/planets-are-too-big.html' title='Planets are Too Big!'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-7994924643373362311</id><published>2008-07-30T18:04:00.000-07:00</published><updated>2010-04-18T22:43:22.036-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Go Simple, Go Fast</title><content type='html'>I've made the executive decision to just go with the simple spherical lighting.  It's already working and it's 3 times faster than the surface normal generation method.  Besides, it will be simple to calculate the surface normal in a geometry shader later.  Unfortunately XNA doesn't support geometry shaders currently.  However if it ever adds that functionality in the future, I'll be able to add very realistic lighting rather quickly.&lt;br /&gt;&lt;br /&gt;I'm now going to move onto something else.  What that is exactly, I'm still not sure of.  I have a list of TODOs, but I need to determine which one is a higher priority right now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-7994924643373362311?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/7994924643373362311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=7994924643373362311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7994924643373362311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/7994924643373362311'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/go-simple-go-fast.html' title='Go Simple, Go Fast'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-4053497966571698579</id><published>2008-07-29T21:32:00.000-07:00</published><updated>2010-04-18T22:43:29.067-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Do You See the Light?</title><content type='html'>I promised myself that I wouldn't post another update until I had lighting on my planetary terrain.  I have &lt;span style="font-style: italic;"&gt;partially&lt;/span&gt; fulfilled that promise.&lt;br /&gt;&lt;br /&gt;While I did successfully get lighting on the terrain, it is not as realistic as I want it.  I currently have two solutions.  The first is that I'm simply illuminating the planet as a sphere.  While this looks great in places where the light is coming straight down, it looks bad on the edges where there should be long shadows. (Ignore the square-ish terrain.)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_hGl_uKJzpS0/SI_t_yewJHI/AAAAAAAADyI/x1vu2ZR9Xdo/s1600-h/screenshot2.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_hGl_uKJzpS0/SI_t_yewJHI/AAAAAAAADyI/x1vu2ZR9Xdo/s400/screenshot2.png" alt="" id="BLOGGER_PHOTO_ID_5228659372538733682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second solution I have actually tries to calculate the surface normal in the vertex shader.  I estimate where the neighboring vertices are to the right and above the current vertex.  I calculate the two edge vectors and then take the cross product of them to acquire the normal of the surface.  While this all sounds good and makes sense in theory, it isn't yielding the correct results.  I have random shadow and light "splotches"  scattering over the planet, except for one quarter-sphere (is that what a half of a hemisphere is called?) that tu&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_hGl_uKJzpS0/SI_s7rY1lRI/AAAAAAAADyA/3sVOtc7uDQs/s1600-h/screenshot.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_hGl_uKJzpS0/SI_s7rY1lRI/AAAAAAAADyA/3sVOtc7uDQs/s400/screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5228658202403771666" border="0" /&gt;&lt;/a&gt;rns out all black.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On a sidenote that's rather strange, if I use the XNA screenshot component that I wrote, the shadows all come out as white.  If I use Alt-Print Screen and capture the whole window, it comes out as black (which is what is actually displayed).  Check out the white versions:&lt;br /&gt;[Edit: Ha ha! I didn't realize until I posted the screenshots that they aren't coming out as white, they are coming out as transparent, which makes much more sense!)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_hGl_uKJzpS0/SI_uqXKD24I/AAAAAAAADyQ/irZ16aRBWnA/s1600-h/screenshot_633529635357812500.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_hGl_uKJzpS0/SI_uqXKD24I/AAAAAAAADyQ/irZ16aRBWnA/s400/screenshot_633529635357812500.png" alt="" id="BLOGGER_PHOTO_ID_5228660103938562946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_hGl_uKJzpS0/SI_sImC3UlI/AAAAAAAADx4/nZVjjdbX5ig/s1600-h/screenshot_633529629442343750.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_hGl_uKJzpS0/SI_sImC3UlI/AAAAAAAADx4/nZVjjdbX5ig/s400/screenshot_633529629442343750.png" alt="" id="BLOGGER_PHOTO_ID_5228657324796105298" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-4053497966571698579?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/4053497966571698579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=4053497966571698579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4053497966571698579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/4053497966571698579'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/do-you-see-light.html' title='Do You See the Light?'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_hGl_uKJzpS0/SI_t_yewJHI/AAAAAAAADyI/x1vu2ZR9Xdo/s72-c/screenshot2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-6560441764218988471</id><published>2008-07-23T19:25:00.000-07:00</published><updated>2010-04-18T22:42:03.387-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Rotation Solved!</title><content type='html'>Well I implemented my pseudocode in XNA last night, made just some minor changes, and then I had a working rotating mesh.  The guidance I received from Steve Hazen on the official XNA forums really helped me out and pointed me in the right direction.&lt;br /&gt;&lt;br /&gt;I would post the code here, but I don't know how to post it without it looking atrocious.&lt;br /&gt;&lt;br /&gt;I have the code posted in the XNA forums:&lt;br /&gt;&lt;a href="http://forums.xna.com/forums/p/14547/76204.aspx"&gt;http://forums.xna.com/forums/p/14547/76204.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see from the final postings, Steve recommends some tweaks to the code that would increase accuracy and make it more efficient.&lt;br /&gt;&lt;br /&gt;I'm really happy to finally have this problem solved.  It took me four days to finally get a working solution.  Now I can move on to the next item to implement.  It's going to be tough as well, but no where near as tough as the rotation.  At least that's what I'm hoping.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-6560441764218988471?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/6560441764218988471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=6560441764218988471' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6560441764218988471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6560441764218988471'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/rotation-solved.html' title='Rotation Solved!'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5164649658515961894</id><published>2008-07-22T22:32:00.000-07:00</published><updated>2010-04-18T22:41:52.490-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Rotation Solution?</title><content type='html'>I think I may have a solution to the rotation problems I was having.  I have pseudocode scrawled out on some paper I found.  (Along with several drawings of 3D axes with angles, cones, and cameras in various positions.)&lt;br /&gt;&lt;br /&gt;My goal tonight is to implement the pseudocode in XNA and experiment with it.  I'll report my findings tomorrow.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5164649658515961894?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5164649658515961894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5164649658515961894' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5164649658515961894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5164649658515961894'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/rotation-solution.html' title='Rotation Solution?'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-5452226749240938080</id><published>2008-07-21T19:23:00.000-07:00</published><updated>2010-04-18T22:41:08.401-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Rotation Issues</title><content type='html'>I have been working hard on coming up with a new LOD algorithm that eliminates that pesky "water" effect.  I think I have a pretty good idea for a system that would not only remove that problem, but would also make the vertex shader faster.&lt;br /&gt;&lt;br /&gt;Unfortunately I am currently stuck facing some problems with rotations.  I have a mesh that I want to rotate around a sphere so that is always points at the camera.  I could create a billboard matrix and use that, but there is a problem.  That would create the water effect again.  What I need to do is move the mesh in steps.  If the camera moves beyond an angle threshold for either  left/right or up/down, then the mesh should be moved one step in the appropriate direction.&lt;br /&gt;&lt;br /&gt;I decided to use spherical coordinates to calculate the horizontal and vertical angles of the camera.  This works great until you reach the north or south poles.  Once you cross the poles, the mesh is rotated 180 degrees. &lt;br /&gt;&lt;br /&gt;Here is the reason why that happens:&lt;br /&gt;&lt;br /&gt;The "vertical" angle, theta, ranges from 0 to pi.  Where 0 is pointing down the -Y axis and pi is pointing up the +Y axis. The "horizontal" angle, phi, ranges from 0 to 2pi.  Where 0 is pointing along the +X axis, pi/2 is pointing along the +Z axis, pi is pointing along the -X axis, and 3pi/2 is pointing along the -Z axis.&lt;br /&gt;&lt;br /&gt;In the case when the camera passes over the north (+Y) pole, theta is at its peak (pi) but then starts decreasing as you continue to the other side.  Whereas phi essentially gets +pi added to it (or -pi depending up where the pole is crossed).  That is why the object is being rotated 180 degrees (pi radians).&lt;br /&gt;&lt;br /&gt;Whew!&lt;br /&gt;&lt;br /&gt;The problem is that I don't know how to fix this rotation.  I have been tinkering around with it for the last several days to no avail.  I certainly hope I come up with a solution soon.  I really want to continue work on my new LOD algorithm.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-5452226749240938080?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/5452226749240938080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=5452226749240938080' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5452226749240938080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/5452226749240938080'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/rotation-issues.html' title='Rotation Issues'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-1014117624060607590</id><published>2008-07-20T10:07:00.001-07:00</published><updated>2010-04-18T22:40:47.726-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>LOD Algorithm</title><content type='html'>I thought I would explain the algorithm I used for the planetary LOD in more detail.&lt;br /&gt;&lt;br /&gt;When you first start the program, two meshes are generated: a cone and a ring.  Both of these meshes are configurable at creation.  For a cone, you can define how many "slices" it is broken into (imagine a pie and cutting into equal slices).  For a ring, you can define how many slices as well as how many inner rings the ring has.  For example, you can have a ring mesh that is made up of  five inner rings and split into forty-five slices. Both of these meshes are scaled to a unit sphere (its actual just a hemisphere) which is centered at the the origin and "points" out along the -Z axis.&lt;br /&gt;&lt;br /&gt;At the lowest level of detail, the planet is just a cone.  If the level is increased, the cone is shrunk in half and a ring is drawn attached to the bottom of the cone.  If the level is increased again, the cone is shrunk in half again, the existing ring is shrunk in half, and another new ring is attached to the bottom of the existing ring.  This process continues until the highest level of detail is reached.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_hGl_uKJzpS0/SINzTgjIG_I/AAAAAAAADxM/J6jT1WFejEA/s1600-h/screenshot_633520093963593750.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_hGl_uKJzpS0/SINzTgjIG_I/AAAAAAAADxM/J6jT1WFejEA/s400/screenshot_633520093963593750.png" alt="" id="BLOGGER_PHOTO_ID_5225146771671882738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The resizing of the meshes is all done in the vertex shader.  The terrain height is also calculated in the vertex shader via 8 octaves of fBm Perlin noise.  This means that after the mesh generation in the beginning, the CPU does practically nothing.  It just keeps track of what the current level is, and updates the shader parameter as necessary.&lt;br /&gt;&lt;br /&gt;The hemisphere is updated every frame to be centered at the camera by simply calculating a billboard matrix as the world matrix of the hemisphere.&lt;br /&gt;&lt;br /&gt;Well that should give you a decent grasp of how my LOD algorithm functions.  As I mentioned in my previous post, it's not perfect because the centering of the hemisphere every frame really has a nasty looking "water" effect.  I'm already at work on fixes for that, so if I get that working, I'll post what I did.&lt;br /&gt;&lt;br /&gt;I'll leave you with a quick video of my LOD algorithm at work.&lt;br /&gt;&lt;br /&gt;&lt;a style="left: 0px ! important; top: 0px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-07346071016285516 visible ontop" href="http://www.youtube.com/v/-vMqOy2-xsc&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0"&gt;&lt;/a&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/-vMqOy2-xsc&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;embed src="http://www.youtube.com/v/-vMqOy2-xsc&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-1014117624060607590?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/1014117624060607590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=1014117624060607590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1014117624060607590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/1014117624060607590'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/lod-algorithm.html' title='LOD Algorithm'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_hGl_uKJzpS0/SINzTgjIG_I/AAAAAAAADxM/J6jT1WFejEA/s72-c/screenshot_633520093963593750.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-2696726222281407675</id><published>2008-07-19T08:10:00.000-07:00</published><updated>2010-04-18T22:40:34.523-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Planetary LOD</title><content type='html'>I have been spending the last week writing my own implementation of an LOD system for a planet.  It is &lt;span style="font-style: italic;"&gt;inspired&lt;/span&gt; by Spherical Clipmaps, but it is not an actual &lt;span style="font-style: italic;"&gt;implementation &lt;/span&gt;of them.&lt;br /&gt;&lt;br /&gt;As I said, I began writing it last week (exactly a week ago today) and I finally have it all up and running (using real-time 3D Perlin Noise in the Vertex Shader and texture blending, no less!).  Unfortunately, I have it running &lt;span style="font-style: italic;"&gt;too&lt;/span&gt; smoothly, if you can believe that.  I have the vertices being updated and centered under the camera every frame. This leads to the terrain looking similar to flowing water as you fly around the planet.  As long as the camera is stationary, everything looks great.  You can spin the camera around and look at all of the terrain around you.  As soon as you start moving though, the "water" effect is very apparent.&lt;br /&gt;&lt;br /&gt;I first tried to fix it by having the terrain position updated only once a second, but that looked terrible.  So, I ended up saving the old camera position and then calculating the angle between the current camera position and the old position each frame.  If the angle becomes greater than a threshold (I used something like Pi/64, yes that's sixty-four!) then I update the terrain position.  This looks alot better than the time-based updating and it removes the "water" effect.  Unfortunately, it also makes the terrain very "poppy".  For example, if you see a mountain in the distance and you start to fly toward it, you would suddenly see more detail "pop" in as you got closer.&lt;br /&gt;&lt;br /&gt;I think what I have now is pretty decent, but I want to have very smooth terrain, with no popping and no water effect.  So, I'm kind of back to the drawing board trying to think of a system that fixes both of those problems.  Not everything I have now is throw-away code though.  I think I should be able to carry over alot from this project to the updated LOD system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-2696726222281407675?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/2696726222281407675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=2696726222281407675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2696726222281407675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/2696726222281407675'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/planetary-lod.html' title='Planetary LOD'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9153918266310828368.post-6529734965740734143</id><published>2008-07-18T20:59:00.000-07:00</published><updated>2008-07-18T21:02:10.920-07:00</updated><title type='text'>First Blog Entry</title><content type='html'>Greetings!  Here is my first blog post .... um ever!&lt;br /&gt;&lt;br /&gt;I will attempt to use this space to talk about some of the graphics projects that I am working on.  Hopefully I actually stay devoted to it.  I always seem to slack off on things similar to this.&lt;br /&gt;&lt;br /&gt;It's your duty as a reader to reprimand me if I fall behind on updates!&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9153918266310828368-6529734965740734143?l=recreationstudios.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recreationstudios.blogspot.com/feeds/6529734965740734143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9153918266310828368&amp;postID=6529734965740734143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6529734965740734143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9153918266310828368/posts/default/6529734965740734143'/><link rel='alternate' type='text/html' href='http://recreationstudios.blogspot.com/2008/07/first-blog-entry.html' title='First Blog Entry'/><author><name>Patrick</name><uri>http://www.blogger.com/profile/11884568868011584937</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_hGl_uKJzpS0/SsgBqk3_OBI/AAAAAAAAFR4/6Mfsz4dAr-Q/S220/me_small3.jpg'/></author><thr:total>0</thr:total></entry></feed>
