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 <vlGraphics/RayIntersector.hpp>
00033 #include <vlGraphics/SceneManager.hpp>
00034 #include <vlGraphics/LineIterator.hpp>
00035 #include <iostream>
00036
00037 using namespace vl;
00038
00039
00040 void RayIntersector::intersect(const Ray& ray, SceneManager* scene_manager)
00041 {
00042 actors()->clear();
00043 scene_manager->extractActors( *actors() );
00044 setRay(ray);
00045 intersect();
00046 }
00047
00048 void RayIntersector::intersect()
00049 {
00050 mIntersections.clear();
00051 for(int i=0; i<actors()->size(); ++i)
00052 {
00053 if (!frustum().cull(actors()->at(i)->boundingBox()))
00054 {
00055 intersect(actors()->at(i));
00056 }
00057 }
00058
00059 std::sort( mIntersections.begin(), mIntersections.end(), sorter );
00060 }
00061
00062 void RayIntersector::intersect(Actor* act)
00063 {
00064 Geometry* geom = cast<Geometry>(act->lod(0));
00065 if (geom)
00066 intersectGeometry(act, geom);
00067 }
00068
00069 void RayIntersector::intersectGeometry(Actor* act, Geometry* geom)
00070 {
00071 ArrayAbstract* posarr = geom->vertexArray() ? geom->vertexArray() : geom->vertexAttribArray(vl::VA_Position) ? geom->vertexAttribArray(vl::VA_Position)->data() : NULL;
00072 if (posarr)
00073 {
00074 mat4 matrix = act->transform() ? act->transform()->worldMatrix() : mat4();
00075 for(int i=0; i<geom->drawCalls()->size(); ++i)
00076 {
00077 DrawCall* prim = geom->drawCalls()->at(i);
00078 int itri = 0;
00079 if(prim->primitiveType() == vl::PT_LINES ||
00080 prim->primitiveType() == vl::PT_LINE_STRIP ||
00081 prim->primitiveType() == vl::PT_LINE_LOOP)
00082 {
00083 for(LineIterator liit = prim->lineIterator(); liit.hasNext(); liit.next(), ++itri)
00084 {
00085 int ia = liit.a();
00086 int ib = liit.b();
00087 vec3 a = posarr->getAsVec3(ia);
00088 vec3 b = posarr->getAsVec3(ib);
00089 if(act->transform())
00090 {
00091 a = matrix * a;
00092 b = matrix * b;
00093 }
00094
00095 intersectLine(a, b, ia, ib, act, geom, prim, itri);
00096 }
00097 }
00098 else if(prim->primitiveType() == vl::PT_POINTS)
00099 {
00100 for(unsigned int i = 0; i < posarr->size(); i += 3, ++itri)
00101 {
00102 vec3 a = posarr->getAsVec3(i);
00103 if(act->transform())
00104 {
00105 a = matrix * a;
00106 }
00107 intersectPoint(a, i, act, geom, prim, itri);
00108 }
00109 }
00110 else
00111 {
00112 for(TriangleIterator trit = prim->triangleIterator(); trit.hasNext(); trit.next(), ++itri)
00113 {
00114 int ia = trit.a();
00115 int ib = trit.b();
00116 int ic = trit.c();
00117 vec3 a = posarr->getAsVec3(ia);
00118 vec3 b = posarr->getAsVec3(ib);
00119 vec3 c = posarr->getAsVec3(ic);
00120 if (act->transform())
00121 {
00122 a = matrix * a;
00123 b = matrix * b;
00124 c = matrix * c;
00125 }
00126 intersectTriangle(a, b, c, ia, ib, ic, act, geom, prim, itri);
00127 }
00128 }
00129 }
00130 }
00131 }
00132
00133 template<class T>
00134 void RayIntersector::intersectTriangle(const T& a, const T& b, const T& c, int ia, int ib, int ic, Actor* act, Geometry* geom, DrawCall* prim, int tri_idx)
00135 {
00136 T v1 = b-a;
00137 T v2 = c-a;
00138 T n = cross(v1,v2).normalize();
00139 real det = (real)dot(n,(T)ray().direction());
00140 if(det == 0)
00141 return;
00142 real t = (real)dot(n, a-(T)ray().origin()) / det;
00143 if (t<0)
00144 return;
00145 vec3 rp = ray().origin() + ray().direction() * t;
00146 T fp = (T)rp;
00147 T pts[] = { a, b, c, a };
00148 for(int i=0; i<3; ++i)
00149 {
00150 T bi_norm = -cross(pts[i+1]-pts[i],n).normalize();
00151 if (dot(fp-pts[i],bi_norm) < 0)
00152 return;
00153 }
00154
00155
00156 T aRp = rp - a;
00157 T bRp = rp - b;
00158 T cRp = rp - c;
00159
00160 T v3 = b - c;
00161 float d1 = cross(aRp, v1).length() / v1.length();
00162 float d2 = cross(aRp, v2).length() / v2.length();
00163 float d3 = cross(cRp, v3).length() / v3.length();
00164
00165 int ila, ilb;
00166 int l_idx;
00167 if(d1 < d2)
00168 {
00169 if(d1 < d3)
00170 {
00171 ila = ia;
00172 ilb = ib;
00173 l_idx = 1;
00174 }
00175 else
00176 {
00177 ila = ic;
00178 ilb = ib;
00179 l_idx = 2;
00180 }
00181 }
00182 else
00183 {
00184 if(d2 < d3)
00185 {
00186 ila = ia;
00187 ilb = ic;
00188 l_idx = 3;
00189 }
00190 else
00191 {
00192 ila = ic;
00193 ilb = ib;
00194 l_idx = 2;
00195 }
00196 }
00197
00198 ref<RayIntersectionGeometry> record = new vl::RayIntersectionGeometry;
00199 record->setIntersectionPoint( rp );
00200 record->setTriangleIndex(tri_idx);
00201 record->setTriangle(ia, ib, ic);
00202 record->setLineIndex(l_idx);
00203 record->setLine(ila, ilb);
00204 record->setNearestPoint(aRp.lengthSquared() < bRp.lengthSquared() ? (aRp.lengthSquared() < cRp.lengthSquared() ? ia : ic) : (bRp.lengthSquared() < cRp.lengthSquared() ? ib : ic));
00205 record->setActor(act);
00206 record->setGeometry(geom);
00207 record->setPrimitives(prim);
00208 record->setDistance( t );
00209 mIntersections.push_back(record);
00210 }
00211
00212 template<class T>
00213 void RayIntersector::intersectLine(const T& a, const T& b, int ia, int ib, Actor* act, Geometry* geom, DrawCall* prim, int tri_idx)
00214 {
00215 T v1 = b-a;
00216
00217
00218
00219
00220 float denominator = ray().direction().y() * (b.x() - a.x()) - ray().direction().x() * (b.y() - a.y());
00221 if(denominator == 0)
00222 return;
00223 float t = (ray().direction().x() * (a.y() - ray().origin().y()) - ray().direction().y() * (a.x() - ray().origin().x())) / denominator;
00224 if(t < 0 || t > 1)
00225 return;
00226
00227
00228
00229
00230
00231
00232
00233 T u = b - a;
00234 T v = ray().direction();
00235 T w = a - ray().origin();
00236 float a1 = dot(u,u);
00237 float b1 = dot(u,v);
00238 float c = dot(v,v);
00239 float d = dot(u,w);
00240 float e = dot(v,w);
00241 float D = a1*c - b1*b1;
00242 float sc, tc;
00243
00244
00245 if (D < 00000001) {
00246 sc = 0.0;
00247 tc = (b1>c ? d/b1 : e/c);
00248 }
00249 else {
00250 sc = (b1*e - c*d) / D;
00251 tc = (a1*e - b1*d) / D;
00252 }
00253
00254
00255 T dP = w + (sc * u) - (tc * v);
00256
00257 float dist = dP.length();
00258
00259 std::cout << "iligne : " << tri_idx << "; Dist : " << dist << "\n" << std::endl;
00260 if(dist > 1)
00261 return;
00262
00263
00264 ref<RayIntersectionGeometry> record = new vl::RayIntersectionGeometry;
00265
00266 record->setTriangleIndex(-1);
00267 record->setTriangle(-1, -1, -1);
00268 record->setLineIndex(tri_idx);
00269 record->setLine(ia, ib);
00270 record->setNearestPoint(-1);
00271
00272 record->setActor(act);
00273 record->setGeometry(geom);
00274 record->setPrimitives(prim);
00275
00276 mIntersections.push_back(record);
00277
00278 }
00279
00280 template<class T>
00281 void RayIntersector::intersectPoint(const T& a, int ia, Actor* act, Geometry* geom, DrawCall* prim, int prim_idx)
00282 {
00283
00284 float nd = ray().direction().x() * a.x() + ray().direction().y() * a.y() + ray().direction().z() * a.z();
00285
00286
00287 float k = (-nd - ray().direction().x() * ray().origin().x() - ray().direction().y() * ray().origin().y() - ray().direction().z() * ray().origin().z());
00288
00289
00290
00291 T intersectionPoint(ray().origin().x() + k * ray().direction().x(),
00292 ray().origin().y() + k * ray().direction().y(),
00293 ray().origin().z() + k * ray().direction().z());
00294
00295 float distance = length(a - intersectionPoint);
00296 if(distance > 0.1)
00297 return;
00298
00299 ref<RayIntersectionGeometry> record = new vl::RayIntersectionGeometry;
00300 record->setIntersectionPoint(a);
00301 record->setTriangleIndex(-1);
00302 record->setTriangle(-1, -1, -1);
00303 record->setLineIndex(-1);
00304 record->setLine(-1, -1);
00305 record->setNearestPoint(prim_idx);
00306 record->setActor(act);
00307 record->setGeometry(geom);
00308 record->setPrimitives(prim);
00309 mIntersections.push_back(record);
00310
00311 }
00312