source: GTP/trunk/Lib/Vis/Preprocessing/src/Mesh.cpp @ 860

Revision 860, 13.4 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include "Ray.h"
2#include "Mesh.h"
3#include "MeshKdTree.h"
4#include "Triangle3.h"
5
6using namespace GtpVisibilityPreprocessor {
7
8
9int Intersectable::sMailId = 21843194198;
10int Intersectable::sReservedMailboxes = 1;
11
12struct SortableVertex {
13
14  Vector3 vertex;
15
16  int originalId;
17  int newId;
18  int finalPos;
19
20  SortableVertex() {}
21
22  SortableVertex(const Vector3 &v,
23                                 const int id):
24        vertex(v),
25        originalId(id),
26        newId(id)
27  {}
28 
29  friend bool operator<(const SortableVertex &a,
30                                                const SortableVertex &b)
31  {
32        if (a.vertex.x < b.vertex.x)
33          return true;
34        else
35          if (a.vertex.x > b.vertex.x)
36                return false;
37       
38        if (a.vertex.y < b.vertex.y)
39          return true;
40        else
41          if (a.vertex.y > b.vertex.y)
42                return false;
43       
44        if (a.vertex.z < b.vertex.z)
45          return true;
46        else
47          //      if (a.z > b.z)
48          return false;
49       
50        //      return false;
51  }
52
53};
54
55
56void
57Mesh::ComputeBoundingBox()
58{
59
60  mBox.Initialize();
61  VertexContainer::const_iterator vi = mVertices.begin();
62  for (; vi != mVertices.end(); vi++) {
63    mBox.Include(*vi);
64  }
65
66}
67
68void
69Mesh::Preprocess()
70{
71 Cleanup();
72   
73   ComputeBoundingBox();
74   
75  /** true if it is a watertight convex mesh */
76  mIsConvex = false;
77 
78  if (mFaces.size() > MeshKdTree::mTermMinCost) {
79    mKdTree = new MeshKdTree(this);
80    MeshKdLeaf *root = (MeshKdLeaf *)mKdTree->GetRoot();
81    for (int i = 0; i < mFaces.size(); i++)
82      root->mFaces.push_back(i);
83    cout<<"KD";
84    mKdTree->Construct();
85       
86    if (mKdTree->GetRoot()->IsLeaf()) {
87      cout<<"d";
88      delete mKdTree;
89          mKdTree = NULL;
90    }
91  }
92}
93
94
95void
96Mesh::IndexVertices()
97{
98  int i;
99  // check whether the vertices can be simplfied and reindexed
100  vector<SortableVertex> svertices(mVertices.size());
101
102  for (i=0; i < mVertices.size(); i++)
103        svertices[i] = SortableVertex(mVertices[i], i);
104
105  sort(svertices.begin(), svertices.end());
106
107  for (i=0; i < svertices.size() - 1; i++)
108        if (svertices[i].vertex == svertices[i+1].vertex)
109          svertices[i+1].newId = svertices[i].newId;
110
111  // remove the same vertices
112  int k = 0;
113  mVertices[0] = svertices[0].vertex;
114  svertices[0].finalPos = 0;
115 
116  for (i=1; i < svertices.size(); i++) {
117        if (svertices[i].newId != svertices[i-1].newId)
118          k++;
119       
120        mVertices[k] = svertices[i].vertex;
121        svertices[i].finalPos = k;
122  }
123
124  mVertices.resize(k + 1);
125 
126  vector<int> remapBuffer(svertices.size());
127  for (i = 0; i < svertices.size(); i++)
128        remapBuffer[svertices[i].originalId] = svertices[i].finalPos;
129 
130  // remap all faces
131 
132  for (int faceIndex = 0; faceIndex < mFaces.size(); faceIndex++) {
133        Face *face = mFaces[faceIndex];
134        for (int i = 0; i < face->mVertexIndices.size(); i++) {
135          face->mVertexIndices[i] = remapBuffer[face->mVertexIndices[i]];
136        }
137  }
138}
139
140AxisAlignedBox3
141Mesh::GetFaceBox(const int faceIndex)
142{
143  Face *face = mFaces[faceIndex];
144  AxisAlignedBox3 box;
145  box.SetMin( mVertices[face->mVertexIndices[0]] );
146  box.SetMax(box.Min());
147  for (int i = 1; i < face->mVertexIndices.size(); i++) {
148    box.Include(mVertices[face->mVertexIndices[i]]);
149  }
150  return box;
151}
152
153int
154Mesh::CastRayToFace(
155                                                                                const int faceIndex,
156                                                                                Ray &ray,
157                                                                                float &nearestT,
158                                                                                int &nearestFace,
159                                                                                Intersectable *instance
160                                                                                )
161{
162  float t;
163  int hit = 0;
164  if (RayFaceIntersection(faceIndex, ray, t, nearestT) == Ray::INTERSECTION) {
165    switch (ray.GetType()) {
166    case Ray::GLOBAL_RAY:
167      ray.intersections.push_back(Ray::Intersection(t, instance, faceIndex));
168      hit++;
169      break;
170    case Ray::LOCAL_RAY:
171      nearestT = t;
172      nearestFace = faceIndex;
173      hit++;
174      break;
175    case Ray::LINE_SEGMENT:
176      if (t <= 1.0f) {
177                                ray.intersections.push_back(Ray::Intersection(t, instance, faceIndex));
178                                hit++;
179      }
180      break;
181    }
182  }
183  return hit;
184}
185
186int
187Mesh::CastRay(
188                          Ray &ray,
189                          MeshInstance *instance
190                          )
191{
192  if (mKdTree) {
193    return mKdTree->CastRay(ray, instance);
194  }
195 
196  int faceIndex = 0;
197  int hits = 0;
198  float nearestT = MAX_FLOAT;
199  int nearestFace = -1;
200 
201  if (ray.GetType() == Ray::LOCAL_RAY && ray.intersections.size())
202    nearestT = ray.intersections[0].mT;
203
204       
205  for ( ;
206                faceIndex < mFaces.size();
207                faceIndex++) {
208    hits += CastRayToFace(faceIndex, ray, nearestT, nearestFace, instance);
209    if (mIsConvex && nearestFace != -1)
210      break;
211  }
212 
213  if ( hits && ray.GetType() == Ray::LOCAL_RAY ) {
214    if (ray.intersections.size())
215      ray.intersections[0] = Ray::Intersection(nearestT, instance, nearestFace);
216    else
217      ray.intersections.push_back(Ray::Intersection(nearestT, instance, nearestFace));
218  }
219 
220  return hits;
221}
222
223int
224Mesh::CastRayToSelectedFaces(
225                                                         Ray &ray,
226                                                         const vector<int> &faces,
227                                                         Intersectable *instance
228                                                         )
229{
230  vector<int>::const_iterator fi;
231  int faceIndex = 0;
232  int hits = 0;
233  float nearestT = MAX_FLOAT;
234  int nearestFace = -1;
235
236  if (ray.GetType() == Ray::LOCAL_RAY && ray.intersections.size())
237    nearestT = ray.intersections[0].mT;
238
239  for ( fi = faces.begin();
240                                fi != faces.end();
241                                fi++) {
242    hits += CastRayToFace(*fi, ray, nearestT, nearestFace, instance);
243    if (mIsConvex && nearestFace != -1)
244      break;
245  }
246 
247  if ( hits && ray.GetType() == Ray::LOCAL_RAY ) {
248    if (ray.intersections.size())
249      ray.intersections[0] = Ray::Intersection(nearestT, instance, nearestFace);
250    else
251      ray.intersections.push_back(Ray::Intersection(nearestT, instance, nearestFace));
252  }
253 
254  return hits;
255}
256
257
258// int_lineseg returns 1 if the given line segment intersects a 2D
259// ray travelling in the positive X direction.  This is used in the
260// Jordan curve computation for polygon intersection.
261inline int
262int_lineseg(float px,
263                        float py,
264                        float u1,
265                        float v1,
266                        float u2,
267                        float v2)
268{
269  float ydiff;
270
271  u1 -= px; u2 -= px;     // translate line
272  v1 -= py; v2 -= py;
273
274  if ((v1 > 0 && v2 > 0) ||
275      (v1 < 0 && v2 < 0) ||
276      (u1 < 0 && u2 < 0))
277    return 0;
278
279  if (u1 > 0 && u2 > 0)
280    return 1;
281
282  ydiff = v2 - v1;
283  if (fabs(ydiff) < Limits::Small) {      // denominator near 0
284    if (((fabs(v1) > Limits::Small) ||
285                 (u1 > 0) || (u2 > 0)))
286      return 0;
287    return 1;
288  }
289 
290  double t = -v1 / ydiff;                 // Compute parameter
291
292  double thresh;
293  if (ydiff < 0.0f)
294        thresh = -1e20;
295  else
296        thresh = 1e20;
297
298 
299  return (u1 + t * (u2 - u1)) > thresh; //-Limits::Small;
300}
301
302
303
304// intersection with the polygonal face of the mesh
305int
306Mesh::RayFaceIntersection(const int faceIndex,
307                                                  const Ray &ray,
308                                                  float &t,
309                                                  const float nearestT
310                                                  )
311{
312  Face *face  = mFaces[faceIndex];
313
314  Plane3 plane = GetFacePlane(faceIndex);
315  float dot = DotProd(plane.mNormal, ray.GetDir());
316 
317  // Watch for near-zero denominator
318  // ONLY single sided polygons!!!!!
319  if (ray.mFlags & Ray::CULL_BACKFACES) {
320        if (dot > -Limits::Small)
321          //  if (fabs(dot) < Limits::Small)
322          return Ray::NO_INTERSECTION;
323  } else {
324        if (fabs(dot) < Limits::Small)
325          return Ray::NO_INTERSECTION;
326  }
327 
328  t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
329 
330  if (t <= Limits::Small)
331    return Ray::INTERSECTION_OUT_OF_LIMITS;
332 
333  if (t >= nearestT) {
334    return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
335  }
336 
337  int count = 0;
338  float u, v, u1, v1, u2, v2;
339  int i;
340
341  int paxis = plane.mNormal.DrivingAxis();
342
343  // Project the intersection point onto the coordinate plane
344  // specified by which.
345  ray.Extrap(t).ExtractVerts(&u, &v, paxis);
346
347
348  int size = (int)face->mVertexIndices.size();
349
350  mVertices[face->mVertexIndices[size - 1]].
351    ExtractVerts(&u1, &v1, paxis );
352 
353  //$$JB changed 12.4.2006 from 0 ^^
354  if (0 && size <= 4) {
355    // assume a convex face
356    for (i = 0; i < size; i++) {
357      mVertices[face->mVertexIndices[i]].ExtractVerts(&u2, &v2, paxis);
358      // line u1, v1, u2, v2
359      if ((v1 - v2)*(u - u1) + (u2 - u1)*(v - v1) > 0)
360                return Ray::NO_INTERSECTION;
361      u1 = u2;
362      v1 = v2;
363    }
364   
365    return Ray::INTERSECTION;
366  }
367 
368  // We're stuck with the Jordan curve computation.  Count number
369  // of intersections between the line segments the polygon comprises
370  // with a ray originating at the point of intersection and
371  // travelling in the positive X direction.
372  for (i = 0; i < size; i++) {
373    mVertices[face->mVertexIndices[i]].ExtractVerts(&u2, &v2, paxis);
374    count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
375    u1 = u2;
376    v1 = v2;
377  }
378
379  // We hit polygon if number of intersections is odd.
380  return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
381}
382
383int
384Mesh::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
385{
386  int faceIndex = (int)RandomValue(0, (Real)((int)mFaces.size()-1));
387 
388  // assume the face is convex and generate a convex combination
389  //
390  Face *face = mFaces[faceIndex];
391  point = Vector3(0,0,0);
392  float sum = 0.0f;
393  for (int i = 0; i < face->mVertexIndices.size(); i++) {
394    float r = RandomValue(0,1);
395    sum += r;
396    point += mVertices[face->mVertexIndices[i]]*r;
397  }
398  point *= 1.0f/sum;
399       
400        normal = GetFacePlane(faceIndex).mNormal;
401
402        return faceIndex;
403}
404
405int
406Mesh::GetRandomVisibleSurfacePoint(Vector3 &point,
407                                                                                                                                         Vector3 &normal,
408                                                                                                                                         const Vector3 &viewpoint,
409                                                                                                                                         const int maxTries
410                                                                                                                                         )
411{
412  Plane3 plane;
413  int faceIndex = (int)RandomValue(0, (Real)((int)mFaces.size()-1));
414        int tries;
415  for (tries = 0; tries < maxTries; tries++) {
416    Face *face = mFaces[faceIndex];
417    plane = GetFacePlane(faceIndex);
418   
419    if (plane.Side(viewpoint) > 0) {
420      point = Vector3(0,0,0);
421      float sum = 0.0f;
422      // pickup a point inside this triangle
423      for (int i = 0; i < face->mVertexIndices.size(); i++) {
424                                float r = RandomValue(0,1);
425                                sum += r;
426                                point += mVertices[face->mVertexIndices[i]]*r;
427      }
428      point *= 1.0f/sum;
429      break;
430    }
431  }
432 
433  normal = plane.mNormal;
434  return (tries < maxTries) ? faceIndex + 1 : 0;
435}
436
437
438int
439MeshInstance::CastRay(
440                                          Ray &ray
441                                          )
442{
443  int res = mMesh->CastRay(ray, this);
444  return res;
445}
446
447int
448MeshInstance::CastRay(
449                                          Ray &ray,
450                                          const vector<int> &faces
451                                          )
452{
453  return mMesh->CastRayToSelectedFaces(ray, faces, this);
454}
455
456
457
458int
459MeshInstance::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
460{
461  return mMesh->GetRandomSurfacePoint(point, normal);
462}
463
464int
465MeshInstance::GetRandomVisibleSurfacePoint(Vector3 &point,
466                                                                                                                                                                         Vector3 &normal,
467                                                                                                                                                                         const Vector3 &viewpoint,
468                                                                                                                                                                         const int maxTries
469                                                                                                                                                                         )
470{
471        return mMesh->GetRandomVisibleSurfacePoint(point, normal, viewpoint, maxTries);
472}
473
474
475int
476TransformedMeshInstance::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
477{
478  int index = mMesh->GetRandomSurfacePoint(point, normal);
479  point = mWorldTransform*point;
480  normal = TransformNormal(mWorldTransform, normal);
481  return index;
482}
483
484Plane3
485Mesh::GetFacePlane(const int faceIndex)
486{
487  Face *face = mFaces[faceIndex];
488        return Plane3(mVertices[face->mVertexIndices[0]],
489                                                                mVertices[face->mVertexIndices[1]],
490                                                                mVertices[face->mVertexIndices[2]]);
491}
492
493bool
494Mesh::ValidateFace(const int i)
495{
496        Face *face = mFaces[i];
497
498        Plane3 plane = Plane3(mVertices[face->mVertexIndices[0]],
499                                                                                                mVertices[face->mVertexIndices[1]],
500                                                                                                mVertices[face->mVertexIndices[2]]);
501       
502        if (!eq(Magnitude(plane.mNormal), 1.0f))
503                return false;
504
505        return true;
506}
507
508void
509Mesh::Cleanup()
510{
511        int toRemove = 0;
512        FaceContainer newFaces;
513        for (int i=0; i < mFaces.size(); i++)
514                if (ValidateFace(i)) {
515                        newFaces.push_back(mFaces[i]);
516                } else {
517                        cout<<"d";
518                        delete mFaces[i];
519                        toRemove++;
520                }
521       
522        if (toRemove) {
523                mFaces = newFaces;
524        }
525       
526        // cleanup vertices??
527}
528
529int
530TransformedMeshInstance::CastRay(
531                                                                 Ray &ray
532                                                                 )
533{
534  ray.ApplyTransform(Invert(mWorldTransform));
535  int res = mMesh->CastRay(ray, this);
536  ray.ApplyTransform(mWorldTransform);
537 
538  return res;
539}
540
541
542void
543Mesh::AddTriangle(const Triangle3 &triangle)
544{
545  int index = (int)mVertices.size();
546
547  for (int i=0; i < 3; i++) {
548    mVertices.push_back(triangle.mVertices[i]);
549  }
550 
551  AddFace(new Face(index + 0, index + 1, index + 2) );
552}
553
554void
555Mesh::AddRectangle(const Rectangle3 &rect)
556{
557  int index = (int)mVertices.size();
558
559  for (int i=0; i < 4; i++) {
560    mVertices.push_back(rect.mVertices[i]);
561  }
562 
563  AddFace(new Face(index + 0, index + 1, index + 2, index + 3) );
564}
565
566void
567Mesh::AssignRandomMaterial()
568{
569  if (!mMaterial)
570        mMaterial = new Material;
571  *mMaterial = RandomMaterial();
572
573}
574
575
576Mesh *CreateBox(const AxisAlignedBox3 &box)
577{
578        Mesh *mesh = new Mesh;
579  // add 8 vertices of the box
580  int index = (int)mesh->mVertices.size();
581  for (int i=0; i < 8; i++) {
582    Vector3 v;
583    box.GetVertex(i, v);
584    mesh->mVertices.push_back(v);
585  }
586 
587  mesh->AddFace(new Face(index + 0, index + 1, index + 3, index + 2) );
588  mesh->AddFace(new Face(index + 0, index + 2, index + 6, index + 4) );
589  mesh->AddFace(new Face(index + 4, index + 6, index + 7, index + 5) );
590 
591  mesh->AddFace(new Face(index + 3, index + 1, index + 5, index + 7) );
592  mesh->AddFace(new Face(index + 0, index + 4, index + 5, index + 1) );
593  mesh->AddFace(new Face(index + 2, index + 3, index + 7, index + 6) );
594 
595  return mesh;
596}
597
598}
Note: See TracBrowser for help on using the repository browser.