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

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