<?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-8216868933119618528</id><updated>2012-01-31T02:03:10.867-08:00</updated><category term='GPU Pathtracing'/><category term='GPU Raytracing'/><category term='GPU Volume Rendering'/><category term='PhysX 2.8.X Tutorials'/><category term='Shader Stuff'/><category term='PhysX3.1 Tutorials'/><category term='PhysX3 Tutorials'/><category term='Dynamics'/><category term='Win32/C++/Programming'/><category term='OpenGL'/><category term='WebGL'/><title type='text'>An eye into my World -Tricks, Thoughts, Ideas, Solutions</title><subtitle type='html'>A collection of tricks, thoughts, ideas and solutions from a graphics programmer. This blog contains my experiences, tips and tricks, everyday problems and their solutions. This blog serves not only as my reference but also for the whole world at large.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>61</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7798448675876349574</id><published>2012-01-21T13:18:00.000-08:00</published><updated>2012-01-31T02:03:10.876-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><category scheme='http://www.blogger.com/atom/ns#' term='WebGL'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>A simple cloth in WebGL using THREE.js</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;This time, I have tried to do simple cloth simulation in HTML5 canvas element using the famous THREE.js javascript rendering engine. The engine is very fast and very good. I will be extending this work to use WebGL and GPUs later but this was to just get my feet wet. &lt;/div&gt;For full view non-textured: http://www3.ntu.edu.sg/home2007/mova0002/test/CanvasCloth/SimpleCloth.html&lt;iframe src ="http://www3.ntu.edu.sg/home2007/mova0002/test/CanvasCloth/SimpleCloth.html" width="100%" height="300"&gt;&lt;p&gt;A simple cloth simiulation in WebGL using THREE.js and javascript.&lt;/p&gt;&lt;/iframe&gt;For full view textured version: http://www3.ntu.edu.sg/home2007/mova0002/test/CanvasCloth/SimpleClothTextured.html&lt;iframe src ="http://www3.ntu.edu.sg/home2007/mova0002/test/CanvasCloth/SimpleClothTextured.html" width="100%" height="300"&gt;&lt;p&gt;A simple texture mapped cloth simiulation in WebGL using THREE.js and javascript.&lt;/p&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7798448675876349574?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7798448675876349574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7798448675876349574' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7798448675876349574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7798448675876349574'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2012/01/simple-cloth-in-html5-canvas-using.html' title='A simple cloth in WebGL using THREE.js'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-9144637068550992309</id><published>2011-12-04T06:09:00.001-08:00</published><updated>2011-12-09T15:59:25.421-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Pathtracing'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Cooks scene in my pathtracer</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I managed to get the Cook's scene from his 1980's paper in my GLSL Pathtracer. Here is the snapshot from the demo.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-HPeepm50gPM/Ttt_PqeMZ7I/AAAAAAAAANI/bge4PKa5Dhg/s1600/cookBilliardScene.png" imageanchor="1"&gt;&lt;img alt="Cook's Billiard Scene" border="0" height="320" src="http://4.bp.blogspot.com/-HPeepm50gPM/Ttt_PqeMZ7I/AAAAAAAAANI/bge4PKa5Dhg/s320/cookBilliardScene.png" width="316" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Note that I have deliberately reduced the bounces because natural billiards ball are not that reflective that they bounce more than two times. Here is the video.&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/20aR31oEPps" width="420"&gt;&lt;/iframe&gt;&lt;br /&gt;Enjoy!!!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-9144637068550992309?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/9144637068550992309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=9144637068550992309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9144637068550992309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9144637068550992309'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/12/cooks-scene-in-my-pathtracer.html' title='Cooks scene in my pathtracer'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-HPeepm50gPM/Ttt_PqeMZ7I/AAAAAAAAANI/bge4PKa5Dhg/s72-c/cookBilliardScene.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7401016208223920090</id><published>2011-11-23T18:52:00.001-08:00</published><updated>2011-12-09T16:00:02.273-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Pathtracing'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Snapshot from my latest GLSL Path tracer</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Here is a snapshot from my latest GLSL Path tracer which was inspired by the excellently done path tracer in WebGL by Evan Wallace(http://madebyevan.com/webgl-path-tracing/). I have modified his code considerably to make it run even faster on PC. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-bx5MzloTRjk/Ts2zZJQLK_I/AAAAAAAAAM8/NpWuU_lJG78/s1600/pathtrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="GLSL Pathtracer" border="0" height="320" src="http://3.bp.blogspot.com/-bx5MzloTRjk/Ts2zZJQLK_I/AAAAAAAAAM8/NpWuU_lJG78/s320/pathtrace.png" width="299" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It runs at ~70fps with 128 samples per pixel for an output res. of 1024x1024. Check this video captured live from a session.&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/PMj4kEaZhRY" width="420"&gt;&lt;/iframe&gt;&lt;br /&gt;Another video showing a live editing session.&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/1FuZhTeI-9o" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;br /&gt;Another video showing the famous Cornell Box scene.&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/bdteeIknjPk" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;br&gt;This demo renders the famous Cornell Box scene in realtime. You can edit all the parameters live and it renders at ~240 fps on my NVIDIA Quadro FX 5800 on an output resolution of 1024x1024. I have not added importance sampling or any other optimization. Adding those will certainly make it even faster.&lt;br&gt;Yet another video of Cornell Box&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/aPDXRrBRwRc" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;br&gt;This time it is even better with more photons. Takes a bit longer to converge but the output is worth it.Enjoy!!!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7401016208223920090?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7401016208223920090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7401016208223920090' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7401016208223920090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7401016208223920090'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/11/snapshot-from-my-latest-glsl-path.html' title='Snapshot from my latest GLSL Path tracer'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-bx5MzloTRjk/Ts2zZJQLK_I/AAAAAAAAAM8/NpWuU_lJG78/s72-c/pathtrace.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8167870761739470970</id><published>2011-11-20T22:04:00.001-08:00</published><updated>2011-12-09T16:00:40.920-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Some recent snapshot and demo video on GPU raycasting</title><content type='html'>Here is a snapshot and video from my GPU raycasting demo.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-n3_YVlfsdcE/TsnqC2RWBHI/AAAAAAAAAMw/nrYBFlow2MA/s1600/manix.png" imageanchor="1" style=""&gt;&lt;img alt="GPU Raycasting with Manix dataset" border="0" height="286" width="320" src="http://1.bp.blogspot.com/-n3_YVlfsdcE/TsnqC2RWBHI/AAAAAAAAAMw/nrYBFlow2MA/s320/manix.png" /&gt;&lt;/a&gt;&lt;/div&gt;Here is the like to the video.&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/LsOQ-BVQrA8" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8167870761739470970?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8167870761739470970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8167870761739470970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8167870761739470970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8167870761739470970'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/11/some-recent-snapshot-and-demo-video-on.html' title='Some recent snapshot and demo video on GPU raycasting'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-n3_YVlfsdcE/TsnqC2RWBHI/AAAAAAAAAMw/nrYBFlow2MA/s72-c/manix.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8379919234984923620</id><published>2011-11-18T02:15:00.001-08:00</published><updated>2011-12-09T16:01:09.570-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Twirl filter in GLSL</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I had worked on image processing project back in my high school days and so the last memories returned recently when I wanted to implement the twirl filter in GLSL. Mathematically, it is easily given as the following function in polar coordinates,&lt;br /&gt;F(r,theta)=f(r,theta+amt)&lt;br /&gt;In normal world though, we are working in Cartesian coordiates so we need to add that conversion in. Other than that, it is the same function. Here is the output from my shader.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-3rZ-T1eljGc/TsYvgPeVepI/AAAAAAAAAMc/Wydhri4IOlM/s1600/twirl.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img alt="Twirl Filter in GLSL" border="0" height="182" src="http://1.bp.blogspot.com/-3rZ-T1eljGc/TsYvgPeVepI/AAAAAAAAAMc/Wydhri4IOlM/s400/twirl.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;The Lena image filtered with the twirl filter in GLSL.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;And here is the GLSL fragment shader for doing this.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;uniform sampler2D textureMap;//image&lt;/span&gt;&lt;br /&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;uniform float amount; //amount of twirl&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;void main() {&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; vec2 uv = gl_TexCoord[0].st-0.5;&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; float angle = atan2(uv.y,uv.x); &lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; float radius = length(uv);&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; angle+= radius*amount;&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; vec2 shifted = radius*vec2(cos(angle), sin(angle));&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; gl_FragColor = texture(textureMap, (shifted+0.5)); &lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: inherit;"&gt;I hope it is useful for others too. &lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;span style="font-family: inherit;"&gt;Enjoy!!!&lt;/span&gt;&lt;/div&gt;&lt;div style="-qt-block-indent: 0; -qt-user-state: 0; margin: 0px; text-indent: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8379919234984923620?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8379919234984923620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8379919234984923620' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8379919234984923620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8379919234984923620'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/11/twirl-filter-in-glsl.html' title='Twirl filter in GLSL'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-3rZ-T1eljGc/TsYvgPeVepI/AAAAAAAAAMc/Wydhri4IOlM/s72-c/twirl.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5561569211454626921</id><published>2011-10-17T10:00:00.000-07:00</published><updated>2011-12-09T16:01:37.986-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3.1 Tutorials'/><title type='text'>Cloth in PhysX 3.1</title><content type='html'>Before I start of this tutorial, here is my disclaimer&lt;blockquote&gt;I wrote this tutorial based on some hints from the PhysX3.1 guide since it hardly tells the reader how to do the basic cloth. Therefore, this might not be the perfect way of doing cloth with PhysX3.1. Since the documentation is severely lacking such down to core tutorials, I wrote this tutorial to bridge the gap for beginners. If you find anything wrong, please let me know.&lt;/blockquote&gt;This is the first tutorial on doing cloth in PhysX3.1. The major changes in PhysX 3.1 has been the cloth API and hopefully, I will try to detail how to do a simple cloth using the new cloth API.  Ok so now lets get started. This tutorial is building up on the picking tutorial I did earlier so head to it if you have not understood it completely. As usual, here are the headers and libs that we would need for this tutorial.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &lt; iostream &gt;&lt;br /&gt;#include &lt; GL/freeglut.h &gt;&lt;br /&gt;#include &lt; PxPhysicsAPI.h &gt; &lt;br /&gt;#include &lt; PxExtensionsAPI.h &gt;   &lt;br /&gt;#include "Stream.h"&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;using namespace physx;&lt;br /&gt;&lt;br /&gt;#pragma comment(lib, "PhysX3_x86.lib")&lt;br /&gt;#pragma comment(lib, "PhysX3Cooking_x86.lib")&lt;br /&gt;#pragma comment(lib, "PxTask.lib")&lt;br /&gt;#pragma comment(lib, "Foundation.lib")&lt;br /&gt;#pragma comment(lib, "PhysX3Extensions.lib")&lt;br /&gt;#pragma comment(lib, "GeomUtils.lib") &lt;br /&gt;&lt;/pre&gt;Next, we generate the cloth variables and vectors to store the cloth positions and normals. In the previous PhysX version, we could hook the receivebuffers but now this has changed and we need to manually copy the data from the cloth and also calculate the normals. In this demo, we will do a simple collision of the cloth with a simple box. In PhysX3.1, there is no direct support for rigid body collision with a cloth. Instead, the new API provides methods for intersection between the cloth and the capsule/spheres.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;vector&lt; PxVec3 &gt; pos;&lt;br /&gt;vector&lt; PxVec3 &gt; normal;&lt;br /&gt;vector&lt; PxU32 &gt; indices;&lt;br /&gt;PxCloth* cloth; &lt;br /&gt;PxClothCollisionSphere box_collider;&lt;br /&gt;&lt;/pre&gt;The initialization of PhysX and other stuff is similar to the Picking tutorial. After initializing PhysX and the scene, the scene visualization parameters are set.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;gScene-&gt;setVisualizationParameter(PxVisualizationParameter::eSCALE, 1.0);&lt;br /&gt;gScene-&gt;setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);&lt;br /&gt;&lt;/pre&gt; &lt;b&gt;Creating the Cloth object:&lt;/b&gt;&lt;br&gt;The steps required to create a cloth are as follows,1) Fill in the PxClothMeshDesc and specify the cloth geometry and topology.2) Cook the cloth fabric by using the mesh desc generated in step 1.3) Use the cooked buffer to generate the PxClothFabric.4) Initialize and fill the PxClothParticle buffer with the cloth point positions and masses.5) Call createCloth on physicsSDK pointer.6) Adjust the cloth properties using the PxClothPhaseSolverConfig (to specify the individual stiffness and stretch limits of the PxClothFabric fibres) and assign the damping using PxCloth::setDampingCoefficient function.7) Add the cloth actor to the scene.Now we will show the relevant code of each step.Step1:&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//Create cloth&lt;br /&gt;PxClothMeshDesc meshDesc;&lt;br /&gt;meshDesc.setToDefault();&lt;br /&gt; &lt;br /&gt;//Fill the geometry&lt;br /&gt;int w = 8, h=7;&lt;br /&gt;float hw = w / 2.0f;&lt;br /&gt;float hh = h / 2.0f;&lt;br /&gt;d = 0.2f;&lt;br /&gt;int numX = (int)(w / d) + 1;    &lt;br /&gt;int numY = (int)(h / d) + 1;    &lt;br /&gt;meshDesc.points.count= (numX+1) * (numY+1);        &lt;br /&gt;meshDesc.triangles.count= numX*numY*2;    &lt;br /&gt;meshDesc.points.stride= sizeof(PxVec3);  &lt;br /&gt;meshDesc.triangles.stride= 3*sizeof(PxU32);  &lt;br /&gt;meshDesc.points.data= (PxVec3*)malloc(sizeof(PxVec3)*meshDesc.points.count);    &lt;br /&gt;meshDesc.triangles.data= (PxU32*)malloc(sizeof(PxU32)*meshDesc.triangles.count*3);    &lt;br /&gt;meshDesc.edgeFlags = 0;&lt;br /&gt;&lt;br /&gt;//Fill the geometry&lt;br /&gt;int i,j;    &lt;br /&gt;PxVec3 *p = (PxVec3*)meshDesc.points.data;   &lt;br /&gt; &lt;br /&gt;pos.resize(meshDesc.points.count);&lt;br /&gt;normal.resize(meshDesc.points.count);&lt;br /&gt;indices.resize(meshDesc.triangles.count*3);&lt;br /&gt;&lt;br /&gt;for (i = 0; i &lt;= numY; i++) {        &lt;br /&gt;   for (j = 0; j &lt;= numX; j++) {            &lt;br /&gt;   p -&gt; x = d*j-hw;&lt;br /&gt;   p -&gt; y = float(h);&lt;br /&gt;   p -&gt; z = d*i;             &lt;br /&gt;   p++;   &lt;br /&gt;   }    &lt;br /&gt;}   &lt;br /&gt;&lt;br /&gt;memcpy(&amp;pos[0].x, (meshDesc.points.data), sizeof(PxVec3)*meshDesc.points.count);&lt;br /&gt;&lt;br /&gt;//Fill the topology&lt;br /&gt;PxU32 *id = (PxU32*)meshDesc.triangles.data;  &lt;br /&gt;for (i = 0; i &lt; numY; i++) {        &lt;br /&gt;   for (j = 0; j &lt; numX; j++) {            &lt;br /&gt;   PxU32 i0 = i * (numX+1) + j;            &lt;br /&gt;   PxU32 i1 = i0 + 1;            &lt;br /&gt;   PxU32 i2 = i0 + (numX+1);            &lt;br /&gt;   PxU32 i3 = i2 + 1;            &lt;br /&gt;   if ((j+i)%2) {                &lt;br /&gt;  *id++ = i0; *id++ = i2; *id++ = i1;                &lt;br /&gt;  *id++ = i1; *id++ = i2; *id++ = i3;            &lt;br /&gt;   } else {                &lt;br /&gt;  *id++ = i0; *id++ = i2; *id++ = i3;                &lt;br /&gt;  *id++ = i0; *id++ = i3; *id++ = i1;            &lt;br /&gt;   }      &lt;br /&gt;   }    &lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;memcpy(&amp;indices[0], meshDesc.triangles.data, sizeof(PxU32)*meshDesc.triangles.count*3);&lt;br /&gt;&lt;br /&gt;//Make sure everything is fine so far&lt;br /&gt;if(!(meshDesc.isValid()))&lt;br /&gt;   cerr &lt;&lt; "Mesh invalid."&lt;&lt; endl;&lt;br /&gt;&lt;/pre&gt;In the above lines, we generate the cloth mesh descriptor and fill its relevant fields and then give the geometry and topology of our cloth mesh. Within these lines we also store the positions and indices for rendering the cloth later. To make sure that everything that is required has been given,we call the isValid function.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//Start cooking of fibres&lt;br /&gt;PxCookingParams cp; &lt;br /&gt;PxCooking* cooking = PxCreateCooking(PX_PHYSICS_VERSION, &amp;(gPhysicsSDK-&gt;getFoundation()), cp);&lt;br /&gt;MemoryWriteBuffer buf;&lt;br /&gt;bool status = cooking-&gt;cookClothFabric(meshDesc,sceneDesc.gravity, buf);&lt;br /&gt;if(!status) {&lt;br /&gt;   cerr &lt;&lt; "Problem cooking mesh.\nExiting ..."&lt;&lt; endl;&lt;br /&gt;   exit(1);&lt;br /&gt;}&lt;br /&gt;     &lt;br /&gt;PxClothFabric* fabric=gPhysicsSDK-&gt;createClothFabric(MemoryReadBuffer(buf.data));&lt;br /&gt;&lt;/pre&gt;In the above lines, we cook the meshDesc and then create the Cloth Fabric using the cooked buffer data.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;PxTransform tr;&lt;br /&gt;tr.p = PxVec3(0,10,0); tr.q = PxQuat::createIdentity();&lt;br /&gt;&lt;br /&gt;PxClothParticle* points=(PxClothParticle*)malloc(sizeof(PxClothParticle)*meshDesc.points.count);&lt;br /&gt;p = (PxVec3*)meshDesc.points.data;  &lt;br /&gt;for(size_t i=0;i &lt; meshDesc.points.count;i++) {&lt;br /&gt;    points[i].pos = *p;&lt;br /&gt; //Fixing the top corner points&lt;br /&gt; if(i==0 || i==numX) &lt;br /&gt;     points[i].invWeight =0;&lt;br /&gt;else &lt;br /&gt;     points[i].invWeight = 1.f;&lt;br /&gt;     p++;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;In the above lines, we allocate the ClothParticles buffer filling it with positions and mass weights. To fix the top corner masses, their inverse weights are set as 0. &lt;pre class="brush:cpp"&gt;&lt;br /&gt;PxClothCollisionData cd;&lt;br /&gt;cd.setToDefault();&lt;br /&gt; &lt;br /&gt;cd.numSpheres=1;&lt;br /&gt;cd.pairIndexBuffer=0;&lt;br /&gt; &lt;br /&gt;box_collider.pos= PxVec3(0.0f,2.0f,0.0f);&lt;br /&gt;box_collider.radius=1;&lt;br /&gt;cd.spheres=&amp;box_collider;&lt;br /&gt;&lt;br /&gt;cloth = gPhysicsSDK-&gt;createCloth(tr,*fabric,points, cd, PxClothFlag::eSWEPT_CONTACT);&lt;br /&gt;&lt;/pre&gt;In the above lines, we generate the PxClothCollisionData which is used to performa collision with our box rigid body. In the new PhysX3.1 API, the cloth can only collide with capsules or spheres. We fill in the PxClothCollisionData giving it the sphere primitive's buffer. The cloth global pose, the cloth fabric, the cloth's particles and the collision data are then passed to the gPhysicsSDK::createCloth function that returns the cloth actor.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;if(cloth) { &lt;br /&gt;    PxClothPhaseSolverConfig bendCfg;  &lt;br /&gt;    bendCfg.solverType= PxClothPhaseSolverConfig::eFAST;&lt;br /&gt;    bendCfg.stiffness = 1;&lt;br /&gt;    bendCfg.stretchStiffness = 0.5; &lt;br /&gt;&lt;br /&gt;    cloth-&gt;setPhaseSolverConfig(PxClothFabricPhaseType::eBENDING,  bendCfg) ; &lt;br /&gt;    cloth-&gt;setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING, bendCfg) ; &lt;br /&gt;    cloth-&gt;setPhaseSolverConfig(PxClothFabricPhaseType::eSHEARING, bendCfg) ; &lt;br /&gt;    cloth-&gt;setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING_HORIZONTAL, bendCfg) ;&lt;br /&gt;  &lt;br /&gt;    cloth-&gt;setDampingCoefficient(0.125f);    &lt;br /&gt;    gScene-&gt;addActor(*cloth); &lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;    cerr &lt;&lt; "Cannot create cloth" &lt;&lt; endl;&lt;br /&gt;&lt;/pre&gt; If we have a valid cloth object, we assign the bending, shearing and stretching stiffness for the three kinds of cloth fibers.Then we assign the cloths damping value and finally add the cloth to the scene.&lt;br&gt;&lt;b&gt;Extracting the PhysX cloth particle positions for rendering:&lt;/b&gt;&lt;br&gt; Now that we know how the cloth may be generated, we can look into how to extract the modified positions from the PhysX cloth API. Like in the previous tutorials, the render function calls the  StepPhysX(); function. For cloth, we can apply some more steps after this function call. First we set the rigid bodies collision sphere as the current clothCollisionSphere. The box_collider object is updated with the box's transform in the box's rendering function. This is done in the following code.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;if (gScene) &lt;br /&gt;{ &lt;br /&gt;    StepPhysX(); &lt;br /&gt;&lt;br /&gt;    //update collider position based on the new position of box;  &lt;br /&gt;    cloth-&gt;setCollisionSpheres(&amp;box_collider); &lt;br /&gt;&lt;/pre&gt;Next, we extract the current cloth particle positions using a call to PxCloth::lockClothReadData function.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//update the cloth data&lt;br /&gt;   PxClothReadData* pData = cloth-&gt;lockClothReadData();&lt;br /&gt;   PxClothParticle* pParticles = const_cast&lt;PxClothParticle*&gt;(pData-&gt;particles);&lt;br /&gt;  &lt;br /&gt;   //update the positions&lt;br /&gt;   for(size_t i=0;i &lt; pos.size();i++) {&lt;br /&gt;      pos[i] = pParticles[i].pos;&lt;br /&gt;      if(pos[i].y &lt; 0) {&lt;br /&gt;   pos[i].y=0;&lt;br /&gt;   pParticles[i].pos.y=0;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;pData-&gt;unlock();&lt;br /&gt;&lt;/pre&gt;The above lines lock the particle positions and then apply the floor collision constraint. Next we generate the cloth normals.&lt;pre class ="brush:cpp"&gt;&lt;br /&gt;   //update normals&lt;br /&gt;   for(size_t i=0;i &lt; indices.size();i+=3) {&lt;br /&gt;  PxVec3 p1 = pos[indices[i]];&lt;br /&gt; PxVec3 p2 = pos[indices[i+1]];&lt;br /&gt; PxVec3 p3 = pos[indices[i+2]];&lt;br /&gt; PxVec3 n  = (p2-p1).cross(p3-p1);&lt;br /&gt;&lt;br /&gt; normal[indices[i]]    += n/3.0f ; &lt;br /&gt; normal[indices[i+1]]  += n/3.0f ; &lt;br /&gt; normal[indices[i+2]]  += n/3.0f ;    &lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   for(size_t i=0;i &lt; normal.size();i++) { &lt;br /&gt; PxVec3&amp; n  = normal[i];&lt;br /&gt; n= n.getNormalized();&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br&gt;&lt;b&gt;Cloth rendering: &lt;/b&gt;&lt;br&gt;For rendering, we simply pass the positions and normals to the vertex arrays and then use the indices to render the cloth as shown in the following lines of code.&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void RenderCloth() {&lt;br /&gt; glEnableClientState(GL_VERTEX_ARRAY);&lt;br /&gt; glEnableClientState(GL_NORMAL_ARRAY);&lt;br /&gt;&lt;br /&gt; glVertexPointer(3, GL_FLOAT, sizeof(PxVec3), &amp;(pos[0].x));&lt;br /&gt; glNormalPointer(GL_FLOAT, sizeof(PxVec3), &amp;(normal[0].x));&lt;br /&gt;&lt;br /&gt; glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, &amp;indices[0]);&lt;br /&gt;&lt;br /&gt; glDisableClientState(GL_NORMAL_ARRAY);&lt;br /&gt; glDisableClientState(GL_VERTEX_ARRAY);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br&gt;That's it. You can now render the cloth in PhysX3.1 using the new cloth API. The performance of the new API is significantly better as compared to the previous PhysX sdks. Running the code gives the following output.&lt;br&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fw-jI3oqi5M/Tpxdm-g-eII/AAAAAAAAAL8/ZVwTMAgPgUg/s1600/Physx3_1_Cloth.png" imageanchor="1" style=""&gt;&lt;img alt="Cloth in PhysX 3.1" border="0" height="250" width="320" src="http://4.bp.blogspot.com/-fw-jI3oqi5M/Tpxdm-g-eII/AAAAAAAAAL8/ZVwTMAgPgUg/s320/Physx3_1_Cloth.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/SimpleCloth(PhysX3.1).zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5561569211454626921?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5561569211454626921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5561569211454626921' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5561569211454626921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5561569211454626921'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/10/cloth-in-physx-31.html' title='Cloth in PhysX 3.1'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-fw-jI3oqi5M/Tpxdm-g-eII/AAAAAAAAAL8/ZVwTMAgPgUg/s72-c/Physx3_1_Cloth.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7871454626635715513</id><published>2011-10-14T08:39:00.000-07:00</published><updated>2011-12-09T16:01:50.556-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3.1 Tutorials'/><title type='text'>Converting the existing PhysX3.0 Tutorials to PhysX3.1</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Recently, NVIDIA has released the new PhysX 3.1 sdk which has revamped the API a little bit. The support for cloth has been improved plus a lot of improvements. &lt;br /&gt;&lt;br /&gt;In the new PhsyX 3.1 sdk, the classes have now been added into a namespace called physx so to get any object, you need to either add physx:: to it or you can add the following directive at the top of the code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;using namespace physx;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once you add the namespace directive, my exisiting PhysX 3.0 tutorials would work in the new sdk. Thats it, the codes should run fine. In a later tutorial, I will be detail how to do cloth and soft bodies in PhysX 3.1 sdk.&lt;br /&gt;&lt;br /&gt;You can download all of my PhysX3 tutorials ported to PhysX 3.1 in a single zip file &lt;a href=http://www3.ntu.edu.sg/home2007/mova0002/PhysX/Physx3.1.zip&gt;here&lt;/a&gt;&lt;br&gt;Please make sure to copy the PhysX3_x86.dll into the folder containing the .vcproj file of the solution you are working on.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7871454626635715513?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7871454626635715513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7871454626635715513' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7871454626635715513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7871454626635715513'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/10/converting-existing-physx30-tutorials.html' title='Converting the existing PhysX3.0 Tutorials to PhysX3.1'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1277547294643180394</id><published>2011-09-19T03:58:00.000-07:00</published><updated>2011-12-09T16:02:01.516-08:00</updated><title type='text'>Resolving WebGL cross domain image loading error SECURITY_ERR: DOM Exception 18</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;If u have tried webGL and specially loading textures recently due to the tighter security features you get&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;Uncaught Error: SECURITY_ERR: DOM Exception 18&lt;/span&gt;&lt;/b&gt; in Google Chrome and &lt;br /&gt;&lt;b&gt;&lt;span style="color: red; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;Error: uncaught exception: [Exception... "Security error"  code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"  location: &lt;/span&gt;&lt;a href="file:///some%20directory%20Line:%2046"&gt;&lt;span style="color: red; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;file:///some directory Line: 46&lt;/span&gt;&lt;/a&gt;&lt;span style="color: red; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;]&lt;/span&gt;&lt;/b&gt; in Mozilla Firefox&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution:&lt;/strong&gt;The solution is quite simple. Just go to command prompt and change directory to where your html page is for example for running WebGL/Simple/Test.html u do this on cmd prompt&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;c:\&amp;gt; cd D:/WebGL/Simple/&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Then simply type this&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;D:/WebGL/Simple&amp;gt;python -m SimpleHTTPServer&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This opens up a local http server, let this cmd prompt run. Now go to the web browser firefox/chrome and type this in the address bar to load the webpage&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;"&gt;http://localhost:8000/Test.htm&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This should run the WebGL code fine. Once u r done, you can press Ctrl+C to terminate the http server.I hope it helps others from the pain which I had to bear.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-1277547294643180394?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1277547294643180394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1277547294643180394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1277547294643180394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1277547294643180394'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/09/resolving-webgl-cross-domain-image.html' title='Resolving WebGL cross domain image loading error SECURITY_ERR: DOM Exception 18'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4076272046188335942</id><published>2011-07-20T21:34:00.000-07:00</published><updated>2011-07-30T20:57:43.308-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>OpenCloth: A new open source cloth simulation library</title><content type='html'>I have just released a new open source cloth simulaiton library called OpenCloth. It is intended for beginners so that they can understand the basics required to implement a basic cloth simulation. &lt;br /&gt;&lt;br /&gt;Details are here: http://code.google.com/p/opencloth/&lt;br /&gt;&lt;br /&gt;Comments and critics welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4076272046188335942?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4076272046188335942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4076272046188335942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4076272046188335942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4076272046188335942'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/07/opencloth-new-open-source-cloth.html' title='OpenCloth: A new open source cloth simulation library'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8306591915218984259</id><published>2011-05-30T10:04:00.000-07:00</published><updated>2011-12-09T16:02:35.613-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: Simple distance joint</title><content type='html'>In this tutorial, we will see how to create a simple distance joint. We will reuse the picking code in this tutorial to make things a bit more interesting. So without any further ado, lets get started. We will create two boxes one of which will be a static object. The other box will be manipulated by the mouse hence it will be dynamic.&lt;br /&gt;&lt;strong&gt;Creating the boxes&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;The dynamic box&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//2) Create dynamic cube  &lt;br /&gt;PxReal density = 1.0f;&lt;br /&gt;PxTransform transform(PxVec3(0.0f, 3.0, 0.0f), PxQuat::createIdentity());&lt;br /&gt;PxVec3 dimensions(0.5,0.5,0.5);&lt;br /&gt;PxBoxGeometry geometry(dimensions);    &lt;br /&gt;PxRigidDynamic *dyn_box = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);&lt;br /&gt;if (!dyn_box)&lt;br /&gt;   cerr&amp;lt;&amp;lt;"create actor failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;dyn_box-&amp;gt;setAngularDamping(0.75);&lt;br /&gt;dyn_box-&amp;gt;setLinearVelocity(PxVec3(0,0,0)); &lt;br /&gt;gScene-&amp;gt;addActor(*dyn_box);&lt;br /&gt;boxes.push_back(dyn_box);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines are what we have seen in all the tutorials. &lt;br /&gt;&lt;em&gt;The static box&lt;/em&gt;&lt;br /&gt;For static box, we simply create a PxRigidStatic object reusing the same geometry.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//create static cube&lt;br /&gt;transform.p=PxVec3(0,5,0);&lt;br /&gt;PxRigidStatic *static_box = PxCreateStatic(*gPhysicsSDK, transform, geometry, *mMaterial);&lt;br /&gt;if (!static_box)&lt;br /&gt;   cerr&amp;lt;&amp;lt;"create actor failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;gScene-&amp;gt;addActor(*static_box);&lt;br /&gt;boxes.push_back(static_box);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Creating joint&lt;/strong&gt;&lt;br /&gt;For creating a very basic distance joint, we need to use the PxDistanceJointCreate function. This function takes the PhysX sdk object, the first rigidbody, the local transform of it, the second rigid body and its local transform. Next, the parameters are set for the distance joint as we did for the previous PhysX version.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//create a joint  &lt;br /&gt;PxDistanceJoint* j = PxDistanceJointCreate(*gPhysicsSDK, dyn_box, PxTransform::createIdentity(), static_box, PxTransform::createIdentity());&lt;br /&gt;j-&amp;gt;setDamping(1);&lt;br /&gt;j-&amp;gt;setSpring(200);&lt;br /&gt;j-&amp;gt;setMinDistance(1);&lt;br /&gt;j-&amp;gt;setMaxDistance(2);&lt;br /&gt;j-&amp;gt;setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, true);&lt;br /&gt;j-&amp;gt;setDistanceJointFlag(PxDistanceJointFlag::eMIN_DISTANCE_ENABLED, true);&lt;br /&gt;j-&amp;gt;setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);&lt;br /&gt;j-&amp;gt;setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED, true);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;&lt;strong&gt;Rendering of the distance joint&lt;/strong&gt;&lt;br /&gt;For rendering of the distance joint, we do a fairly simple thing by creating a global array for 2 PxVec3 types. When we are about to draw the box actors, we store their current positions in the global array so the new DrawCube function is this,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//Stored globally&lt;br /&gt;PxVec3 pos[2]; //for storing the two end points of spring&lt;br /&gt;void DrawBox(PxShape* pShape) {&lt;br /&gt;static int count=0;&lt;br /&gt; &lt;br /&gt;PxTransform pT = PxShapeExt::getGlobalPose(*pShape);&lt;br /&gt;pos[(count++)%2] = pT.p;&lt;br /&gt;PxBoxGeometry bg;&lt;br /&gt;pShape-&amp;gt;getBoxGeometry(bg);&lt;br /&gt;PxMat33 m = PxMat33Legacy(pT.q );&lt;br /&gt;float mat[16];&lt;br /&gt;getColumnMajor(m,pT.p, mat);&lt;br /&gt;glPushMatrix(); &lt;br /&gt;glMultMatrixf(mat);&lt;br /&gt;glutSolidCube(bg.halfExtents.x*2);&lt;br /&gt;glPopMatrix(); &lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Next, in the render function, we draw the line between the two positions just stored.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;glColor3f(gMouseJoint!=NULL,gMouseJoint==NULL,gMouseJoint==NULL);&lt;br /&gt;//Draw the spring &lt;br /&gt;glBegin(GL_LINES);&lt;br /&gt;   glVertex3f(pos[0].x, pos[0].y, pos[0].z);&lt;br /&gt;   glVertex3f(pos[1].x, pos[1].y, pos[1].z);&lt;br /&gt;glEnd();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it we have a simple distance joint between two boxes. Here is the snapshot from this application.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s1600/joint.png"&gt;&lt;img alt="Distance Joint in PhysX 3.1" style="cursor:pointer; cursor:hand;width: 320px; height: 247px;" src="http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s320/joint.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5601280573797652034" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/SimpleJoint(PhysX3).zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8306591915218984259?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8306591915218984259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8306591915218984259' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8306591915218984259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8306591915218984259'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/physx3-simple-distance-joint.html' title='PhysX3: Simple distance joint'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s72-c/joint.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4762795102594771933</id><published>2011-05-29T12:21:00.000-07:00</published><updated>2011-12-09T16:02:59.365-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: Picking</title><content type='html'>In this tutorial, we will use the scene of multiple boxes from a previous tutorial. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Picking in PhysX3&lt;/strong&gt;&lt;br /&gt;We have our matrices setup as in the picking tutorial for the previous PhysX version.  We now come on the Pick function. This function takes an x, y screen coordinate, cast a ray from into the scene and returns true if there is an intersection. It also stores a sphere object at the hit point, stores reference to the intersected actor and also store a spring between the hitpoint sphere and the actor. We store the used joint and mouse sphere object pointers globally.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;PxDistanceJoint *gMouseJoint = NULL;&lt;br /&gt;PxRigidDynamic* gMouseSphere = NULL;&lt;br /&gt;PxReal gMouseDepth = 0.0f;&lt;br /&gt;PxRigidDynamic* gSelectedActor=NULL;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The pick actor function is defined as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;bool PickActor(int x, int y)&lt;br /&gt;{&lt;br /&gt; LetGoActor();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We first release all previous helpers (the spring and the last intersection sphere.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;Ray ray;&lt;br /&gt;ViewUnProject(x,y,0.0f, ray.orig);&lt;br /&gt;ViewUnProject(x,y,1.0f, ray.dir);&lt;br /&gt;ray.dir -= ray.orig; ray.dir.normalize();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines create a ray as given in the previous paragraph. In PhysX3 there is no Ray object so we define our own struct for Ray.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;PxRaycastHit hit;&lt;br /&gt;PxShape* closestShape;&lt;br /&gt;gScene-&amp;gt;raycastSingle(ray.orig, ray.dir, length, PxSceneQueryFlag::eIMPACT  ,hit);&lt;br /&gt;closestShape = hit.shape;&lt;br /&gt;if (!closestShape) return false;&lt;br /&gt;if (!closestShape-&amp;gt;getActor().is(PxActorType::eRIGID_DYNAMIC)) return false;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines is where the ray is cast to find the closest actor. If there is none, we return false.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;int hitx, hity;&lt;br /&gt;ViewProject(hit.impact, hitx, hity, gMouseDepth);&lt;br /&gt;gMouseSphere = CreateSphere(hit.impact, 0.1f, 1.0f);&lt;br /&gt;gMouseSphere-&amp;gt;setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines project the hit point back to get the world space position. This is done so that the picking cursor (sphere) could be drawn at the intersection point.&lt;br /&gt;The sphere's body flag is raised to kinematic since it will be attached to an actor through a distance joint (see next few lines). &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;gSelectedActor = (PxRigidDynamic*) &amp;amp;closestShape-&amp;gt;getActor();&lt;br /&gt;gSelectedActor-&amp;gt;wakeUp();&lt;br /&gt;PxTransform mFrame, sFrame;&lt;br /&gt;mFrame.q = gMouseSphere-&amp;gt;getGlobalPose().q;&lt;br /&gt;mFrame.p = gMouseSphere-&amp;gt;getGlobalPose().transformInv(hit.impact );&lt;br /&gt;sFrame.q = gSelectedActor-&amp;gt;getGlobalPose().q;&lt;br /&gt;sFrame.p = gSelectedActor-&amp;gt;getGlobalPose().transformInv(hit.impact );&lt;br /&gt;gMouseJoint = PxDistanceJointCreate(*gPhysicsSDK, gMouseSphere, mFrame, gSelectedActor, sFrame);&lt;br /&gt;gMouseJoint-&amp;gt;setDamping(1);&lt;br /&gt;gMouseJoint-&amp;gt;setSpring(200);&lt;br /&gt;gMouseJoint-&amp;gt;setMinDistance(0);&lt;br /&gt;gMouseJoint-&amp;gt;setMaxDistance(0);&lt;br /&gt;gMouseJoint-&amp;gt;setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);&lt;br /&gt;gMouseJoint-&amp;gt;setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED, true);&lt;br /&gt;return true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These lines create a distance joint btween the mouse sphere and the picked object; having one end point, our sphere cursor and the other end point our intersected actor.&lt;br /&gt;The object's global pose is used to transform the hit point from world space to object's local space so that the joint could be oriented properly.&lt;br /&gt;Finally, the joint parameters are filled in and a joint is created. Note that on every mouse click, the old cursor (sphere) and joint are released and a new pair is created. The LetGoActorfunction is defined as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void LetGoActor()&lt;br /&gt;{&lt;br /&gt;if (gMouseJoint)&lt;br /&gt;  gMouseJoint-&amp;gt;release();&lt;br /&gt;  gMouseJoint = NULL;&lt;br /&gt;if (gMouseSphere)&lt;br /&gt;  gMouseSphere-&amp;gt;release();&lt;br /&gt;  gMouseSphere = NULL;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nothing fancy here either. We just release the created objects (the sphere cursor and the joint).&lt;br /&gt;&lt;br /&gt;That's it. You need to call the pick function in the mouse function and handle the drag event. Enjoy this snapshot from the demo.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s1600/pick.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s320/pick.png" alt="Picking in PhysX3.1" id="BLOGGER_PHOTO_ID_5600625104323758818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/Picking%28PhysX3%29.zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4762795102594771933?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4762795102594771933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4762795102594771933' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4762795102594771933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4762795102594771933'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/physx3-picking.html' title='PhysX3: Picking'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s72-c/pick.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7207173704493233902</id><published>2011-05-28T20:05:00.000-07:00</published><updated>2011-12-09T16:03:23.625-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: Using the visual debugger</title><content type='html'>&lt;strong&gt;How to enable remote debugging in your application&lt;/strong&gt;&lt;br /&gt;On the client side (your application) after you have created the sdk object call this line of code.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;PxExtensionVisualDebugger::connect(gPhysicsSDK-&gt;getPvdConnectionManager(),"localhost",5425, 10000, true);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The parameters are in sequential order the PVD connection manager, the ip of the debugger, the port where the connection will be made, the timeout after which the connection will be dropped. For details about these parameters, consult the help docs of the visual debugger.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Demo run&lt;/strong&gt;&lt;br /&gt;We will now try to see the debugger in action. First, run the visual debugger. Then run your application. You should see all of your objects in the visual debugger. The active objects are green and the inactive (sleep) objects are yellow. This can turn out to be an invaluable tool when we are working on a fairly large project.&lt;br /&gt;&lt;br /&gt;That's it for this demo. There is no source code for this tutorial. Just use any of the existing codes and add in the code snippet given earlier and see it in action.&lt;br /&gt;Here is a snapshot of a debugging session.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s1600/debug.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 187px;" src="http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s320/debug.png" border="0" alt="Using PhysX3.1 Visual Debugger" id="BLOGGER_PHOTO_ID_5600817865435962498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We will look at how to create joints in the next tutorial.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7207173704493233902?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7207173704493233902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7207173704493233902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7207173704493233902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7207173704493233902'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/physx3-using-visual-debugger.html' title='PhysX3: Using the visual debugger'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s72-c/debug.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8538915835278724725</id><published>2011-05-28T19:42:00.000-07:00</published><updated>2011-12-09T16:03:45.616-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: Multiple bouncing boxes</title><content type='html'>In this tutorial, we will add multiple boxes to the scene. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial on the simple box. In fact, the only thing changed when we need to add multiple boxes is the InitializePhysX function. In addition, we need to store the references to the boxes into a vector so we create a new vector.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;vector &amp;lt;PxRigidActor*&amp;gt; boxes;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This InitializePhysX function is given as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void InitializePhysX() {&lt;br /&gt; gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );&lt;br /&gt;if(gPhysicsSDK == NULL) {&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Error creating PhysX device."&amp;lt;&amp;lt;endl;&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt;  exit(1);&lt;br /&gt; }&lt;br /&gt; if(!PxInitExtensions(*gPhysicsSDK))&lt;br /&gt;    cerr&amp;lt;&amp;lt; "PxInitExtensions failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; //Create the scene&lt;br /&gt; PxSceneDesc sceneDesc(gPhysicsSDK-&amp;gt; getTolerancesScale());&lt;br /&gt; sceneDesc.gravity=PxVec3(0.0f, -9.8f, 0.0f);&lt;br /&gt; if(!sceneDesc.cpuDispatcher) {&lt;br /&gt;   PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);&lt;br /&gt;   if(!mCpuDispatcher)&lt;br /&gt;      cerr&amp;lt;&amp;lt;"PxDefaultCpuDispatcherCreate failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;      sceneDesc.cpuDispatcher = mCpuDispatcher;&lt;br /&gt;   } &lt;br /&gt;   if(!sceneDesc.filterShader)&lt;br /&gt;      sceneDesc.filterShader  = gDefaultFilterShader;&lt;br /&gt;&lt;br /&gt;   gScene = gPhysicsSDK-&gt;createScene(sceneDesc);&lt;br /&gt;   if (!gScene)&lt;br /&gt;       cerr&amp;lt;&amp;lt;"createScene failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt; gScene-&amp;gt;setVisualizationParameter(PxVisualizationParameter::eSCALE,     1.0);&lt;br /&gt; gScene-&amp;gt;setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);&lt;br /&gt;PxMaterial* mMaterial = gPhysicsSDK-&amp;gt;createMaterial(0.5,0.5,0.5);&lt;br /&gt;  &lt;br /&gt;//Create actors &lt;br /&gt;//1) Create ground plane&lt;br /&gt;PxReal d = 0.0f;  &lt;br /&gt;PxTransform pose = PxTransform(PxVec3(0.0f, 0, 0.0f),PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));&lt;br /&gt;PxRigidStatic* plane = gPhysicsSDK-&amp;gt;createRigidStatic(pose);&lt;br /&gt;if (!plane)&lt;br /&gt;   cerr&amp;lt;&amp;lt;"create plane failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;PxShape* shape = plane-&gt;createShape(PxPlaneGeometry(), *mMaterial);&lt;br /&gt;if (!shape)&lt;br /&gt;   cerr&amp;lt;&amp;lt;"create shape failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;gScene-&amp;gt;addActor(*plane); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We are repeating the same steps as we did in the last tutorial. We first initialize the PhysX library and its extensions. Next we create the scene object and then we create a static ground plane rigidbody.  &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;//2) Create cube  &lt;br /&gt;PxReal density = 1.0f;&lt;br /&gt;PxTransform transform(PxVec3(0.0f, 5.0, 0.0f), PxQuat::createIdentity());&lt;br /&gt;PxVec3 dimensions(0.5,0.5,0.5);&lt;br /&gt;PxBoxGeometry geometry(dimensions);    &lt;br /&gt;for(int i=0;i&amp;lt;10;i++) {&lt;br /&gt; transform.p  = PxVec3(0.0f,5.0f+5*i,0.0f);&lt;br /&gt;PxRigidDynamic *actor = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);&lt;br /&gt; if (!actor)&lt;br /&gt;   cerr&amp;lt;&amp;lt;"create actor failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt; actor-&amp;gt;setAngularDamping(0.75);&lt;br /&gt; actor-&amp;gt;setLinearVelocity(PxVec3(0,0,0)); &lt;br /&gt; gScene-&amp;gt;addActor(*actor);&lt;br /&gt; boxes.push_back(actor);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we loop 10 times. We generate a new y position using the loop variable and then assign this position to the global pose of the current actor. In the previous PhysX release, we would create a new actor and give it the same descriptor. Now we have to create a new actor with new transform. Next we call the addActor function to create a new object for us. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Rendering of multiple boxes&lt;/strong&gt;&lt;br /&gt;In PhysX3, the rendering of objects has greatly been simplified. Since at the time of creation of our rigid bodies, we stored them into a vector. We use that vector for rendering. The RenderActors function and the other related functions are implemented as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void RenderActors()  { &lt;br /&gt;  // Render all the actors in the scene &lt;br /&gt;  for(int i=0;i&amp;lt;boxes.size();i++ ) {&lt;br /&gt;    DrawActor(boxes[i]);&lt;br /&gt;  }&lt;br /&gt;} &lt;br /&gt;void DrawBox(PxShape* pShape) {&lt;br /&gt;  PxTransform pT = PxShapeExt::getGlobalPose(*pShape);&lt;br /&gt;  PxBoxGeometry bg;&lt;br /&gt;  pShape-&amp;gt;getBoxGeometry(bg);&lt;br /&gt;  PxMat33 m = PxMat33Legacy(pT.q );&lt;br /&gt;  float mat[16];&lt;br /&gt;  getColumnMajor(m,pT.p, mat);&lt;br /&gt;  glPushMatrix(); &lt;br /&gt;     glMultMatrixf(mat);&lt;br /&gt;  glutSolidCube(bg.halfExtents.x*2);&lt;br /&gt;  glPopMatrix(); &lt;br /&gt;}&lt;br /&gt;void DrawShape(PxShape* shape)  { &lt;br /&gt;  PxGeometryType::Enum type = shape-&amp;gt;getGeometryType();&lt;br /&gt;  switch(type) &lt;br /&gt;  {          &lt;br /&gt;     case PxGeometryType::eBOX:&lt;br /&gt; DrawBox(shape);&lt;br /&gt; break;&lt;br /&gt;  } &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;void DrawActor(PxRigidActor* actor)  {  &lt;br /&gt;  PxU32 nShapes = actor-&amp;gt;getNbShapes(); &lt;br /&gt;  PxShape** shapes=new PxShape*[nShapes];&lt;br /&gt;  actor-&amp;gt;getShapes(shapes, nShapes);     &lt;br /&gt;  while (nShapes--) &lt;br /&gt;  { &lt;br /&gt;     DrawShape(shapes[nShapes]); &lt;br /&gt;  } &lt;br /&gt;  delete [] shapes;&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The only difference between this RenderActor function and the one in the previous&lt;br /&gt;tutorial is that this function loops over all of the rigid bodies. That's it. The rest of the code remains the same since it will loop through all of the actors and determine their types to call the appropriate draw function as detailed in the last tutorial. &lt;br /&gt;&lt;br /&gt;Running the code gives us the following output.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s1600/demo.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s320/demo.png" border="0" alt="PhysX3.1 Multiple Boxes" id="BLOGGER_PHOTO_ID_5600314097524176594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/MultipleBoxes(PhysX3).zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8538915835278724725?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8538915835278724725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8538915835278724725' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8538915835278724725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8538915835278724725'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/physx3-multiple-bouncing-boxes.html' title='PhysX3: Multiple bouncing boxes'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s72-c/demo.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4939879945290613252</id><published>2011-05-27T23:43:00.000-07:00</published><updated>2011-12-09T16:04:02.642-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: A simple bouncing box</title><content type='html'>In this tutorial, I will show you how to create a simple box at a specific position and let it bounce under influence of gravity. We will be adding to the code base from the previous tutorials. We first create the PhysX3 sdk object and store it into a global pointer as given in the previous tutorial. For this tutorial, the following headers and libs are needed.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;GL/freeglut.h&amp;gt; &lt;br /&gt;#include &amp;lt; PxPhysicsAPI.h&amp;gt; &lt;br /&gt;#include &amp;lt; PxExtensionsAPI.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxDefaultErrorCallback.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxDefaultAllocator.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxDefaultSimulationFilterShader.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxDefaultCpuDispatcher.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxShapeExt.h&amp;gt;&lt;br /&gt;#include &amp;lt; PxMat33Legacy.h&amp;gt; &lt;br /&gt;#include &amp;lt; PxSimpleFactory.h&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;#pragma comment(lib, "PhysX3_x86.lib")&lt;br /&gt;#pragma comment(lib, "PxTask.lib")&lt;br /&gt;#pragma comment(lib, "Foundation.lib")&lt;br /&gt;#pragma comment(lib, "PhysX3Extensions.lib")&lt;br /&gt;#pragma comment(lib, "GeomUtils.lib") &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see, now we have to add a lot of headers this is because a lot of parameters which were given by default in the previous PhysX versions have to be given explicitly.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;const int WINDOW_WIDTH=1024, &lt;br /&gt;WINDOW_HEIGHT=768;&lt;br /&gt;&lt;br /&gt;static PxPhysics* gPhysicsSDK = NULL;&lt;br /&gt;static PxDefaultErrorCallback gDefaultErrorCallback;&lt;br /&gt;static PxDefaultAllocator gDefaultAllocatorCallback;&lt;br /&gt;static PxSimulationFilterShader gDefaultFilterShader=PxDefaultSimulationFilterShader;&lt;br /&gt;&lt;br /&gt;PxScene* gScene = NULL;&lt;br /&gt;PxReal myTimestep = 1.0f/60.0f;&lt;br /&gt;PxRigidActor *box;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we store the variables for screen size, the global physx sdk pointer, scene pointer and the box rigid body pointer. In PhysX3, we no more need to provide the shape desc for objects since now only the geometry has to be specified using the available classes as we will see in a minute.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt; gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );&lt;br /&gt; if(gPhysicsSDK == NULL) {&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Error creating PhysX3 device."&amp;lt;&amp;lt;endl;&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt;  exit(1);&lt;br /&gt; }&lt;br /&gt;  &lt;br /&gt;    if(!PxInitExtensions(*gPhysicsSDK))&lt;br /&gt;  cerr&amp;lt;&amp;lt; "PxInitExtensions failed!" &amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we call the CreatePhysX function.Now in PhysX3, we need to provide the allocator and the error callback. We pass in the default handlers provided by the PhysX3 sdk. Once we have a valid PhysX object, we initialize the extensions. This is required so that the other extensions are setup properly.&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:cpp"&gt;&lt;br /&gt;  //Create the scene&lt;br /&gt;  PxSceneDesc sceneDesc(gPhysicsSDK-&gt;getTolerancesScale());&lt;br /&gt;  sceneDesc.gravity=PxVec3(0.0f, -9.8f, 0.0f);&lt;br /&gt;  if(!sceneDesc.cpuDispatcher) {&lt;br /&gt;    PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);&lt;br /&gt;    if(!mCpuDispatcher)&lt;br /&gt;       cerr&amp;lt;&amp;lt;"PxDefaultCpuDispatcherCreate failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;        sceneDesc.cpuDispatcher = mCpuDispatcher;&lt;br /&gt;    } &lt;br /&gt;    if(!sceneDesc.filterShader)&lt;br /&gt;        sceneDesc.filterShader  = gDefaultFilterShader;&lt;br /&gt;&lt;br /&gt;    gScene = gPhysicsSDK-&gt;createScene(sceneDesc);&lt;br /&gt;    if (!gScene)&lt;br /&gt;        cerr&amp;lt;&amp;lt;"createScene failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;gScene-&amp;gt;setVisualizationParameter(PxVisualizationParameter::eSCALE,     1.0);&lt;br /&gt; gScene-&amp;gt;setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, the scene object is created and the parameters for the simulation are passed in as was in the previous physX versions. In this case, we ask PhysX to set up the global scene gravity to 9.8 m/s^2 The -ve sign is to make it point downwards.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp" &gt;&lt;br /&gt; PxMaterial* mMaterial = gPhysicsSDK-&gt;createMaterial(0.5,0.5,0.5);&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we set the default material's physical properties like static and dynamic friction and the coefficient of restitution. In PhysX3, the default materials are not accessed by index now we need to give an a new object.  &lt;br /&gt;&lt;b&gt;Creating actors&lt;/b&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;   //Create actors &lt;br /&gt;   //1) Create ground plane&lt;br /&gt;  PxReal d = 0.0f;  &lt;br /&gt;  PxTransform pose = PxTransform(PxVec3(0.0f, 0, 0.0f),PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));&lt;br /&gt;   PxRigidStatic* plane = gPhysicsSDK-&amp;gt;createRigidStatic(pose);&lt;br /&gt;   if (!plane)&lt;br /&gt;     cerr&amp;lt;&amp;lt;"create plane failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;   PxShape* shape = plane-&gt;createShape(PxPlaneGeometry(), *mMaterial);&lt;br /&gt;   if (!shape)&lt;br /&gt;      cerr&amp;lt;&amp;lt;"create shape failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt;      gScene-&amp;gt;addActor(*plane);&lt;br /&gt;&lt;br /&gt;   //2) Create cube  &lt;br /&gt;  PxReal density = 1.0f;&lt;br /&gt; PxTransform transform(PxVec3(0.0f, 10.0f, 0.0f), PxQuat::createIdentity());&lt;br /&gt; PxVec3 dimensions(0.5,0.5,0.5);&lt;br /&gt; PxBoxGeometry geometry(dimensions);&lt;br /&gt;    &lt;br /&gt; PxRigidDynamic *actor = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);&lt;br /&gt;    actor-&gt;setAngularDamping(0.75);&lt;br /&gt;    actor-&gt;setLinearVelocity(PxVec3(0,0,0)); &lt;br /&gt; if (!actor)&lt;br /&gt;  cerr&amp;lt;&amp;lt;"create actor failed!"&amp;lt;&amp;lt;endl;&lt;br /&gt; gScene-&amp;gt;addActor(*actor);&lt;br /&gt;&lt;br /&gt; box = actor;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we create two actors for the ground plane and the box. For each of these actors, we first set their transform. In PhysX3 the transforms are now given as quaternions. We then create the PxRigid[Static/Dynamic] object by calling appropriate function to create a static/dynamic object. Next, the shape of the object is specified and then the actor is added to the scene. For box, the box geometry is specified here. We use this geometry object by storing the actor reference into a global variable. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Handling PhysX stepping loop&lt;/b&gt;&lt;br /&gt;Once the actor stuff is done, the next thing we need to handle is the PhysX loop. This will allow the simulation to step ahead in time. We will implement an asynchronous loop which can be done using the following lines of code.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void StepPhysX() &lt;br /&gt;{ &lt;br /&gt;   gScene-&amp;gt;simulate(myTimestep);        &lt;br /&gt;    &lt;br /&gt;   //...perform useful work here using previous frame's state data        &lt;br /&gt;   while(!gScene-&amp;gt;fetchResults() )     &lt;br /&gt;   {&lt;br /&gt;      // do something useful        &lt;br /&gt;   }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These lines were copied directly from the documentation so rather than commenting anything on these, I would ask you to go and read the asynchronous loop section in the PhysX documentation. We will call this function once from our display function.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rendering of Actors&lt;/b&gt;&lt;br /&gt;The next step is to render the actors. To make easier for use to work with PhysX, I have modularized the code into functions. First, the RenderActors() function is implemented as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void RenderActors() &lt;br /&gt;{ &lt;br /&gt;    // Render all the actors in the scene &lt;br /&gt;    DrawActor(box);&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;Nothing fancy here, we just call the DrawActor function passing it the box actor reference. The DrawActor function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;void DrawActor(PxRigidActor* actor) &lt;br /&gt;{  &lt;br /&gt;   PxU32 nShapes = actor-&gt;getNbShapes(); &lt;br /&gt;   PxShape** shapes=new PxShape*[nShapes];&lt;br /&gt; &lt;br /&gt;   actor-&gt;getShapes(shapes, nShapes);     &lt;br /&gt;   while (nShapes--) &lt;br /&gt;   { &lt;br /&gt;      DrawShape(shapes[nShapes]); &lt;br /&gt;   } &lt;br /&gt;   delete [] shapes;&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It looks a lot like the previous PhysX version DrawActor function. It basically ask the actor for the number of shapes it has and then calls the DrawShapes function with the shape parameter. The DrawShape function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void DrawShape(PxShape* shape) &lt;br /&gt;{ &lt;br /&gt;    PxGeometryType::Enum type = shape-&gt;getGeometryType();&lt;br /&gt;    switch(type) &lt;br /&gt;    {          &lt;br /&gt;       case PxGeometryType::eBOX:&lt;br /&gt;          DrawBox(shape);&lt;br /&gt;       break;&lt;br /&gt;    } &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This function first identifies the type of the shape and then uses a switch case to call the appropriate Draw function. For our case, we check for the Box object and then call the DrawBox function passing it the shape parameter. The DrawBox function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void DrawBox(PxShape* pShape) {&lt;br /&gt; PxTransform pT = PxShapeExt::getGlobalPose(*pShape);&lt;br /&gt; PxBoxGeometry bg;&lt;br /&gt; pShape-&amp;gt;getBoxGeometry(bg);&lt;br /&gt; PxMat33 m = PxMat33Legacy(pT.q );&lt;br /&gt;    float mat[16];&lt;br /&gt; getColumnMajor(m,pT.p, mat);&lt;br /&gt; glPushMatrix(); &lt;br /&gt;  glMultMatrixf(mat);&lt;br /&gt;  glutSolidCube(bg.halfExtents.x*2);&lt;br /&gt;    glPopMatrix(); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The DrawBox function gets the current Global pose (basically the shapes tranform matrix) and then converts it into a column major form (so that we can pass this matrix to OpenGL). Next, the currnet transformation matrix is stored (glPushMatrix) and then the box's matrix is multiplied to the current matrix. Then, we draw the box's geometry (using the glutSolidCube function) and finally revert the old transformation back by calling glPopMatrix.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Display Function&lt;/b&gt;&lt;br /&gt;Now after these function definitions, the display function becomes this,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void Display() {&lt;br /&gt;   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);&lt;br /&gt;   glLoadIdentity();&lt;br /&gt;   //setup the view transformation using &lt;br /&gt;   //gluLookAt(...);&lt;br /&gt;&lt;br /&gt;   //Update PhysX &lt;br /&gt;   if (gScene) &lt;br /&gt;   { &lt;br /&gt;       StepPhysX(); &lt;br /&gt;   }   &lt;br /&gt;&lt;br /&gt;   RenderActors();&lt;br /&gt;&lt;br /&gt;   glutSwapBuffers();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it. Attached is the complete source code for this tutorial. Here is the snapshot of the application.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s1600/box.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 248px;" src="http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s320/box.png" border="0" alt="PhysX3.1 Simple Box" id="BLOGGER_PHOTO_ID_5600256862866064994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/SimpleBox(PhysX3).zip"&gt;Source code for this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4939879945290613252?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4939879945290613252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4939879945290613252' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4939879945290613252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4939879945290613252'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/simple-bouncing-box-physx3.html' title='PhysX3: A simple bouncing box'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s72-c/box.png' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5244557045487466009</id><published>2011-05-27T10:22:00.000-07:00</published><updated>2011-07-30T20:56:04.276-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX3 Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX3: Getting started</title><content type='html'>There has been a major revamp of the PhysX API from version 3. I will try to convert all of the existing tutorials into PhysX3 so here I go with the first getting started tutorial.&lt;br /&gt;&lt;b&gt;Visual studio2008 project include directories&lt;/b&gt;&lt;br /&gt;To ensure that you can follow smoothly along with me in the rest of the tutorials, make sure that the visual studio project directories contain the following directories in the include path. (This option is accessible through Tools-&gt;Options-&gt;Projects &amp; Solutions-&gt;VC++ Directories. Here YOUR_PHYSX_PATH is where the PhysX3 folder is stored on your harddisk.)&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\PhysXAPI&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\PhysXAPI\foundation&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\PhysXAPI\extensions&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\PhysXAPI\common&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\PhysXAPI\pxtask\include&lt;br /&gt;YOUR_PHYSX_PATH\Samples\SampleFramework\framework\include&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lib path&lt;/b&gt;&lt;br /&gt;This path is added in the lib paths.&lt;br /&gt;YOUR_PHYSX_PATH\SDKs\lib\win32&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Getting started with NVIDIA PhysX3&lt;/b&gt;&lt;br /&gt;We need to include the headers first.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;gl/freeglut.h&amp;gt;&lt;br /&gt;#include &amp;lt;pxphysicsapi.h&amp;gt;&lt;br /&gt;#include &amp;lt;pxdefaulterrorcallback.h&amp;gt;&lt;br /&gt;#include &amp;lt;pxdefaultallocator.h&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;#pragma comment(lib, "PhysX3_x86.lib")&lt;br /&gt;#pragma comment(lib, "Foundation")&lt;br /&gt;#pragma comment(lib, "PhysX3Extensions.lib")&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The PhysX header is now PxPhysicsAPI.h. This header is needed for PhysX. The rest are for c++ output/input stuff and freeglut API stuff. I like to programmatically add the linker libraries. For this basic startup demo, we need PhysX3_x86.lib/dll,  Foundation.lib/dll, PhysX3Extensions.lib/dll so we link to them.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;const int WINDOW_WIDTH=1024,&lt;br /&gt;  WINDOW_HEIGHT=768;&lt;br /&gt;&lt;br /&gt;static PxPhysics* gPhysicsSDK = NULL;&lt;br /&gt;static PxDefaultErrorCallback gDefaultErrorCallback;&lt;br /&gt;static PxDefaultAllocator gDefaultAllocatorCallback;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;IN the above lines, we setup the window dimensions. Then we store the PhysX object pointer. In the previous sdk, only first parameter was needed now all of the parameters are needed. These include the allocator and error callback handlers. The sdk provides default handlers so we use them.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void InitializePhysX() {&lt;br /&gt;   gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );&lt;br /&gt;   if(gPhysicsSDK == NULL) {&lt;br /&gt; cerr&amp;lt;&amp;lt;"Error creating PhysX device."&amp;lt;&amp;lt;endl;&lt;br /&gt; cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt; exit(1);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;void ShutdownPhysX() {&lt;br /&gt;   gPhysicsSDK-&amp;gt;release();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Like before, we call the PxCreatePhysics function and pass it all the parameters. If the call succeeds, we get the object otherwise we prompt an error and exit. For release, we need to call the release function of the sdk object reference.&lt;br /&gt;&lt;br /&gt;Thats it. The code should not give u any errors. To make sure everything is fine and there are no problems, copy PhysX3_x86.dll to the current solution directory. Hope you will enjoy the rest of the tutorials.&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/GettingStarted(PhysX3).zip"&gt;Source code&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5244557045487466009?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5244557045487466009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5244557045487466009' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5244557045487466009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5244557045487466009'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/05/getting-started-with-physx-3.html' title='PhysX3: Getting started'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5218447090076733763</id><published>2011-04-30T00:19:00.000-07:00</published><updated>2011-12-09T16:04:34.981-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Joint Basics</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, joint, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;In this tutorial, we will see how to create a simple distance joint. We will reuse the picking code in this tutorial to make things a bit more interesting. So without any further ado, lets get started. We will create two boxes one of which will be a static object. The other box will be manipulated by the mouse hence it will be dynamic.&lt;br /&gt;&lt;strong&gt;Creating the boxes&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;The dynamic box&lt;/em&gt;&lt;br /&gt;We simply call the box descriptor as discussed in the past tutorials. Nothing new here.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;NxBodyDesc bodyDesc;&lt;br /&gt;&lt;br /&gt;bodyDesc.angularDamping = 0.75f;&lt;br /&gt;&lt;br /&gt;bodyDesc.linearVelocity = NxVec3(0,0,0);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NxBoxShapeDesc boxDesc;&lt;br /&gt;&lt;br /&gt;size_t box_size = 1;&lt;br /&gt;&lt;br /&gt;boxDesc.dimensions = NxVec3(box_size/2.0f, box_size/2.0f, box_size/2.0f);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;actorDesc2.shapes.pushBack(&amp;boxDesc);&lt;br /&gt;&lt;br /&gt;actorDesc2.body   = &amp;bodyDesc;&lt;br /&gt;&lt;br /&gt;actorDesc2.density  = 1.0f;&lt;br /&gt;&lt;br /&gt;actorDesc2.globalPose.t  = NxVec3(0.0f,3.0f,0.0f);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NxActor* dynamicBox = gScene-&gt;createActor(actorDesc2);&lt;br /&gt;&lt;br /&gt;dynamicBox-&gt;userData= (void*)box_size; &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;The static box&lt;/em&gt;&lt;br /&gt;For static box, we simply create the actor as before and then raise the body flag to be NX_BF_FROZEN.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;//create another box which is static&lt;br /&gt;&lt;br /&gt;actorDesc2.globalPose.t  = NxVec3(0.0f,5.0f,0.0f); &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;NxActor* staticBox = gScene-&gt;createActor(actorDesc2);&lt;br /&gt;&lt;br /&gt;staticBox-&gt;userData= (void*)box_size; &lt;br /&gt;&lt;br /&gt;staticBox-&gt;raiseBodyFlag(NX_BF_FROZEN); &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Creating joint&lt;/strong&gt;&lt;br /&gt;For creating a very basic distance joint, we need to fill in the descriptor called &lt;br /&gt;NxDistanceJointDesc. The first things we will give it are the actors that the joint links. &lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;//create a joint&lt;br /&gt;&lt;br /&gt;NxDistanceJointDesc desc;&lt;br /&gt;&lt;br /&gt;desc.actor[0] = dynamicBox;&lt;br /&gt;&lt;br /&gt;desc.actor[1] = staticBox;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For this, we store the references returned from createActor function as shown in the previous section. Next, we specify the different properties of the joint descriptor.&lt;br /&gt;The max/minDistance denote the limits of stretch/compression for this joint respectively.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;desc.maxDistance = 2.0f;&lt;br /&gt;&lt;br /&gt;desc.minDistance = 1.0f;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The damper determines how damped the springiness of the spring is. A high value dampens the spring and vice verse for spring value. &lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;desc.spring.damper = 1.0f;&lt;br /&gt;&lt;br /&gt;desc.spring.spring = 200.0f;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The next two lines are very important. The first setsup the desc's flags. This controls whether the min, max limit of the distance joint, and the spring in the distance joint is enabled. If you dont add these flags, there will be no limit and no springiness to the joint. Likewise the jointFlags are also important. If u want that the actors connected to the distance joint collide, you must pass the NX_JF_COLLISION_ENABLED flag to the jointFlags descriptor. Finally, the spring is created as any other object that we have covered in the past tutorials.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;desc.flags |= NX_DJF_MIN_DISTANCE_ENABLED | NX_DJF_MAX_DISTANCE_ENABLED | NX_DJF_SPRING_ENABLED;&lt;br /&gt;&lt;br /&gt;desc.jointFlags |= NX_JF_COLLISION_ENABLED;&lt;br /&gt;&lt;br /&gt;gScene-&gt;createJoint(desc);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Rendering of the distance joint&lt;/strong&gt;&lt;br /&gt;For rendering of the distance joint, we do a fairly simple thing by creating a global array for 2 NxVec3 types. When we are about to draw the box actors, we store their current positions in the global array so the new DrawCube function is this,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;//Stored globally&lt;br /&gt;&lt;br /&gt;NxVec3 pos[2]; //for storing the two end points of spring&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void DrawBox(NxShape* pShape, size_t size) {&lt;br /&gt;&lt;br /&gt;   static int count=0;&lt;br /&gt;&lt;br /&gt;   pos[(count++)%2] = pShape-&gt;getGlobalPosition();&lt;br /&gt;&lt;br /&gt;   NxMat34 pose = pShape-&gt;getGlobalPose(); &lt;br /&gt;&lt;br /&gt;   float mat[16];&lt;br /&gt;&lt;br /&gt;   pose.getColumnMajor44(mat);&lt;br /&gt;&lt;br /&gt;   glPushMatrix(); &lt;br /&gt;&lt;br /&gt;      glMultMatrixf(mat);&lt;br /&gt;&lt;br /&gt;      glutSolidCube(size);&lt;br /&gt;&lt;br /&gt;   glPopMatrix(); &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Next, in the render function, we draw the line between the two positions just stored.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;glColor3f(gMouseJoint!=NULL,gMouseJoint==NULL,gMouseJoint==NULL);&lt;br /&gt;&lt;br /&gt;//Draw the spring &lt;br /&gt;&lt;br /&gt;glBegin(GL_LINES);&lt;br /&gt;&lt;br /&gt;   glVertex3f(pos[0].x, pos[0].y, pos[0].z);&lt;br /&gt;&lt;br /&gt;   glVertex3f(pos[1].x, pos[1].y, pos[1].z);&lt;br /&gt;&lt;br /&gt;glEnd();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it we have a simple distance joint between two boxes. Here is the snapshot from this application.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s1600/joint.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 247px;" src="http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s320/joint.png" border="0" alt="PhysX Basics" id="BLOGGER_PHOTO_ID_5601280573797652034" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/PhysX_Tutorial_SimpleJoint.zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5218447090076733763?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5218447090076733763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5218447090076733763' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5218447090076733763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5218447090076733763'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/physx-basics-tutorial-joint-basics.html' title='PhysX Basics Tutorial: Joint Basics'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-pA9j5I7Fxog/Tbu_AUiBVkI/AAAAAAAAAK8/ckIV5uID1uw/s72-c/joint.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2610041057086989145</id><published>2011-04-28T18:41:00.000-07:00</published><updated>2011-12-09T16:04:53.140-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Using the Visual Debugger</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, using, visual, debugger, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;In this tutorial, we will see how to connect our client application to the visual debugger. Usually, when you start the visual debugger, it will try to connect to an application. If there is no application connecting to it, it will do nothing.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;How to enable remote debugging in your application&lt;/strong&gt;&lt;br /&gt;On the client side (your application) after you have created the sdk object call this line of code.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;gPhysicsSDK-&gt;getFoundationSDK().getRemoteDebugger()-&gt;connect ("localhost", 5425);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The first parameter of the connect function is the ip address (for local debugging, you can use localhost (127.0.0.1)), the second parameter is the port where the connection will be made.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Demo run&lt;/strong&gt;&lt;br /&gt;We will now try to see the debugger in action. First, run the visual debugger. Then run your application. You should see all of your objects in the visual debugger. The active objects are green and the inactive (sleep) objects are yellow. This can turn out to be an invaluable tool when we are working on a fairly large project.&lt;br /&gt;&lt;br /&gt;That's it for this demo. There is no source code for this tutorial. Just use any of the existing codes and add in the code snippet given earlier and see it in action.&lt;br /&gt;Here is a snapshot of a debugging session.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s1600/debug.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 187px;" src="http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s320/debug.png" border="0" alt="Using PhysX Visual Debugger" id="BLOGGER_PHOTO_ID_5600817865435962498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We will look at how to create joints in the next tutorial.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2610041057086989145?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2610041057086989145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2610041057086989145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2610041057086989145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2610041057086989145'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/physx-basics-tutorial-using-visual.html' title='PhysX Basics Tutorial: Using the Visual Debugger'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-2ylnRhckVUE/TboaLJj43II/AAAAAAAAAI0/fApz7RrQ2-8/s72-c/debug.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-3842746814067479623</id><published>2011-04-28T05:54:00.000-07:00</published><updated>2011-12-09T16:05:12.235-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Picking</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, picking, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;In this tutorial, we will use the scene of multiple boxes from the last tutorial. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;General picking&lt;/strong&gt;&lt;br /&gt;We will first look at how picking works in general. The user picks on a point on the window. The 2D point coordinates are converted to a 3d point. Then, a ray is generated. The origin and direction of the ray are first calculated by unprojecting the clicked point at different depths. The same point coordinates are used but with two depths (z=0 and z=1) for the near hit point and the far hit point respectively. Once we have constructed the ray, the scene is asked to find an intersecting actor. If the ray has intersected with any actor, a dynamic spring is created between the  intersected actor and a sphere at the intersection point. In the mouse motion funciton, depending on whether the actor has been intersected the intersected actor is manipulated. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Picking in PhysX&lt;/strong&gt;&lt;br /&gt;We define two new functions  ViewProject and ViewUnProject as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void ViewProject(NxVec3 &amp;v, int &amp;xi, int &amp;yi, float &amp;depth)&lt;br /&gt;&lt;br /&gt;{  &lt;br /&gt;&lt;br /&gt;   GLdouble winX, winY, winZ;&lt;br /&gt;&lt;br /&gt;   gluProject((GLdouble) v.x, (GLdouble) v.y, (GLdouble) v.z, modelMatrix, projMatrix, viewPort, &amp;winX, &amp;winY, &amp;winZ);&lt;br /&gt;&lt;br /&gt;   xi = (int)winX; yi = viewPort[3] - (int)winY - 1; depth = (float)winZ; &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void ViewUnProject(int xi, int yi, float depth, NxVec3 &amp;v)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;   yi = viewPort[3] - yi - 1;&lt;br /&gt;&lt;br /&gt;   GLdouble wx, wy, wz;&lt;br /&gt;&lt;br /&gt;   gluUnProject((GLdouble) xi, (GLdouble) yi, (GLdouble) depth,&lt;br /&gt;&lt;br /&gt;   modelMatrix, projMatrix, viewPort, &amp;wx, &amp;wy, &amp;wz);&lt;br /&gt;&lt;br /&gt;   v.set((NxReal)wx, (NxReal)wy, (NxReal)wz);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above functions simply call the glu[Un]Project function. Nothing fancy here. Both of these functions need the viewport, modelview and projection matrices so we store these matrices globally. We obtain the viewport values and projection matrix when they are setup (in the resize handler) as shown below.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void OnReshape(int nw, int nh) {&lt;br /&gt;&lt;br /&gt;   glViewport(0,0,nw, nh);&lt;br /&gt;&lt;br /&gt;   glMatrixMode(GL_PROJECTION);&lt;br /&gt;&lt;br /&gt;   glLoadIdentity();&lt;br /&gt;&lt;br /&gt;   gluPerspective(60, (GLfloat)nw / (GLfloat)nh, 0.1f, 1000.0f);&lt;br /&gt;&lt;br /&gt;   glGetIntegerv(GL_VIEWPORT, viewPort);&lt;br /&gt;&lt;br /&gt;   glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);&lt;br /&gt;&lt;br /&gt;   glMatrixMode(GL_MODELVIEW);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Similarly, we obtain the modelview matrix in the render function just after the viewing transformation is set.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;glLoadIdentity();&lt;br /&gt;&lt;br /&gt;//setting up modelview matrix&lt;br /&gt;&lt;br /&gt;glTranslatef(0,0,dist);&lt;br /&gt;&lt;br /&gt;glRotatef(rX,1,0,0);&lt;br /&gt;&lt;br /&gt;glRotatef(rY,0,1,0);&lt;br /&gt;&lt;br /&gt;glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;//rest of display function&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So now we have our matrices.  We now come on the Pick function. This function takes an x, y screen coordinate, cast a ray from into the scene and returns true if there is an intersection. It also stores a sphere object at the hit point, stores reference to the intersected actor and also store a spring between the hitpoint sphere and the actor. This function is defined as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;bool PickActor(int x, int y)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  ReleaseHelpers();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We first release all previous helpers (the spring and the last intersection sphere.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt; NxRay ray; &lt;br /&gt;&lt;br /&gt; ViewUnProject(x,y,0.0f, ray.orig);&lt;br /&gt;&lt;br /&gt; ViewUnProject(x,y,1.0f, ray.dir);&lt;br /&gt;&lt;br /&gt; ray.dir -= ray.orig; ray.dir.normalize();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines create a ray as given in the previous paragraph.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt; NxRaycastHit hit;&lt;br /&gt;&lt;br /&gt; NxShape* closestShape = gScene-&amp;gt;raycastClosestShape(ray, NX_ALL_SHAPES, hit);&lt;br /&gt;&lt;br /&gt; if (!closestShape) return false;&lt;br /&gt;&lt;br /&gt; if (!closestShape-&amp;gt;getActor().isDynamic()) return false;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines is where the ray is cast to find the closest actor. If there is none, we return false. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt; int hitx, hity;&lt;br /&gt;&lt;br /&gt; ViewProject(hit.worldImpact, hitx, hity, gMouseDepth);&lt;br /&gt;&lt;br /&gt; gMouseSphere = CreateSphere(hit.worldImpact, 0.1f, 1.0f);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; gMouseSphere-&amp;gt;raiseBodyFlag(NX_BF_KINEMATIC);&lt;br /&gt;&lt;br /&gt; gMouseSphere-&amp;gt;raiseActorFlag(NX_AF_DISABLE_COLLISION);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines project the hit point back to get the world space position. This is done so that the picking cursor (sphere) could be drawn at the intersection point.&lt;br /&gt;The sphere's body flag is raised to kinematic since it will be attached to an actor(see next few lines). The collisions are also disabled since we donot want our cursor to intersect with any geometry.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; NxDistanceJointDesc desc;&lt;br /&gt;&lt;br /&gt; gSelectedActor = &amp;closestShape-&gt;getActor();&lt;br /&gt;&lt;br /&gt; gSelectedActor-&amp;gt;wakeUp();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; desc.actor[0] = gMouseSphere;&lt;br /&gt;&lt;br /&gt; desc.actor[1] = gSelectedActor;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These lines create a descriptor for a joint having one end point, our sphere cursor and the other end point our intersected actor.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt; gMouseSphere-&amp;gt;getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[0]);&lt;br /&gt;&lt;br /&gt; gSelectedActor-&amp;gt;getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[1]);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above lines modify the transformation of the intersected actor based on the hit point.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt; desc.maxDistance = 0.0f;&lt;br /&gt;&lt;br /&gt; desc.minDistance = 0.0f;&lt;br /&gt;&lt;br /&gt; desc.spring.damper = 1.0f;&lt;br /&gt;&lt;br /&gt; desc.spring.spring = 200.0f;&lt;br /&gt;&lt;br /&gt; desc.flags |= NX_DJF_MAX_DISTANCE_ENABLED | NX_DJF_SPRING_ENABLED;&lt;br /&gt;&lt;br /&gt; NxJoint* joint = gScene-&amp;gt;createJoint(desc);&lt;br /&gt;&lt;br /&gt; gMouseJoint = (NxDistanceJoint*)joint-&amp;gt;is(NX_JOINT_DISTANCE);&lt;br /&gt;&lt;br /&gt; return true; &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, the descriptor parameters are filled in and a joint is created. Note that on every mouse click, the old cursor (sphere) and joint are released and a new pair is created. The ReleaseHelpers function is defined as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void ReleaseHelpers()&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;   if (gMouseJoint) &lt;br /&gt;&lt;br /&gt;      gScene-&amp;gt;releaseJoint(*gMouseJoint);&lt;br /&gt;&lt;br /&gt;   gMouseJoint = NULL;&lt;br /&gt;&lt;br /&gt;   if (gMouseSphere)&lt;br /&gt;&lt;br /&gt;      gScene-&amp;gt;releaseActor(*gMouseSphere);&lt;br /&gt;&lt;br /&gt;   gMouseSphere = NULL;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nothing fancy here either. We just release the created objects (the sphere cursor and the joint).&lt;br /&gt;&lt;br /&gt;That's it. You need to call the pick function in the mouse function and handle the drag event. Enjoy this snapshot from the demo.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s1600/pick.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s320/pick.png" border="0" alt="PhysX Picking" id="BLOGGER_PHOTO_ID_5600625104323758818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/PhysX_Tutorial_Picking.zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-3842746814067479623?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/3842746814067479623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=3842746814067479623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/3842746814067479623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/3842746814067479623'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/physx-basics-tutorial-picking.html' title='PhysX Basics Tutorial: Picking'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-tx7J17kiv5k/Tblq2-daSuI/AAAAAAAAAIs/7LtrTu6vXsw/s72-c/pick.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1074792137957946280</id><published>2011-04-27T10:08:00.000-07:00</published><updated>2011-12-09T16:05:30.197-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Multiple Bouncing Box</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, multiple, box, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;In this tutorial, we will add multiple boxes to the scene. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial on the simple box. In fact, the only thing changed when we need to add multiple boxes is the InitializePhysX function. This function is given as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void InitializePhysX() {&lt;br /&gt;&lt;br /&gt; gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);&lt;br /&gt;&lt;br /&gt; if(gPhysicsSDK == NULL) {&lt;br /&gt;&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Error creating PhysX device."&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;  cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;  exit(1);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; //Create the scene&lt;br /&gt;&lt;br /&gt; NxSceneDesc sceneDesc;&lt;br /&gt;&lt;br /&gt; sceneDesc.gravity.set(0.0f, -9.8f, 0.0f);&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt; gScene = gPhysicsSDK-&amp;gt;createScene(sceneDesc);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; NxMaterial* defaultMaterial = gScene-&amp;gt;getMaterialFromIndex(0);&lt;br /&gt;&lt;br /&gt; defaultMaterial-&amp;gt;setRestitution(0.5);&lt;br /&gt;&lt;br /&gt; defaultMaterial-&amp;gt;setStaticFriction(0.5);&lt;br /&gt;&lt;br /&gt; defaultMaterial-&amp;gt;setDynamicFriction(0.5);&lt;br /&gt;&lt;br /&gt;      &lt;br /&gt;&lt;br /&gt; gScene-&gt;setTiming(myTimestep / 4.0f, 4, NX_TIMESTEP_FIXED);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; //Create actors &lt;br /&gt;&lt;br /&gt;    //1) Create ground plane&lt;br /&gt;&lt;br /&gt; NxPlaneShapeDesc planeDesc; &lt;br /&gt;&lt;br /&gt; NxActorDesc actorDesc, actorDesc2;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt; actorDesc.shapes.pushBack(&amp;planeDesc);&lt;br /&gt;&lt;br /&gt; gScene-&amp;gt;createActor(actorDesc);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; //2) Create cube  &lt;br /&gt;&lt;br /&gt; NxBodyDesc bodyDesc;&lt;br /&gt;&lt;br /&gt; bodyDesc.angularDamping = 0.75f;&lt;br /&gt;&lt;br /&gt; bodyDesc.linearVelocity = NxVec3(0,0,0);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; NxBoxShapeDesc boxDesc;&lt;br /&gt;&lt;br /&gt; size_t box_size = 1;&lt;br /&gt;&lt;br /&gt; boxDesc.dimensions = NxVec3(box_size/2.0f, box_size/2.0f, box_size/2.0f);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; actorDesc2.shapes.pushBack(&amp;boxDesc);&lt;br /&gt;&lt;br /&gt; actorDesc2.body   = &amp;bodyDesc;&lt;br /&gt;&lt;br /&gt; actorDesc2.density  = 1.0f;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We are repeating the same steps as we did in the last tutorial. The only thing that we need to do in case when we need multiple objects of the same type is that we need to create new actors using the scene object. All of this reuse the same actor descriptor object.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;      for(int i=0;i&amp;lt;10;i++) {&lt;br /&gt;&lt;br /&gt;         actorDesc2.globalPose.t  = NxVec3(0.0f,5.0f+5*i,0.0f);&lt;br /&gt;&lt;br /&gt;  gScene-&amp;gt;createActor(actorDesc2) &lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we loop 10 times. We generate a new y position using the loop variable and then assign this position to the global pose of the actor descriptor. Next we call the createActor function passing it the modified descriptor to create a new object for us. &lt;br /&gt;&lt;br /&gt;That's it. The rest of the code remains the same since it will loop through all of the actors and determine their types to call the appropriate draw function as detailed in the last tutorial. &lt;br /&gt;&lt;br /&gt;Running the code gives us the following output.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s1600/demo.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s320/demo.png" border="0" alt="PhysX Multiple Bouncing Boxes" id="BLOGGER_PHOTO_ID_5600314097524176594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/PhysX_Tutorial_MultipleBoxes.zip"&gt;Source code of this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-1074792137957946280?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1074792137957946280/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1074792137957946280' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1074792137957946280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1074792137957946280'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/physx-basics-tutorial-simple-bouncing_27.html' title='PhysX Basics Tutorial: Multiple Bouncing Box'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-SmhCzw8UM5g/TbhP__2KdtI/AAAAAAAAAIU/ZCnKca-uddw/s72-c/demo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-151936374320339166</id><published>2011-04-27T05:55:00.001-07:00</published><updated>2011-12-09T16:05:43.683-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: A Simple Bouncing Box</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, simple, box, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;In this tutorial, I will show you how to create a simple box at a specific position and let it bounce under influence of gravity. We will be adding to the code base from the previous tutorials. We first create the PhysX sdk object and store it into a global pointer like this,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;GL/freeglut.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;NxPhysics.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#pragma comment(lib, "PhysXLoader.lib")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NxPhysicsSDK* gPhysicsSDK = NULL;&lt;br /&gt;&lt;br /&gt;NxScene* gScene = NULL;&lt;br /&gt;&lt;br /&gt;NxActor* groundPlane; &lt;br /&gt;&lt;br /&gt;NxActor* box; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NxReal myTimestep = 1.0f/60.0f;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void InitializePhysX() {&lt;br /&gt;&lt;br /&gt;   gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);&lt;br /&gt;&lt;br /&gt;   if(gPhysicsSDK == NULL) {&lt;br /&gt;&lt;br /&gt;      cerr&amp;lt;&amp;lt;"Error creating PhysX device."&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;      cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt;&lt;br /&gt;      exit(1);&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we just store pointers to the PhysX sdk object, the scene object and two actors (our ground plane and the box) and the timeStep value for stepping the PhysX simulation.&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;   //Create the scene&lt;br /&gt;&lt;br /&gt;   NxSceneDesc sceneDesc;&lt;br /&gt;&lt;br /&gt;   sceneDesc.gravity.set(0.0f, -9.8f, 0.0f); &lt;br /&gt;&lt;br /&gt;   gScene = gPhysicsSDK-&amp;gt;createScene(sceneDesc);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In PhysX any physics object you want to make, you need to fill a relevant descriptor and then pass that descriptor to the sdk function (through the PhysX sdk pointer) responsible for creating the object for you. In this case, we ask PhysX to set up the global scene gravity to 9.8 m/s^2 The -ve sign is to make it point downwards.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp" &gt;&lt;br /&gt;&lt;br /&gt;   NxMaterial* defaultMaterial = gScene-&amp;gt;getMaterialFromIndex(0);&lt;br /&gt;&lt;br /&gt;   defaultMaterial-&amp;gt;setRestitution(0.5);&lt;br /&gt;&lt;br /&gt;   defaultMaterial-&amp;gt;setStaticFriction(0.5);&lt;br /&gt;&lt;br /&gt;   defaultMaterial-&amp;gt;setDynamicFriction(0.5);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   gScene-&amp;gt;setTiming(myTimestep / 4.0f, 4, NX_TIMESTEP_FIXED);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we set the default material's physical properties like static and dynamic friction and the coefficient of restitution. Next, we set the update timing for the PhysX sdk. We ask the sdk to use a fix time stepping. For the simple demo like this, fixed time steps should suffice.&lt;br /&gt;&lt;b&gt;Creating actors&lt;/b&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;   //Create actors &lt;br /&gt;&lt;br /&gt;   //1) Create ground plane&lt;br /&gt;&lt;br /&gt;   NxPlaneShapeDesc planeDesc;&lt;br /&gt;&lt;br /&gt;   NxActorDesc actorDesc, actorDesc2;&lt;br /&gt;&lt;br /&gt;   actorDesc.shapes.pushBack(&amp;planeDesc);&lt;br /&gt;&lt;br /&gt;   gScene-&amp;gt;createActor(actorDesc);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   //2) Create cube  &lt;br /&gt;&lt;br /&gt;   NxBodyDesc bodyDesc;&lt;br /&gt;&lt;br /&gt;   bodyDesc.angularDamping = 0.75f;&lt;br /&gt;&lt;br /&gt;   bodyDesc.linearVelocity = NxVec3(0,0,0);&lt;br /&gt;&lt;br /&gt;   NxBoxShapeDesc boxDesc;&lt;br /&gt;&lt;br /&gt;   boxDesc.dimensions = NxVec3(0.5, 0.5, 0.5);&lt;br /&gt;&lt;br /&gt;   actorDesc2.shapes.pushBack(&amp;boxDesc);&lt;br /&gt;&lt;br /&gt;   actorDesc2.body   = &amp;bodyDesc;&lt;br /&gt;&lt;br /&gt;   actorDesc2.density  = 1.0f;&lt;br /&gt;&lt;br /&gt;   actorDesc2.globalPose.t  = NxVec3(0,10,0);&lt;br /&gt;&lt;br /&gt;   gScene-&amp;gt;createActor(actorDesc2);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we create two actors for the ground plane and the box. For each of these actors, their descriptors are filled first to allow us to adjust the parameters. For the ground plane, the default parameters create a ground plane at origin and a positive Y normal direction. Once created, the actor descriptor is given to the scene's createActor function. Next, the same steps are taken for the box. In case of box however the body descriptot is first filled to store the box's linear velocity and angular damping. Then the box's shape descriptor is filled to fill its dimensions. This shape is then adde to the actors shapes list. Next, the actor descriptor sets the body, density and the initial position (globalPose.t). Finally, the createActor function is invoked again. Thats it, we have successfully added the two actors to the PhysX engine.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Handling PhysX stepping loop&lt;/b&gt;&lt;br /&gt;Once the actor stuff is done, the next thing we need to handle is the PhysX loop. This will allow the simulation to step ahead in time. We will implement an asynchronous loop which can be done using the following lines of code.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void StepPhysX() &lt;br /&gt;&lt;br /&gt;{ &lt;br /&gt;&lt;br /&gt;   gScene-&amp;gt;simulate(myTimestep);        &lt;br /&gt;&lt;br /&gt;   gScene-&amp;gt;flushStream();        &lt;br /&gt;&lt;br /&gt;   //...perform useful work here using previous frame's state data        &lt;br /&gt;&lt;br /&gt;   while(!gScene-&amp;gt;fetchResults(NX_RIGID_BODY_FINISHED, false) )     &lt;br /&gt;&lt;br /&gt;   {&lt;br /&gt;&lt;br /&gt;      // do something useful        &lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These lines were copied directly from the documentation so rather than commenting anything on these, I would ask you to go and read the asynchronous loop section in the PhysX documentation. We will call this function once from our display function.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rendering of Actors&lt;/b&gt;&lt;br /&gt;The next step is to render the actors. To make easier for use to work with PhysX, I have modularized the code into functions. First, the RenderActors() function is implemented as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void RenderActors() &lt;br /&gt;&lt;br /&gt;{ &lt;br /&gt;&lt;br /&gt;    // Render all the actors in the scene &lt;br /&gt;&lt;br /&gt;    int nbActors = gScene-&amp;gt;getNbActors(); &lt;br /&gt;&lt;br /&gt;    NxActor** actors = gScene-&amp;gt;getActors(); &lt;br /&gt;&lt;br /&gt;    while (nbActors--) &lt;br /&gt;&lt;br /&gt;    { &lt;br /&gt;&lt;br /&gt;        NxActor* actor = *actors++; &lt;br /&gt;&lt;br /&gt;        DrawActor(actor); &lt;br /&gt;&lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;Nothing fancy here, we first query the scene for the total number of actors it contains. Then, we loop through each actor and draw it by calling the DrawActor function. The DrawActor function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;void DrawActor(NxActor* actor) &lt;br /&gt;&lt;br /&gt;{ &lt;br /&gt;&lt;br /&gt;    NxShape* const* shapes = actor-&amp;gt;getShapes(); &lt;br /&gt;&lt;br /&gt;    NxU32 nShapes = actor-&amp;gt;getNbShapes(); &lt;br /&gt;&lt;br /&gt;    nShapes = actor-&amp;gt;getNbShapes(); &lt;br /&gt;&lt;br /&gt;    while (nShapes--) &lt;br /&gt;&lt;br /&gt;    { &lt;br /&gt;&lt;br /&gt;        DrawShape(shapes[nShapes]); &lt;br /&gt;&lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It looks a lot like the previous function doesn't it. It basically ask the actor for the number of shapes it has and then calls the DrawShapes function with the shape parameter. The DrawShape function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void DrawShape(NxShape* shape) &lt;br /&gt;&lt;br /&gt;{ &lt;br /&gt;&lt;br /&gt;   int type = shape-&amp;gt;getType();&lt;br /&gt;&lt;br /&gt;   switch(type) &lt;br /&gt;&lt;br /&gt;   {          &lt;br /&gt;&lt;br /&gt;      case NX_SHAPE_BOX:&lt;br /&gt;&lt;br /&gt;         DrawBox(shape);&lt;br /&gt;&lt;br /&gt;      break;&lt;br /&gt;&lt;br /&gt;   } &lt;br /&gt;&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This function first identifies the type of the shape and then uses a switch case to call the appropriate Draw function. For our case, we check for the Box object and then call the DrawBox function passing it the shape parameter. THe DrawBox function is implemented as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void DrawBox(NxShape* pShape) {&lt;br /&gt;&lt;br /&gt;   NxMat34 pose = pShape-&amp;gt;getGlobalPose(); &lt;br /&gt;&lt;br /&gt;   float mat[16];&lt;br /&gt;&lt;br /&gt;   pose.getColumnMajor44(mat);&lt;br /&gt;&lt;br /&gt;   glPushMatrix(); &lt;br /&gt;&lt;br /&gt;      glMultMatrixf(mat);&lt;br /&gt;&lt;br /&gt;      glutSolidCube(1);&lt;br /&gt;&lt;br /&gt;   glPopMatrix(); &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The DrawBox function gets the current Global pose (basically the shapes tranform matrix) and then converts it into a column major form (so that we can pass this matrix to OpenGL). Next, the currnet transformation matrix is stored (glPushMatrix) and then the box's matrix is multiplied to the current matrix. Then, we draw the box's geometry (using the glutSolitCube function) and finally revert the old transformation back by calling glPopMatrix.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Display Function&lt;/b&gt;&lt;br /&gt;Now after these function definitions, the display function becomes this,&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;&lt;br /&gt;void Display() {&lt;br /&gt;&lt;br /&gt;   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;   glLoadIdentity();&lt;br /&gt;&lt;br /&gt;   //setup the view transformation using &lt;br /&gt;&lt;br /&gt;   //gluLookAt(...);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   //Update PhysX &lt;br /&gt;&lt;br /&gt;   if (gScene) &lt;br /&gt;&lt;br /&gt;   { &lt;br /&gt;&lt;br /&gt;       StepPhysX(); &lt;br /&gt;&lt;br /&gt;   }   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   RenderActors();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   glutSwapBuffers();&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it. Attached is the complete source code for this tutorial. Here is the snapshot of the application.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s1600/box.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 248px;" src="http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s320/box.png" border="0" alt="PhysX Simple Box" id="BLOGGER_PHOTO_ID_5600256862866064994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/PhysX/PhysX_Tutorial_SimpleBox.zip"&gt;Source code for this tutorial&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-151936374320339166?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/151936374320339166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=151936374320339166' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/151936374320339166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/151936374320339166'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/physx-basics-tutorial-simple-bouncing.html' title='PhysX Basics Tutorial: A Simple Bouncing Box'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-P-nArvf4uVY/Tbgb8gITRmI/AAAAAAAAAIM/nngkMwt_Pn8/s72-c/box.png' height='72' width='72'/><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5658327254540599127</id><published>2011-04-26T11:04:00.000-07:00</published><updated>2011-07-30T20:56:04.278-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Using GLUT with PhysX</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, using, glut, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;This tutorial is on how to setup freeglut with NVIDIA PhysX sdk. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;GL/freeglut.h&amp;gt;&lt;br /&gt;#include &amp;lt;NxPhysics.h&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;#pragma comment(lib, "PhysXLoader.lib")&lt;br /&gt;&lt;br /&gt;const int WINDOW_WIDTH=1024, &lt;br /&gt;   WINDOW_HEIGHT=768;&lt;br /&gt;&lt;br /&gt;static NxPhysicsSDK* gPhysicsSDK = NULL;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above lines, we first include the required headers. Then the requried linker library is linked programmatically. Next we setup the variables for the screen size and a global pointer to the PhysX sdk. This is done so that PhysX is conveniently accessible throughout the code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void InitializePhysX() {&lt;br /&gt;   gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);&lt;br /&gt;   if(gPhysicsSDK == NULL) {&lt;br /&gt;      cerr&amp;lt;&amp;lt;"Error creating PhysX device."&amp;lt;&amp;lt;endl;&lt;br /&gt;      cerr&amp;lt;&amp;lt;"Exiting..."&amp;lt;&amp;lt;endl;&lt;br /&gt;      exit(1);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;void ShutdownPhysX() {&lt;br /&gt;   NxReleasePhysicsSDK(gPhysicsSDK);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These two functions were discussed in the previous tutorial so nothing new here. For the NXCreatePhysicsSDK function, the other parameters are ignored.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;void InitGL() { &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void OnReshape(int nw, int nh) {&lt;br /&gt; glViewport(0,0,nw, nh);&lt;br /&gt; glMatrixMode(GL_PROJECTION);&lt;br /&gt; glLoadIdentity();&lt;br /&gt; gluPerspective(60, (GLfloat)nw / (GLfloat)nh, 0.1f, 100.0f);&lt;br /&gt; glMatrixMode(GL_MODELVIEW);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void OnRender() {&lt;br /&gt; glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt; glLoadIdentity();&lt;br /&gt; glutSwapBuffers();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void OnShutdown() {&lt;br /&gt; ShutdownPhysX();&lt;br /&gt;}&lt;br /&gt;void main(int argc, char** argv) {&lt;br /&gt; atexit(OnShutdown);&lt;br /&gt; glutInit(&amp;argc, argv);&lt;br /&gt; glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);&lt;br /&gt; glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);&lt;br /&gt; glutCreateWindow("GLUT PhysX Demo");&lt;br /&gt;&lt;br /&gt; glutDisplayFunc(OnRender);&lt;br /&gt; glutReshapeFunc(OnReshape);&lt;br /&gt; &lt;br /&gt; InitGL();&lt;br /&gt; InitializePhysX();&lt;br /&gt;&lt;br /&gt; glutMainLoop();  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These lines setup a glut window with double buffer support. It also hooks up two functions for resize handling and display. Thats it. The glut window is now setup with PhysX. The next tutorial will discuss how to add a basic cube that falls due to gravity into a glut window.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5658327254540599127?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5658327254540599127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5658327254540599127' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5658327254540599127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5658327254540599127'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/glut-with-physx.html' title='PhysX Basics Tutorial: Using GLUT with PhysX'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4279020843527045870</id><published>2011-04-26T10:25:00.000-07:00</published><updated>2011-07-30T20:56:04.279-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PhysX 2.8.X Tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics'/><title type='text'>PhysX Basics Tutorial: Getting started with NVIDIA PhysX</title><content type='html'>&lt;meta name="PhysX Tutorial" content="PhysX, basics, getting, started, tutorial"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;I went to see the power of the NVIDIA PhysX sdk. So I downloaded the sdk from the PhysX developer site. While the sdk contains a lot of demos, for a beginner like me it was quite tedious to get started. I initially started with the documentation and I must say it is pretty good at explaining the API. So my next step was to look at the internet to find out if there are any basic tutorials. Fortunately, I came across Swiftless Tutorials (http://www.swiftless.com/misctuts/physxtuts.html) on AGEIA PhysX (before acquired by NVIDIA, AGEIA owned this sdk). These were very helpful for me in understanding how to get up and running with NVIDIA PhysX sdk. So I will try to fill the gap by doing basic PhysX tutorials.&lt;br /&gt;&lt;br /&gt;These tutorials are based on the latest NVIDIA PhysX sdk version 2.8.4. This sdk does not ask u for installing the system software. Thus its your responsibilty to handle the dlls required. Which dlls u need I will explain in a minute. I will use freeglut in this tutorial series.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Getting started with NVIDIA PhysX&lt;/b&gt;&lt;br /&gt;We need to include the headers first.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#include &amp;lt;iostream &amp;gt;&lt;br /&gt;#include &amp;lt;nxphysics.h &amp;gt;&lt;br /&gt;using namespace std;&lt;br /&gt;#pragma comment(lib, "PhysXLoader.lib")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The last header NxPhysics.h is the header needed for PhysX. The rest are for c++ output/input stuff. I like to programmatically add the linker libraries. For this basic startup demo, we only need the PhysxLoader.lib/dll so we link to it.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void main() {&lt;br /&gt; NxSDKCreateError whatError;&lt;br /&gt; NxPhysicsSDK* pPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION,0,0,   NxPhysicsSDKDesc(), &amp;amp;whatError);&lt;br /&gt; if(pPhysicsSDK) {&lt;br /&gt;    NxReleasePhysicsSDK(pPhysicsSDK);&lt;br /&gt; } else {&lt;br /&gt; cerr &amp;lt;&amp;lt; "Cannot create PhysX device." &amp;lt;&amp;lt; endl; &lt;br /&gt; cerr &amp;lt;&amp;lt; "Reason: " &amp;lt;&amp;lt; whatError;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Thats it. If u try to compile and run the code, the pPhysicsSDK pointer will be NULL and the error code will be NXCE_PHYSX_NOT_FOUND. The reason for this is because the required dlls are needed to be copied to the current solution folder. These dlls are PhysXLoader.dll and PhsyXCore.dll. That's it you have the helloworld PhysX program.&lt;br /&gt;&lt;br /&gt;Next, we will look at how to hook glut with PhysX in the next tutorial. &lt;br /&gt;Hope you will enjoy the rest of the tutorials.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4279020843527045870?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4279020843527045870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4279020843527045870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4279020843527045870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4279020843527045870'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/getting-started-with-nvidia-physx.html' title='PhysX Basics Tutorial: Getting started with NVIDIA PhysX'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7157533382742537549</id><published>2011-04-06T01:59:00.000-07:00</published><updated>2011-07-30T21:00:10.576-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>ARB_transform_feedback2</title><content type='html'>I could not find enough demos on how to use the new ARB transform feedback2 extension. Basically it goes like this,&lt;br /&gt;1) You need to call &lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glGenTransformFeedbacks(1, &amp;tfID); &lt;br /&gt;glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;like any other function in OpenGL.&lt;br /&gt;&lt;br /&gt;2) You specify the buffer and the shader varyings.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glBindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfvbo ); glTransformFeedbackVaryings( pg, 1, attr, GL_INTERLEAVED_ATTRIBS); //(my cards does not support the EXT function&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3) In the render function u don’t call glDraw[*] functions instead u call &lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glDrawTransformFeedback(GL_POINTS, tfID); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The buffer binding is taken from the tfID transform feedback buffer.&lt;br /&gt;Thats it. The new way simplifies the handling of buffers.&lt;br /&gt;Attached is the full source code.&lt;br /&gt; &lt;br /&gt; &lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/test/main.cpp"&gt;Source Code&lt;/a&gt;&lt;br /&gt; &lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/test/TF.exe"&gt;Binary (Requires freeglut and glew)&lt;/a&gt;&lt;br /&gt; &lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/test/ARB_TransformFeedback2_Demo.zip"&gt;Visual Studio 2008 sln (Requires freeglut and glew)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://docs.google.com/leaf?id=0BxcB5MrnPZS2NzMwYmQ4YzQtMzc3NC00NjM0LTlkY2QtMWRhNmUzODQ3NWRl&amp;hl=en&amp;authkey=CKGYj_sN"&gt;Download solution from Google Docs&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7157533382742537549?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7157533382742537549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7157533382742537549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7157533382742537549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7157533382742537549'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/04/arbtransformfeedback2.html' title='ARB_transform_feedback2'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4663440634339378177</id><published>2011-02-24T06:51:00.000-08:00</published><updated>2011-07-30T20:59:49.235-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Recollections from the past</title><content type='html'>Sharing some videos from the past.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Half angle slicing&lt;/strong&gt;&lt;br /&gt;&lt;object &gt;&lt;param name="movie" value="http://www.youtube.com/v/GVvd17aMoOA&amp;hl=en&amp;fs=1"&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/GVvd17aMoOA&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width=480 height=385 &gt;&lt;/embed&gt;&lt;/object&gt; &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;GPU Splatting&lt;/strong&gt;&lt;br /&gt;&lt;object&gt;&lt;param name="movie" value="http://www.youtube.com/v/DscCq11VMp8&amp;hl=en&amp;fs=1"&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/DscCq11VMp8&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width=480 height=385&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/8216868933119618528-4663440634339378177?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4663440634339378177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4663440634339378177' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4663440634339378177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4663440634339378177'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/02/recollections-from-past.html' title='Recollections from the past'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1762388574921392894</id><published>2011-02-20T00:44:00.000-08:00</published><updated>2011-12-09T16:07:04.670-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Implementing histogram pyramid</title><content type='html'>Just recently, I wanted to implement the histogram pyramid datastructure as detailed &lt;a href=http://www.mpi-inf.mpg.de/~gziegler/gpu_pointlist/paper17_gpu_pointclouds.pdf&gt; here&lt;/a&gt; and &lt;a href=http://www.tevs.eu/project_vmv06.html &gt;here&lt;/a&gt;  however I could not figure it out immediately how to go about it. Fortunately, I was able to find &lt;a href=http://www.rauwendaal.net/courses/computer-animation/histopyramids&gt;this&lt;/a&gt; website. Even though this website was a good starting point however it also left the gaps to be filled in by the readers themselves. Then, I looked into a GPL library &lt;a href=http://www.sintef.no/hpmc&gt;HPMC&lt;/a&gt;) which made it easier for me to understnad how the histogram pyramid is actually implemented although the code is well written the shader stuff was a bit difficult for me to get hold of. So I went forward to implement the original technique from scratch on my own so here it is. I hope that the discussion here is useful for others. Here is a snapshot of what you would get in the end.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-8h9xzG7sPH0/TWDg9WnsHpI/AAAAAAAAAH0/5_eBp5-mHok/s1600/histoPyramid.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 316px; height: 320px;" src="http://4.bp.blogspot.com/-8h9xzG7sPH0/TWDg9WnsHpI/AAAAAAAAAH0/5_eBp5-mHok/s320/histoPyramid.png" border="0" alt="Histogram Pyramid" id="BLOGGER_PHOTO_ID_5575703683333365394" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you are able to produce something interesting out of this, do let me know I would love to see what you come up with. So here are the missing details. &lt;br /&gt;&lt;br /&gt;The histogram pyramid starts with first generating a 2D texture out of your geometry. The first thing needed is generating a series of FBOs with multiple attacments that would act as storage for our histogram pyramid levels. We do so by first generating a series of FBOs with different attachments as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;vector&lt;GLuint&gt; fboIDs;&lt;br /&gt;GLuint histopyramid_texID;&lt;br /&gt;int size = 2048;&lt;br /&gt;int max_level = (int)(log(size)/log(2));&lt;br /&gt;void InitFBOs() {&lt;br /&gt;   glGenTextures(1, &amp;histopyramid_texID);&lt;br /&gt;   glBindTexture( GL_TEXTURE_2D, histopyramid_texID);&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0 );&lt;br /&gt;   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_level);&lt;br /&gt;   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F,  size, size, 0, GL_RGBA, GL_FLOAT, NULL );&lt;br /&gt;   glGenerateMipmap( GL_TEXTURE_2D );&lt;br /&gt;    &lt;br /&gt;   fboIDs.resize(max_level+1 );&lt;br /&gt;   glGenFramebuffers( static_cast&lt;GLsizei&gt;( fboIDs.size() ), &amp;fboIDs[0] );&lt;br /&gt;   for( GLuint m=0; m&lt; fboIDs.size(); m++) {&lt;br /&gt;        glBindFramebuffer( GL_DRAW_FRAMEBUFFER,fboIDs[m] );&lt;br /&gt;        glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, histopyramid_texID, m );&lt;br /&gt;        if( !checkFBOStatus( __FILE__, __LINE__ ) ) {&lt;br /&gt;            cerr &lt;&lt; "OpenGL error: Framebuffer for HP level " &lt;&lt; m &lt;&lt; " incomplete." &lt;&lt; endl;&lt;br /&gt;            exit(EXIT_FAILURE);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   glBindFramebuffer( GL_DRAW_FRAMEBUFFER,0 );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After setting up the fbo, we attach it to allow offscreen rendering and clear it.&lt;br /&gt;Note that we need to setup the MAX mipmap level for directing the output to the correct mipmap level.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glBindTexture( GL_TEXTURE_2D, histopyramid_texID );&lt;br /&gt;glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);&lt;br /&gt;glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[0] );&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next is the slicing of the 3D geometry. We can do so by using the glOrtho function as follows.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;int tileX = 16, tileY=16;&lt;br /&gt;int w = size/tileX;&lt;br /&gt;int h = size/tileY;&lt;br /&gt;float teapot_size = 0.5;&lt;br /&gt;float t_size_2    = teapot_size*2;&lt;br /&gt;float clip_d      = -t_size_2;&lt;br /&gt;int x=0, y=0;&lt;br /&gt;float dZ = (2*abs(clip_d))/(tileX*tileY);&lt;br /&gt;for(int j=0;j&lt; tileY;j++) {&lt;br /&gt;   x=0;&lt;br /&gt;   for(int i=0;i&lt; tileX;i++) {&lt;br /&gt;      glLoadIdentity(); &lt;br /&gt;      glOrtho(-t_size_2,t_size_2,-t_size_2,t_size_2,clip_d, clip_d+dZ);&lt;br /&gt;      glViewport( x, y,  w,  h);&lt;br /&gt;         glutSolidTeapot(teapot_size);&lt;br /&gt;      clip_d+=dZ;&lt;br /&gt;      x+=w;&lt;br /&gt;   }&lt;br /&gt;   y+=h;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This gives us something like this image&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-kM1PusfvqjQ/TWDW3U8_vII/AAAAAAAAAHs/H6jQ6f5SEzE/s1600/histo2D.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 316px; height: 320px;" src="http://3.bp.blogspot.com/-kM1PusfvqjQ/TWDW3U8_vII/AAAAAAAAAHs/H6jQ6f5SEzE/s320/histo2D.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5575692584690367618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So now we have our geometry rendered to the base (0) level of the histogram pyramid. The original paper on building point clouds using histogram pyramid used descriminator to determine the active cells. We do this by using alpha test on the output during build process of the histogram pyramid (see the next code snippet). Now we need to build the histogram pyramid. We do so by using a reduction fragment shader and invoke it on a fullscreen quad. For each histogram pyramid level, we bind a new fbo and render the fullscreen quad. Thus, each successive level is a reduced version of its predecessor. This is achieved as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;base_shader.Use();&lt;br /&gt;   glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[0] );&lt;br /&gt;   glViewport( 0, 0, size, size );&lt;br /&gt;      glEnable(GL_ALPHA_TEST);&lt;br /&gt;      glAlphaFunc(GL_GREATER, 0.1f);&lt;br /&gt;  RenderFullscreenQuad();  &lt;br /&gt;      glDisable(GL_ALPHA_TEST);&lt;br /&gt;      if( max_level &lt; 1 ) {&lt;br /&gt;        return true;&lt;br /&gt;      }&lt;br /&gt;   reduction_shader.Use();&lt;br /&gt;   glBindTexture( GL_TEXTURE_2D, histopyramid_texID );&lt;br /&gt;     glUniform2f( reduction_shader_floor("delta"), -0.5f/size,0.5f/size );&lt;br /&gt;     glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[1] );&lt;br /&gt;     glViewport( 0, 0,  size/2,  size/2 ); &lt;br /&gt; RenderFullscreenQuad();&lt;br /&gt;     if( max_level &lt; 2 ) {&lt;br /&gt;        return true;&lt;br /&gt;     }&lt;br /&gt;     for(GLsizei m=2; m&lt;=max_level; m++) {&lt;br /&gt;        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, m-1 );&lt;br /&gt;        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m-1 );&lt;br /&gt;&lt;br /&gt;        glUniform2f(reduction_shader("delta"),-0.5f/(1&lt;&lt;(max_level+1-m)),0.5f/(1&lt;&lt;(max_level+1-m)) );&lt;br /&gt;&lt;br /&gt;        glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[m] );&lt;br /&gt;        glViewport( 0, 0, 1&lt;&lt;(max_level-m), 1&lt;&lt;(max_level-m) );&lt;br /&gt;        RenderFullscreenQuad();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;   reduction_shader.UnUse();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The base level shader is simply outputting the color from the histogram pyramid. The alpha test rejects all the zero entries and we are only left with the non-zero data.&lt;br /&gt;The reduction shader I use is this,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;uniform sampler2D  histopyramid;&lt;br /&gt;uniform vec2       delta;&lt;br /&gt;void&lt;br /&gt;main()&lt;br /&gt;{&lt;br /&gt;    gl_FragColor  = vec4(&lt;br /&gt;        dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.xx ) ) ),&lt;br /&gt;        dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.yx ) ) ),&lt;br /&gt;        dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.xy ) ) ),&lt;br /&gt;        dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.yy ) ) )&lt;br /&gt;    ); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;Obtaining total vertices&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;To see how many data items (points in our case) we have, we lookup the top element of the histogram pyramid. We do so by using a PBO, attach it to the histogram top level and then call glGetTexImage function as follows,&lt;br /&gt;  &lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;    glBindBuffer( GL_PIXEL_PACK_BUFFER,histoPBOID );&lt;br /&gt;    glBindTexture( GL_TEXTURE_2D, histopyramid_texID );&lt;br /&gt;    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL, max_level);&lt;br /&gt;    glGetTexImage( GL_TEXTURE_2D, max_level,GL_RGBA, GL_FLOAT, NULL );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, we call the glBufferSubData function to extract the total vertices as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;    float data[4];&lt;br /&gt;    glGetBufferSubData( GL_PIXEL_PACK_BUFFER,0, sizeof(GLfloat)*4, &amp;data[0] ); &lt;br /&gt;    totalVertices = static_cast&lt;int&gt;( floorf(data[0]) +  floorf(data[1]) +  floorf(data[2]) + data(mem[3]) ); &lt;br /&gt;    glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Rendering point cloud&lt;/strong&gt;&lt;br /&gt;For rendering of points, we first bind a temp VBO containing indices incremented linearly. The temp VBO is setup at the initialization as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;   enumerate_vbo_n = 3*1000;&lt;br /&gt;   glGenBuffers( 1, &amp;enumVBOID);&lt;br /&gt;   glBindBuffer( GL_ARRAY_BUFFER, enumVBOID);&lt;br /&gt;   glBufferData( GL_ARRAY_BUFFER, 3*sizeof(GLfloat)* enumerate_vbo_n,NULL,GL_STATIC_DRAW );&lt;br /&gt;   GLfloat* ptr = reinterpret_cast&lt;GLfloat*&gt;( glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY ) );&lt;br /&gt;   for(int i=0; i&lt; enumerate_vbo_n; i++) {&lt;br /&gt;      *ptr++ = static_cast&lt;GLfloat&gt;( i );&lt;br /&gt;      *ptr++ = 0.0f;&lt;br /&gt;      *ptr++ = 0.0f;&lt;br /&gt;   }&lt;br /&gt;   glUnmapBuffer( GL_ARRAY_BUFFER );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We could also have used the gl_VertexID builtin attribute to accesss the vertex ID which is used to index into the histogram pyramid. We bind this VBO and then call the glDrawArrays function as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;   glBindBuffer( GL_ARRAY_BUFFER, enumVBOID );&lt;br /&gt;   glVertexPointer( 3, GL_FLOAT, 0, NULL );&lt;br /&gt;   glEnableClientState( GL_VERTEX_ARRAY );&lt;br /&gt;&lt;br /&gt;   user_shader.Use(); &lt;br /&gt;&lt;br /&gt;   GLsizei N = totalVertices;&lt;br /&gt;   for(GLsizei i=0; i&lt; N; i+= enumerate_vbo_n) {&lt;br /&gt;        glUniform1f( user_shader("key_offset"), static_cast&lt;GLfloat&gt;( i ) );&lt;br /&gt;        glDrawArrays( GL_POINTS, 0, min( N-i, enumerate_vbo_n ) );&lt;br /&gt;   }&lt;br /&gt;   user_shader.UnUse();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The user shader accepts the incoming vertex stream and converts it into a 3d position. This vertex and fragment shaders are given below.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;uniform sampler2D  histopyramid; &lt;br /&gt;uniform float      key_offset;  &lt;br /&gt;uniform int max_level;&lt;br /&gt;uniform float TILE_X,&lt;br /&gt;  TILE_Y,      &lt;br /&gt;  TOTAL; &lt;br /&gt;&lt;br /&gt;#define FUNC_X TILE_X/2.0&lt;br /&gt;#define FUNC_Y TILE_Y/2.0&lt;br /&gt;void&lt;br /&gt;getVertexPos( out vec3 p )&lt;br /&gt;{&lt;br /&gt;    float key_ix = gl_Vertex.x  + key_offset;&lt;br /&gt;    vec2 texpos = vec2(0.5);&lt;br /&gt;    vec4 delta_x = vec4( -0.5,  0.5, -0.5, 0.25 );&lt;br /&gt;    vec4 delta_y = vec4(  0.0, -0.5,  0.0, 0.25 );&lt;br /&gt;    vec4 sums,hist,mask;&lt;br /&gt;    for(int i=max_level; i&gt;0; i--) {&lt;br /&gt;        vec4 sums = texture2DLod( histopyramid, texpos, float(i) );&lt;br /&gt;        vec4 hist = sums;&lt;br /&gt;        hist.w   += hist.z;&lt;br /&gt;        hist.zw  += hist.yy;&lt;br /&gt;        hist.yzw += hist.xxx;&lt;br /&gt;        vec4 mask = vec4( lessThan( vec4(key_ix), hist ) );&lt;br /&gt;        texpos   += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );&lt;br /&gt;        key_ix   -= dot( sums.xyz, vec3(1.0)-mask.xyz );&lt;br /&gt;        delta_x  *= 0.5;&lt;br /&gt;        delta_y  *= 0.5;&lt;br /&gt;    }&lt;br /&gt;    vec4 raw  = texture2DLod( histopyramid, texpos, 0.0 );&lt;br /&gt;    sums = floor(raw);&lt;br /&gt;    hist = sums;&lt;br /&gt;    hist.w   += hist.z;&lt;br /&gt;    hist.zw  += hist.yy;&lt;br /&gt;    hist.yzw += hist.xxx;&lt;br /&gt;    mask = vec4( lessThan( vec4(key_ix), hist ) );&lt;br /&gt;    float nib = dot(vec4(mask), vec4(-1.0,-1.0,-1.0, 3.0));&lt;br /&gt;    texpos   += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );&lt;br /&gt;    key_ix   -= dot( sums.xyz, vec3(1.0)-mask.xyz );&lt;br /&gt;    float val = fract( dot( raw, vec4(equal(vec4(nib),vec4(0,1,2,3))) ) );&lt;br /&gt;    &lt;br /&gt;    vec2 foo = vec2(TILE_X,TILE_Y)*texpos;&lt;br /&gt;    vec2 tp = vec2( (2.0*TILE_X)/FUNC_X, (2.0*TILE_Y)/FUNC_Y ) * fract(foo);&lt;br /&gt;    float slice = dot( vec2(1.0, TILE_Y), floor(foo));&lt;br /&gt;    &lt;br /&gt;    p = vec3(tp, slice)/vec3(1.0,1.0,TOTAL);  &lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main() &lt;br /&gt;{&lt;br /&gt;   vec3 p;&lt;br /&gt;   getVertexPos( p);&lt;br /&gt;   gl_Position = gl_ModelViewProjectionMatrix * vec4( p, 1.0 ); &lt;br /&gt;   //debug&lt;br /&gt;   gl_FrontColor = vec4(p,1);&lt;br /&gt;   //gl_FrontColor = gl_Color ;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The interesting bit is happening in the getVertexPos function. First the delta values for moving to the next cell are calculated. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;float key_ix = gl_Vertex.x  + key_offset;&lt;br /&gt;vec2 texpos = vec2(0.5);&lt;br /&gt;vec4 delta_x = vec4( -0.5,  0.5, -0.5, 0.25 );&lt;br /&gt;vec4 delta_y = vec4(  0.0, -0.5,  0.0, 0.25 );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then the traversal loop is initiated. This loop runs log_2(size) that is the total levels in the histogram pyramid. Since we are using 4 channels for each entry of the histogram pyramid, we do a partial sum by first looking up the value at the current histogram pyramid level. The swizzle part shown below calcualtes the end ranges for each child node.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;for(int i=max_level; i&gt;0; i--) {&lt;br /&gt;   vec4 sums = texture2DLod( histopyramid, texpos, float(i) );&lt;br /&gt;   vec4 hist = sums;&lt;br /&gt;   hist.w   += hist.z;&lt;br /&gt;   hist.zw  += hist.yy;&lt;br /&gt;   hist.yzw += hist.xxx;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, based on the current key_index, the mask is calculated to see whether the current key_index is less than the current sum at the current histogram pyramid level. This mask is used to calculate the texture lookup position and the new key_index is upated accordingly. After updating the key_index and texture position, the delta values are updated for the next level of the histogram pyramid. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;   vec4 mask = vec4( lessThan( vec4(key_ix), hist ) );&lt;br /&gt;   texpos   += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );&lt;br /&gt;   key_ix   -= dot( sums.xyz, vec3(1.0)-mask.xyz );&lt;br /&gt;   delta_x  *= 0.5;&lt;br /&gt;   delta_y  *= 0.5;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After the traversal loop ends, we are already at the base level of the histogram pyramid. We find the raw value at the texture lookup position again calculating the sum and the end ranges as earlier. Then the mask is calculated and the texture lookup position and the key index are updated. The actual value is then calculated.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;vec4 raw  = texture2DLod( histopyramid, texpos, 0.0 );&lt;br /&gt;sums = floor(raw);&lt;br /&gt;hist = sums;&lt;br /&gt;hist.w   += hist.z;&lt;br /&gt;hist.zw  += hist.yy;&lt;br /&gt;hist.yzw += hist.xxx;&lt;br /&gt;mask = vec4( lessThan( vec4(key_ix), hist ) );&lt;br /&gt;float nib = dot(vec4(mask), vec4(-1.0,-1.0,-1.0, 3.0));&lt;br /&gt;texpos   += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );&lt;br /&gt;key_ix   -= dot( sums.xyz, vec3(1.0)-mask.xyz );&lt;br /&gt;float val = fract( dot( raw, vec4(equal(vec4(nib),vec4(0,1,2,3))) ) );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, the 3D position of the vertex is calculated by multiplying the texture position with the tile size. The Z value is approximated using the Y tiling values.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;vec2 foo = vec2(TILE_X,TILE_Y)*texpos;&lt;br /&gt;vec2 tp = vec2( (2.0*TILE_X)/FUNC_X, (2.0*TILE_Y)/FUNC_Y ) * fract(foo);&lt;br /&gt;float slice = dot( vec2(1.0, TILE_Y), floor(foo));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lastly, the 3D coordinate is calculated as follows,&lt;br /&gt;    &lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;p = vec3(tp, slice)/vec3(1.0,1.0,TOTAL);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This position is then rendered, giving us the following output.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-8h9xzG7sPH0/TWDg9WnsHpI/AAAAAAAAAH0/5_eBp5-mHok/s1600/histoPyramid.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 316px; height: 320px;" src="http://4.bp.blogspot.com/-8h9xzG7sPH0/TWDg9WnsHpI/AAAAAAAAAH0/5_eBp5-mHok/s320/histoPyramid.png" border="0" alt="Histogram Pyramid" id="BLOGGER_PHOTO_ID_5575703683333365394" /&gt;&lt;/a&gt;&lt;br /&gt;The performance of the histogram pyramid is pretty fast. If u find anything interesting, do drop me an email.&lt;br /&gt;&lt;br /&gt;Happy OpenGL coding.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-1762388574921392894?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1762388574921392894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1762388574921392894' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1762388574921392894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1762388574921392894'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/02/implementing-histogram-pyramid.html' title='Implementing histogram pyramid'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-8h9xzG7sPH0/TWDg9WnsHpI/AAAAAAAAAH0/5_eBp5-mHok/s72-c/histoPyramid.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4556411962786171758</id><published>2011-02-06T17:29:00.000-08:00</published><updated>2011-11-18T22:32:01.766-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>A C++ class for GLSLShader</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I had written a pure C++ class called GLSLShader for handling the common GLSLShader compilation and linking chores. Here are the details:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Class Interface &lt;/b&gt;&lt;br /&gt;&lt;pre class="brush:cpp; "&gt; &lt;br /&gt;&lt;br /&gt;#pragma once&lt;br /&gt;#include &amp;lt;GL/glew.h&amp;gt;&lt;br /&gt;#include &amp;lt;map&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class GLSLShader&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt; GLSLShader(void);&lt;br /&gt; ~GLSLShader(void); &lt;br /&gt; void LoadFromString(GLenum whichShader, const string source);&lt;br /&gt; void LoadFromFile(GLenum whichShader, const string filename);&lt;br /&gt; void CreateAndLinkProgram();&lt;br /&gt; void Use();&lt;br /&gt; void UnUse();&lt;br /&gt; void AddAttribute(const string attribute);&lt;br /&gt; void AddUniform(const string uniform);&lt;br /&gt; GLuint GetProgram() const;&lt;br /&gt; //An indexer that returns the location of the attribute/uniform&lt;br /&gt; GLuint operator[](const string attribute);&lt;br /&gt; GLuint operator()(const string uniform);&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt; enum ShaderType {VERTEX_SHADER, FRAGMENT_SHADER, GEOMETRY_SHADER};&lt;br /&gt; GLuint _program;&lt;br /&gt; int _totalShaders;&lt;br /&gt; GLuint _shaders[3];//0-&amp;gt; vertexshader, 1-&amp;gt; fragmentshader, 2-&amp;gt; geometryshader&lt;br /&gt; map&amp;lt;string,gluint&amp;gt; _attributeList;&lt;br /&gt; map&amp;lt;string,gluint&amp;gt; _uniformLocationList;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The attributes and uniform locations are stored in a map which are populated once so that we dont get the locations of the attributes and uniforms everytime. Then using an indexer (using () or [] operator), the locations of the attribute and uniform are accessed so that client application can modify them as needed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Typical usage&lt;/b&gt; &lt;br /&gt;Create a reference first and then call the LoadFromFile function to load a GLSLShader from a text file or call LoadFromString to load a GLSL shader from a string. The first parameter is the shader type which may be (GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER). The second parameter is either the file name (for LoadFromFile function) or a string containing the shader contents (for LoadFromString function).&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;GLSLShader shader;&lt;br /&gt;shader.LoadFromFile(GL_VERTEX_SHADER,"Shader.vp");&lt;br /&gt;shader.LoadFromFile(GL_FRAGMENT_SHADER,"Shader.fp");&lt;/pre&gt;&lt;br /&gt;Next the call to compile and link is issued.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;shader.CreateAndLinkProgram();&lt;/pre&gt;&lt;br /&gt;Once compiled we may use the shader and then add the uniforms and attributes as needed. For one time uniforms, we may set their values here.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;shader.Use(); &lt;br /&gt;   shader.AddAttribute("vVertex");&lt;br /&gt;   shader.AddAttribute("vNormal");&lt;br /&gt;   shader.AddAttribute("vTexCoord");&lt;br /&gt;   shader.AddUniform("MVP");&lt;br /&gt;shader.UnUse();&lt;/pre&gt;&lt;br /&gt;When we want to get the location of any attribute for the vertex buffers, we may use the indexers as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glEnableVertexAttribArray(shader["vVertex"]);&lt;br /&gt;glVertexAttribPointer(shader["vVertex"],  4, GL_FLOAT, GL_FALSE, 0, 0);&lt;/pre&gt;&lt;br /&gt;Note that shader["vVertex"] returns the attribute location of "vVertex" attribute from the shader. Likewise, for handling of uniforms, we may do something like this in the render function,&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;shader.Use();&lt;br /&gt;   glUniformMatrix4fv(shader("MVP"), 1, GL_FALSE,  glm::value_ptr(MVP)); &lt;br /&gt;   glDrawElements(GL_TRIANGLES, ...);&lt;br /&gt;shader.UnUse();&lt;/pre&gt;&lt;br /&gt;The class also handles the deletion of program and shaders on exit making this a very compact class for handling of GLSLShaders. &lt;a href="http://www3.ntu.edu.sg/home2007/mova0002/test/GLSLShader.zip"&gt;Here&lt;/a&gt; are the source files.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4556411962786171758?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4556411962786171758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4556411962786171758' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4556411962786171758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4556411962786171758'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/02/c-class-for-glslshader.html' title='A C++ class for GLSLShader'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5424678341603150620</id><published>2011-01-25T20:11:00.000-08:00</published><updated>2011-12-09T16:08:26.452-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Mass spring system in OpenGL 3.3</title><content type='html'>Finally, I was able to code the mass spring shader using the vertex shader and info. given in Chapter 11 of OpenGL superbible fifth edition. The demo was missing from the opengl super bible 5th ed. svn as well as the book website. Basically, we need &lt;br /&gt;&lt;br /&gt;2 vaos -&gt; 1 for update and 1 for rendering&lt;br /&gt;4 vbos -&gt; 2 position and 2 velocities&lt;br /&gt;1 connection vbo&lt;br /&gt;1 indices vbo&lt;br /&gt;2 textures -&gt; for two texture buffer objects attached to the position VBO.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;VBO/VAO Setup&lt;/strong&gt;&lt;br /&gt;The code for setting this up is repetetive. This is how the VBOs and VAOs are setup.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;// create buffer object&lt;br /&gt;glGenVertexArrays(2, vaoUpdateID);&lt;br /&gt;glGenVertexArrays(2, vaoRenderID);&lt;br /&gt;&lt;br /&gt;glGenBuffers( 2, vboID_Pos);&lt;br /&gt;glGenBuffers( 2, vboID_Vel);&lt;br /&gt;glGenBuffers( 1, &amp;vboID_Con);&lt;br /&gt;glGenBuffers(1, &amp;vboIndices);&lt;br /&gt;glGenTextures(2, texPosID);&lt;br /&gt;  &lt;br /&gt;//set update vao&lt;br /&gt;for(int i=0;i&lt;2;i++) {&lt;br /&gt;  glBindVertexArray(vaoUpdateID[i]);&lt;br /&gt;  glBindBuffer( GL_ARRAY_BUFFER, vboID_Pos[i]);&lt;br /&gt;  glBufferData( GL_ARRAY_BUFFER, sizeof(position_mass_data), &amp;(position_mass_data[0]), GL_DYNAMIC_COPY);  &lt;br /&gt;  glEnableVertexAttribArray(0);&lt;br /&gt;    glVertexAttribPointer(0,  4, GL_FLOAT, GL_FALSE, 0, 0);&lt;br /&gt;  &lt;br /&gt;  glBindBuffer( GL_ARRAY_BUFFER, vboID_Vel[i]);&lt;br /&gt;  glBufferData( GL_ARRAY_BUFFER, sizeof(velocity_data), &amp;(velocity_data[0]), GL_DYNAMIC_COPY); &lt;br /&gt;  glEnableVertexAttribArray(1);&lt;br /&gt;  glVertexAttribPointer(1,  4, GL_FLOAT, GL_FALSE, 0,0);  &lt;br /&gt;&lt;br /&gt;  glBindBuffer( GL_ARRAY_BUFFER, vboID_Con);&lt;br /&gt;  if(i==0)&lt;br /&gt;    glBufferData( GL_ARRAY_BUFFER, sizeof(connection_data), &amp;(connection_data[0]), GL_STATIC_DRAW);&lt;br /&gt;&lt;br /&gt;  glEnableVertexAttribArray(2);   &lt;br /&gt;  glVertexAttribIPointer(2,  4, GL_INT, 0,0); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//set render vao&lt;br /&gt;for(int i=0;i&lt;2;i++) {&lt;br /&gt;  glBindVertexArray(vaoRenderID[i]);&lt;br /&gt;  glBindBuffer( GL_ARRAY_BUFFER, vboID_Pos[i]);&lt;br /&gt;  glEnableVertexAttribArray(0);&lt;br /&gt;  glVertexAttribPointer(0,  4, GL_FLOAT, GL_FALSE, 0, 0);&lt;br /&gt;&lt;br /&gt;  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndices);&lt;br /&gt;  if(i==0)&lt;br /&gt;    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &amp;indices[0], GL_STATIC_DRAW);&lt;br /&gt;}&lt;br /&gt;glBindVertexArray(0);&lt;br /&gt;&lt;br /&gt;//setup texture buffers&lt;br /&gt;for(int i=0;i&lt;2;i++) {&lt;br /&gt;  glBindTexture( GL_TEXTURE_BUFFER, texPosID[i]);&lt;br /&gt;  glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, vboID_Pos[i]);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Setting up transform feedback&lt;/strong&gt;&lt;br /&gt;For transform feedback, I have output two shader attributes out_position_mass and out_velocity as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;const char* varying_names[]={"out_position_mass", "out_velocity"}; &lt;br /&gt;glTransformFeedbackVaryings(massSpringShader.GetProgram(), 2, varying_names, GL_SEPARATE_ATTRIBS);  &lt;br /&gt;glLinkProgram(massSpringShader.GetProgram());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Transform feedback&lt;/strong&gt;&lt;br /&gt;The shader is first assigned and then the uniforms are sent to it. Finally the transform feedback buffer is bound to the position and velocity VBOs. I use basic ping pong technique to swap read and write buffers on each render.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;//attach shader and pass uniforms&lt;br /&gt;massSpringShader.Use();&lt;br /&gt;glUniformMatrix4fv(massSpringShader("MVP"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());   &lt;br /&gt;glUniform1f(massSpringShader("t"), 0.1f);&lt;br /&gt;glUniform1f(massSpringShader("k"),  k); &lt;br /&gt;glUniform1f(massSpringShader("c"),  c); &lt;br /&gt;glUniform1f(massSpringShader("rest_length"), l);&lt;br /&gt;&lt;br /&gt;//attach texture buffers&lt;br /&gt;glActiveTexture( GL_TEXTURE0);     &lt;br /&gt;glBindTexture( GL_TEXTURE_BUFFER, texPosID[writeID]);&lt;br /&gt;&lt;br /&gt;//attach the vao for updating the positions/velocities&lt;br /&gt;glBindVertexArray( vaoUpdateID[writeID]);&lt;br /&gt;glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vboID_Pos[readID]);&lt;br /&gt;glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, vboID_Vel[readID]);&lt;br /&gt;   &lt;br /&gt;glEnable(GL_RASTERIZER_DISCARD);    // disable rasterization&lt;br /&gt;glBeginTransformFeedback(GL_POINTS);&lt;br /&gt;   glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);&lt;br /&gt;      glDrawArrays(GL_POINTS, 0, MAX_MASSES);&lt;br /&gt;   glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);&lt;br /&gt;glEndTransformFeedback();&lt;br /&gt;glDisable(GL_RASTERIZER_DISCARD);  &lt;br /&gt;glGetQueryObjectuiv(query, GL_QUERY_RESULT, &amp;primitives_written);&lt;br /&gt;massSpringShader.UnUse();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Rendering of the mesh and masses&lt;/strong&gt;&lt;br /&gt;After the transform feedback, the rendering is carried out using the render VAO.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;glBindVertexArray(vaoRenderID[writeID]);&lt;br /&gt;&lt;br /&gt;renderShader.Use();&lt;br /&gt;   glUniformMatrix4fv(renderShader("MVP"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());  &lt;br /&gt;      glDrawElements(GL_TRIANGLE_STRIP, sizeof(indices)/sizeof(indices[0])  , GL_UNSIGNED_SHORT,0);    &lt;br /&gt;renderShader.UnUse();&lt;br /&gt;&lt;br /&gt;particleShader.Use();&lt;br /&gt;   glUniform1i(particleShader("selected_index"), selected_index);&lt;br /&gt;   glUniformMatrix4fv(particleShader("MV"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); &lt;br /&gt;   glUniformMatrix4fv(particleShader("MVP"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());          &lt;br /&gt;   //draw the masses last      &lt;br /&gt;   glDrawArrays(GL_POINTS, 0, MAX_MASSES);     &lt;br /&gt;particleShader.UnUse();   &lt;br /&gt;glBindVertexArray( 0);  &lt;br /&gt;&lt;br /&gt;//swap the read/write buffers for next frame&lt;br /&gt;int tmp = readID;&lt;br /&gt;readID=writeID;&lt;br /&gt;writeID = tmp;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Updating positions on modification&lt;/strong&gt;&lt;br /&gt;Handling update of positions when user selects a mass and uses arrow keys to move it is quite trivial. There are three ways to do it&lt;br /&gt;1) Use glBufferSubData to put the new positions again. While this approach is the most naive, its a waste of GPU resources. This can be achieved by the following call. (4*total_masses floats to be copied again)&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(position_mass_data), position_mass_data);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;2) Use glBufferSubData to only set the current position of the mass to the new value (4 floats to be copied again). &lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;glBufferSubData(GL_ARRAY_BUFFER, selected_index*4*sizeof(float) ,  4*sizeof(GLfloat), &amp;position_mass_data[selected_index*4]);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;3) Use glBufferSubData to only set the single (current) value i.e the y position of the mass to the new value (only 1 float to be copied again). This is the approach I use here,&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;switch(key) {&lt;br /&gt;case GLUT_KEY_UP: position_mass_data[selected_index*4+1]+= 0.1f; break;&lt;br /&gt;case GLUT_KEY_DOWN: position_mass_data[selected_index*4+1]-= 0.1f; break;&lt;br /&gt;}&lt;br /&gt;glBindVertexArray(vaoRenderID[readID]);&lt;br /&gt;  glBindBuffer(GL_ARRAY_BUFFER, vboID_Pos[writeID]);  &lt;br /&gt;  glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*(selected_index*4+1) ,  sizeof(GLfloat), &amp;position_mass_data[selected_index*4+1]);&lt;br /&gt;glBindVertexArray(0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Thats it. You have the mass spring model ready. Extending it for volume should be trivial. &lt;br /&gt;Here is a snapshot from the demo.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-CDbNXCEjEVM/Tbj-LC0F_9I/AAAAAAAAAIc/3W-H4rVIU4w/s1600/spr.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://4.bp.blogspot.com/-CDbNXCEjEVM/Tbj-LC0F_9I/AAAAAAAAAIc/3W-H4rVIU4w/s320/spr.png" border="0" alt="Mass sprin system OpenGL3.3" id="BLOGGER_PHOTO_ID_5600505602322595794" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is the VDO. You may also watch it on &lt;a href="http://www.youtube.com/watch?v=B_IE6E6J7zc"&gt;youtube&lt;/a&gt; The video shows how the individual masses may be modified and the effect passes on to the neighbours. In addition, I adjust the resting length of springs to show the effect it has on the simulation.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/B_IE6E6J7zc?hl=en&amp;fs=1"&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/B_IE6E6J7zc?hl=en&amp;fs=1" 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/8216868933119618528-5424678341603150620?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5424678341603150620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5424678341603150620' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5424678341603150620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5424678341603150620'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/01/mass-spring-system-in-opengl-33.html' title='Mass spring system in OpenGL 3.3'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-CDbNXCEjEVM/Tbj-LC0F_9I/AAAAAAAAAIc/3W-H4rVIU4w/s72-c/spr.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2278502663622694908</id><published>2011-01-25T08:53:00.000-08:00</published><updated>2011-07-30T20:57:01.792-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>OpenGL 3.0 and above deprecated func. and their replacement</title><content type='html'>Hi,&lt;br /&gt;  Here i am writing a quick reference list for deprecated functionality in OpenGL3.3 and its replacements. I will update this list regularly.&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Deprecated functionality&lt;/th&gt;&lt;th&gt;Replacement in OpenGL3.3&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fixed function pipeline&lt;/td&gt;&lt;td&gt;Shaders&lt;/td&gt;&lt;/tr&gt; &lt;br /&gt;&lt;tr&gt;&lt;td&gt;glRotate*/glTranslate*/glScale*&lt;br /&gt;/glMatrixMode/glLoadMatrix/glMultMatrix etc.&lt;/td&gt;&lt;td&gt;Use either a custom matrix library or public libraries like glm.&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;glTexEnvf&lt;/td&gt;&lt;td&gt;Combine textures in anyway using fragment shaders. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gluBuild2DMipmaps &lt;/td&gt;&lt;td&gt;Use either GL_GENERATE_MIPMAP texture parameter or the glGenerateMipmap function. Set the max mipmap level and the base mipmap level using &lt;blockquote&gt;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);&lt;/blockquote&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;glEnable(GL_POINT_SMOOTH)&lt;/td&gt;&lt;td&gt;Use custom shader&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;glEnable(GL_TEXTURE_2D)&lt;/td&gt;&lt;td&gt;No need. Ue glActiveTexture(GL_TEXTUREn) and bind the texture to the nth texture unit.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt; glVertex*/glColor*/glNormal*/glTexCoord*&lt;/td&gt;&lt;td&gt; Use vbo and vao to maintain the vbo states. Drawing is done using glDraw[Arrays,Elements, RangeElements, InterleavedElements etc.] functions.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;br /&gt;[to be contd.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2278502663622694908?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2278502663622694908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2278502663622694908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2278502663622694908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2278502663622694908'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/01/opengl-30-and-above-deprecated-func-and.html' title='OpenGL 3.0 and above deprecated func. and their replacement'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7722107100240718883</id><published>2011-01-25T08:29:00.000-08:00</published><updated>2011-12-09T16:09:06.176-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Point sprites as spheres in OpenGL3.3</title><content type='html'>Someone asked on opengl.org forums to generate sphere without any loop. It is possible to do so using particle sprites. The bulk of the stuff goes in the fragment shader which is as follows,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;#version 330&lt;br /&gt;out vec4 vFragColor;&lt;br /&gt;&lt;br /&gt;uniform vec3 Color;&lt;br /&gt;uniform vec3 lightDir;&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;    // calculate normal from texture coordinates&lt;br /&gt;    vec3 N;&lt;br /&gt;    N.xy = gl_PointCoord* 2.0 - vec2(1.0);    &lt;br /&gt;    float mag = dot(N.xy, N.xy);&lt;br /&gt;    if (mag &gt; 1.0) discard;   // kill pixels outside circle&lt;br /&gt;    N.z = sqrt(1.0-mag);&lt;br /&gt;&lt;br /&gt;    // calculate lighting&lt;br /&gt;    float diffuse = max(0.0, dot(lightDir, N));&lt;br /&gt;&lt;br /&gt;    vFragColor = vec4(Color,1) * diffuse;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;which first gets the normal from the texture coordinates. Then, it does a dot product of the normal with the light vector. Adding specular component should be trivial. This gives the following output. You may download the source code from &lt;a href="http://www.spacesimulator.net/wiki/index.php/3d_Engine_Projects"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TT77nI0x8BI/AAAAAAAAAHg/wG1hFlZ0xZY/s1600/particlesAsSpheres.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 258px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TT77nI0x8BI/AAAAAAAAAHg/wG1hFlZ0xZY/s320/particlesAsSpheres.png" border="0" alt="Point sprite as spheres" id="BLOGGER_PHOTO_ID_5566162839278841874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Adding in the specular term gives even better result. Have a look at this image.&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-YBSzL6o9ePI/TbDcpvHWS2I/AAAAAAAAAIE/arpAd0B714U/s1600/sp.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 249px;" src="http://3.bp.blogspot.com/-YBSzL6o9ePI/TbDcpvHWS2I/AAAAAAAAAIE/arpAd0B714U/s320/sp.png" border="0" alt="Point sprite as spheres with specular" id="BLOGGER_PHOTO_ID_5598216946401561442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This image was generated using the following shader.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;&lt;br /&gt;#version 330&lt;br /&gt;out vec4 vFragColor;&lt;br /&gt;&lt;br /&gt;uniform vec3 Color;&lt;br /&gt;uniform vec3 lightDir;&lt;br /&gt;float Ns = 250;&lt;br /&gt;vec4 mat_specular=vec4(1); &lt;br /&gt;vec4 light_specular=vec4(1); &lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;    // calculate normal from texture coordinates&lt;br /&gt;    vec3 N;&lt;br /&gt;    N.xy = gl_PointCoord* 2.0 - vec2(1.0);    &lt;br /&gt;    float mag = dot(N.xy, N.xy);&lt;br /&gt;    if (mag &gt; 1.0) discard;   // kill pixels outside circle&lt;br /&gt;    N.z = sqrt(1.0-mag);&lt;br /&gt;&lt;br /&gt;    // calculate lighting&lt;br /&gt;    float diffuse = max(0.0, dot(lightDir, N));&lt;br /&gt; &lt;br /&gt;    vec3 eye = vec3 (0.0, 0.0, 1.0);&lt;br /&gt;    vec3 halfVector = normalize( eye + lightDir);&lt;br /&gt;    float spec = max( pow(dot(N,halfVector), Ns), 0.); &lt;br /&gt;    vec4 S = light_specular*mat_specular* spec;&lt;br /&gt;    vFragColor = vec4(Color,1) * diffuse + S;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The spheres rendered this way will not change their size when we zoom in and out. I will show in a later blog entry how to do that by setting the point size in the vertex shader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7722107100240718883?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7722107100240718883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7722107100240718883' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7722107100240718883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7722107100240718883'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2011/01/point-sprites-as-spheres-in-opengl33.html' title='Point sprites as spheres in OpenGL3.3'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/TT77nI0x8BI/AAAAAAAAAHg/wG1hFlZ0xZY/s72-c/particlesAsSpheres.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2603951667835073149</id><published>2010-12-30T01:33:00.000-08:00</published><updated>2011-12-09T16:10:54.671-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Circular and arbitrary shaped point sprites in opengl 3.3</title><content type='html'>I recently tried to convert an old OpenGL source of mine OpenGL 2.1 i guess to OpenGL 3.3 based on the new core profile. To my surprise some of the functions like glEnable(GL_POINT_SMOOTH) are deprecated in the core profile and it generates an error. That meant I could not use the built-in facility to render smooth anti-aliased roudned points. I was looking out for solutions and then I figured out a simple way of doing it using the fragment shader. In OpenGL 3.0 and above, you can use the gl_PointCoord variable to obtain the point's uv coordinates (which are in range of 0-1). This variable is what I needed. To generate the circular point sprite, you can do the following&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;#version 330&lt;br /&gt;smooth out vec4 vFragColor;&lt;br /&gt;uniform vec4 vColor;&lt;br /&gt;&lt;br /&gt;void main() { &lt;br /&gt; &lt;br /&gt; if(dot(gl_PointCoord-0.5,gl_PointCoord-0.5)&gt;0.25) &lt;br /&gt;   discard;&lt;br /&gt; else&lt;br /&gt;   vFragColor = vColor;  &lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This gives the following output&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxUNjxZDOI/AAAAAAAAAGw/Pt6Ke8nFcjo/s1600/round.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 317px; height: 320px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxUNjxZDOI/AAAAAAAAAGw/Pt6Ke8nFcjo/s320/round.png" border="0" alt="Circular point sprites" id="BLOGGER_PHOTO_ID_5556408632185785570" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Which basically offsets the uv coordinates and then solves to see if the sqrt of distance is equal to 0.5 the radius of our point. I squre both sides to get the expression i have used. Similarly, a lot of interesting shapes could be generated as i show below. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Parametric coordinates:&lt;/strong&gt;&lt;br /&gt;We can use the parametric coordinate system (http://en.wikipedia.org/wiki/Polar_coordinate_system) to generate a lot of neat shapes of particles as I show below. For the polar coordinates, we need two things, radius and angle theta,&lt;br /&gt;We get radius using&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;vec2 p = gl_PointCoord* 2.0 - vec2(1.0);&lt;br /&gt;float r = sqrt(dot(p,p));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For theta, we use&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;float theta = atan(p.y,p.x);&lt;/pre&gt;&lt;br /&gt;Now I show u how to generate a lot of neat shapes based on the polar coordinate expressions on the wikipedia page linked above,&lt;br /&gt;&lt;strong&gt;Polar rose:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;if(dot(p,p) &gt; cos(theta*5))&lt;br /&gt;  discard;&lt;br /&gt;else &lt;br /&gt;  vFragColor = vColor;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This gives the following output,&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxV8Do_h6I/AAAAAAAAAG4/U1i5pNs3WYA/s1600/polar_rose.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 316px; height: 320px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxV8Do_h6I/AAAAAAAAAG4/U1i5pNs3WYA/s320/polar_rose.png" border="0" alt="POlar rose" id="BLOGGER_PHOTO_ID_5556410530526103458" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Round ring:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;if(dot(p,p) &gt; r || dot(p,p) &lt; r*0.75)&lt;br /&gt;  discard;&lt;br /&gt;else &lt;br /&gt;  vFragColor = vColor;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can change the multiplier to change the hole size.&lt;br /&gt;This gives the following output,&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TRxWuT5jAVI/AAAAAAAAAHI/zyY8fIQyfz8/s1600/polar_ring.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 270px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TRxWuT5jAVI/AAAAAAAAAHI/zyY8fIQyfz8/s320/polar_ring.png" border="0" alt="POlar ring" id="BLOGGER_PHOTO_ID_5556411393883963730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Spiral:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;if(dot(p,p)&gt; 5.0/cos(theta-20*r))&lt;br /&gt;  discard;&lt;br /&gt;else &lt;br /&gt;  vFragColor = vColor;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This gives the following output,&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TRxXoYf5yAI/AAAAAAAAAHQ/lNQJlGNMxgg/s1600/polar_spiral.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 318px; height: 320px;" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TRxXoYf5yAI/AAAAAAAAAHQ/lNQJlGNMxgg/s320/polar_spiral.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5556412391550994434" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Rounded star:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;if(dot(p,p) &gt; 0.5*(exp(cos(theta*5)*0.75)) )&lt;br /&gt;  discard;&lt;br /&gt;else &lt;br /&gt;  vFragColor = vColor;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This gives the following output,&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxYHEUX_gI/AAAAAAAAAHY/nLoEBu82C1A/s1600/polar_star.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 318px; height: 320px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxYHEUX_gI/AAAAAAAAAHY/nLoEBu82C1A/s320/polar_star.png" border="0" alt="Polar star" id="BLOGGER_PHOTO_ID_5556412918709878274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There might be other simpler ways of generating these shapes but these are some simpler ways to generate the various point sprite shapes.&lt;br /&gt;&lt;br /&gt;Happy OpenGL coding.&lt;br /&gt;Mobeen&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2603951667835073149?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2603951667835073149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2603951667835073149' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2603951667835073149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2603951667835073149'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/12/circular-point-sprites-in-opengl-33.html' title='Circular and arbitrary shaped point sprites in opengl 3.3'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/TRxUNjxZDOI/AAAAAAAAAGw/Pt6Ke8nFcjo/s72-c/round.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2363011253811349782</id><published>2010-11-29T00:11:00.000-08:00</published><updated>2011-12-09T16:11:12.063-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Order independent transparency (Dual depth peeling)</title><content type='html'>This information is extracted from the original NVIDIA whitepaper on dual depth peeling http://developer.download.nvidia.com/SDK/10.5/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf&lt;br /&gt;&lt;br /&gt;To sumup this is how it is implemented.&lt;br /&gt;You need two fbo (one for depth test and other for final blending), two depth textures(RG32F not depth attachments), two textures (front/back fragments) and a color blend final texture. The fbo setup code is as follows,&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;void setup_fbo() {&lt;br /&gt;glGenFramebuffersEXT(1, &amp;dualDepthfboID); &lt;br /&gt;glGenTextures (2, texID);&lt;br /&gt;glGenTextures (2, backTexID);&lt;br /&gt;glGenTextures (2, depthTexID);&lt;br /&gt;for(int i=0;i&lt;2;i++) {&lt;br /&gt;glBindTexture(GL_TEXTURE_RECTANGLE_ARB, depthTexID[i]);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP); &lt;br /&gt;glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,&lt;strong&gt;GL_FLOAT_RG32_NV&lt;/strong&gt;, width, height, 0, &lt;strong&gt;GL_RGB&lt;/strong&gt;, GL_FLOAT, NULL);&lt;br /&gt;&lt;br /&gt;glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texID[i]);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL);&lt;br /&gt;&lt;br /&gt;glBindTexture(GL_TEXTURE_RECTANGLE_ARB,backTexID[i]);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL); &lt;br /&gt;}&lt;br /&gt;glGenTextures(1, &amp;colorBlenderID);&lt;br /&gt;glBindTexture(GL_TEXTURE_RECTANGLE_ARB, colorBlenderID);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, &lt;strong&gt;GL_RGB&lt;/strong&gt;, width, height, 0, &lt;strong&gt;GL_RGB&lt;/strong&gt;, GL_FLOAT, 0);&lt;br /&gt;&lt;br /&gt;glGenFramebuffersEXT(1, &amp;colorBlenderFBOID);&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);&lt;br /&gt; &lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, colorBlenderID, 0);&lt;br /&gt;&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dualDepthfboID);&lt;br /&gt;CHECK_GL_ERRORS;&lt;br /&gt;&lt;br /&gt;int j = 0;&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[j], 0);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[j], 0);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_RECTANGLE_ARB, backTexID[j], 0);&lt;br /&gt;j = 1;&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[j], 0);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT4_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[j], 0);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT5_EXT, GL_TEXTURE_RECTANGLE_ARB, backTexID[j], 0);&lt;br /&gt;&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT6_EXT, GL_TEXTURE_RECTANGLE_ARB, colorBlenderID, 0);&lt;br /&gt;&lt;br /&gt;GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);&lt;br /&gt;if(status == GL_FRAMEBUFFER_COMPLETE_EXT )&lt;br /&gt;printf("OK for render to texture\n");&lt;br /&gt;else&lt;br /&gt;printf("Problem with FBO.");&lt;br /&gt;&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The rendering code is similar to the front to back depth peeling except that now the code initialized the depths twice once for front and next for back fragments in the same pass. This is accompalished using Min/Max blending as follows&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;//matrix manipulation stuff..&lt;br /&gt;glDisable(GL_DEPTH_TEST);&lt;br /&gt;glEnable(GL_BLEND);&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;// 1. Initialize Min-Max Depth Buffer&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dualDepthfboID);&lt;br /&gt;&lt;br /&gt;// Render targets 1 and 2 store the front and back colors&lt;br /&gt;// Clear to 0.0 and use MAX blending to filter written color&lt;br /&gt;// At most one front color and one back color can be written every pass&lt;br /&gt;glDrawBuffers(2, &amp;g_drawBuffers[1]);&lt;br /&gt;glClearColor(0, 0, 0, 0);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;// Render target 0 stores (-minDepth, maxDepth, alphaMultiplier)&lt;br /&gt;glDrawBuffer(g_drawBuffers[0]); &lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;glBlendEquationEXT(GL_MAX_EXT);&lt;br /&gt;g_shaderDualInit.bind();  &lt;br /&gt;   RenderScene(angle);  &lt;br /&gt;g_shaderDualInit.unbind();&lt;br /&gt;&lt;br /&gt;//The init shader above assigns float2(-1,1) to gl_FragCoord.xy;&lt;br /&gt;&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;// 2. Dual Depth Peeling + Blending&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;// Since we cannot blend the back colors in the geometry passes,&lt;br /&gt;// we use another render target to do the alpha blending&lt;br /&gt;glDrawBuffer(g_drawBuffers[6]);&lt;br /&gt;glClearColor(g_backgroundColor[0], g_backgroundColor[1], g_backgroundColor[2], 0);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;int currId = 0;&lt;br /&gt;for (int pass = 1; g_useOQ || pass &lt; NUM_PASSES; pass++) {&lt;br /&gt;currId = pass % 2;&lt;br /&gt;int prevId = 1 - currId;&lt;br /&gt;int bufId = currId * 3;&lt;br /&gt;&lt;br /&gt;glDrawBuffers(2, &amp;g_drawBuffers[bufId+1]);&lt;br /&gt;glClearColor(0, 0, 0, 0);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;glDrawBuffer(g_drawBuffers[bufId+0]);&lt;br /&gt;glClearColor(-MAX_DEPTH, -MAX_DEPTH, 0, 0);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;// Render target 0: RG32F MAX blending&lt;br /&gt;// Render target 1: RGBA MAX blending&lt;br /&gt;// Render target 2: RGBA MAX blending&lt;br /&gt;glDrawBuffers(3, &amp;g_drawBuffers[bufId+0]);&lt;br /&gt;glBlendEquationEXT(GL_MAX_EXT);&lt;br /&gt;g_shaderDualPeel.bind();&lt;br /&gt;g_shaderDualPeel.bindTextureRECT("DepthBlenderTex", depthTexID[prevId], 0);&lt;br /&gt;g_shaderDualPeel.bindTextureRECT("FrontBlenderTex", texID[prevId], 1);&lt;br /&gt;g_shaderDualPeel.setUniform("Alpha", (float*)&amp;g_opacity, 1);&lt;br /&gt; RenderScene(angle);&lt;br /&gt;g_shaderDualPeel.unbind();&lt;br /&gt;&lt;br /&gt;// Full screen pass to alpha-blend the back color&lt;br /&gt;glDrawBuffer(g_drawBuffers[6]);&lt;br /&gt;glBlendEquationEXT(GL_FUNC_ADD);&lt;br /&gt;glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);&lt;br /&gt;if (g_useOQ) {&lt;br /&gt;glBeginQuery(GL_SAMPLES_PASSED_ARB, g_queryId);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;g_shaderDualBlend.bind();&lt;br /&gt;g_shaderDualBlend.bindTextureRECT("TempTex", backTexID[currId], 0);&lt;br /&gt;  DrawFullScreenQuad();&lt;br /&gt;g_shaderDualBlend.unbind();&lt;br /&gt;&lt;br /&gt;if (g_useOQ) {&lt;br /&gt;glEndQuery(GL_SAMPLES_PASSED_ARB);&lt;br /&gt;GLuint sample_count;&lt;br /&gt;glGetQueryObjectuiv(g_queryId, GL_QUERY_RESULT_ARB, &amp;sample_count);&lt;br /&gt;if (sample_count == 0) {&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;glDisable(GL_BLEND);&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;// 3. Final Pass&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;glDrawBuffer(GL_BACK);&lt;br /&gt;g_shaderDualFinal.bind();&lt;br /&gt;g_shaderDualFinal.bindTextureRECT("DepthBlenderTex", depthTexID[currId], 0);&lt;br /&gt;g_shaderDualFinal.bindTextureRECT("FrontBlenderTex", texID[currId], 1);&lt;br /&gt;g_shaderDualFinal.bindTextureRECT("BackBlenderTex", colorBlenderID, 2);&lt;br /&gt; DrawFullScreenQuad();&lt;br /&gt;g_shaderDualFinal.unbind();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Thats it. The output this gives is as follows.&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/TPNjQ2RTNXI/AAAAAAAAAGk/OCq3XAfhJH4/s1600/dualdepthpeeling.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 248px;" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/TPNjQ2RTNXI/AAAAAAAAAGk/OCq3XAfhJH4/s320/dualdepthpeeling.png" border="0" alt="Dual Depth Peeling" id="BLOGGER_PHOTO_ID_5544884707320345970" /&gt;&lt;/a&gt;&lt;br /&gt;The inset displays the front and the back fragments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2363011253811349782?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2363011253811349782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2363011253811349782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2363011253811349782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2363011253811349782'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/11/order-independent-transparency-dual.html' title='Order independent transparency (Dual depth peeling)'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_sjK-Ll7Byw0/TPNjQ2RTNXI/AAAAAAAAAGk/OCq3XAfhJH4/s72-c/dualdepthpeeling.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8277997186230961215</id><published>2010-11-28T23:47:00.000-08:00</published><updated>2011-12-09T16:11:32.400-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Order independent transparency (Front to back depth peeling)</title><content type='html'>I had been looking through a lot of docs on order independent transparency. I started off with http://developer.nvidia.com/object/order_independent_transparency.html&lt;br /&gt;also called Front to Back Depth Peeling.&lt;br /&gt;This is how it works.&lt;br /&gt;&lt;br /&gt;You need three fbos, two fbos for depth sorting and one for final rendering. You need five fbo attachements in all, two for depth and two for front/back fragments and one texture for the final output. These are attached to the fbo as given in the setup code:&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;void setup_FBO() {&lt;br /&gt;glGenFramebuffersEXT(2, fbo); &lt;br /&gt;glGenTextures (2, texID);&lt;br /&gt;glGenTextures (2, depthTexID);&lt;br /&gt;for(int i=0;i&lt;2;i++) {&lt;br /&gt;  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, depthTexID[i]);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP); &lt;br /&gt;  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_DEPTH_COMPONENT32F_NV, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);&lt;br /&gt;&lt;br /&gt;  glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texID[i]);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB , 0,GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL);&lt;br /&gt;&lt;br /&gt;  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[i]);&lt;br /&gt;  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,     GL_TEXTURE_RECTANGLE_ARB, depthTexID[i], 0);&lt;br /&gt;  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, texID[i], 0);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;glGenTextures(1, &amp;colorBlenderID);&lt;br /&gt;glBindTexture(GL_TEXTURE_RECTANGLE_ARB, colorBlenderID);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, 0);&lt;br /&gt;&lt;br /&gt;glGenFramebuffersEXT(1, &amp;colorBlenderFBOID);&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, depthTexID[0], 0);&lt;br /&gt;glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, colorBlenderID, 0);&lt;br /&gt;&lt;br /&gt;GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);&lt;br /&gt;if(status == GL_FRAMEBUFFER_COMPLETE_EXT )&lt;br /&gt; printf("OK for render to texture\n");&lt;br /&gt;else&lt;br /&gt; printf("Problem");&lt;br /&gt;&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Next, the rendering code uses this information as follows&lt;br /&gt;&lt;br /&gt;//matrix setup and other stuff&lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);&lt;br /&gt;glDrawBuffer(g_drawBuffers[0]);&lt;br /&gt;glClearColor(0, 0, 0, 1);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );&lt;br /&gt;//In the first pass, we render normally with depth test enabled to get the nearest surface&lt;br /&gt;glEnable(GL_DEPTH_TEST);&lt;br /&gt;g_shaderFrontInit.bind();&lt;br /&gt;g_shaderFrontInit.setUniform("Alpha", (float*)&amp;g_opacity, 1);&lt;br /&gt;  RenderScene(angle); //do your rendering here&lt;br /&gt;g_shaderFrontInit.unbind();&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;// 2. Depth Peeling + Blending&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;int numLayers = (NUM_PASSES - 1) * 2;&lt;br /&gt;for (int layer = 1; g_useOQ || layer &lt; numLayers; layer++) {&lt;br /&gt;  int currId = layer % 2;&lt;br /&gt;  int prevId = 1 - currId;&lt;br /&gt;&lt;br /&gt;  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[currId]);&lt;br /&gt;  glDrawBuffer(g_drawBuffers[0]);&lt;br /&gt;  glClearColor(0, 0, 0, 0);&lt;br /&gt;  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;  glDisable(GL_BLEND);&lt;br /&gt;  glEnable(GL_DEPTH_TEST);&lt;br /&gt;  if (g_useOQ) {&lt;br /&gt;     glBeginQuery(GL_SAMPLES_PASSED_ARB, g_queryId);&lt;br /&gt;  }&lt;br /&gt;  g_shaderFrontPeel.bind();&lt;br /&gt;  g_shaderFrontPeel.bindTextureRECT("DepthTex", depthTexID[prevId], 0);&lt;br /&gt;  g_shaderFrontPeel.setUniform("Alpha", (float*)&amp;g_opacity, 1);&lt;br /&gt;     RenderScene(angle);&lt;br /&gt;  g_shaderFrontPeel.unbind();&lt;br /&gt;&lt;br /&gt;  if (g_useOQ) {&lt;br /&gt;    glEndQuery(GL_SAMPLES_PASSED_ARB);&lt;br /&gt;  }&lt;br /&gt;  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, colorBlenderFBOID);&lt;br /&gt;  glDrawBuffer(g_drawBuffers[0]);&lt;br /&gt;  glDisable(GL_DEPTH_TEST);&lt;br /&gt;  glEnable(GL_BLEND);&lt;br /&gt;  glBlendEquation(GL_FUNC_ADD);&lt;br /&gt;  glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE,GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);&lt;br /&gt;  g_shaderFrontBlend.bind();&lt;br /&gt;  g_shaderFrontBlend.bindTextureRECT("TempTex", texID[currId], 0);&lt;br /&gt;    DrawFullScreenQuad();&lt;br /&gt;  g_shaderFrontBlend.unbind();&lt;br /&gt;  glDisable(GL_BLEND);&lt;br /&gt;  if (g_useOQ) {&lt;br /&gt;   GLuint sample_count;&lt;br /&gt;   glGetQueryObjectuiv(g_queryId, GL_QUERY_RESULT_ARB, &amp;sample_count);&lt;br /&gt;   if (sample_count == 0) {&lt;br /&gt; break;&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;// 3. Final Pass&lt;br /&gt;// ---------------------------------------------------------------------&lt;br /&gt;//remove the render to texture and set the back buffer as render target &lt;br /&gt;glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;glDrawBuffer(GL_BACK);&lt;br /&gt;glDisable(GL_DEPTH_TEST); &lt;br /&gt;glDisable(GL_BLEND);&lt;br /&gt;&lt;br /&gt;//attach the blending shader&lt;br /&gt;g_shaderFrontFinal.bind();&lt;br /&gt;g_shaderFrontFinal.setUniform("BackgroundColor", g_backgroundColor, 3);&lt;br /&gt;g_shaderFrontFinal.bindTextureRECT("ColorTex", colorBlenderID, 0);&lt;br /&gt;   DrawFullScreenQuad();&lt;br /&gt;g_shaderFrontFinal.unbind();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Thats it, this gives the following output.&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TPNflXZcc5I/AAAAAAAAAGc/BaSZyFA4h1E/s1600/fronttobackblend.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 248px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TPNflXZcc5I/AAAAAAAAAGc/BaSZyFA4h1E/s320/fronttobackblend.png" border="0" alt="Dual Depth Peeling Front to Back" id="BLOGGER_PHOTO_ID_5544880661763748754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next, I will post infor on how to do dual depth peeling in opengl&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8277997186230961215?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8277997186230961215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8277997186230961215' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8277997186230961215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8277997186230961215'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/11/order-independent-transparency.html' title='Order independent transparency (Front to back depth peeling)'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/TPNflXZcc5I/AAAAAAAAAGc/BaSZyFA4h1E/s72-c/fronttobackblend.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5495416408147102696</id><published>2010-10-27T07:09:00.000-07:00</published><updated>2011-12-09T16:11:47.017-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Another image from my half angle slicer</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TMgy0Aj_4zI/AAAAAAAAAGU/CiC3kWS8h0o/s1600/halfAngle.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/TMgy0Aj_4zI/AAAAAAAAAGU/CiC3kWS8h0o/s320/halfAngle.png" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5532728011310228274" /&gt;&lt;/a&gt;&lt;br /&gt;Enjoy!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5495416408147102696?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5495416408147102696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5495416408147102696' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5495416408147102696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5495416408147102696'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/10/another-image-from-my-half-angle-slicer.html' title='Another image from my half angle slicer'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/TMgy0Aj_4zI/AAAAAAAAAGU/CiC3kWS8h0o/s72-c/halfAngle.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-6032248895748944703</id><published>2010-09-21T22:44:00.000-07:00</published><updated>2011-12-09T16:58:15.244-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Pathtracing'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>Comparing naive path tracing to bi-directional path tracing</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJma24p-3ZI/AAAAAAAAAGE/cTx0Md8xAWE/s1600/PathTracing.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 287px;" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJma24p-3ZI/AAAAAAAAAGE/cTx0Md8xAWE/s320/PathTracing.png" border="0" alt="Naive Path Tracing with 64 samples per pixel" id="BLOGGER_PHOTO_ID_5519613086031338898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt; Naive Path Tracing with 64 samples per pixel &lt;/h3&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TJma75gYXkI/AAAAAAAAAGM/lGINL8BOs5E/s1600/BiDirectionalPathTracing.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 287px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TJma75gYXkI/AAAAAAAAAGM/lGINL8BOs5E/s320/BiDirectionalPathTracing.png" border="0" alt="Bi-Directional Path Tracing with 32 samples per pixel" id="BLOGGER_PHOTO_ID_5519613172158848578" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt; Bi-Directional Path Tracing with 32 samples per pixel&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Here I am comparing the results of naive path tracing (top) with bi-directional path tracing (bottom). The later gives much better results at almost half the number of samples per pixel. Check the reflections on the spheres.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-6032248895748944703?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/6032248895748944703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=6032248895748944703' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6032248895748944703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6032248895748944703'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/comparing-path-tracing-to-bi.html' title='Comparing naive path tracing to bi-directional path tracing'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJma24p-3ZI/AAAAAAAAAGE/cTx0Md8xAWE/s72-c/PathTracing.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2960033228055546846</id><published>2010-09-17T18:48:00.001-07:00</published><updated>2011-12-09T16:57:41.503-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Pathtracing'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>Another image rendered from my GLSL based path tracer</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJQa0JbyfvI/AAAAAAAAAFU/OIYLMJYVcWg/s1600/none2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 294px;" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJQa0JbyfvI/AAAAAAAAAFU/OIYLMJYVcWg/s320/none2.jpg" border="0" alt="Another image rendered from my GLSL based path tracer" id="BLOGGER_PHOTO_ID_5518064926623694578" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2960033228055546846?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2960033228055546846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2960033228055546846' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2960033228055546846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2960033228055546846'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/another-image-rendered-from-my-glsl.html' title='Another image rendered from my GLSL based path tracer'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_sjK-Ll7Byw0/TJQa0JbyfvI/AAAAAAAAAFU/OIYLMJYVcWg/s72-c/none2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8216162085820392268</id><published>2010-09-14T07:05:00.000-07:00</published><updated>2011-07-30T21:02:21.623-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Pathtracing'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>Path tracing in GLSL</title><content type='html'>Finally, I was able to implement path tracing in GLSL. The results are stunning. Currently, my path tracer handles diffuse and specular shading. Adding refraction would be easy. Willl add it in a day or two.  Here is the video. The demo runs at 15 fps with 128 samples per ray.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/wDzGiDosv-w?hl=en&amp;fs=1"&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/wDzGiDosv-w?hl=en&amp;fs=1" 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/8216868933119618528-8216162085820392268?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8216162085820392268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8216162085820392268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8216162085820392268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8216162085820392268'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/path-tracing-in-glsl.html' title='Path tracing in GLSL'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8297881261938263678</id><published>2010-09-07T22:08:00.001-07:00</published><updated>2011-07-30T21:01:32.738-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>Area lights and soft shadows</title><content type='html'>I added area lights and soft shadows in my GLSL raytracer. The performance is quite good. The video contains 64 shadow rays per sample. &lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/47qNGBJuEKc?fs=1&amp;amp;hl=en_US"&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/47qNGBJuEKc?fs=1&amp;amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&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/8216868933119618528-8297881261938263678?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8297881261938263678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8297881261938263678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8297881261938263678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8297881261938263678'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/area-lights-and-soft-shadows.html' title='Area lights and soft shadows'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8899682368078547220</id><published>2010-09-07T02:26:00.001-07:00</published><updated>2011-07-30T21:01:32.739-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>GLSL based GPU Raytracer (Video)</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/XqDRDegB5yk?hl=en&amp;fs=1"&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/XqDRDegB5yk?hl=en&amp;fs=1" 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/8216868933119618528-8899682368078547220?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8899682368078547220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8899682368078547220' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8899682368078547220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8899682368078547220'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/glsl-based-gpu-raytracer-video.html' title='GLSL based GPU Raytracer (Video)'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1493453305049852461</id><published>2010-09-07T02:11:00.001-07:00</published><updated>2011-12-09T16:57:05.308-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>Some more raytraced results</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIYB4efJliI/AAAAAAAAAFM/afqSxJ5n5iA/s1600/r2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 247px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIYB4efJliI/AAAAAAAAAFM/afqSxJ5n5iA/s320/r2.png" border="0" alt="Some more GLSL raytracing results" id="BLOGGER_PHOTO_ID_5514096863529768482" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-1493453305049852461?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1493453305049852461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1493453305049852461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1493453305049852461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1493453305049852461'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/some-more-raytraced-results.html' title='Some more raytraced results'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIYB4efJliI/AAAAAAAAAFM/afqSxJ5n5iA/s72-c/r2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7796785409451597500</id><published>2010-09-05T22:20:00.000-07:00</published><updated>2011-12-09T16:56:39.670-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Raytracing'/><title type='text'>GLSL based GPU Raytracer</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIR6-E-MthI/AAAAAAAAAE8/4bnXDip2K3w/s1600/GPURaytracer.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 220px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIR6-E-MthI/AAAAAAAAAE8/4bnXDip2K3w/s320/GPURaytracer.png" border="0" alt=GLSL based GPU Raytracer"" id="BLOGGER_PHOTO_ID_5513667050713429522" /&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;Googling online i got a lot of links on GPU based raytracing. But I could not find a simple implementation so I thought I would give it a try. Here is the output obtained through my glsl raytracer. I will publish the details and workable source code later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7796785409451597500?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7796785409451597500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7796785409451597500' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7796785409451597500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7796785409451597500'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2010/09/glsl-based-gpu-raytracer.html' title='GLSL based GPU Raytracer'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/TIR6-E-MthI/AAAAAAAAAE8/4bnXDip2K3w/s72-c/GPURaytracer.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-105130984148174928</id><published>2009-10-29T06:35:00.001-07:00</published><updated>2011-12-09T16:56:21.862-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Half angle slicing</title><content type='html'>&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/Su5KwBpjNxI/AAAAAAAAAEs/CJWaFP8K-5g/s1600-h/snap.PNG"&gt;&lt;br /&gt;&lt;img style="MARGIN: 0px 0px 0px 0px; WIDTH: 320px; FLOAT: left; HEIGHT: 239px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5399335192200689426" border="0" alt="Half angle slicing" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/Su5KwBpjNxI/AAAAAAAAAEs/CJWaFP8K-5g/s320/snap.PNG" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/Su5BryLYBUI/AAAAAAAAAEk/o731UmQIbKs/s1600-h/snap.PNG"&gt;&lt;br /&gt;&lt;img style="MARGIN: 0px 0px 0px 0px; WIDTH: 320px; FLOAT: left; HEIGHT: 240px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5399325223723468098" border="0" alt="Half angle slicing" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/Su5BryLYBUI/AAAAAAAAAEk/o731UmQIbKs/s320/snap.PNG" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SuvoSnaOMjI/AAAAAAAAAEc/ePYYycZZxns/s1600-h/snap.PNG"&gt;&lt;br /&gt;&lt;img style="MARGIN: 0px 0px 0px 0px; WIDTH: 320px; FLOAT: left; HEIGHT: 250px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5398663984847925810" border="0" alt="Half angle slicing" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SuvoSnaOMjI/AAAAAAAAAEc/ePYYycZZxns/s320/snap.PNG" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SuvoSnaOMjI/AAAAAAAAAEc/ePYYycZZxns/s1600-h/snap.PNG"&gt;&lt;/a&gt;&lt;br /&gt;I was looking to implement Half angle slicing but&lt;br /&gt; due to some problems I was unable to get the results.&lt;br /&gt;see the image below. The problems included how to&lt;br /&gt;update the OpenGL blending order front to back&lt;br /&gt;and back to front for the light and eye buffers. &lt;br /&gt;Once this was sorted, I was still not getting the same&lt;br /&gt;output as was shown in the paper by Joe Kniss.&lt;br /&gt;So just today I noticed I was not clearing the eye&lt;br /&gt;and light buffers doing so removed the bugs. Finally,&lt;br /&gt;I managed to get it working. Compare the above images&lt;br /&gt;to this one.&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SumaO4yAT1I/AAAAAAAAAEU/LbMiWbxKHu0/s1600-h/snap.PNG"&gt;&lt;br /&gt;&lt;img style="MARGIN: 0px 0px 0px 0px; WIDTH: 320px; FLOAT: left; HEIGHT: 251px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5398015208931217234" border="0" alt="Half angle slicing" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SumaO4yAT1I/AAAAAAAAAEU/LbMiWbxKHu0/s320/snap.PNG" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-105130984148174928?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/105130984148174928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=105130984148174928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/105130984148174928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/105130984148174928'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/10/half-angle-slicing.html' title='Half angle slicing'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_sjK-Ll7Byw0/Su5KwBpjNxI/AAAAAAAAAEs/CJWaFP8K-5g/s72-c/snap.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-6202187507270818115</id><published>2009-05-23T02:36:00.000-07:00</published><updated>2011-12-09T16:54:56.871-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Half angle slicing</title><content type='html'>&lt;meta name="HalfAngleSlicing" content="3D texture slicing, view aligned, half angle slicing"/&gt;&lt;br /&gt;&lt;br /&gt;Half angle slicing is a really wonderful technique invented by Joe Kniss. The details are given in GPUGems1-Chapter 39. I implemented it and the results are amazing. I will post videos after the whole thing is finished. Till then, enjoy some snapshots.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/ShfIAOjFTQI/AAAAAAAAADk/XI8WQDTJAkA/s1600-h/a.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/ShfIAOjFTQI/AAAAAAAAADk/XI8WQDTJAkA/s320/a.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955789501811970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/ShfIL9_s4wI/AAAAAAAAAEM/sVmCwE8-ZkY/s1600-h/f.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/ShfIL9_s4wI/AAAAAAAAAEM/sVmCwE8-ZkY/s320/f.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955991216874242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/ShfILlOuwpI/AAAAAAAAAEE/tWOsM9po7j0/s1600-h/e.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 251px;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/ShfILlOuwpI/AAAAAAAAAEE/tWOsM9po7j0/s320/e.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955984569025170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/ShfILvyE73I/AAAAAAAAAD8/zRYojv2ewTI/s1600-h/d.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 251px;" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/ShfILvyE73I/AAAAAAAAAD8/zRYojv2ewTI/s320/d.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955987401633650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/ShfILd5R3aI/AAAAAAAAAD0/LUUrW8c_HaM/s1600-h/c.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 251px;" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/ShfILd5R3aI/AAAAAAAAAD0/LUUrW8c_HaM/s320/c.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955982600002978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/ShfILLN1K9I/AAAAAAAAADs/h3eUXXVkpu4/s1600-h/b.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 251px;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/ShfILLN1K9I/AAAAAAAAADs/h3eUXXVkpu4/s320/b.PNG" border="0" alt="Half angle slicing" id="BLOGGER_PHOTO_ID_5338955977585929170" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-6202187507270818115?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/6202187507270818115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=6202187507270818115' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6202187507270818115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6202187507270818115'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/05/half-angle-slicing.html' title='Half angle slicing'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/ShfIAOjFTQI/AAAAAAAAADk/XI8WQDTJAkA/s72-c/a.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5394474164279931764</id><published>2009-05-01T05:11:00.001-07:00</published><updated>2011-07-30T21:00:44.199-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>GPU based raycasting with MIP ray function</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/O76im8h0_JU&amp;hl=en&amp;fs=1"&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/O76im8h0_JU&amp;hl=en&amp;fs=1" 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/8216868933119618528-5394474164279931764?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5394474164279931764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5394474164279931764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5394474164279931764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5394474164279931764'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/05/gpu-based-raycasting-with-mip-ray.html' title='GPU based raycasting with MIP ray function'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7325910830484189985</id><published>2009-05-01T04:54:00.001-07:00</published><updated>2011-07-30T21:00:44.199-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>GPU based raycasting with average ray function</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/54PNhxp0oz4&amp;hl=en&amp;fs=1"&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/54PNhxp0oz4&amp;hl=en&amp;fs=1" 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/8216868933119618528-7325910830484189985?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7325910830484189985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7325910830484189985' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7325910830484189985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7325910830484189985'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/05/gpu-based-raycasting-with-average-ray.html' title='GPU based raycasting with average ray function'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5532648345027657877</id><published>2009-04-12T06:45:00.000-07:00</published><updated>2011-07-30T21:00:44.199-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>GPU ray casting with iso-surface function.</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Tt6g6cTikg8&amp;hl=en&amp;fs=1"&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/Tt6g6cTikg8&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;Yet another demo. Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5532648345027657877?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5532648345027657877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5532648345027657877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5532648345027657877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5532648345027657877'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/04/gpu-ray-casting-with-iso-surface.html' title='GPU ray casting with iso-surface function.'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1727072627957814566</id><published>2009-04-08T03:27:00.000-07:00</published><updated>2011-12-09T16:54:13.949-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><title type='text'>Screen space water on GPU</title><content type='html'>I saw an interesting demo from NVIDIA in the OpenGL sdk using render to 3D texture functionality to run a realtime water simulation. I thought I would replicate the same thing in 2D atleast to get started. So here it is. &lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/S95zM2rDwOQ&amp;hl=en&amp;fs=1"&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/S95zM2rDwOQ&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The reference for this was &lt;a href="http://freespace.virgin.net/hugo.elias/graphics/x_water.htm" &gt;this&lt;/a&gt; wonderful article. The snapshot from the application is on the top. Here is how I implemented this on OpenGL. I created 3 textures and attached them to the three color attachments using the FBO. The first color attachement was for the 3D scene (the teapot and the plane). The second and third color attachments were for the water simulation. Basically I have simply converted the main code given in the article. See it for details in this regard. In the display function, first the scene is rendered and then the water simulation is rendered by ping pongging btw color attachment 1 and 2. The complete fragment shader for water is given below&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;fragment_out fragment_water( frag_vertex IN, &lt;br /&gt;        uniform sampler2D currentMap, &lt;br /&gt;        uniform sampler2D prevMap)&lt;br /&gt;{ &lt;br /&gt;  fragment_out OUT;  &lt;br /&gt;  float4 smoothed;&lt;br /&gt;  float4 prev = tex2D(prevMap, IN.UV);&lt;br /&gt;&lt;br /&gt;  smoothed  = tex2D(currentMap, IN.UV + float2(s.x, 0));&lt;br /&gt;  smoothed += tex2D(currentMap, IN.UV + float2(-s.x,0));&lt;br /&gt;  smoothed += tex2D(currentMap, IN.UV + float2(0, s.y));&lt;br /&gt;  smoothed += tex2D(currentMap, IN.UV + float2(0,-s.y));&lt;br /&gt;  smoothed /= 4.0;&lt;br /&gt;  OUT.Color = (smoothed*2.0 - prev)*damping;&lt;br /&gt;  return OUT;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;After this, we have three rendered outputs the first one containing the rendering result, the second and third contain the water buffer. These textures are then used in another fragment shader to show the final output. The fragment shader is given below.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;fragment_out fragment_main( frag_vertex IN, &lt;br /&gt;       uniform sampler2D buffer,&lt;br /&gt;       uniform sampler2D textureMap)&lt;br /&gt;{&lt;br /&gt;   fragment_out OUT; &lt;br /&gt;   float Xoffset = tex2D(buffer, IN.UV+half2(-s.x, 0)) - &lt;br /&gt;                   tex2D(buffer, IN.UV+half2(s.x, 0));&lt;br /&gt;   float Yoffset = tex2D(buffer, IN.UV+half2(0, -s.y)) - &lt;br /&gt;                   tex2D(buffer, IN.UV+half2(0, s.y));&lt;br /&gt;   half4 t = tex2D(textureMap, IN.UV+half2(Xoffset,Yoffset));&lt;br /&gt;   OUT.Color =  t+half4(Xoffset);       &lt;br /&gt;   return OUT;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;This gives the result shown in the image below. &lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-8lGy9fUW8s4/Tbj-swEp6lI/AAAAAAAAAIk/5Sr9OH17jFg/s1600/w.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 294px; height: 284px;" src="http://3.bp.blogspot.com/-8lGy9fUW8s4/Tbj-swEp6lI/AAAAAAAAAIk/5Sr9OH17jFg/s320/w.png" border="0" alt="Screen space water on GPU" id="BLOGGER_PHOTO_ID_5600506181407337042" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Rest is just openGL bits and pieces.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-1727072627957814566?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1727072627957814566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1727072627957814566' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1727072627957814566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1727072627957814566'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/04/screen-space-water-on-gpu.html' title='Screen space water on GPU'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-8lGy9fUW8s4/Tbj-swEp6lI/AAAAAAAAAIk/5Sr9OH17jFg/s72-c/w.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-231403426292274330</id><published>2009-03-11T01:58:00.000-07:00</published><updated>2011-07-30T21:02:40.324-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><title type='text'>A cool screen space magnifier</title><content type='html'>Hi,&lt;br /&gt;   After working on the raindrop shader, i was able to come up with this magnifier in less than half an hour. Enjoy!!!&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/mZhfdFxd-lA&amp;hl=en&amp;fs=1"&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/mZhfdFxd-lA&amp;hl=en&amp;fs=1" 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/8216868933119618528-231403426292274330?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/231403426292274330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=231403426292274330' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/231403426292274330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/231403426292274330'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/03/cool-screen-space-magnifier.html' title='A cool screen space magnifier'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2407116474663157987</id><published>2009-03-10T20:04:00.000-07:00</published><updated>2011-07-30T21:02:40.325-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><title type='text'>Rain drops on the camera screen</title><content type='html'>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/OfIHtigij9s&amp;hl=en&amp;fs=1"&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/OfIHtigij9s&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;I was playing around with some post processing effects. Here is a cool effect of water drops dropping on the camera screen. It looks amazing. Enjoy!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2407116474663157987?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2407116474663157987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2407116474663157987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2407116474663157987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2407116474663157987'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/03/rain-drops-on-camera-screen.html' title='Rain drops on the camera screen'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2313879988401136843</id><published>2009-01-15T18:33:00.000-08:00</published><updated>2011-07-30T21:00:44.200-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Something interesting 3D texture slicing with spheremapping</title><content type='html'>Check this out!!!&lt;br /&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ZvRkG_Bt73I&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/ZvRkG_Bt73I&amp;hl=en&amp;fs=1" 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/8216868933119618528-2313879988401136843?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2313879988401136843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2313879988401136843' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2313879988401136843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2313879988401136843'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2009/01/something-interesting-3d-texture.html' title='Something interesting 3D texture slicing with spheremapping'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-1082586575312214972</id><published>2008-11-09T20:20:00.000-08:00</published><updated>2011-07-30T21:00:44.200-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Watch a demo from my application</title><content type='html'>Check this out.&lt;br /&gt;&lt;object width="425" height="350"&gt; &lt;param name="movie" value="http://www.youtube.com/v/nWx4zRjb1t0"&gt; &lt;/param&gt; &lt;embed src="http://www.youtube.com/v/nWx4zRjb1t0" type="application/x-shockwave-flash" width="425" height="350"&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/8216868933119618528-1082586575312214972?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/1082586575312214972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=1082586575312214972' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1082586575312214972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/1082586575312214972'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/11/watch-demo-from-my-application.html' title='Watch a demo from my application'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-7468347382167367286</id><published>2008-10-25T22:34:00.000-07:00</published><updated>2011-07-30T21:03:18.879-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Win32/C++/Programming'/><title type='text'>Odd Magic Square NxN C++ code</title><content type='html'>The blogger interface is stupid it keeps formatting my input so I am attaching the whole cpp file. Get the &lt;a href=http://www.geocities.com/mobeen211/MagicSquare.cpp.zip&gt;C++ Code&lt;/a&gt;. Ofcourse rename the file remove the .zip extension&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-7468347382167367286?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/7468347382167367286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=7468347382167367286' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7468347382167367286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/7468347382167367286'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/10/odd-magic-square-nxn-c-code.html' title='Odd Magic Square NxN C++ code'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-9122662204484634993</id><published>2008-10-25T22:10:00.000-07:00</published><updated>2011-07-30T21:03:18.880-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Win32/C++/Programming'/><title type='text'>Magic Squares Algorithm &amp; C++ implementation</title><content type='html'>Hi all,&lt;br /&gt;This time around its something a bit tricky generating an odd magic square. Details are given everywhere. The wiki entry is sufficient, check it out http://en.wikipedia.org/wiki/Magic_square.&lt;br /&gt;&lt;br /&gt;I base on the same logic which is commonly followed the one up one right stepping strategy. Here is the pseudocode,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;//n is the dimension of magic square for a 3*3 square n=3; &lt;br&gt;&lt;br /&gt;int magic[n][n]={0};&lt;br&gt;&lt;br /&gt;curRow=0, curCol=1;&lt;br&gt;&lt;br /&gt;oldRow=0, oldCol=0;&lt;br&gt;&lt;br /&gt;count =0;&lt;br&gt;&lt;br /&gt;for(i=1;i&lt;=n;i++) &lt;br&gt;&lt;br /&gt;{    &lt;br&gt;&lt;br /&gt;   for(j=1;j&lt;=n;j++)      &lt;br&gt;&lt;br /&gt;   {       &lt;br&gt;&lt;br /&gt;      //See if we are into an empty cell       &lt;br&gt;&lt;br /&gt;      if( magic[curRow][curCol]==0 )       &lt;br&gt;&lt;br /&gt;      {           &lt;br&gt;&lt;br /&gt;          magic[curRow][curCol] = ++count;       &lt;br&gt;&lt;br /&gt;      }     &lt;br&gt;&lt;br /&gt;      else &lt;br&gt;&lt;br /&gt;      {        &lt;br&gt;  &lt;br /&gt;         //Move down from the previous row but keep the same column           &lt;br&gt;&lt;br /&gt;         magic[(oldRow+1)%n][oldCol] = ++count;           &lt;br&gt;&lt;br /&gt;         curRow = (oldRow+1)%n;           &lt;br&gt;&lt;br /&gt;         curCol = oldCol;       &lt;br&gt;&lt;br /&gt;      }        &lt;br&gt;&lt;br /&gt;      //Store the last row and column index        &lt;br&gt;&lt;br /&gt;      oldRow=curRow;       &lt;br&gt;&lt;br /&gt;      oldCol=curCol;        &lt;br&gt;&lt;br /&gt;      &lt;br&gt;&lt;br /&gt;      //Move one up and one right       &lt;br&gt;&lt;br /&gt;      curRow=(curRow-1)%n;       &lt;br&gt;&lt;br /&gt;      curCol=(curCol+1)%n;              &lt;br&gt;&lt;br /&gt;     &lt;br&gt;&lt;br /&gt;      //Wrap around the size       &lt;br&gt;&lt;br /&gt;      if(curRow&lt;0) &lt;br&gt;&lt;br /&gt;         curRow =n-1;&lt;br&gt;&lt;br /&gt;   }&lt;br&gt;&lt;br /&gt;}&lt;br&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-9122662204484634993?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/9122662204484634993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=9122662204484634993' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9122662204484634993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9122662204484634993'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/10/magic-squares-algorithm-c.html' title='Magic Squares Algorithm &amp; C++ implementation'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-6048996303515200020</id><published>2008-10-19T20:22:00.000-07:00</published><updated>2011-12-09T16:52:56.227-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Some recent stuff</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/SPv54D53ueI/AAAAAAAAACM/UQfefoYq1UU/s1600-h/liver1.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/SPv54D53ueI/AAAAAAAAACM/UQfefoYq1UU/s320/liver1.PNG" border="0" alt="GPU volume rendering recent stuff liver dataset" id="BLOGGER_PHOTO_ID_5259071731401210338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/SPv54e79WRI/AAAAAAAAACU/xfLJ8KmpfVw/s1600-h/liver2.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/SPv54e79WRI/AAAAAAAAACU/xfLJ8KmpfVw/s320/liver2.PNG" border="0" alt="GPU volume rendering of liver dataset" id="BLOGGER_PHOTO_ID_5259071738657724690" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-6048996303515200020?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/6048996303515200020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=6048996303515200020' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6048996303515200020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6048996303515200020'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/10/some-recent-stuff.html' title='Some recent stuff'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_sjK-Ll7Byw0/SPv54D53ueI/AAAAAAAAACM/UQfefoYq1UU/s72-c/liver1.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-3436376076519269094</id><published>2008-06-19T20:00:00.000-07:00</published><updated>2011-07-30T21:03:18.881-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Win32/C++/Programming'/><title type='text'>Getting a list of files of a specific extension in a specified folder in Win32 API for c/c++</title><content type='html'>Often in a Win32/C/C++ application, we need a function to go through a specific folder and snatch all files matching a specified extension. While there is support for doing so in C# but there is no convenient function to do it in Win32/C/C++. Here I am sharing the function I use quite often in my day to day applications. It might help others also.&lt;br /&gt;&lt;pre class="brush:cpp"&gt; &lt;br /&gt;&lt;br /&gt;void GetFileList (std::vector&lt;std::string&gt;&amp; list, std::string dir, std::string extension)&lt;br /&gt;{&lt;br /&gt; WIN32_FIND_DATA findData;&lt;br /&gt; HANDLE fileHandle;&lt;br /&gt; int flag = 1;&lt;br /&gt; std::string search ("*.");&lt;br /&gt; if (dir.length() == 0) dir = ".";&lt;br /&gt; dir += "/";&lt;br /&gt; //search = dir + search + extension;&lt;br /&gt; std::string temp = dir;&lt;br /&gt; temp.append(search);&lt;br /&gt; temp.append(extension);&lt;br /&gt; search = temp;&lt;br /&gt; // SetCurrentDirectory(dir.c_str());&lt;br /&gt; fileHandle = FindFirstFile(search.c_str(), &amp;findData);&lt;br /&gt; &lt;br /&gt; if (fileHandle == INVALID_HANDLE_VALUE) return;&lt;br /&gt; while (flag)&lt;br /&gt; {&lt;br /&gt;  list.push_back(findData.cFileName);&lt;br /&gt;  flag = FindNextFile(fileHandle, &amp;findData);&lt;br /&gt; }&lt;br /&gt; FindClose(fileHandle);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-3436376076519269094?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/3436376076519269094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=3436376076519269094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/3436376076519269094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/3436376076519269094'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/getting-list-of-files-of-specific.html' title='Getting a list of files of a specific extension in a specified folder in Win32 API for c/c++'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-8301634472666426306</id><published>2008-06-10T19:56:00.000-07:00</published><updated>2011-12-09T16:52:11.942-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Here's something intersting</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE8_CIPxafI/AAAAAAAAACA/YXkORMQXEng/s1600-h/Bonsai.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE8_CIPxafI/AAAAAAAAACA/YXkORMQXEng/s320/Bonsai.PNG" border="0" alt="Something interesting" id="BLOGGER_PHOTO_ID_5210452599696878066" /&gt;&lt;/a&gt;&lt;br /&gt;Check this out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-8301634472666426306?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/8301634472666426306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=8301634472666426306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8301634472666426306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/8301634472666426306'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/heres-something-intersting.html' title='Here&apos;s something intersting'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE8_CIPxafI/AAAAAAAAACA/YXkORMQXEng/s72-c/Bonsai.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-6744515540187534647</id><published>2008-06-09T06:55:00.001-07:00</published><updated>2011-12-09T16:51:59.668-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Light makes a very big difference.</title><content type='html'>&lt;p&gt;&lt;br /&gt;Don't believe me take at a look at the snapshots yourself. I have added gradient based lighting on the 2D object based texture slice volume rendering.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE02oRQqZPI/AAAAAAAAABw/0rbo0csK6IU/s1600-h/engineNew1.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE02oRQqZPI/AAAAAAAAABw/0rbo0csK6IU/s320/engineNew1.PNG" border="0" alt="Lit engine volume rendering" id="BLOGGER_PHOTO_ID_5209880409393489138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE02ounlKbI/AAAAAAAAAB4/S8ImxJ04W34/s1600-h/engineNew2.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE02ounlKbI/AAAAAAAAAB4/S8ImxJ04W34/s320/engineNew2.PNG" border="0" alt="Lit engine volume rendering" id="BLOGGER_PHOTO_ID_5209880417274243506" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-6744515540187534647?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/6744515540187534647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=6744515540187534647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6744515540187534647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/6744515540187534647'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/light-makes-very-big-difference.html' title='Light makes a very big difference.'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/SE02oRQqZPI/AAAAAAAAABw/0rbo0csK6IU/s72-c/engineNew1.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-5581370461341291898</id><published>2008-06-08T02:03:00.001-07:00</published><updated>2011-12-09T16:51:20.828-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Transfer function loaded into 2D object based texture slicing</title><content type='html'>&lt;p&gt;&lt;br /&gt;Today, I added the transfer functions. First I made a simple class to wrap a transfer function. This class has a very easy interface. To add color point curve, simply call &lt;em&gt;TransferFunction::AddPoint(int intensity, float opacity).&lt;/em&gt; Then I added it to my object based 2D texture slicer. See the snapshots for details.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SEuhe2hS1tI/AAAAAAAAABo/9ihEkwIGgrg/s1600-h/transferFn.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SEuhe2hS1tI/AAAAAAAAABo/9ihEkwIGgrg/s320/transferFn.PNG" border="0" alt="Transfer function object based texture slicing" id="BLOGGER_PHOTO_ID_5209434945387419346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEugvShTMoI/AAAAAAAAABY/NbwTY-Bz2Ds/s1600-h/engineTF2.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEugvShTMoI/AAAAAAAAABY/NbwTY-Bz2Ds/s320/engineTF2.PNG" border="0" alt="Transfer function object based texture slicing" id="BLOGGER_PHOTO_ID_5209434128269914754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_sjK-Ll7Byw0/SEugv85z0cI/AAAAAAAAABg/fuHPPrkrNWQ/s1600-h/engineTF.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_sjK-Ll7Byw0/SEugv85z0cI/AAAAAAAAABg/fuHPPrkrNWQ/s320/engineTF.PNG" border="0" alt="Transfer function object based texture slicing" id="BLOGGER_PHOTO_ID_5209434139647005122" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-5581370461341291898?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/5581370461341291898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=5581370461341291898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5581370461341291898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/5581370461341291898'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/transfer-function-loaded-into-2d-object.html' title='Transfer function loaded into 2D object based texture slicing'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sjK-Ll7Byw0/SEuhe2hS1tI/AAAAAAAAABo/9ihEkwIGgrg/s72-c/transferFn.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-4818778096880970612</id><published>2008-06-07T02:37:00.000-07:00</published><updated>2011-12-09T16:49:52.471-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>View aligned 3D Texture Slicing</title><content type='html'>&lt;p&gt;&lt;br /&gt;Today I did the View aligned 3D Texture Slicing. The only thing different here is that we have to get the intersection test between a plane parallel to the viewing plane and intersect it to the unit cube placed at origin.&lt;br /&gt;&lt;br /&gt;I will add transfer functions to this and the object aligned version later.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEpYcnpXxfI/AAAAAAAAABQ/zRnV3ugTtio/s1600-h/engine2.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEpYcnpXxfI/AAAAAAAAABQ/zRnV3ugTtio/s320/engine2.PNG" border="0" alt="View aligned 3d texture slicing" id="BLOGGER_PHOTO_ID_5209073167709488626" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-4818778096880970612?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/4818778096880970612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=4818778096880970612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4818778096880970612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/4818778096880970612'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/view-aligned-3d-texture-slicing.html' title='View aligned 3D Texture Slicing'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEpYcnpXxfI/AAAAAAAAABQ/zRnV3ugTtio/s72-c/engine2.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-2460591022684347877</id><published>2008-06-05T07:53:00.000-07:00</published><updated>2011-12-09T16:49:34.560-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPU Volume Rendering'/><title type='text'>Object aligned slice based volume rendering</title><content type='html'>&lt;p&gt;&lt;br /&gt;I just finished 2D texture slices based volume rendering today. Here are the snapshots of the application. Its damn fast. I will be adding some transfer function editing facility into it tomorrow.&lt;br /&gt;&lt;br /&gt;A cool idea though will now work on transfer functions and then view aligned slicing of 3D texture.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEkNa8C_xTI/AAAAAAAAABI/z61QuWUIFK0/s1600-h/engine.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEkNa8C_xTI/AAAAAAAAABI/z61QuWUIFK0/s320/engine.PNG" border="0" alt="Object aligned slicing" id="BLOGGER_PHOTO_ID_5208709200477144370" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Implementation details:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I used glut and OpenGL for this b/c I think its much more fast to develop applications in OpenGL and glut. First I determine the current view direction vector which is simply obtained using the following code&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;GLfloat&lt;/span&gt; matView[16];&lt;br /&gt;   glGetFloatv(GL_MODELVIEW_MATRIX, matView);&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;GLfloat&lt;/span&gt; viewDir[3]={ -matView[2], -matView[6], -matView[10]};&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;Next a 3d texture is loaded from the CT/MRI scans and then using this code, object space quad slices are generated. Here I am only giving the code for the PosZ axis. A slight modification is needed for the other axes.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color:#3333ff;"&gt;void&lt;/span&gt; DrawSliceZPos()&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;float&lt;/span&gt; zPos = 0.5;&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;float&lt;/span&gt; zAmt = -1.0f/zSlices;&lt;br /&gt;&lt;br /&gt;   glBindTexture(GL_TEXTURE_3D,textureID);&lt;br /&gt;   glBegin(GL_QUADS);&lt;br /&gt;&lt;br /&gt;   //offset the slice so its in the middle&lt;br /&gt;   zPos += zAmt/2.0f;&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;for&lt;/span&gt;(&lt;span style="color:#3333ff;"&gt;int&lt;/span&gt; i=zSlices-1;i&gt;=0;i--)&lt;br /&gt;   {&lt;br /&gt;      float tex = (((float)i)/zSlices);&lt;br /&gt;      glTexCoord3f(0,0,tex); glVertex3f(-0.5, -0.5, zPos);&lt;br /&gt;      glTexCoord3f(0,1,tex); glVertex3f(-0.5,  0.5, zPos);&lt;br /&gt;      glTexCoord3f(1,1,tex); glVertex3f( 0.5,  0.5, zPos);&lt;br /&gt;      glTexCoord3f(1,0,tex); glVertex3f( 0.5, -0.5, zPos);&lt;br /&gt;      zPos += zAmt;&lt;br /&gt;   }&lt;br /&gt;   glEnd();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The appropriate slices are drawn based on the maximum abs value of the current view direction as&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color:#3333ff;"&gt;switch&lt;/span&gt;(GetMaxDim(viewDir))&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;case&lt;/span&gt; 0:&lt;br /&gt;      &lt;span style="color:#3333ff;"&gt;if&lt;/span&gt;(viewDir[maxDim] &gt; 0.0f)&lt;br /&gt;         DrawSlicePosX();&lt;br /&gt;      &lt;span style="color:#3333ff;"&gt;else&lt;/span&gt;&lt;br /&gt;         DrawSliceNegX();&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;break&lt;/span&gt;;&lt;br /&gt;   ...&lt;br /&gt;   &lt;span style="color:#3333ff;"&gt;case&lt;/span&gt; n: ... and so on&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Thats it and finally the result is blended to produce the rendering as shown above.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-2460591022684347877?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/2460591022684347877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=2460591022684347877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2460591022684347877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/2460591022684347877'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/object-aligned-slice-based-volume.html' title='Object aligned slice based volume rendering'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/SEkNa8C_xTI/AAAAAAAAABI/z61QuWUIFK0/s72-c/engine.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-874674316351764865</id><published>2008-06-02T19:58:00.001-07:00</published><updated>2011-12-09T16:48:34.275-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>A simple 3d mesh viewer using C++,  JUCE and OpenGL</title><content type='html'>&lt;p&gt;&lt;br /&gt;This is the current project I am working on. Its made completely in C++ using JUCE and OpenGL. &lt;br /&gt;I had a lot of fun making this.  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_sjK-Ll7Byw0/SES1A6XPA7I/AAAAAAAAAA4/Upx8cpCwfmM/s1600-h/MV2.PNG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5207486096418472882" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand" alt="" src="http://1.bp.blogspot.com/_sjK-Ll7Byw0/SES1A6XPA7I/AAAAAAAAAA4/Upx8cpCwfmM/s320/MV2.PNG" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SESz2aXPA5I/AAAAAAAAAAo/KRG36SKs4yY/s1600-h/MV1.PNG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5207484816518218642" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand" alt="3d mesh viewer c++ JUCE OpenGL" src="http://3.bp.blogspot.com/_sjK-Ll7Byw0/SESz2aXPA5I/AAAAAAAAAAo/KRG36SKs4yY/s320/MV1.PNG" width="320" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8216868933119618528-874674316351764865?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/874674316351764865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=874674316351764865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/874674316351764865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/874674316351764865'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/06/simple-3d-mesh-viewer-using-c-juce-and.html' title='A simple 3d mesh viewer using C++,  JUCE and OpenGL'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_sjK-Ll7Byw0/SES1A6XPA7I/AAAAAAAAAA4/Upx8cpCwfmM/s72-c/MV2.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8216868933119618528.post-9217763034999482412</id><published>2008-05-24T01:36:00.000-07:00</published><updated>2011-12-09T16:48:13.241-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shader Stuff'/><title type='text'>A simple 3d wave CG shader</title><content type='html'>&lt;p&gt;&lt;br /&gt;I have been doing GPU programming for a while and during my learning I made this small demo showing a 3D wave using OpenGL and GLSL. The idea is pretty simple though.&lt;br /&gt;&lt;br /&gt;Just for fun.&lt;br /&gt;&lt;/p&gt; &lt;a href="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SDfUnaXPA2I/AAAAAAAAAAQ/xTZfKRStqf0/s1600-h/RippleDemo.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5203861668006658914" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand" alt="3d wave shader" src="http://2.bp.blogspot.com/_sjK-Ll7Byw0/SDfUnaXPA2I/AAAAAAAAAAQ/xTZfKRStqf0/s320/RippleDemo.JPG" 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/8216868933119618528-9217763034999482412?l=mmmovania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mmmovania.blogspot.com/feeds/9217763034999482412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8216868933119618528&amp;postID=9217763034999482412' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9217763034999482412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8216868933119618528/posts/default/9217763034999482412'/><link rel='alternate' type='text/html' href='http://mmmovania.blogspot.com/2008/05/simple-3d-wave-cg-shader.html' title='A simple 3d wave CG shader'/><author><name>Mobeen</name><uri>http://www.blogger.com/profile/02716826252349695343</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_sjK-Ll7Byw0/SDfUnaXPA2I/AAAAAAAAAAQ/xTZfKRStqf0/s72-c/RippleDemo.JPG' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
