{"id":76,"date":"2010-07-24T23:28:25","date_gmt":"2010-07-24T21:28:25","guid":{"rendered":"http:\/\/blog.teleranek.org\/?p=76"},"modified":"2026-07-04T23:19:26","modified_gmt":"2026-07-04T21:19:26","slug":"papervision3d-real-time-level-of-detail-lod","status":"publish","type":"post","link":"https:\/\/blog.teleranek.org\/?p=76","title":{"rendered":"Papervision3D real-time level of detail ( LOD )"},"content":{"rendered":"<p>I&#8217;ve changed my old quadrics decimation library to make it run in real-time.<\/p>\n<p>Previous quadrics were intended to work with big meshes ( that is over 5000 faces, meshes with such number of faces slows pv3d down very much, and they can&#8217;t be used on the web ) and task of decimating such mesh involved converting to my mesh format ( instead of papervision&#8217;s TriangleMesh ), decimating and then converting back to TriangleMesh. This type of workflow excluded the possibility of real-time LOD ( for games for example ) because to make LOD work in real time in papervision, we must extend TriangleMesh class and refine geometry that is currently displayed on screen.<\/p>\n<p>New library, &#8220;qemlive&#8221; depends on HEMesh ( the name comes from Half-Edge mesh because it uses half-edges for adjacency lookup ) class that extends Papervision&#8217;s TriangleMesh class and during decimation, HEMesh refines TriangleMesh&#8217;es GeometryObject3D. It also remembers everything that was changed during decimation, to effectively revert decimation and come back to the original form of a mesh. To speed-up the decimation process, edge collapses don&#8217;t compute new vertex positions, best vertex is chosen among face&#8217;s vertices.<\/p>\n<p>Now, the examples ( notice the speed-up in fps )<br \/>\n<strong>CYLINDER<\/strong><br \/>\n<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"800\" height=\"600\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"name\" value=\"cylinder\" \/><param name=\"bgcolor\" value=\"#0\" \/><param name=\"align\" value=\"middle\" \/><param name=\"src\" value=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/cylinder.swf\" \/><embed type=\"application\/x-shockwave-flash\" width=\"800\" height=\"600\" src=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/cylinder.swf\" align=\"middle\" bgcolor=\"#0\" name=\"cylinder\"><\/embed><\/object><\/p>\n<p><strong>CUBE<\/strong><br \/>\n<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"800\" height=\"600\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"name\" value=\"cube\" \/><param name=\"bgcolor\" value=\"#0\" \/><param name=\"align\" value=\"middle\" \/><param name=\"src\" value=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/cube.swf\" \/><embed type=\"application\/x-shockwave-flash\" width=\"800\" height=\"600\" src=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/cube.swf\" align=\"middle\" bgcolor=\"#0\" name=\"cube\"><\/embed><\/object><br \/>\n<strong> <\/strong><br \/>\n<strong> SPHERE<\/strong><br \/>\n<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"800\" height=\"600\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"name\" value=\"sphere\" \/><param name=\"bgcolor\" value=\"#0\" \/><param name=\"align\" value=\"middle\" \/><param name=\"src\" value=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/sphere.swf\" \/><embed type=\"application\/x-shockwave-flash\" width=\"800\" height=\"600\" src=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/sphere.swf\" align=\"middle\" bgcolor=\"#0\" name=\"sphere\"><\/embed><\/object><br \/>\nHere, uv coords and normal&#8217;s prevervation ( described further ) was used to preserve spherical shape of the sphere<br \/>\n<strong> X-WING<\/strong><br \/>\n<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"800\" height=\"600\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"name\" value=\"cube\" \/><param name=\"bgcolor\" value=\"#0\" \/><param name=\"align\" value=\"middle\" \/><param name=\"src\" value=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/xwing.swf\" \/><embed type=\"application\/x-shockwave-flash\" width=\"800\" height=\"600\" src=\"http:\/\/blog.teleranek.org\/wp-content\/uploads\/2010\/07\/xwing.swf\" align=\"middle\" bgcolor=\"#0\" name=\"cube\"><\/embed><\/object><br \/>\n<strong> <\/strong><br \/>\nWhen decimating xwing, uv and normal preservation was used, to preserve two &#8220;antennas&#8221; in the front of the xwing. The texture mapping breaks down a bit while decimating, this is because there are many discontinuities in xwing&#8217;s texture.<\/p>\n<p>All models use almost the same decimation settings, only interpolation method was changed. There are many other settings that changes algorithm&#8217;s behaviour? but yah, too lazy to document it. Nobody likes to make a documentation I suppose ; )<\/p>\n<p>The library isn&#8217;t public-ready because the code is without documentation and with some debug variables ( as always :p ) but I&#8217;ve decided to show the source code, it&#8217;s available on googlecode:<br \/>\n<a href=\"http:\/\/code.google.com\/p\/bartekz\/source\/browse\/\">http:\/\/code.google.com\/p\/bartekz\/source\/browse<\/a><\/p>\n<p><a href=\"http:\/\/code.google.com\/p\/bartekz\/source\/browse\/\"><\/a><br \/>\nZipped qemlive:<br \/>\n<a href=\"http:\/\/code.google.com\/p\/bartekz\/downloads\/list\">http:\/\/code.google.com\/p\/bartekz\/downloads\/list<\/a><\/p>\n<p><a href=\"http:\/\/code.google.com\/p\/bartekz\/downloads\/list\"><\/a><br \/>\nDemo source ( not too clean, but the hell ? )<br \/>\n<a href=\"http:\/\/dl.dropbox.com\/u\/1268089\/QEMLive.as\">http:\/\/dl.dropbox.com\/u\/1268089\/QEMLive.as<\/a><\/p>\n<p>To instantiate HEMesh, just do this:<\/p>\n<p><code>var model:HEMesh = new HEMesh( null , null, null , TeleQEM.INTERPOLATE_UV_AND_NORMALS );<br \/>\nmodel.init( new Sphere( new WireframeMaterial(), 100 , 20 , 20 ) );<\/code><\/p>\n<p>See the null&#8217;s at the beginning of the constructor? This is one of the reason&#8217;s that this library isn&#8217;t &#8220;public-ready&#8221; :p<br \/>\nThe fourth parameter controls the way the mesh is decimated ( there are million of other parameters that you can figure out yourself in TeleQEM class ). The possible values are:<br \/>\n<code>TeleQEM.INTERPOLATE_NOTHING<\/code> &#8211; look only at geometry when decimating<br \/>\n<code>TeleQEM.INTERPOLATE_UV<\/code> &#8211; look at uv coordinates during decimation &#8211; algorithm tries to preserve correct uv mapping<br \/>\n<code>TeleQEM.INTERPOLATE_UV_AND_NORMAL<\/code>S &#8211; look at face normals during decimation as well as uv coordinates &#8211; algorithm tries to preserve correct shape of a geometry<\/p>\n<p>We can listen for mesh creation completion:<br \/>\n<code>model.addEventListener( Event.COMPLETE , initComplete );<\/code><\/p>\n<p><code> <\/code><\/p>\n<p><code>private function initComplete( e:Event ):void{<br \/>\ndo some stuff?<br \/>\n}<\/code><\/p>\n<p>To decimate triangles:<br \/>\n<code>model.newqem( model.numFaces*PERCENT_OF_FACES_WE_WANT_TO_LEAVE );<\/code><\/p>\n<p>We can set up a listener to listen for decimation completion:<\/p>\n<p><code>model.addEventListener( TeleQEM.COMPLETE_DECIMATION , decimationCompleted );<br \/>\nprivate function decimationCompleted( e:Event ):void{<br \/>\ndo some stuff?<br \/>\n}<\/code><\/p>\n<p>ps. This LOD can be optimized by changing as3&#8217;s arrays into vectors. My old decimation algorithm has been made for flash player 9, but the science moves forward &#8230; ;) So maybe this will be fixed in the future.<\/p>\n<p>ps2. During &#8220;undecimation&#8221;, geometry is &#8220;forgotten&#8221; to free up some memory. If it weren&#8217;t, the second decimation could use this fogotten information to decimate the model faster. I think I will make this as an option in HEMesh class in the next update of qemlive &#8211; to reuse the decimaton info.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve changed my old quadrics decimation library to make it run in real-time.<\/p>\n<p>Previous quadrics were intended to work with big meshes ( that is over 5000 faces, meshes with such number of faces slows pv3d down very much, and they can&#8217;t be used on the web ) and task of decimating such mesh involved converting to my mesh format ( instead of papervision&#8217;s TriangleMesh ), decimating and then converting back to TriangleMesh. This type of workflow excluded the possibility of real-time LOD ( for games for example ) because to make LOD work in real time in papervision, we must extend TriangleMesh class and refine geometry that is currently displayed on screen.<\/p>\n<p>New library, &#8220;qemlive&#8221; depends on HEMesh ( the name comes from Half-Edge mesh because it uses half-edges for adjacency lookup ) class that extends Papervision&#8217;s TriangleMesh class and during decimation, HEMesh refines TriangleMesh&#8217;es GeometryObject3D. It also remembers everything that was changed during decimation, to effectively revert decimation and come back to the original form of a mesh. To speed-up the decimation process, edge collapses don&#8217;t compute new vertex positions, best vertex is chosen among face&#8217;s vertices.<\/p>\n<p>Now, the examples ( notice the speed-up in fps ) &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[61,60,12,11,36],"class_list":["post-76","post","type-post","status-publish","format-standard","hentry","category-flash-experiments","tag-level-of-detail","tag-lod","tag-papervision","tag-pv3d","tag-qem"],"_links":{"self":[{"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/posts\/76","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=76"}],"version-history":[{"count":17,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/posts\/76\/revisions"}],"predecessor-version":[{"id":386,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=\/wp\/v2\/posts\/76\/revisions\/386"}],"wp:attachment":[{"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=76"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=76"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.teleranek.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=76"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}