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

Revision 1005, 16.9 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#include "ResourceManager.h"
6
7namespace GtpVisibilityPreprocessor {
8
9bool MeshDebug = false;
10
11int Intersectable::sMailId = 21843194198;
12int Intersectable::sReservedMailboxes = 1;
13
14struct SortableVertex {
15
16  Vector3 vertex;
17
18  int originalId;
19  int newId;
20  int finalPos;
21
22  SortableVertex() {}
23
24  SortableVertex(const Vector3 &v,
25                                 const int id):
26        vertex(v),
27        originalId(id),
28        newId(id)
29  {}
30 
31  friend bool operator<(const SortableVertex &a,
32                                                const SortableVertex &b)
33  {
34        if (a.vertex.x < b.vertex.x)
35          return true;
36        else
37          if (a.vertex.x > b.vertex.x)
38                return false;
39       
40        if (a.vertex.y < b.vertex.y)
41          return true;
42        else
43          if (a.vertex.y > b.vertex.y)
44                return false;
45       
46        if (a.vertex.z < b.vertex.z)
47          return true;
48        else
49          //      if (a.z > b.z)
50          return false;
51       
52        //      return false;
53  }
54
55};
56
57
58void
59Mesh::ComputeBoundingBox()
60{
61
62  mBox.Initialize();
63  VertexContainer::const_iterator vi = mVertices.begin();
64  for (; vi != mVertices.end(); vi++) {
65    mBox.Include(*vi);
66  }
67//mBox.Enlarge(1e-4f);
68}
69
70void
71Mesh::Preprocess()
72{
73        Cleanup();
74   
75        ComputeBoundingBox();
76   
77        /** true if it is a watertight convex mesh
78        */
79        mIsConvex = false;
80
81        if (mFaces.size() > MeshKdTree::mTermMinCost)
82        {
83                mKdTree = new MeshKdTree(this);
84                MeshKdLeaf *root = (MeshKdLeaf *)mKdTree->GetRoot();
85               
86                for (int i = 0; i < mFaces.size(); i++)
87                        root->mFaces.push_back(i);
88               
89                cout<<"KD";
90                mKdTree->Construct();
91
92                if (mKdTree->GetRoot()->IsLeaf())
93                {
94                        cout<<"d";
95                        delete mKdTree;
96                        mKdTree = NULL;
97                }
98        }
99}
100
101
102void
103Mesh::IndexVertices()
104{
105  int i;
106  // check whether the vertices can be simplfied and reindexed
107  vector<SortableVertex> svertices(mVertices.size());
108
109  for (i=0; i < mVertices.size(); i++)
110        svertices[i] = SortableVertex(mVertices[i], i);
111
112  sort(svertices.begin(), svertices.end());
113
114  for (i=0; i < svertices.size() - 1; i++)
115        if (svertices[i].vertex == svertices[i+1].vertex)
116          svertices[i+1].newId = svertices[i].newId;
117
118  // remove the same vertices
119  int k = 0;
120  mVertices[0] = svertices[0].vertex;
121  svertices[0].finalPos = 0;
122 
123  for (i=1; i < svertices.size(); i++) {
124        if (svertices[i].newId != svertices[i-1].newId)
125          k++;
126       
127        mVertices[k] = svertices[i].vertex;
128        svertices[i].finalPos = k;
129  }
130
131  mVertices.resize(k + 1);
132 
133  vector<int> remapBuffer(svertices.size());
134  for (i = 0; i < svertices.size(); i++)
135        remapBuffer[svertices[i].originalId] = svertices[i].finalPos;
136 
137  // remap all faces
138 
139  for (int faceIndex = 0; faceIndex < mFaces.size(); faceIndex++) {
140        Face *face = mFaces[faceIndex];
141        for (int i = 0; i < face->mVertexIndices.size(); i++) {
142          face->mVertexIndices[i] = remapBuffer[face->mVertexIndices[i]];
143        }
144  }
145}
146
147AxisAlignedBox3
148Mesh::GetFaceBox(const int faceIndex)
149{
150  Face *face = mFaces[faceIndex];
151  AxisAlignedBox3 box;
152  box.SetMin( mVertices[face->mVertexIndices[0]] );
153  box.SetMax(box.Min());
154  for (int i = 1; i < face->mVertexIndices.size(); i++) {
155    box.Include(mVertices[face->mVertexIndices[i]]);
156  }
157  return box;
158}
159
160int
161Mesh::CastRayToFace(
162                                        const int faceIndex,
163                                        Ray &ray,
164                                        float &nearestT,
165                                        int &nearestFace,
166                                        Intersectable *instance
167                                        )
168{
169  float t;
170  int hit = 0;
171  if (RayFaceIntersection(faceIndex, ray, t, nearestT) == Ray::INTERSECTION) {
172    switch (ray.GetType()) {
173    case Ray::GLOBAL_RAY:
174      ray.intersections.push_back(Ray::Intersection(t, instance, faceIndex));
175      hit++;
176      break;
177    case Ray::LOCAL_RAY:
178      nearestT = t;
179      nearestFace = faceIndex;
180      hit++;
181      break;
182    case Ray::LINE_SEGMENT:
183      if (t <= 1.0f) {
184                ray.intersections.push_back(Ray::Intersection(t, instance, faceIndex));
185                hit++;
186      }
187      break;
188    }
189  }
190  return hit;
191}
192
193int
194Mesh::CastRay(
195                          Ray &ray,
196                          MeshInstance *instance
197                          )
198{
199  if (mKdTree) {
200    return mKdTree->CastRay(ray, instance);
201  }
202 
203  int faceIndex = 0;
204  int hits = 0;
205  float nearestT = MAX_FLOAT;
206  int nearestFace = -1;
207 
208  if (ray.GetType() == Ray::LOCAL_RAY && ray.intersections.size())
209    nearestT = ray.intersections[0].mT;
210
211       
212  for ( ;
213                faceIndex < mFaces.size();
214                faceIndex++) {
215    hits += CastRayToFace(faceIndex, ray, nearestT, nearestFace, instance);
216    if (mIsConvex && nearestFace != -1)
217      break;
218  }
219 
220  if ( hits && ray.GetType() == Ray::LOCAL_RAY ) {
221    if (ray.intersections.size())
222      ray.intersections[0] = Ray::Intersection(nearestT, instance, nearestFace);
223    else
224      ray.intersections.push_back(Ray::Intersection(nearestT, instance, nearestFace));
225  }
226 
227  return hits;
228}
229
230int
231Mesh::CastRayToSelectedFaces(
232                                                         Ray &ray,
233                                                         const vector<int> &faces,
234                                                         Intersectable *instance
235                                                         )
236{
237  vector<int>::const_iterator fi;
238  int faceIndex = 0;
239  int hits = 0;
240  float nearestT = MAX_FLOAT;
241  int nearestFace = -1;
242
243  if (ray.GetType() == Ray::LOCAL_RAY && ray.intersections.size())
244    nearestT = ray.intersections[0].mT;
245
246  for ( fi = faces.begin();
247                fi != faces.end();
248                fi++) {
249    hits += CastRayToFace(*fi, ray, nearestT, nearestFace, instance);
250    if (mIsConvex && nearestFace != -1)
251      break;
252  }
253 
254  if ( hits && ray.GetType() == Ray::LOCAL_RAY ) {
255    if (ray.intersections.size())
256      ray.intersections[0] = Ray::Intersection(nearestT, instance, nearestFace);
257    else
258      ray.intersections.push_back(Ray::Intersection(nearestT, instance, nearestFace));
259  }
260 
261  return hits;
262}
263
264
265// int_lineseg returns 1 if the given line segment intersects a 2D
266// ray travelling in the positive X direction.  This is used in the
267// Jordan curve computation for polygon intersection.
268inline int
269int_lineseg(float px,
270                        float py,
271                        float u1,
272                        float v1,
273                        float u2,
274                        float v2)
275{
276  float ydiff;
277
278  u1 -= px; u2 -= px;     // translate line
279  v1 -= py; v2 -= py;
280
281  if ((v1 > 0 && v2 > 0) ||
282      (v1 < 0 && v2 < 0) ||
283      (u1 < 0 && u2 < 0))
284    return 0;
285
286  if (u1 > 0 && u2 > 0)
287    return 1;
288
289  ydiff = v2 - v1;
290  if (fabs(ydiff) < Limits::Small) {      // denominator near 0
291    if (((fabs(v1) > Limits::Small) ||
292                 (u1 > 0) || (u2 > 0)))
293      return 0;
294    return 1;
295  }
296 
297  double t = -v1 / ydiff;                 // Compute parameter
298
299  double thresh;
300
301  if (ydiff < 0.0f)
302        thresh = -1e-20;
303  else
304        thresh = 1e-20;
305
306 
307  return (u1 + t * (u2 - u1)) > thresh; //-Limits::Small;
308}
309
310
311
312// intersection with the polygonal face of the mesh
313int
314Mesh::RayFaceIntersection(const int faceIndex,
315                                                  const Ray &ray,
316                                                  float &t,
317                                                  const float nearestT
318                                                  )
319{
320  Face *face  = mFaces[faceIndex];
321
322  Plane3 plane = GetFacePlane(faceIndex);
323  float dot = DotProd(plane.mNormal, ray.GetDir());
324
325  if (MeshDebug) {
326        cout<<endl<<endl;
327        cout<<"normal="<<plane.mNormal<<endl;
328        cout<<"dot="<<dot<<endl;
329  }
330 
331       
332  // Watch for near-zero denominator
333  // ONLY single sided polygons!!!!!
334  if (ray.mFlags & Ray::CULL_BACKFACES) {
335        if (dot > -Limits::Small)
336          //  if (fabs(dot) < Limits::Small)
337          return Ray::NO_INTERSECTION;
338  } else {
339        if (fabs(dot) < Limits::Small)
340          return Ray::NO_INTERSECTION;
341  }
342 
343  t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
344
345  if (MeshDebug)
346        cout<<"t="<<t<<endl;
347
348  if (t <= Limits::Small)
349    return Ray::INTERSECTION_OUT_OF_LIMITS;
350 
351  if (t >= nearestT) {
352    return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
353  }
354 
355  int count = 0;
356  float u, v, u1, v1, u2, v2;
357  int i;
358
359  int paxis = plane.mNormal.DrivingAxis();
360
361 
362  // Project the intersection point onto the coordinate plane
363  // specified by which.
364  ray.Extrap(t).ExtractVerts(&u, &v, paxis);
365
366
367  int size = (int)face->mVertexIndices.size();
368
369  if (MeshDebug)
370        cout<<"size="<<size<<endl;
371 
372  mVertices[face->mVertexIndices[size - 1]].
373    ExtractVerts(&u1, &v1, paxis );
374 
375  //$$JB changed 12.4.2006 from 0 ^^
376  if (0 && size <= 4) {
377    // assume a convex face
378    for (i = 0; i < size; i++) {
379      mVertices[face->mVertexIndices[i]].ExtractVerts(&u2, &v2, paxis);
380      // line u1, v1, u2, v2
381      if ((v1 - v2)*(u - u1) + (u2 - u1)*(v - v1) > 0) {
382                if (MeshDebug)
383                  cout<<"exit on "<<i<<endl;
384                return Ray::NO_INTERSECTION;
385          }
386      u1 = u2;
387      v1 = v2;
388    }
389   
390    return Ray::INTERSECTION;
391  }
392 
393  // We're stuck with the Jordan curve computation.  Count number
394  // of intersections between the line segments the polygon comprises
395  // with a ray originating at the point of intersection and
396  // travelling in the positive X direction.
397  for (i = 0; i < size; i++) {
398    mVertices[face->mVertexIndices[i]].ExtractVerts(&u2, &v2, paxis);
399    count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
400    u1 = u2;
401    v1 = v2;
402  }
403
404  if (MeshDebug)
405        cout<<"count="<<count<<endl;
406
407  // We hit polygon if number of intersections is odd.
408  return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
409}
410
411int
412Mesh::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
413{
414  int faceIndex = (int)RandomValue(0, (Real)((int)mFaces.size()-1));
415 
416  // assume the face is convex and generate a convex combination
417  //
418  Face *face = mFaces[faceIndex];
419  point = Vector3(0,0,0);
420  float sum = 0.0f;
421  for (int i = 0; i < face->mVertexIndices.size(); i++) {
422    float r = RandomValue(0,1);
423    sum += r;
424    point += mVertices[face->mVertexIndices[i]]*r;
425  }
426  point *= 1.0f/sum;
427       
428        normal = GetFacePlane(faceIndex).mNormal;
429
430        return faceIndex;
431}
432
433int
434Mesh::GetRandomVisibleSurfacePoint(Vector3 &point,
435                                                                   Vector3 &normal,
436                                                                   const Vector3 &viewpoint,
437                                                                   const int maxTries)
438{
439  Plane3 plane;
440  int faceIndex = (int)RandomValue(0, (Real)((int)mFaces.size()-1));
441        int tries;
442  for (tries = 0; tries < maxTries; tries++) {
443    Face *face = mFaces[faceIndex];
444    plane = GetFacePlane(faceIndex);
445   
446    if (plane.Side(viewpoint) > 0) {
447      point = Vector3(0,0,0);
448      float sum = 0.0f;
449      // pickup a point inside this triangle
450      for (int i = 0; i < face->mVertexIndices.size(); i++) {
451                                float r = RandomValue(0,1);
452                                sum += r;
453                                point += mVertices[face->mVertexIndices[i]]*r;
454      }
455      point *= 1.0f/sum;
456      break;
457    }
458  }
459 
460  normal = plane.mNormal;
461  return (tries < maxTries) ? faceIndex + 1 : 0;
462}
463
464
465Plane3
466Mesh::GetFacePlane(const int faceIndex)
467{
468  Face *face = mFaces[faceIndex];
469        return Plane3(mVertices[face->mVertexIndices[0]],
470                                                                mVertices[face->mVertexIndices[1]],
471                                                                mVertices[face->mVertexIndices[2]]);
472}
473
474bool
475Mesh::ValidateFace(const int i)
476{
477        Face *face = mFaces[i];
478
479        Plane3 plane = Plane3(mVertices[face->mVertexIndices[0]],
480                                                                                                mVertices[face->mVertexIndices[1]],
481                                                                                                mVertices[face->mVertexIndices[2]]);
482       
483        if (!eq(Magnitude(plane.mNormal), 1.0f))
484                return false;
485
486        return true;
487}
488
489void
490Mesh::Cleanup()
491{
492        int toRemove = 0;
493        FaceContainer newFaces;
494        for (int i=0; i < mFaces.size(); i++)
495                if (ValidateFace(i)) {
496                        newFaces.push_back(mFaces[i]);
497                } else {
498                        cout<<"d";
499                        delete mFaces[i];
500                        toRemove++;
501                }
502       
503        if (toRemove) {
504                mFaces = newFaces;
505        }
506       
507        // cleanup vertices??
508}
509
510
511void
512Mesh::AddTriangle(const Triangle3 &triangle)
513{
514  int index = (int)mVertices.size();
515
516  for (int i=0; i < 3; i++) {
517    mVertices.push_back(triangle.mVertices[i]);
518  }
519 
520  AddFace(new Face(index + 0, index + 1, index + 2) );
521}
522
523void
524Mesh::AddRectangle(const Rectangle3 &rect)
525{
526  int index = (int)mVertices.size();
527
528  for (int i=0; i < 4; i++) {
529    mVertices.push_back(rect.mVertices[i]);
530  }
531 
532  AddFace(new Face(index + 0, index + 1, index + 2, index + 3) );
533}
534
535void
536Mesh::AssignRandomMaterial()
537
538        mMaterial = MaterialManager::GetSingleton()->CreateResource();
539 
540        Material randMat = RandomMaterial();
541
542        mMaterial->mDiffuseColor = randMat.mDiffuseColor;
543        mMaterial->mSpecularColor = randMat.mSpecularColor;
544        mMaterial->mAmbientColor = randMat.mAmbientColor;
545}
546
547
548Mesh *CreateMeshFromBox(const AxisAlignedBox3 &box)
549{
550        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
551
552        // add 8 vertices of the box
553        const int index = (int)mesh->mVertices.size();
554       
555        for (int i=0; i < 8; ++ i)
556        {
557        Vector3 v;
558                box.GetVertex(i, v);
559                mesh->mVertices.push_back(v);
560        }
561
562        mesh->AddFace(new Face(index + 0, index + 1, index + 3, index + 2) );
563        mesh->AddFace(new Face(index + 0, index + 2, index + 6, index + 4) );
564        mesh->AddFace(new Face(index + 4, index + 6, index + 7, index + 5) );
565 
566        mesh->AddFace(new Face(index + 3, index + 1, index + 5, index + 7) );
567        mesh->AddFace(new Face(index + 0, index + 4, index + 5, index + 1) );
568        mesh->AddFace(new Face(index + 2, index + 3, index + 7, index + 6) );
569 
570        return mesh;
571}
572
573
574Mesh::Mesh(const int id, const int vertices, const int faces):
575mFaces(),
576mMaterial(NULL),
577mKdTree(NULL),
578mVertices(),
579mIsConvex(false),
580mIsWatertight(false),
581mId(id)
582{
583    mVertices.reserve(vertices);
584    mFaces.reserve(faces);
585}
586
587
588Mesh::Mesh(const int id):
589mId(id), mVertices(), mFaces(), mMaterial(NULL), mKdTree(NULL)
590{}
591
592
593// apply transformation to each vertex
594void Mesh::ApplyTransformation(const Matrix4x4 &m)
595{
596        VertexContainer::iterator it, it_end = mVertices.end();
597
598        for (it = mVertices.begin(); it != it_end; ++ it)
599        {
600                (*it) = m * (*it);       
601        }
602}
603
604
605Mesh::Mesh(const Mesh &rhs)
606{
607        mVertices = rhs.mVertices;
608        mFaces.reserve(rhs.mFaces.size());
609        mId = rhs.mId;
610        mMaterial = rhs.mMaterial;
611
612        FaceContainer::const_iterator it, it_end = rhs.mFaces.end();
613
614        for (it = rhs.mFaces.begin(); it != it_end; ++ it)
615        {
616                Face *face = *it;
617                mFaces.push_back(new Face(*face));
618        }
619}
620
621
622Mesh& Mesh::operator=(const Mesh& m)
623{
624    if (this == &m)
625                return *this;
626 
627        CLEAR_CONTAINER(mFaces);
628
629        mVertices = m.mVertices;
630        mFaces.reserve(m.mFaces.size());
631        mMaterial = m.mMaterial;
632        // note: we don't copy id on purpose
633        //mId = m.mId;
634       
635        FaceContainer::const_iterator it, it_end = m.mFaces.end();
636
637        for (it = m.mFaces.begin(); it != it_end; ++ it)
638        {
639                Face *face = *it;
640                mFaces.push_back(new Face(*face));
641        }
642
643        return *this;
644}
645
646
647Mesh::~Mesh()
648{
649        for (int i=0; i < mFaces.size(); ++ i)
650                delete mFaces[i];
651
652        DEL_PTR(mKdTree);
653}
654 
655
656void Mesh::Clear()
657{
658        mVertices.clear();
659        mFaces.clear();
660
661        DEL_PTR(mKdTree);
662}
663
664/********************************************************/
665/*                      MeshInstance implementation             */
666/********************************************************/
667
668int
669MeshInstance::CastRay(
670                                          Ray &ray
671                                          )
672{
673  int res = mMesh->CastRay(ray, this);
674  return res;
675}
676
677int
678MeshInstance::CastRay(
679                                          Ray &ray,
680                                          const vector<int> &faces
681                                          )
682{
683  return mMesh->CastRayToSelectedFaces(ray, faces, this);
684}
685
686
687
688int
689MeshInstance::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
690{
691  return mMesh->GetRandomSurfacePoint(point, normal);
692}
693
694int
695MeshInstance::GetRandomVisibleSurfacePoint(Vector3 &point,
696                                                                                   Vector3 &normal,
697                                                                                   const Vector3 &viewpoint,
698                                                                                   const int maxTries)
699{
700        return mMesh->GetRandomVisibleSurfacePoint(point, normal, viewpoint, maxTries);
701}
702
703
704void MeshInstance::SetMaterial(Material *mat)
705{
706        mMaterial = mat;
707}
708
709Material *MeshInstance::GetMaterial() const
710{
711        return mMaterial;
712}
713
714
715/*************************************************************/
716/*           TransformedMeshInstance implementation          */
717/*************************************************************/
718
719TransformedMeshInstance::TransformedMeshInstance(Mesh *mesh):
720MeshInstance(mesh)
721{
722    mWorldTransform = IdentityMatrix();
723}
724
725
726int TransformedMeshInstance::GetRandomSurfacePoint(Vector3 &point, Vector3 &normal)
727{
728  int index = mMesh->GetRandomSurfacePoint(point, normal);
729  point = mWorldTransform*point;
730  normal = TransformNormal(mWorldTransform, normal);
731  return index;
732}
733
734
735int TransformedMeshInstance::CastRay(Ray &ray)
736{
737        ray.ApplyTransform(Invert(mWorldTransform));
738       
739        const int res = mMesh->CastRay(ray, this);
740        ray.ApplyTransform(mWorldTransform);
741
742    return res;
743}
744
745int TransformedMeshInstance::CastRay(Ray &ray, const vector<int> &faces)
746{
747        ray.ApplyTransform(Invert(mWorldTransform));
748
749        const int res = mMesh->CastRayToSelectedFaces(ray, faces, this);
750        ray.ApplyTransform(mWorldTransform);
751
752         return res;
753}
754
755
756void TransformedMeshInstance::ApplyWorldTransform(const Matrix4x4 &m)
757{
758        mWorldTransform = m * mWorldTransform;
759}
760
761
762void TransformedMeshInstance::LoadWorldTransform(const Matrix4x4 &m)
763{
764        mWorldTransform = m;
765}
766
767
768void TransformedMeshInstance::GetWorldTransform(Matrix4x4 &m)
769{
770        m = mWorldTransform;
771}
772
773
774AxisAlignedBox3 TransformedMeshInstance::GetBox()
775{
776    return Transform(mMesh->mBox, mWorldTransform);
777}
778
779 void TransformedMeshInstance::GetTransformedMesh(Mesh &transformedMesh)
780 {
781         // copy mesh
782        transformedMesh = *mMesh;
783        transformedMesh.ApplyTransformation(mWorldTransform);
784 }
785
786}
Note: See TracBrowser for help on using the repository browser.