# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/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 v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:46.
Permission is granted to use this page to write and publish articles regarding Visualization Library.