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

Revision 1199, 17.3 KB checked in by bittner, 18 years ago (diff)

code merge

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