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

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