00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "shape.h"
00026 #include "paramset.h"
00027
00028 class TriangleMesh : public Shape {
00029 public:
00030
00031 TriangleMesh(const Transform &o2w, bool ro,
00032 int ntris, int nverts, const int *vptr,
00033 const Point *P, const Normal *N,
00034 const Vector *S, const float *uv);
00035 ~TriangleMesh();
00036 BBox ObjectBound() const;
00037 BBox WorldBound() const;
00038 bool CanIntersect() const { return false; }
00039 void Refine(vector<Reference<Shape> > &refined) const;
00040 friend class Triangle;
00041 template <class T> friend class VertexTexture;
00042 protected:
00043
00044 int ntris, nverts;
00045 int *vertexIndex;
00046 Point *p;
00047 Normal *n;
00048 Vector *s;
00049 float *uvs;
00050 };
00051 class Triangle : public Shape {
00052 public:
00053
00054 Triangle(const Transform &o2w, bool ro,
00055 TriangleMesh *m, int n)
00056 : Shape(o2w, ro) {
00057 mesh = m;
00058 v = &mesh->vertexIndex[3*n];
00059
00060 static StatsCounter trisMade("Geometry",
00061 "Triangles created");
00062 ++trisMade;
00063 }
00064 BBox ObjectBound() const;
00065 BBox WorldBound() const;
00066 bool Intersect(const Ray &ray, float *tHit,
00067 DifferentialGeometry *dg) const;
00068 bool IntersectP(const Ray &ray) const;
00069 void GetUVs(float uv[3][2]) const;
00070 float Area() const;
00071 virtual void GetShadingGeometry(const Transform &obj2world,
00072 const DifferentialGeometry &dg,
00073 DifferentialGeometry *dgShading) const {
00074 if (!mesh->n && !mesh->s) {
00075 *dgShading = dg;
00076 return;
00077 }
00078
00079
00080 float b[3];
00081
00082 float uv[3][2];
00083 GetUVs(uv);
00084 float A[2][2] =
00085 { { uv[1][0] - uv[0][0], uv[2][0] - uv[0][0] },
00086 { uv[1][1] - uv[0][1], uv[2][1] - uv[0][1] } };
00087 float C[2] = { dg.u - uv[0][0], dg.v - uv[0][1] };
00088 if (!SolveLinearSystem2x2(A, C, &b[1])) {
00089
00090 b[0] = b[1] = b[2] = 1.f/3.f;
00091 }
00092 else
00093 b[0] = 1.f - b[1] - b[2];
00094
00095 Normal ns;
00096 Vector ss, ts;
00097 if (mesh->n) ns = Normalize(obj2world(b[0] * mesh->n[v[0]] +
00098 b[1] * mesh->n[v[1]] + b[2] * mesh->n[v[2]]));
00099 else ns = dg.nn;
00100 if (mesh->s) ss = Normalize(obj2world(b[0] * mesh->s[v[0]] +
00101 b[1] * mesh->s[v[1]] + b[2] * mesh->s[v[2]]));
00102 else ss = Normalize(dg.dpdu);
00103 ts = Normalize(Cross(ss, ns));
00104 ss = Cross(ts, ns);
00105 Vector dndu, dndv;
00106 if (mesh->n) {
00107
00108 float uvs[3][2];
00109 GetUVs(uvs);
00110
00111 float du1 = uvs[0][0] - uvs[2][0];
00112 float du2 = uvs[1][0] - uvs[2][0];
00113 float dv1 = uvs[0][1] - uvs[2][1];
00114 float dv2 = uvs[1][1] - uvs[2][1];
00115 Vector dn1 = Vector(mesh->n[v[0]] - mesh->n[v[2]]);
00116 Vector dn2 = Vector(mesh->n[v[1]] - mesh->n[v[2]]);
00117 float determinant = du1 * dv2 - dv1 * du2;
00118 if (determinant == 0)
00119 dndu = dndv = Vector(0,0,0);
00120 else {
00121 float invdet = 1.f / determinant;
00122 dndu = ( dv2 * dn1 - dv1 * dn2) * invdet;
00123 dndv = (-du2 * dn1 + du1 * dn2) * invdet;
00124 }
00125 }
00126 else
00127 dndu = dndv = Vector(0,0,0);
00128 *dgShading = DifferentialGeometry(dg.p, ss, ts,
00129 ObjectToWorld(dndu), ObjectToWorld(dndv), dg.u, dg.v, dg.shape);
00130 dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx;
00131 dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy;
00132 dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy;
00133 }
00134 Point Sample(float u1, float u2, Normal *Ns) const;
00135 private:
00136
00137 Reference<TriangleMesh> mesh;
00138 int *v;
00139 };
00140
00141 TriangleMesh::TriangleMesh(const Transform &o2w, bool ro,
00142 int nt, int nv, const int *vi, const Point *P,
00143 const Normal *N, const Vector *S, const float *uv)
00144 : Shape(o2w, ro) {
00145 ntris = nt;
00146 nverts = nv;
00147 vertexIndex = new int[3 * ntris];
00148 memcpy(vertexIndex, vi, 3 * ntris * sizeof(int));
00149
00150 if (uv) {
00151 uvs = new float[2*nverts];
00152 memcpy(uvs, uv, 2*nverts*sizeof(float));
00153 }
00154 else uvs = NULL;
00155 p = new Point[nverts];
00156 if (N) {
00157 n = new Normal[nverts];
00158 memcpy(n, N, nverts*sizeof(Normal));
00159 }
00160 else n = NULL;
00161 if (S) {
00162 s = new Vector[nverts];
00163 memcpy(s, S, nverts*sizeof(Vector));
00164 }
00165 else s = NULL;
00166
00167 for (int i = 0; i < nverts; ++i)
00168 p[i] = ObjectToWorld(P[i]);
00169 }
00170 TriangleMesh::~TriangleMesh() {
00171 delete[] vertexIndex;
00172 delete[] p;
00173 delete[] s;
00174 delete[] n;
00175 delete[] uvs;
00176 }
00177 BBox TriangleMesh::ObjectBound() const {
00178 BBox bobj;
00179 for (int i = 0; i < nverts; i++)
00180 bobj = Union(bobj, WorldToObject(p[i]));
00181 return bobj;
00182 }
00183 BBox TriangleMesh::WorldBound() const {
00184 BBox worldBounds;
00185 for (int i = 0; i < nverts; i++)
00186 worldBounds = Union(worldBounds, p[i]);
00187 return worldBounds;
00188 }
00189 void
00190 TriangleMesh::Refine(vector<Reference<Shape> > &refined)
00191 const {
00192 for (int i = 0; i < ntris; ++i)
00193 refined.push_back(new Triangle(ObjectToWorld,
00194 reverseOrientation,
00195 (TriangleMesh *)this,
00196 i));
00197 }
00198 BBox Triangle::ObjectBound() const {
00199
00200 const Point &p1 = mesh->p[v[0]];
00201 const Point &p2 = mesh->p[v[1]];
00202 const Point &p3 = mesh->p[v[2]];
00203 return Union(BBox(WorldToObject(p1), WorldToObject(p2)),
00204 WorldToObject(p3));
00205 }
00206 BBox Triangle::WorldBound() const {
00207
00208 const Point &p1 = mesh->p[v[0]];
00209 const Point &p2 = mesh->p[v[1]];
00210 const Point &p3 = mesh->p[v[2]];
00211 return Union(BBox(p1, p2), p3);
00212 }
00213 bool Triangle::Intersect(const Ray &ray, float *tHit,
00214 DifferentialGeometry *dg) const {
00215
00216 static
00217 StatsPercentage triangleHits("Geometry",
00218 "Triangle Ray Intersections");
00219
00220 triangleHits.Add(0, 1);
00221
00222
00223 const Point &p1 = mesh->p[v[0]];
00224 const Point &p2 = mesh->p[v[1]];
00225 const Point &p3 = mesh->p[v[2]];
00226 Vector e1 = p2 - p1;
00227 Vector e2 = p3 - p1;
00228 Vector s1 = Cross(ray.d, e2);
00229 float divisor = Dot(s1, e1);
00230 if (divisor == 0.)
00231 return false;
00232 float invDivisor = 1.f / divisor;
00233
00234 Vector d = ray.o - p1;
00235 float b1 = Dot(d, s1) * invDivisor;
00236 if (b1 < 0. || b1 > 1.)
00237 return false;
00238
00239 Vector s2 = Cross(d, e1);
00240 float b2 = Dot(ray.d, s2) * invDivisor;
00241 if (b2 < 0. || b1 + b2 > 1.)
00242 return false;
00243
00244 float t = Dot(e2, s2) * invDivisor;
00245 if (t < ray.mint || t > ray.maxt)
00246 return false;
00247 triangleHits.Add(1, 0);
00248
00249
00250 Vector dpdu, dpdv;
00251 float uvs[3][2];
00252 GetUVs(uvs);
00253
00254 float du1 = uvs[0][0] - uvs[2][0];
00255 float du2 = uvs[1][0] - uvs[2][0];
00256 float dv1 = uvs[0][1] - uvs[2][1];
00257 float dv2 = uvs[1][1] - uvs[2][1];
00258 Vector dp1 = p1 - p3, dp2 = p2 - p3;
00259 float determinant = du1 * dv2 - dv1 * du2;
00260 if (determinant == 0.f) {
00261
00262 CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv);
00263 }
00264 else {
00265 float invdet = 1.f / determinant;
00266 dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet;
00267 dpdv = (-du2 * dp1 + du1 * dp2) * invdet;
00268 }
00269
00270 float b0 = 1 - b1 - b2;
00271 float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0];
00272 float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1];
00273 *dg = DifferentialGeometry(ray(t), dpdu, dpdv,
00274 Vector(0,0,0), Vector(0,0,0),
00275 tu, tv, this);
00276 *tHit = t;
00277 return true;
00278 }
00279 bool Triangle::IntersectP(const Ray &ray) const {
00280
00281 static
00282 StatsPercentage triangleHits("Geometry",
00283 "Triangle Ray Intersections");
00284
00285 triangleHits.Add(0, 1);
00286
00287
00288 const Point &p1 = mesh->p[v[0]];
00289 const Point &p2 = mesh->p[v[1]];
00290 const Point &p3 = mesh->p[v[2]];
00291 Vector e1 = p2 - p1;
00292 Vector e2 = p3 - p1;
00293 Vector s1 = Cross(ray.d, e2);
00294 float divisor = Dot(s1, e1);
00295 if (divisor == 0.)
00296 return false;
00297 float invDivisor = 1.f / divisor;
00298
00299 Vector d = ray.o - p1;
00300 float b1 = Dot(d, s1) * invDivisor;
00301 if (b1 < 0. || b1 > 1.)
00302 return false;
00303
00304 Vector s2 = Cross(d, e1);
00305 float b2 = Dot(ray.d, s2) * invDivisor;
00306 if (b2 < 0. || b1 + b2 > 1.)
00307 return false;
00308
00309 float t = Dot(e2, s2) * invDivisor;
00310 if (t < ray.mint || t > ray.maxt)
00311 return false;
00312 triangleHits.Add(1, 0);
00313 return true;
00314 }
00315 void Triangle::GetUVs(float uv[3][2]) const {
00316 if (mesh->uvs) {
00317 uv[0][0] = mesh->uvs[2*v[0]];
00318 uv[0][1] = mesh->uvs[2*v[0]+1];
00319 uv[1][0] = mesh->uvs[2*v[1]];
00320 uv[1][1] = mesh->uvs[2*v[1]+1];
00321 uv[2][0] = mesh->uvs[2*v[2]];
00322 uv[2][1] = mesh->uvs[2*v[2]+1];
00323 } else {
00324 uv[0][0] = 0.; uv[0][1] = 0.;
00325 uv[1][0] = 1.; uv[1][1] = 0.;
00326 uv[2][0] = 1.; uv[2][1] = 1.;
00327 }
00328 }
00329 float Triangle::Area() const {
00330
00331 const Point &p1 = mesh->p[v[0]];
00332 const Point &p2 = mesh->p[v[1]];
00333 const Point &p3 = mesh->p[v[2]];
00334 return 0.5f * Cross(p2-p1, p3-p1).Length();
00335 }
00336 Point Triangle::Sample(float u1, float u2,
00337 Normal *Ns) const {
00338 float b1, b2;
00339 UniformSampleTriangle(u1, u2, &b1, &b2);
00340
00341 const Point &p1 = mesh->p[v[0]];
00342 const Point &p2 = mesh->p[v[1]];
00343 const Point &p3 = mesh->p[v[2]];
00344 Point p = b1 * p1 + b2 * p2 + (1.f - b1 - b2) * p3;
00345 Normal n = Normal(Cross(p2-p1, p3-p1));
00346 *Ns = Normalize(n);
00347 if (reverseOrientation) *Ns *= -1.f;
00348 return p;
00349 }
00350 extern "C" DLLEXPORT Shape *CreateShape(const Transform &o2w,
00351 bool reverseOrientation, const ParamSet ¶ms) {
00352 int nvi, npi, nuvi, nsi, nni;
00353 const int *vi = params.FindInt("indices", &nvi);
00354 const Point *P = params.FindPoint("P", &npi);
00355 const float *uvs = params.FindFloat("uv", &nuvi);
00356 if (!uvs) uvs = params.FindFloat("st", &nuvi);
00357
00358 if (uvs) {
00359 if (nuvi < 2 * npi) {
00360 Error("Not enough of \"uv\"s for triangle mesh. Expencted %d, "
00361 "found %d. Discarding.\n", 2*npi, nuvi);
00362 uvs = NULL;
00363 }
00364 else if (nuvi > 2 * npi)
00365 Warning("More \"uv\"s provided than will be used for triangle "
00366 "mesh. (%d expcted, %d found)\n", 2*npi, nuvi);
00367 }
00368 if (!vi || !P) return NULL;
00369 const Vector *S = params.FindVector("S", &nsi);
00370 if (S && nsi != npi) {
00371 Error("Number of \"S\"s for triangle mesh must match \"P\"s");
00372 S = NULL;
00373 }
00374 const Normal *N = params.FindNormal("N", &nni);
00375 if (N && nni != npi) {
00376 Error("Number of \"N\"s for triangle mesh must match \"P\"s");
00377 N = NULL;
00378 }
00379 if (uvs && N) {
00380
00381
00382 const int *vp = vi;
00383 for (int i = 0; i < nvi; i += 3, vp += 3) {
00384 float area = .5f * Cross(P[vp[0]]-P[vp[1]], P[vp[2]]-P[vp[1]]).Length();
00385 if (area < 1e-7) continue;
00386 if ((uvs[2*vp[0]] == uvs[2*vp[1]] &&
00387 uvs[2*vp[0]+1] == uvs[2*vp[1]+1]) ||
00388 (uvs[2*vp[1]] == uvs[2*vp[2]] &&
00389 uvs[2*vp[1]+1] == uvs[2*vp[2]+1]) ||
00390 (uvs[2*vp[2]] == uvs[2*vp[0]] &&
00391 uvs[2*vp[2]+1] == uvs[2*vp[0]+1])) {
00392 Warning("Degenerate uv coordinates in triangle mesh. Discarding all uvs.");
00393 uvs = NULL;
00394 break;
00395 }
00396 }
00397 }
00398 for (int i = 0; i < nvi; ++i)
00399 if (vi[i] >= npi) {
00400 Error("trianglemesh has out of-bounds vertex index %d (%d \"P\" values were given",
00401 vi[i], npi);
00402 return NULL;
00403 }
00404 return new TriangleMesh(o2w, reverseOrientation, nvi/3, npi, vi, P,
00405 N, S, uvs);
00406 }