trianglemesh.cpp

Go to the documentation of this file.
00001 
00002 /*
00003  * pbrt source code Copyright(c) 1998-2007 Matt Pharr and Greg Humphreys
00004  *
00005  * All Rights Reserved.
00006  * For educational use only; commercial use expressly forbidden.
00007  * NO WARRANTY, express or implied, for this software.
00008  * (See file License.txt for complete license)
00009  */
00010 
00011 // trianglemesh.cpp*
00012 #include "shape.h"
00013 #include "paramset.h"
00014 // TriangleMesh Declarations
00015 class TriangleMesh : public Shape {
00016 public:
00017         // TriangleMesh Public Methods
00018         TriangleMesh(const Transform &o2w, bool ro,
00019                      int ntris, int nverts, const int *vptr,
00020                                  const Point *P, const Normal *N,
00021                                  const Vector *S, const float *uv);
00022         ~TriangleMesh();
00023         BBox ObjectBound() const;
00024         BBox WorldBound() const;
00025         bool CanIntersect() const { return false; }
00026         void Refine(vector<Reference<Shape> > &refined) const;
00027         friend class Triangle;
00028         template <class T> friend class VertexTexture;
00029 protected:
00030         // TriangleMesh Data
00031         int ntris, nverts;
00032         int *vertexIndex;
00033         Point *p;
00034         Normal *n;
00035         Vector *s;
00036         float *uvs;
00037 };
00038 class Triangle : public Shape {
00039 public:
00040         // Triangle Public Methods
00041         Triangle(const Transform &o2w, bool ro,
00042                  TriangleMesh *m, int n)
00043                         : Shape(o2w, ro) {
00044                 mesh = m;
00045                 v = &mesh->vertexIndex[3*n];
00046                 // Update created triangles stats
00047                 static StatsCounter trisMade("Geometry",
00048                                              "Triangles created");
00049                 ++trisMade;
00050         }
00051         BBox ObjectBound() const;
00052         BBox WorldBound() const;
00053         bool Intersect(const Ray &ray, float *tHit,
00054                        DifferentialGeometry *dg) const;
00055         bool IntersectP(const Ray &ray) const;
00056         void GetUVs(float uv[3][2]) const;
00057         float Area() const;
00058         virtual void GetShadingGeometry(const Transform &obj2world,
00059                         const DifferentialGeometry &dg,
00060                         DifferentialGeometry *dgShading) const {
00061                 if (!mesh->n && !mesh->s) {
00062                         *dgShading = dg;
00063                         return;
00064                 }
00065                 // Initialize _Triangle_ shading geometry with _n_ and _s_
00066                 // Compute barycentric coordinates for point
00067                 float b[3];
00068                 // Initialize _A_ and _C_ matrices for barycentrics
00069                 float uv[3][2];
00070                 GetUVs(uv);
00071                 float A[2][2] =
00072                     { { uv[1][0] - uv[0][0], uv[2][0] - uv[0][0] },
00073                       { uv[1][1] - uv[0][1], uv[2][1] - uv[0][1] } };
00074                 float C[2] = { dg.u - uv[0][0], dg.v - uv[0][1] };
00075                 if (!SolveLinearSystem2x2(A, C, &b[1])) {
00076                         // Handle degenerate parametric mapping
00077                         b[0] = b[1] = b[2] = 1.f/3.f;
00078                 }
00079                 else
00080                         b[0] = 1.f - b[1] - b[2];
00081                 // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_
00082                 Normal ns;
00083                 Vector ss, ts;
00084                 if (mesh->n) ns = Normalize(obj2world(b[0] * mesh->n[v[0]] +
00085                         b[1] * mesh->n[v[1]] + b[2] * mesh->n[v[2]]));
00086                 else   ns = dg.nn;
00087                 if (mesh->s) ss = Normalize(obj2world(b[0] * mesh->s[v[0]] +
00088                         b[1] * mesh->s[v[1]] + b[2] * mesh->s[v[2]]));
00089                 else   ss = Normalize(dg.dpdu);
00090                 ts = Normalize(Cross(ss, ns));
00091                 ss = Cross(ts, ns);
00092                 Vector dndu, dndv;
00093                 if (mesh->n) {
00094                         // Compute \dndu and \dndv for triangle shading geometry
00095                         float uvs[3][2];
00096                         GetUVs(uvs);
00097                         // Compute deltas for triangle partial derivatives of normal
00098                         float du1 = uvs[0][0] - uvs[2][0];
00099                         float du2 = uvs[1][0] - uvs[2][0];
00100                         float dv1 = uvs[0][1] - uvs[2][1];
00101                         float dv2 = uvs[1][1] - uvs[2][1];
00102                         Vector dn1 = Vector(mesh->n[v[0]] - mesh->n[v[2]]);
00103                         Vector dn2 = Vector(mesh->n[v[1]] - mesh->n[v[2]]);
00104                         float determinant = du1 * dv2 - dv1 * du2;
00105                         if (determinant == 0)
00106                                 dndu = dndv = Vector(0,0,0);
00107                         else {
00108                                 float invdet = 1.f / determinant;
00109                                 dndu = ( dv2 * dn1 - dv1 * dn2) * invdet;
00110                                 dndv = (-du2 * dn1 + du1 * dn2) * invdet;
00111                         }
00112                 }
00113                 else
00114                         dndu = dndv = Vector(0,0,0);
00115                 *dgShading = DifferentialGeometry(dg.p, ss, ts,
00116                         ObjectToWorld(dndu), ObjectToWorld(dndv), dg.u, dg.v, dg.shape);
00117                 dgShading->dudx = dg.dudx;  dgShading->dvdx = dg.dvdx; // NOBOOK
00118                 dgShading->dudy = dg.dudy;  dgShading->dvdy = dg.dvdy; // NOBOOK
00119                 dgShading->dpdx = dg.dpdx;  dgShading->dpdy = dg.dpdy; // NOBOOK
00120         }
00121         Point Sample(float u1, float u2, Normal *Ns) const;
00122 private:
00123         // Triangle Data
00124         Reference<TriangleMesh> mesh;
00125         int *v;
00126 };
00127 // TriangleMesh Method Definitions
00128 TriangleMesh::TriangleMesh(const Transform &o2w, bool ro,
00129                 int nt, int nv, const int *vi, const Point *P,
00130                 const Normal *N, const Vector *S, const float *uv)
00131         : Shape(o2w, ro) {
00132         ntris = nt;
00133         nverts = nv;
00134         vertexIndex = new int[3 * ntris];
00135         memcpy(vertexIndex, vi, 3 * ntris * sizeof(int));
00136         // Copy _uv_, _N_, and _S_ vertex data, if present
00137         if (uv) {
00138                 uvs = new float[2*nverts];
00139                 memcpy(uvs, uv, 2*nverts*sizeof(float));
00140         }
00141         else uvs = NULL;
00142         p = new Point[nverts];
00143         if (N) {
00144                 n = new Normal[nverts];
00145                 memcpy(n, N, nverts*sizeof(Normal));
00146         }
00147         else n = NULL;
00148         if (S) {
00149                 s = new Vector[nverts];
00150                 memcpy(s, S, nverts*sizeof(Vector));
00151         }
00152         else s = NULL;
00153         // Transform mesh vertices to world space
00154         for (int i  = 0; i < nverts; ++i)
00155                 p[i] = ObjectToWorld(P[i]);
00156 }
00157 TriangleMesh::~TriangleMesh() {
00158         delete[] vertexIndex;
00159         delete[] p;
00160         delete[] s;
00161         delete[] n;
00162         delete[] uvs;
00163 }
00164 BBox TriangleMesh::ObjectBound() const {
00165         BBox bobj;
00166         for (int i = 0; i < nverts; i++)
00167                 bobj = Union(bobj, WorldToObject(p[i]));
00168         return bobj;
00169 }
00170 BBox TriangleMesh::WorldBound() const {
00171         BBox worldBounds;
00172         for (int i = 0; i < nverts; i++)
00173                 worldBounds = Union(worldBounds, p[i]);
00174         return worldBounds;
00175 }
00176 void
00177 TriangleMesh::Refine(vector<Reference<Shape> > &refined)
00178 const {
00179         for (int i = 0; i < ntris; ++i)
00180                 refined.push_back(new Triangle(ObjectToWorld,
00181                                                reverseOrientation,
00182                                        (TriangleMesh *)this,
00183                                                                            i));
00184 }
00185 BBox Triangle::ObjectBound() const {
00186         // Get triangle vertices in _p1_, _p2_, and _p3_
00187         const Point &p1 = mesh->p[v[0]];
00188         const Point &p2 = mesh->p[v[1]];
00189         const Point &p3 = mesh->p[v[2]];
00190         return Union(BBox(WorldToObject(p1), WorldToObject(p2)),
00191                 WorldToObject(p3));
00192 }
00193 BBox Triangle::WorldBound() const {
00194         // Get triangle vertices in _p1_, _p2_, and _p3_
00195         const Point &p1 = mesh->p[v[0]];
00196         const Point &p2 = mesh->p[v[1]];
00197         const Point &p3 = mesh->p[v[2]];
00198         return Union(BBox(p1, p2), p3);
00199 }
00200 bool Triangle::Intersect(const Ray &ray, float *tHit,
00201                 DifferentialGeometry *dg) const {
00202         // Initialize triangle intersection statistics
00203         static
00204         StatsPercentage triangleHits("Geometry",
00205                                      "Triangle Ray Intersections");
00206         // Update triangle tests count
00207         triangleHits.Add(0, 1);
00208         // Compute $\VEC{s}_1$
00209         // Get triangle vertices in _p1_, _p2_, and _p3_
00210         const Point &p1 = mesh->p[v[0]];
00211         const Point &p2 = mesh->p[v[1]];
00212         const Point &p3 = mesh->p[v[2]];
00213         Vector e1 = p2 - p1;
00214         Vector e2 = p3 - p1;
00215         Vector s1 = Cross(ray.d, e2);
00216         float divisor = Dot(s1, e1);
00217         if (divisor == 0.)
00218                 return false;
00219         float invDivisor = 1.f / divisor;
00220         // Compute first barycentric coordinate
00221         Vector d = ray.o - p1;
00222         float b1 = Dot(d, s1) * invDivisor;
00223         if (b1 < 0. || b1 > 1.)
00224                 return false;
00225         // Compute second barycentric coordinate
00226         Vector s2 = Cross(d, e1);
00227         float b2 = Dot(ray.d, s2) * invDivisor;
00228         if (b2 < 0. || b1 + b2 > 1.)
00229                 return false;
00230         // Compute _t_ to intersection point
00231         float t = Dot(e2, s2) * invDivisor;
00232         if (t < ray.mint || t > ray.maxt)
00233                 return false;
00234         triangleHits.Add(1, 0); //NOBOOK
00235         // Fill in _DifferentialGeometry_ from triangle hit
00236         // Compute triangle partial derivatives
00237         Vector dpdu, dpdv;
00238         float uvs[3][2];
00239         GetUVs(uvs);
00240         // Compute deltas for triangle partial derivatives
00241         float du1 = uvs[0][0] - uvs[2][0];
00242         float du2 = uvs[1][0] - uvs[2][0];
00243         float dv1 = uvs[0][1] - uvs[2][1];
00244         float dv2 = uvs[1][1] - uvs[2][1];
00245         Vector dp1 = p1 - p3, dp2 = p2 - p3;
00246         float determinant = du1 * dv2 - dv1 * du2;
00247         if (determinant == 0.f) {
00248                 // Handle zero determinant for triangle partial derivative matrix
00249                 CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv);
00250         }
00251         else {
00252                 float invdet = 1.f / determinant;
00253                 dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet;
00254                 dpdv = (-du2 * dp1 + du1 * dp2) * invdet;
00255         }
00256         // Interpolate $(u,v)$ triangle parametric coordinates
00257         float b0 = 1 - b1 - b2;
00258         float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0];
00259         float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1];
00260         *dg = DifferentialGeometry(ray(t), dpdu, dpdv,
00261                                    Vector(0,0,0), Vector(0,0,0),
00262                                                            tu, tv, this);
00263         *tHit = t;
00264         return true;
00265 }
00266 bool Triangle::IntersectP(const Ray &ray) const {
00267         // Initialize triangle intersection statistics
00268         static
00269         StatsPercentage triangleHits("Geometry",
00270                                      "Triangle Ray Intersections");
00271         // Update triangle tests count
00272         triangleHits.Add(0, 1);
00273         // Compute $\VEC{s}_1$
00274         // Get triangle vertices in _p1_, _p2_, and _p3_
00275         const Point &p1 = mesh->p[v[0]];
00276         const Point &p2 = mesh->p[v[1]];
00277         const Point &p3 = mesh->p[v[2]];
00278         Vector e1 = p2 - p1;
00279         Vector e2 = p3 - p1;
00280         Vector s1 = Cross(ray.d, e2);
00281         float divisor = Dot(s1, e1);
00282         if (divisor == 0.)
00283                 return false;
00284         float invDivisor = 1.f / divisor;
00285         // Compute first barycentric coordinate
00286         Vector d = ray.o - p1;
00287         float b1 = Dot(d, s1) * invDivisor;
00288         if (b1 < 0. || b1 > 1.)
00289                 return false;
00290         // Compute second barycentric coordinate
00291         Vector s2 = Cross(d, e1);
00292         float b2 = Dot(ray.d, s2) * invDivisor;
00293         if (b2 < 0. || b1 + b2 > 1.)
00294                 return false;
00295         // Compute _t_ to intersection point
00296         float t = Dot(e2, s2) * invDivisor;
00297         if (t < ray.mint || t > ray.maxt)
00298                 return false;
00299         triangleHits.Add(1, 0); //NOBOOK
00300         return true;
00301 }
00302 void Triangle::GetUVs(float uv[3][2]) const {
00303         if (mesh->uvs) {
00304                 uv[0][0] = mesh->uvs[2*v[0]];
00305                 uv[0][1] = mesh->uvs[2*v[0]+1];
00306                 uv[1][0] = mesh->uvs[2*v[1]];
00307                 uv[1][1] = mesh->uvs[2*v[1]+1];
00308                 uv[2][0] = mesh->uvs[2*v[2]];
00309                 uv[2][1] = mesh->uvs[2*v[2]+1];
00310         } else {
00311                 uv[0][0] = 0.; uv[0][1] = 0.;
00312                 uv[1][0] = 1.; uv[1][1] = 0.;
00313                 uv[2][0] = 1.; uv[2][1] = 1.;
00314         }
00315 }
00316 float Triangle::Area() const {
00317         // Get triangle vertices in _p1_, _p2_, and _p3_
00318         const Point &p1 = mesh->p[v[0]];
00319         const Point &p2 = mesh->p[v[1]];
00320         const Point &p3 = mesh->p[v[2]];
00321         return 0.5f * Cross(p2-p1, p3-p1).Length();
00322 }
00323 Point Triangle::Sample(float u1, float u2,
00324                 Normal *Ns) const {
00325         float b1, b2;
00326         UniformSampleTriangle(u1, u2, &b1, &b2);
00327         // Get triangle vertices in _p1_, _p2_, and _p3_
00328         const Point &p1 = mesh->p[v[0]];
00329         const Point &p2 = mesh->p[v[1]];
00330         const Point &p3 = mesh->p[v[2]];
00331         Point p = b1 * p1 + b2 * p2 + (1.f - b1 - b2) * p3;
00332         Normal n = Normal(Cross(p2-p1, p3-p1));
00333         *Ns = Normalize(n);
00334         if (reverseOrientation) *Ns *= -1.f;
00335         return p;
00336 }
00337 extern "C" DLLEXPORT Shape *CreateShape(const Transform &o2w,
00338                 bool reverseOrientation, const ParamSet &params) {
00339         int nvi, npi, nuvi, nsi, nni;
00340         const int *vi = params.FindInt("indices", &nvi);
00341         const Point *P = params.FindPoint("P", &npi);
00342         const float *uvs = params.FindFloat("uv", &nuvi);
00343         if (!uvs) uvs = params.FindFloat("st", &nuvi);
00344         // XXX should complain if uvs aren't an array of 2...
00345         if (!vi || !P) return NULL;
00346         const Vector *S = params.FindVector("S", &nsi);
00347         if (S && nsi != npi) {
00348                 Error("Number of \"S\"s for triangle mesh must match \"P\"s");
00349                 S = NULL;
00350         }
00351         const Normal *N = params.FindNormal("N", &nni);
00352         if (N && nni != npi) {
00353                 Error("Number of \"N\"s for triangle mesh must match \"P\"s");
00354                 N = NULL;
00355         }
00356         if (uvs && N) {
00357                 // if there are normals, check for bad uv's that
00358                 // give degenerate mappings; discard them if so
00359                 const int *vp = vi;
00360                 for (int i = 0; i < nvi; i += 3, vp += 3) {
00361                         float area = .5f * Cross(P[vp[0]]-P[vp[1]], P[vp[2]]-P[vp[1]]).Length();
00362                         if (area < 1e-7) continue; // ignore degenerate tris.
00363                         if ((uvs[2*vp[0]] == uvs[2*vp[1]] &&
00364                                 uvs[2*vp[0]+1] == uvs[2*vp[1]+1]) ||
00365                                 (uvs[2*vp[1]] == uvs[2*vp[2]] &&
00366                                 uvs[2*vp[1]+1] == uvs[2*vp[2]+1]) ||
00367                                 (uvs[2*vp[2]] == uvs[2*vp[0]] &&
00368                                 uvs[2*vp[2]+1] == uvs[2*vp[0]+1])) {
00369                                 Warning("Degenerate uv coordinates in triangle mesh.  Discarding all uvs.");
00370                                 uvs = NULL;
00371                                 break;
00372                         }
00373                 }
00374         }
00375         for (int i = 0; i < nvi; ++i)
00376                 if (vi[i] >= npi) {
00377                         Error("trianglemesh has out of-bounds vertex index %d (%d \"P\" values were given",
00378                                 vi[i], npi);
00379                         return NULL;
00380                 }
00381         return new TriangleMesh(o2w, reverseOrientation, nvi/3, npi, vi, P,
00382                 N, S, uvs);
00383 }

Generated on Wed Sep 26 14:01:22 2007 for pbrt by  doxygen 1.5.1