00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "barytrianglemesh.h"
00025 #include "mc.h"
00026 #include "paramset.h"
00027
00028 using namespace lux;
00029
00030
00031 BaryTriangleMesh::BaryTriangleMesh(const Transform &o2w, bool ro,
00032 int nt, int nv, const int *vi, const Point *P,
00033 const Normal *N, const Vector *S, const float *uv)
00034 : Shape(o2w, ro) {
00035 ntris = nt;
00036 nverts = nv;
00037 vertexIndex = new int[3 * ntris];
00038 memcpy(vertexIndex, vi, 3 * ntris * sizeof(int));
00039
00040 if (uv) {
00041 uvs = new float[2*nverts];
00042 memcpy(uvs, uv, 2*nverts*sizeof(float));
00043 }
00044 else uvs = NULL;
00045 p = new Point[nverts];
00046 if (N) {
00047 n = new Normal[nverts];
00048 memcpy(n, N, nverts*sizeof(Normal));
00049 }
00050 else n = NULL;
00051 if (S) {
00052 s = new Vector[nverts];
00053 memcpy(s, S, nverts*sizeof(Vector));
00054 }
00055 else s = NULL;
00056
00057 for (int i = 0; i < nverts; ++i)
00058 p[i] = ObjectToWorld(P[i]);
00059 }
00060 BaryTriangleMesh::~BaryTriangleMesh() {
00061 delete[] vertexIndex;
00062 delete[] p;
00063 delete[] s;
00064 delete[] n;
00065 delete[] uvs;
00066 }
00067 BBox BaryTriangleMesh::ObjectBound() const {
00068 BBox bobj;
00069 for (int i = 0; i < nverts; i++)
00070 bobj = Union(bobj, WorldToObject(p[i]));
00071 return bobj;
00072 }
00073 BBox BaryTriangleMesh::WorldBound() const {
00074 BBox worldBounds;
00075 for (int i = 0; i < nverts; i++)
00076 worldBounds = Union(worldBounds, p[i]);
00077 return worldBounds;
00078 }
00079
00080 void
00081 BaryTriangleMesh::Refine(vector<boost::shared_ptr<Shape> > &refined)
00082 const {
00083 for (int i = 0; i < ntris; ++i) {
00084 boost::shared_ptr<Shape> o(new BaryTriangle(ObjectToWorld,
00085 reverseOrientation,
00086 (BaryTriangleMesh *)this,
00087 i));
00088 refined.push_back(o);
00089 }
00090 }
00091
00092 BBox BaryTriangle::ObjectBound() const {
00093
00094 const Point &p1 = mesh->p[v[0]];
00095 const Point &p2 = mesh->p[v[1]];
00096 const Point &p3 = mesh->p[v[2]];
00097 return Union(BBox(WorldToObject(p1), WorldToObject(p2)),
00098 WorldToObject(p3));
00099 }
00100 BBox BaryTriangle::WorldBound() 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(p1, p2), p3);
00106 }
00107 bool BaryTriangle::Intersect(const Ray &ray, float *tHit,
00108 DifferentialGeometry *dg) const {
00109
00110 Vector e1, e2, s1;
00111
00112
00113
00114
00115
00116
00117 const Point &p1 = mesh->p[v[0]];
00118 const Point &p2 = mesh->p[v[1]];
00119 const Point &p3 = mesh->p[v[2]];
00120 e1 = p2 - p1;
00121 e2 = p3 - p1;
00122 s1 = Cross(ray.d, e2);
00123 const float divisor = Dot(s1, e1);
00124 if (divisor == 0.f)
00125 return false;
00126 const float invDivisor = 1.f / divisor;
00127
00128 const Vector d = ray.o - p1;
00129 const float b1 = Dot(d, s1) * invDivisor;
00130 if (b1 < 0.f || b1 > 1.f)
00131 return false;
00132
00133 const Vector s2 = Cross(d, e1);
00134 const float b2 = Dot(ray.d, s2) * invDivisor;
00135 if (b2 < 0.f || b1 + b2 > 1.f)
00136 return false;
00137
00138 const float t = Dot(e2, s2) * invDivisor;
00139 if (t < ray.mint || t > ray.maxt)
00140 return false;
00141
00142
00143
00144 Vector dpdu, dpdv;
00145 float uvs[3][2];
00146 GetUVs(uvs);
00147
00148 const float du1 = uvs[0][0] - uvs[2][0];
00149 const float du2 = uvs[1][0] - uvs[2][0];
00150 const float dv1 = uvs[0][1] - uvs[2][1];
00151 const float dv2 = uvs[1][1] - uvs[2][1];
00152 const Vector dp1 = p1 - p3, dp2 = p2 - p3;
00153 const float determinant = du1 * dv2 - dv1 * du2;
00154 if (determinant == 0.f) {
00155
00156 CoordinateSystem(Normalize(Cross(e1, e2)), &dpdu, &dpdv);
00157 }
00158 else {
00159 const float invdet = 1.f / determinant;
00160 dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet;
00161 dpdv = (-du2 * dp1 + du1 * dp2) * invdet;
00162 }
00163
00164
00165 const float b0 = 1 - b1 - b2;
00166 const float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0];
00167 const float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1];
00168 *dg = DifferentialGeometry(ray(t), dpdu, dpdv,
00169 Vector(0, 0, 0), Vector(0, 0, 0),
00170 tu, tv, this);
00171
00172
00173 if(mesh->n) {
00174 if(Dot(ObjectToWorld(mesh->n[v[0]]+mesh->n[v[1]]+mesh->n[v[2]]), dg->nn) < 0)
00175 dg->nn *= -1;
00176 } else {
00177 if(Dot(Cross(e1, e2), dg->nn) < 0)
00178 dg->nn *= -1;
00179 }
00180
00181 *tHit = t;
00182 return true;
00183 }
00184 bool BaryTriangle::IntersectP(const Ray &ray) const {
00185
00186
00187
00188
00189
00190
00191 const Point &p1 = mesh->p[v[0]];
00192 const Point &p2 = mesh->p[v[1]];
00193 const Point &p3 = mesh->p[v[2]];
00194 Vector e1 = p2 - p1;
00195 Vector e2 = p3 - p1;
00196 Vector s1 = Cross(ray.d, e2);
00197 float divisor = Dot(s1, e1);
00198 if (divisor == 0.f)
00199 return false;
00200 float invDivisor = 1.f / divisor;
00201
00202 Vector d = ray.o - p1;
00203 float b1 = Dot(d, s1) * invDivisor;
00204 if (b1 < 0.f || b1 > 1.f)
00205 return false;
00206
00207 Vector s2 = Cross(d, e1);
00208 float b2 = Dot(ray.d, s2) * invDivisor;
00209 if (b2 < 0.f || b1 + b2 > 1.f)
00210 return false;
00211
00212 float t = Dot(e2, s2) * invDivisor;
00213 if (t < ray.mint || t > ray.maxt)
00214 return false;
00215
00216 return true;
00217 }
00218 void BaryTriangle::GetUVs(float uv[3][2]) const {
00219 if (mesh->uvs) {
00220 uv[0][0] = mesh->uvs[2*v[0]];
00221 uv[0][1] = mesh->uvs[2*v[0]+1];
00222 uv[1][0] = mesh->uvs[2*v[1]];
00223 uv[1][1] = mesh->uvs[2*v[1]+1];
00224 uv[2][0] = mesh->uvs[2*v[2]];
00225 uv[2][1] = mesh->uvs[2*v[2]+1];
00226 } else {
00227 uv[0][0] = mesh->p[v[0]].x;
00228 uv[0][1] = mesh->p[v[0]].y;
00229 uv[1][0] = mesh->p[v[1]].x;
00230 uv[1][1] = mesh->p[v[1]].y;
00231 uv[2][0] = mesh->p[v[2]].x;
00232 uv[2][1] = mesh->p[v[2]].y;
00233 }
00234 }
00235 float BaryTriangle::Area() const {
00236
00237 const Point &p1 = mesh->p[v[0]];
00238 const Point &p2 = mesh->p[v[1]];
00239 const Point &p3 = mesh->p[v[2]];
00240 return 0.5f * Cross(p2-p1, p3-p1).Length();
00241 }
00242 Point BaryTriangle::Sample(float u1, float u2,
00243 Normal *Ns) const {
00244 float b1, b2;
00245 UniformSampleTriangle(u1, u2, &b1, &b2);
00246
00247 const Point &p1 = mesh->p[v[0]];
00248 const Point &p2 = mesh->p[v[1]];
00249 const Point &p3 = mesh->p[v[2]];
00250 Point p = b1 * p1 + b2 * p2 + (1.f - b1 - b2) * p3;
00251 Normal n = Normal(Cross(p2-p1, p3-p1));
00252 *Ns = Normalize(n);
00253 if (reverseOrientation) *Ns *= -1.f;
00254 return p;
00255 }
00256 Shape* BaryTriangleMesh::CreateShape(const Transform &o2w,
00257 bool reverseOrientation, const ParamSet ¶ms) {
00258 int nvi, npi, nuvi, nsi, nni;
00259 const int *vi = params.FindInt("indices", &nvi);
00260 const Point *P = params.FindPoint("P", &npi);
00261 const float *uvs = params.FindFloat("uv", &nuvi);
00262 if (!uvs) uvs = params.FindFloat("st", &nuvi);
00263
00264 if (uvs && nuvi != npi * 2) {
00265 luxError(LUX_CONSISTENCY, LUX_ERROR, "Number of \"uv\"s for triangle mesh must match \"P\"s");
00266 uvs = NULL;
00267 }
00268 if (!vi || !P) return NULL;
00269 const Vector *S = params.FindVector("S", &nsi);
00270 if (S && nsi != npi) {
00271 luxError(LUX_CONSISTENCY, LUX_ERROR, "Number of \"S\"s for triangle mesh must match \"P\"s");
00272 S = NULL;
00273 }
00274 const Normal *N = params.FindNormal("N", &nni);
00275 if (N && nni != npi) {
00276 luxError(LUX_CONSISTENCY, LUX_ERROR, "Number of \"N\"s for triangle mesh must match \"P\"s");
00277 N = NULL;
00278 }
00279 if (uvs && N) {
00280
00281
00282 const int *vp = vi;
00283 for (int i = 0; i < nvi; i += 3, vp += 3) {
00284 float area = .5f * Cross(P[vp[0]]-P[vp[1]], P[vp[2]]-P[vp[1]]).Length();
00285 if (area < 1e-7) continue;
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 }
00300 }
00301 for (int i = 0; i < nvi; ++i)
00302 if (vi[i] >= npi) {
00303
00304
00305 std::stringstream ss;
00306 ss<<"trianglemesh has out of-bounds vertex index "<<vi[i]<<" ("<<npi<<" \"P\" values were given";
00307 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00308 return NULL;
00309 }
00310 return new BaryTriangleMesh(o2w, reverseOrientation, nvi/3, npi, vi, P,
00311 N, S, uvs);
00312 }