00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00085 fvec3 texc[] =
00086 {
00087 fvec3(0,0,0), fvec3(1,0,0), fvec3(1,1,0), fvec3(0,1,0),
00088 fvec3(0,0,1), fvec3(1,0,1), fvec3(1,1,1), fvec3(0,1,1)
00089 };
00090 memcpy(mTexCoord, texc, sizeof(texc));
00091 }
00092
00101 void SlicedVolume::updateUniforms(Actor*actor, real, const Camera* camera, Renderable*, const Shader* shader)
00102 {
00103 const GLSLProgram* glsl = shader->getGLSLProgram();
00104
00105 if (glsl->getUniformLocation("light_position") != -1 && glsl->getUniformLocation("light_enable") != -1)
00106 {
00107
00108
00109 int light_enable[4] = { 0,0,0,0 };
00110 fvec3 light_position[4];
00111
00112 for(int i=0; i<4; ++i)
00113 {
00114 const Light* light = shader->getLight(i);
00115 light_enable[i] = light != NULL;
00116 if (light)
00117 {
00118
00119 if (light->boundTransform())
00120 light_position[i] = (fmat4)light->boundTransform()->worldMatrix() * light->position().xyz();
00121
00122 else
00123 light_position[i] = ((fmat4)camera->modelingMatrix() * light->position()).xyz();
00124
00125
00126 if (actor->transform())
00127 light_position[i] = (fmat4)actor->transform()->worldMatrix().getInverse() * light_position[i];
00128 }
00129 }
00130
00131 actor->gocUniform("light_position")->setUniform(4, light_position);
00132 actor->gocUniform("light_enable")->setUniform1i(4, light_enable);
00133 }
00134
00135 if (glsl->getUniformLocation("eye_position") != -1)
00136 {
00137
00138
00139
00140 fvec3 eye = (fvec3)camera->modelingMatrix().getT();
00141
00142 if (actor->transform())
00143 eye = (fmat4)actor->transform()->worldMatrix().getInverse() * eye;
00144 actor->gocUniform("eye_position")->setUniform(eye);
00145 }
00146 }
00147
00148 namespace
00149 {
00150 class Edge
00151 {
00152 public:
00153 int v0, v1, intersection, flags;
00154 bool operator<(const Edge& other) const
00155 {
00156 return intersection > other.intersection;
00157 }
00158 };
00159 }
00160
00161 void SlicedVolume::bindActor(Actor* actor)
00162 {
00163 actor->actorEventCallbacks()->push_back( this );
00164 actor->setLod(0, mGeometry.get());
00165 }
00166
00167 void SlicedVolume::onActorRenderStarted(Actor* actor, real clock, const Camera* camera, Renderable* rend, const Shader* shader, int pass)
00168 {
00169 if (pass>0)
00170 return;
00171
00172
00173
00174 if (shader->getGLSLProgram())
00175 updateUniforms(actor, clock, camera, rend, shader);
00176
00177
00178
00179
00180 fmat4 mat;
00181 if (actor->transform())
00182 mat = (fmat4)(camera->viewMatrix() * actor->transform()->worldMatrix());
00183 else
00184 mat = (fmat4)camera->viewMatrix();
00185
00186 if (mCache == mat)
00187 return;
00188 else
00189 mCache = mat;
00190
00191 fmat4 imat = mat.getInverse();
00192
00193 fvec3 cube_verts[] =
00194 {
00195 fvec3((float)box().minCorner().x(), (float)box().minCorner().y(), (float)box().minCorner().z()),
00196 fvec3((float)box().maxCorner().x(), (float)box().minCorner().y(), (float)box().minCorner().z()),
00197 fvec3((float)box().maxCorner().x(), (float)box().maxCorner().y(), (float)box().minCorner().z()),
00198 fvec3((float)box().minCorner().x(), (float)box().maxCorner().y(), (float)box().minCorner().z()),
00199 fvec3((float)box().minCorner().x(), (float)box().minCorner().y(), (float)box().maxCorner().z()),
00200 fvec3((float)box().maxCorner().x(), (float)box().minCorner().y(), (float)box().maxCorner().z()),
00201 fvec3((float)box().maxCorner().x(), (float)box().maxCorner().y(), (float)box().maxCorner().z()),
00202 fvec3((float)box().minCorner().x(), (float)box().maxCorner().y(), (float)box().maxCorner().z())
00203 };
00204
00205 int min_idx = 0;
00206 int max_idx = 0;
00207 for(int i=0; i<8; ++i)
00208 {
00209 cube_verts[i] = mat * cube_verts[i];
00210 if (fabs(cube_verts[i].z()) < fabs(cube_verts[min_idx].z())) min_idx = i;
00211 if (fabs(cube_verts[i].z()) > fabs(cube_verts[max_idx].z())) max_idx = i;
00212 }
00213
00214 if (cube_verts[min_idx].z() > 0)
00215 {
00216
00217
00218
00219 }
00220
00221 const int TOP = 1;
00222 const int BOTTOM = 2;
00223 const int LEFT = 4;
00224 const int RIGHT = 8;
00225 const int FRONT = 16;
00226 const int BACK = 32;
00227
00228 Edge edges[] =
00229 {
00230 {0,1,-1,FRONT |BOTTOM}, {1,2,-1,FRONT|RIGHT}, {2,3,-1,FRONT|TOP}, {3,0,-1,FRONT |LEFT},
00231 {4,5,-1,BACK |BOTTOM}, {5,6,-1,BACK |RIGHT}, {6,7,-1,BACK |TOP}, {7,4,-1,BACK |LEFT},
00232 {1,5,-1,BOTTOM|RIGHT}, {2,6,-1,TOP |RIGHT}, {3,7,-1,TOP |LEFT}, {0,4,-1,BOTTOM|LEFT}
00233 };
00234
00235 std::vector<fvec3> points;
00236 std::vector<fvec3> points_t;
00237 std::vector<fvec3> polygons;
00238 std::vector<fvec3> polygons_t;
00239
00240 polygons.reserve(sliceCount()*5);
00241 polygons_t.reserve(sliceCount()*5);
00242 float zrange = cube_verts[max_idx].z() - cube_verts[min_idx].z();
00243 float zstep = zrange/(sliceCount()+1);
00244 int vert_idx[12];
00245 for(int islice=0; islice<sliceCount(); ++islice)
00246 {
00247 float z = cube_verts[max_idx].z() - zstep*(islice+1);
00248 fvec3 plane_o(0,0,z);
00249 fvec3 plane_n(0,0,1.0f);
00250 points.clear();
00251 points_t.clear();
00252 for(int iedge=0; iedge<12; ++iedge)
00253 {
00254 edges[iedge].intersection = -1;
00255 fvec3 vi = cube_verts[ edges[iedge].v0 ];
00256 fvec3 eij = cube_verts[ edges[iedge].v1 ] - cube_verts[ edges[iedge].v0 ];
00257 float denom = dot(plane_n,eij);
00258 if (denom == 0)
00259 continue;
00260 float lambda = (z - dot(plane_n,vi))/denom;
00261 if (lambda<0 || lambda>1)
00262 continue;
00263 fvec3 v = vi + eij*lambda;
00264 edges[iedge].intersection = (int)points.size();
00265 points.push_back(v);
00266 fvec3 a = texCoords()[ edges[iedge].v0 ];
00267 fvec3 b = texCoords()[ edges[iedge].v1 ] - texCoords()[ edges[iedge].v0 ];
00268 fvec3 vt = a + b*lambda;
00269 points_t.push_back(vt);
00270 }
00271 std::sort(edges, edges+12);
00272 int vert_idx_c = 0;
00273 for(int ie0=0; ie0<12-1; ++ie0)
00274 {
00275 if (edges[ie0].intersection == -1)
00276 break;
00277 vert_idx[vert_idx_c++] = edges[ie0].intersection;
00278 for(int ie1=ie0+1; ie1<12; ++ie1)
00279 {
00280 if (edges[ie1].intersection == -1)
00281 continue;
00282 if( (edges[ie0].flags & edges[ie1].flags) )
00283 {
00284 Edge t = edges[ie0+1];
00285 edges[ie0+1] = edges[ie1];
00286 edges[ie1] = t;
00287 break;
00288 }
00289 }
00290 }
00291 for(int vc=0; vc<vert_idx_c-2; ++vc)
00292 {
00293 polygons.push_back(imat*points [vert_idx[0]]);
00294 polygons.push_back(imat*points [vert_idx[vc+1]]);
00295 polygons.push_back(imat*points [vert_idx[vc+2]]);
00296 polygons_t.push_back(points_t[vert_idx[0]]);
00297 polygons_t.push_back(points_t[vert_idx[vc+1]]);
00298 polygons_t.push_back(points_t[vert_idx[vc+2]]);
00299 }
00300 #ifndef NDEBUG
00301 for(int ie0=0; ie0<12-1; ++ie0)
00302 {
00303 if (edges[ie0].intersection == -1)
00304 break;
00305 if (edges[ie0+1].intersection == -1)
00306 break;
00307 VL_CHECK(edges[ie0].flags & edges[ie0+1].flags)
00308 }
00309 #endif
00310 }
00311
00312 mGeometry->drawCalls()->clear();
00313 ref<DrawArrays> da = new DrawArrays(PT_TRIANGLES, 0, (int)polygons.size());
00314 mGeometry->drawCalls()->push_back( da.get() );
00315 ref<ArrayFloat3> vertex_array = new ArrayFloat3;
00316 ref<ArrayFloat3> texcoo_array = new ArrayFloat3;
00317 vertex_array->resize(polygons.size());
00318 texcoo_array->resize(polygons_t.size());
00319 VL_CHECK((size_t)vertex_array->bufferObject()->bytesUsed() == sizeof(polygons [0])*polygons. size());
00320 VL_CHECK((size_t)texcoo_array->bufferObject()->bytesUsed() == sizeof(polygons_t[0])*polygons_t.size());
00321 memcpy(vertex_array->ptr(), &polygons [0], vertex_array->bufferObject()->bytesUsed());
00322 memcpy(texcoo_array->ptr(), &polygons_t[0], texcoo_array->bufferObject()->bytesUsed());
00323 mGeometry->setVertexArray(vertex_array.get());
00324 mGeometry->setTexCoordArray(0,texcoo_array.get());
00325
00326 mGeometry->setDisplayListDirty(true);
00327 mGeometry->setBufferObjectDirty(true);
00328
00329
00330
00331
00332 }
00333
00334 void SlicedVolume::generateTextureCoordinates(const ivec3& img_size)
00335 {
00336 if (!img_size.x() || !img_size.y() || !img_size.z())
00337 {
00338 Log::error("SlicedVolume::generateTextureCoordinates(): failed! The img_size passed does not represent a 3D image.\n");
00339 return;
00340 }
00341
00342 float dx = 0.5f/img_size.x();
00343 float dy = 0.5f/img_size.y();
00344 float dz = 0.5f/img_size.z();
00345
00346 float x0 = 0.0f + dx;
00347 float x1 = 1.0f - dx;
00348 float y0 = 0.0f + dy;
00349 float y1 = 1.0f - dy;
00350 float z0 = 0.0f + dz;
00351 float z1 = 1.0f - dz;
00352
00353 fvec3 texc[] =
00354 {
00355 fvec3(x0,y0,z0), fvec3(x1,y0,z0), fvec3(x1,y1,z0), fvec3(x0,y1,z0),
00356 fvec3(x0,y0,z1), fvec3(x1,y0,z1), fvec3(x1,y1,z1), fvec3(x0,y1,z1),
00357 };
00358 memcpy(mTexCoord, texc, sizeof(texc));
00359 }
00360
00361 void SlicedVolume::generateTextureCoordinates(const ivec3& img_size, const ivec3& min_corner, const ivec3& max_corner)
00362 {
00363 if (!img_size.x() || !img_size.y() || !img_size.z())
00364 {
00365 Log::error("SlicedVolume::setDisplayRegion(): failed! The size passed does not represent a 3D image.\n");
00366 return;
00367 }
00368
00369 float dx = 0.5f/img_size.x();
00370 float dy = 0.5f/img_size.y();
00371 float dz = 0.5f/img_size.z();
00372
00373 float x0 = min_corner.x()/(float)img_size.x() + dx;
00374 float x1 = max_corner.x()/(float)img_size.x() - dx;
00375 float y0 = min_corner.y()/(float)img_size.y() + dy;
00376 float y1 = max_corner.y()/(float)img_size.y() - dy;
00377 float z0 = min_corner.z()/(float)img_size.z() + dz;
00378 float z1 = max_corner.z()/(float)img_size.z() - dz;
00379
00380 fvec3 texc[] =
00381 {
00382 fvec3(x0,y0,z0), fvec3(x1,y0,z0), fvec3(x1,y1,z0), fvec3(x0,y1,z0),
00383 fvec3(x0,y0,z1), fvec3(x1,y0,z1), fvec3(x1,y1,z1), fvec3(x0,y1,z1)
00384 };
00385 memcpy(mTexCoord, texc, sizeof(texc));
00386 }
00387
00388 void SlicedVolume::setBox(const AABB& box)
00389 {
00390 mBox = box;
00391 mCache.fill(0);
00392 mGeometry->setBoundingBox( box );
00393 mGeometry->setBoundingSphere( box );
00394 mGeometry->setBoundsDirty(true);
00395 }
00396