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

Revision 752, 13.3 KB checked in by mattausch, 19 years ago (diff)

after rendering workshop submissioin
x3dparser can use def - use constructs
implemented improved evaluation (samples are only stored in leaves, only propagate pvs size)

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