Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlVolume/SlicedVolume.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include <vlVolume/SlicedVolume.hpp>
00033 #include <vlGraphics/GLSL.hpp>
00034 #include <vlGraphics/Camera.hpp>
00035 #include <vlCore/Time.hpp>
00036 
00037 using namespace vl;
00038 
00077 //-----------------------------------------------------------------------------
00079 SlicedVolume::SlicedVolume()
00080 {
00081   VL_DEBUG_SET_OBJECT_NAME()
00082   mSliceCount = 1024;
00083   mGeometry = new Geometry;
00084   mGeometry->setObjectName("vl::SlicedVolume");
00085   
00086   fvec3 texc[] = 
00087   {
00088     fvec3(0,0,0), fvec3(1,0,0), fvec3(1,1,0), fvec3(0,1,0),
00089     fvec3(0,0,1), fvec3(1,0,1), fvec3(1,1,1), fvec3(0,1,1)
00090   };
00091   memcpy(mTexCoord, texc, sizeof(texc));
00092 }
00093 //-----------------------------------------------------------------------------
00102 void SlicedVolume::updateUniforms(Actor*actor, real, const Camera* camera, Renderable*, const Shader* shader)
00103 {
00104   const GLSLProgram* glsl = shader->getGLSLProgram();
00105 
00106   if (glsl->getUniformLocation("light_position") != -1 && glsl->getUniformLocation("light_enable") != -1)
00107   {
00108     // computes up to 4 light positions (in object space) and enables
00109 
00110     int light_enable[4] = { 0,0,0,0 };
00111     fvec3 light_position[4];
00112 
00113     for(int i=0; i<4; ++i)
00114     {
00115       const Light* light = shader->getLight(i);
00116       light_enable[i] = light != NULL;
00117       if (light)
00118       {
00119         // light position following transform
00120         if (light->boundTransform())
00121           light_position[i] = (fmat4)light->boundTransform()->worldMatrix() * light->position().xyz();
00122         // light position following camera
00123         else
00124           light_position[i] = ((fmat4)camera->modelingMatrix() * light->position()).xyz();
00125 
00126         // light position in object space
00127         if (actor->transform())
00128           light_position[i] = (fmat4)actor->transform()->worldMatrix().getInverse() * light_position[i];
00129       }
00130     }
00131 
00132     actor->gocUniform("light_position")->setUniform(4, light_position);
00133     actor->gocUniform("light_enable")->setUniform1i(4, light_enable);
00134   }
00135 
00136   if (glsl->getUniformLocation("eye_position") != -1)
00137   {
00138     // pass the eye position in object space
00139 
00140     // eye postion
00141     fvec3 eye = (fvec3)camera->modelingMatrix().getT();
00142     // world to object space
00143     if (actor->transform())
00144       eye = (fmat4)actor->transform()->worldMatrix().getInverse() * eye;
00145     actor->gocUniform("eye_position")->setUniform(eye);
00146   }
00147 }
00148 //-----------------------------------------------------------------------------
00149 namespace
00150 {
00151   class Edge
00152   {
00153   public:
00154     int v0, v1, intersection, flags;
00155     bool operator<(const Edge& other) const
00156     {
00157       return intersection > other.intersection;
00158     }
00159   };
00160 }
00161 //-----------------------------------------------------------------------------
00162 void SlicedVolume::bindActor(Actor* actor)
00163 {
00164   actor->actorEventCallbacks()->push_back( this );
00165   actor->setLod(0, mGeometry.get());
00166 }
00167 //-----------------------------------------------------------------------------
00168 void SlicedVolume::onActorRenderStarted(Actor* actor, real clock, const Camera* camera, Renderable* rend, const Shader* shader, int pass)
00169 {
00170   if (pass>0)
00171     return;
00172 
00173   // setup uniform variables
00174 
00175   if (shader->getGLSLProgram())
00176     updateUniforms(actor, clock, camera, rend, shader);
00177 
00178   // setup geometry: generate viewport aligned slices
00179 
00180   // skip generation is actor and camera did not move
00181   fmat4 mat;
00182   if (actor->transform())
00183     mat = (fmat4)(camera->viewMatrix() * actor->transform()->worldMatrix());
00184   else
00185     mat = (fmat4)camera->viewMatrix();
00186 
00187   if (mCache == mat)
00188     return;
00189   else
00190     mCache = mat;
00191 
00192   fmat4 imat = mat.getInverse();
00193 
00194   fvec3 cube_verts[] =
00195   {
00196     fvec3((float)box().minCorner().x(), (float)box().minCorner().y(), (float)box().minCorner().z()),
00197     fvec3((float)box().maxCorner().x(), (float)box().minCorner().y(), (float)box().minCorner().z()),
00198     fvec3((float)box().maxCorner().x(), (float)box().maxCorner().y(), (float)box().minCorner().z()),
00199     fvec3((float)box().minCorner().x(), (float)box().maxCorner().y(), (float)box().minCorner().z()),
00200     fvec3((float)box().minCorner().x(), (float)box().minCorner().y(), (float)box().maxCorner().z()),
00201     fvec3((float)box().maxCorner().x(), (float)box().minCorner().y(), (float)box().maxCorner().z()),
00202     fvec3((float)box().maxCorner().x(), (float)box().maxCorner().y(), (float)box().maxCorner().z()),
00203     fvec3((float)box().minCorner().x(), (float)box().maxCorner().y(), (float)box().maxCorner().z())
00204   };
00205 
00206   int min_idx = 0;
00207   int max_idx = 0;
00208   for(int i=0; i<8; ++i)
00209   {
00210     cube_verts[i] = mat * cube_verts[i];
00211     if (fabs(cube_verts[i].z()) < fabs(cube_verts[min_idx].z())) min_idx = i;
00212     if (fabs(cube_verts[i].z()) > fabs(cube_verts[max_idx].z())) max_idx = i;
00213   }
00214 
00215   if (cube_verts[min_idx].z() > 0)
00216   {
00217     // fixme?
00218     // the actor is not visible: remove the geometry or disable the actor?
00219     // return;
00220   }
00221 
00222   const int TOP    = 1;
00223   const int BOTTOM = 2;
00224   const int LEFT   = 4;
00225   const int RIGHT  = 8;
00226   const int FRONT  = 16;
00227   const int BACK   = 32;
00228 
00229   Edge edges[] =
00230   {
00231     {0,1,-1,FRONT |BOTTOM}, {1,2,-1,FRONT|RIGHT}, {2,3,-1,FRONT|TOP},  {3,0,-1,FRONT |LEFT},
00232     {4,5,-1,BACK  |BOTTOM}, {5,6,-1,BACK |RIGHT}, {6,7,-1,BACK |TOP},  {7,4,-1,BACK  |LEFT},
00233     {1,5,-1,BOTTOM|RIGHT},  {2,6,-1,TOP  |RIGHT}, {3,7,-1,TOP  |LEFT}, {0,4,-1,BOTTOM|LEFT}
00234   };
00235 
00236   std::vector<fvec3> points;
00237   std::vector<fvec3> points_t;
00238   std::vector<fvec3> polygons;
00239   std::vector<fvec3> polygons_t;
00240 
00241   polygons.reserve(sliceCount()*5);
00242   polygons_t.reserve(sliceCount()*5);
00243   float zrange = cube_verts[max_idx].z() - cube_verts[min_idx].z();
00244   float zstep  = zrange/(sliceCount()+1);
00245   int vert_idx[12];
00246   for(int islice=0; islice<sliceCount(); ++islice)
00247   {
00248     float z = cube_verts[max_idx].z() - zstep*(islice+1);
00249     fvec3 plane_o(0,0,z);
00250     fvec3 plane_n(0,0,1.0f);
00251     points.clear();
00252     points_t.clear();
00253     for(int iedge=0; iedge<12; ++iedge)
00254     {
00255       edges[iedge].intersection = -1;
00256       fvec3 vi  = cube_verts[ edges[iedge].v0 ];
00257       fvec3 eij = cube_verts[ edges[iedge].v1 ] - cube_verts[ edges[iedge].v0 ];
00258       float denom = dot(plane_n,eij);
00259       if (denom == 0)
00260         continue;
00261       float lambda = (z - dot(plane_n,vi))/denom;
00262       if (lambda<0 || lambda>1)
00263         continue;
00264       fvec3 v = vi + eij*lambda;
00265       edges[iedge].intersection = (int)points.size();
00266       points.push_back(v);
00267       fvec3 a = texCoords()[ edges[iedge].v0 ];
00268       fvec3 b = texCoords()[ edges[iedge].v1 ] - texCoords()[ edges[iedge].v0 ];
00269       fvec3 vt = a + b*lambda;
00270       points_t.push_back(vt);
00271     }
00272     std::sort(edges, edges+12);
00273     int vert_idx_c = 0;
00274     for(int ie0=0; ie0<12-1; ++ie0)
00275     {
00276       if (edges[ie0].intersection == -1)
00277         break;
00278       vert_idx[vert_idx_c++] = edges[ie0].intersection;
00279       for(int ie1=ie0+1; ie1<12; ++ie1)
00280       {
00281         if (edges[ie1].intersection == -1)
00282           continue;
00283         if( (edges[ie0].flags & edges[ie1].flags) )
00284         {
00285           Edge t       = edges[ie0+1];
00286           edges[ie0+1] = edges[ie1];
00287           edges[ie1]   = t;
00288           break;
00289         }
00290       }
00291     }
00292     for(int vc=0; vc<vert_idx_c-2; ++vc)
00293     {
00294       polygons.push_back(imat*points  [vert_idx[0]]);
00295       polygons.push_back(imat*points  [vert_idx[vc+1]]);
00296       polygons.push_back(imat*points  [vert_idx[vc+2]]);
00297       polygons_t.push_back(points_t[vert_idx[0]]);
00298       polygons_t.push_back(points_t[vert_idx[vc+1]]);
00299       polygons_t.push_back(points_t[vert_idx[vc+2]]);
00300     }
00301     #ifndef NDEBUG
00302       for(int ie0=0; ie0<12-1; ++ie0)
00303       {
00304         if (edges[ie0].intersection == -1)
00305           break;
00306         if (edges[ie0+1].intersection == -1)
00307           break;
00308         VL_CHECK(edges[ie0].flags & edges[ie0+1].flags)
00309       }
00310     #endif
00311   }
00312 
00313   mGeometry->drawCalls()->clear();
00314   ref<DrawArrays> da = new DrawArrays(PT_TRIANGLES, 0, (int)polygons.size());
00315   mGeometry->drawCalls()->push_back( da.get() );
00316   ref<ArrayFloat3> vertex_array = new ArrayFloat3;
00317   ref<ArrayFloat3> texcoo_array = new ArrayFloat3;
00318   vertex_array->resize(polygons.size());
00319   texcoo_array->resize(polygons_t.size());
00320   VL_CHECK((size_t)vertex_array->bufferObject()->bytesUsed() == sizeof(polygons  [0])*polygons.  size());
00321   VL_CHECK((size_t)texcoo_array->bufferObject()->bytesUsed() == sizeof(polygons_t[0])*polygons_t.size());
00322   memcpy(vertex_array->ptr(), &polygons  [0], vertex_array->bufferObject()->bytesUsed());
00323   memcpy(texcoo_array->ptr(), &polygons_t[0], texcoo_array->bufferObject()->bytesUsed());
00324   mGeometry->setVertexArray(vertex_array.get());
00325   mGeometry->setTexCoordArray(0,texcoo_array.get());
00326 
00327   mGeometry->setDisplayListDirty(true);
00328   mGeometry->setBufferObjectDirty(true);
00329 
00330   // fixme: 
00331   // it seems we have some problems with camera clipping/culling when the camera is close to the volume: the slices disappear or degenerate.
00332   // it does not seem to depend from camera clipping plane optimization.
00333 }
00334 //-----------------------------------------------------------------------------
00335 void SlicedVolume::generateTextureCoordinates(const ivec3& img_size)
00336 {
00337   if (!img_size.x() || !img_size.y() || !img_size.z())
00338   {
00339     Log::error("SlicedVolume::generateTextureCoordinates(): failed! The img_size passed does not represent a 3D image.\n");
00340     return;
00341   }
00342 
00343   float dx = 0.5f/img_size.x();
00344   float dy = 0.5f/img_size.y();
00345   float dz = 0.5f/img_size.z();
00346 
00347   float x0 = 0.0f + dx;
00348   float x1 = 1.0f - dx;
00349   float y0 = 0.0f + dy;
00350   float y1 = 1.0f - dy;
00351   float z0 = 0.0f + dz;
00352   float z1 = 1.0f - dz;
00353 
00354   fvec3 texc[] = 
00355   {
00356     fvec3(x0,y0,z0), fvec3(x1,y0,z0), fvec3(x1,y1,z0), fvec3(x0,y1,z0),
00357     fvec3(x0,y0,z1), fvec3(x1,y0,z1), fvec3(x1,y1,z1), fvec3(x0,y1,z1),
00358   };
00359   memcpy(mTexCoord, texc, sizeof(texc));
00360 }
00361 //-----------------------------------------------------------------------------
00362 void SlicedVolume::generateTextureCoordinates(const ivec3& img_size, const ivec3& min_corner, const ivec3& max_corner)
00363 {
00364     if (!img_size.x() || !img_size.y() || !img_size.z())
00365     {
00366         Log::error("SlicedVolume::setDisplayRegion(): failed! The size passed does not represent a 3D image.\n");
00367         return;
00368     }
00369 
00370     float dx = 0.5f/img_size.x();
00371     float dy = 0.5f/img_size.y();
00372     float dz = 0.5f/img_size.z();
00373 
00374     float x0 = min_corner.x()/(float)img_size.x() + dx;
00375     float x1 = max_corner.x()/(float)img_size.x() - dx;
00376     float y0 = min_corner.y()/(float)img_size.y() + dy;
00377     float y1 = max_corner.y()/(float)img_size.y() - dy;
00378     float z0 = min_corner.z()/(float)img_size.z() + dz;
00379     float z1 = max_corner.z()/(float)img_size.z() - dz;
00380 
00381     fvec3 texc[] = 
00382     {
00383         fvec3(x0,y0,z0), fvec3(x1,y0,z0), fvec3(x1,y1,z0), fvec3(x0,y1,z0),
00384         fvec3(x0,y0,z1), fvec3(x1,y0,z1), fvec3(x1,y1,z1), fvec3(x0,y1,z1)
00385     };
00386     memcpy(mTexCoord, texc, sizeof(texc));
00387 }
00388 //-----------------------------------------------------------------------------
00389 void SlicedVolume::setBox(const AABB& box) 
00390 {
00391   mBox = box; 
00392   mCache.fill(0);
00393   mGeometry->setBoundingBox( box );
00394   mGeometry->setBoundingSphere( box );
00395   mGeometry->setBoundsDirty(true);
00396 }
00397 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:44.
Permission is granted to use this page to write and publish articles regarding Visualization Library.