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