Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://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 //-----------------------------------------------------------------------------