std::vector<std::shared_ptr<Shape>> CreatePLYMesh( const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms, std::map<std::string, std::shared_ptr<Texture<Float>>> *floatTextures) { const std::string filename = params.FindOneFilename("filename", ""); p_ply ply = ply_open(filename.c_str(), rply_message_callback, 0, nullptr); if (!ply) { Error("Couldn't open PLY file \"%s\"", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } if (!ply_read_header(ply)) { Error("Unable to read the header of PLY file \"%s\"", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } p_ply_element element = nullptr; long vertexCount = 0, faceCount = 0; /* Inspect the structure of the PLY file */ while ((element = ply_get_next_element(ply, element)) != nullptr) { const char *name; long nInstances; ply_get_element_info(element, &name, &nInstances); if (!strcmp(name, "vertex")) vertexCount = nInstances; else if (!strcmp(name, "face")) faceCount = nInstances; } if (vertexCount == 0 || faceCount == 0) { Error("PLY file \"%s\" is invalid! No face/vertex elements found!", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } CallbackContext context; if (ply_set_read_cb(ply, "vertex", "x", rply_vertex_callback, &context, 0x030) && ply_set_read_cb(ply, "vertex", "y", rply_vertex_callback, &context, 0x031) && ply_set_read_cb(ply, "vertex", "z", rply_vertex_callback, &context, 0x032)) { context.p = new Point3f[vertexCount]; } else { Error("PLY file \"%s\": Vertex coordinate property not found!", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } if (ply_set_read_cb(ply, "vertex", "nx", rply_vertex_callback, &context, 0x130) && ply_set_read_cb(ply, "vertex", "ny", rply_vertex_callback, &context, 0x131) && ply_set_read_cb(ply, "vertex", "nz", rply_vertex_callback, &context, 0x132)) context.n = new Normal3f[vertexCount]; /* There seem to be lots of different conventions regarding UV coordinate * names */ if ((ply_set_read_cb(ply, "vertex", "u", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "v", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "s", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "t", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "texture_u", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "texture_v", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "texture_s", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "texture_t", rply_vertex_callback, &context, 0x221))) context.uv = new Point2f[vertexCount]; /* Allocate enough space in case all faces are quads */ context.indices = new int[faceCount * 6]; context.vertexCount = vertexCount; ply_set_read_cb(ply, "face", "vertex_indices", rply_face_callback, &context, 0); if (!ply_read(ply)) { Error("Unable to read the contents of PLY file \"%s\"", filename.c_str()); ply_close(ply); return std::vector<std::shared_ptr<Shape>>(); } ply_close(ply); if (context.error) return std::vector<std::shared_ptr<Shape>>(); // Look up an alpha texture, if applicable std::shared_ptr<Texture<Float>> alphaTex; std::string alphaTexName = params.FindTexture("alpha"); if (alphaTexName != "") { if (floatTextures->find(alphaTexName) != floatTextures->end()) alphaTex = (*floatTextures)[alphaTexName]; else Error("Couldn't find float texture \"%s\" for \"alpha\" parameter", alphaTexName.c_str()); } else if (params.FindOneFloat("alpha", 1.f) == 0.f) { alphaTex.reset(new ConstantTexture<Float>(0.f)); } std::shared_ptr<Texture<Float>> shadowAlphaTex; std::string shadowAlphaTexName = params.FindTexture("shadowalpha"); if (shadowAlphaTexName != "") { if (floatTextures->find(shadowAlphaTexName) != floatTextures->end()) shadowAlphaTex = (*floatTextures)[shadowAlphaTexName]; else Error( "Couldn't find float texture \"%s\" for \"shadowalpha\" " "parameter", shadowAlphaTexName.c_str()); } else if (params.FindOneFloat("shadowalpha", 1.f) == 0.f) shadowAlphaTex.reset(new ConstantTexture<Float>(0.f)); return CreateTriangleMesh(o2w, w2o, reverseOrientation, context.indexCtr / 3, context.indices, vertexCount, context.p, nullptr, context.n, context.uv, alphaTex, shadowAlphaTex); }
std::vector<std::shared_ptr<Shape>> CreatePLYMesh( const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms, std::map<std::string, std::shared_ptr<Texture<Float>>> *floatTextures) { const std::string filename = params.FindOneFilename("filename", ""); p_ply ply = ply_open(filename.c_str(), rply_message_callback, 0, nullptr); if (!ply) { Error("Couldn't open PLY file \"%s\"", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } if (!ply_read_header(ply)) { Error("Unable to read the header of PLY file \"%s\"", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } p_ply_element element = nullptr; long vertexCount = 0, faceCount = 0; /* Inspect the structure of the PLY file */ while ((element = ply_get_next_element(ply, element)) != nullptr) { const char *name; long nInstances; ply_get_element_info(element, &name, &nInstances); if (!strcmp(name, "vertex")) vertexCount = nInstances; else if (!strcmp(name, "face")) faceCount = nInstances; } if (vertexCount == 0 || faceCount == 0) { Error("PLY file \"%s\" is invalid! No face/vertex elements found!", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } CallbackContext context; if (ply_set_read_cb(ply, "vertex", "x", rply_vertex_callback, &context, 0x030) && ply_set_read_cb(ply, "vertex", "y", rply_vertex_callback, &context, 0x031) && ply_set_read_cb(ply, "vertex", "z", rply_vertex_callback, &context, 0x032)) { context.p = new Point3f[vertexCount]; } else { Error("PLY file \"%s\": Vertex coordinate property not found!", filename.c_str()); return std::vector<std::shared_ptr<Shape>>(); } if (ply_set_read_cb(ply, "vertex", "nx", rply_vertex_callback, &context, 0x130) && ply_set_read_cb(ply, "vertex", "ny", rply_vertex_callback, &context, 0x131) && ply_set_read_cb(ply, "vertex", "nz", rply_vertex_callback, &context, 0x132)) context.n = new Normal3f[vertexCount]; /* There seem to be lots of different conventions regarding UV coordinate * names */ if ((ply_set_read_cb(ply, "vertex", "u", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "v", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "s", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "t", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "texture_u", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "texture_v", rply_vertex_callback, &context, 0x221)) || (ply_set_read_cb(ply, "vertex", "texture_s", rply_vertex_callback, &context, 0x220) && ply_set_read_cb(ply, "vertex", "texture_t", rply_vertex_callback, &context, 0x221))) context.uv = new Point2f[vertexCount]; /* Allocate enough space in case all faces are quads */ context.indices = new int[faceCount * 6]; context.vertexCount = vertexCount; ply_set_read_cb(ply, "face", "vertex_indices", rply_face_callback, &context, 0); if (!ply_read(ply)) { Error("Unable to read the contents of PLY file \"%s\"", filename.c_str()); ply_close(ply); return std::vector<std::shared_ptr<Shape>>(); } ply_close(ply); if (context.error) return std::vector<std::shared_ptr<Shape>>(); // Look up an alpha texture, if applicable std::shared_ptr<Texture<Float>> alphaTex; std::string alphaTexName = params.FindTexture("alpha"); if (alphaTexName != "") { if (floatTextures->find(alphaTexName) != floatTextures->end()) alphaTex = (*floatTextures)[alphaTexName]; else Error("Couldn't find float texture \"%s\" for \"alpha\" parameter", alphaTexName.c_str()); } else if (params.FindOneFloat("alpha", 1.f) == 0.f) { alphaTex.reset(new ConstantTexture<Float>(0.f)); } std::shared_ptr<Texture<Float>> shadowAlphaTex; std::string shadowAlphaTexName = params.FindTexture("shadowalpha"); if (shadowAlphaTexName != "") { if (floatTextures->find(shadowAlphaTexName) != floatTextures->end()) shadowAlphaTex = (*floatTextures)[shadowAlphaTexName]; else Error("Couldn't find float texture \"%s\" for \"shadowalpha\" parameter", shadowAlphaTexName.c_str()); } else if (params.FindOneFloat("shadowalpha", 1.f) == 0.f) shadowAlphaTex.reset(new ConstantTexture<Float>(0.f)); bool discardDegenerateUVs = params.FindOneBool("discarddegenerateUVs", false); if (discardDegenerateUVs && context.uv && context.n) { // if there are normals, check for bad uv's that // give degenerate mappings; discard them if so const int *vp = context.indices; const Point3f *P = context.p; const Point2f *uv = context.uv; for (int i = 0; i < context.indexCtr; i += 3, vp += 3) { Float area = .5f * Cross(P[vp[0]] - P[vp[1]], P[vp[2]] - P[vp[1]]).Length(); if (area < 1e-7) continue; // ignore degenerate tris. if ((uv[vp[0]].x == uv[vp[1]].x && uv[vp[0]].y == uv[vp[1]].y) || (uv[vp[1]].x == uv[vp[2]].x && uv[vp[1]].y == uv[vp[2]].y) || (uv[vp[2]].x == uv[vp[0]].x && uv[vp[2]].y == uv[vp[0]].y)) { Warning( "Degenerate uv coordinates in triangle mesh. Discarding " "all uv."); delete[] context.uv; context.uv = nullptr; break; } } } return CreateTriangleMesh( o2w, w2o, reverseOrientation, context.indexCtr / 3, context.indices, vertexCount, context.p, nullptr, context.n, context.uv, alphaTex, shadowAlphaTex); }
std::vector<std::shared_ptr<Shape>> CreateTriangleMeshShape( const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms, std::map<std::string, std::shared_ptr<Texture<Float>>> *floatTextures) { int nvi, npi, nuvi, nsi, nni; const int *vi = params.FindInt("indices", &nvi); const Point3f *P = params.FindPoint3f("P", &npi); const Point2f *uvs = params.FindPoint2f("uv", &nuvi); if (!uvs) uvs = params.FindPoint2f("st", &nuvi); std::vector<Point2f> tempUVs; if (!uvs) { const Float *fuv = params.FindFloat("uv", &nuvi); if (!fuv) fuv = params.FindFloat("st", &nuvi); if (fuv) { nuvi /= 2; tempUVs.reserve(nuvi); for (int i = 0; i < nuvi; ++i) tempUVs.push_back(Point2f(fuv[2 * i], fuv[2 * i + 1])); uvs = &tempUVs[0]; } } bool discardDegenerateUVs = params.FindOneBool("discarddegenerateUVs", false); if (uvs) { if (nuvi < npi) { Error( "Not enough of \"uv\"s for triangle mesh. Expencted %d, " "found %d. Discarding.", npi, nuvi); uvs = nullptr; } else if (nuvi > npi) Warning( "More \"uv\"s provided than will be used for triangle " "mesh. (%d expcted, %d found)", npi, nuvi); } if (!vi) { Error( "Vertex indices \"indices\" not provided with triangle mesh shape"); return std::vector<std::shared_ptr<Shape>>(); } if (!P) { Error("Vertex positions \"P\" not provided with triangle mesh shape"); return std::vector<std::shared_ptr<Shape>>(); } const Vector3f *S = params.FindVector3f("S", &nsi); if (S && nsi != npi) { Error("Number of \"S\"s for triangle mesh must match \"P\"s"); S = nullptr; } const Normal3f *N = params.FindNormal3f("N", &nni); if (N && nni != npi) { Error("Number of \"N\"s for triangle mesh must match \"P\"s"); N = nullptr; } if (discardDegenerateUVs && uvs && N) { // if there are normals, check for bad uv's that // give degenerate mappings; discard them if so const int *vp = vi; for (int i = 0; i < nvi; i += 3, vp += 3) { Float area = .5f * Cross(P[vp[0]] - P[vp[1]], P[vp[2]] - P[vp[1]]).Length(); if (area < 1e-7) continue; // ignore degenerate tris. if ((uvs[vp[0]].x == uvs[vp[1]].x && uvs[vp[0]].y == uvs[vp[1]].y) || (uvs[vp[1]].x == uvs[vp[2]].x && uvs[vp[1]].y == uvs[vp[2]].y) || (uvs[vp[2]].x == uvs[vp[0]].x && uvs[vp[2]].y == uvs[vp[0]].y)) { Warning( "Degenerate uv coordinates in triangle mesh. Discarding " "all uvs."); uvs = nullptr; break; } } } for (int i = 0; i < nvi; ++i) if (vi[i] >= npi) { Error( "trianglemesh has out of-bounds vertex index %d (%d \"P\" " "values were given", vi[i], npi); return std::vector<std::shared_ptr<Shape>>(); } std::shared_ptr<Texture<Float>> alphaTex; std::string alphaTexName = params.FindTexture("alpha"); if (alphaTexName != "") { if (floatTextures->find(alphaTexName) != floatTextures->end()) alphaTex = (*floatTextures)[alphaTexName]; else Error("Couldn't find float texture \"%s\" for \"alpha\" parameter", alphaTexName.c_str()); } else if (params.FindOneFloat("alpha", 1.f) == 0.f) alphaTex.reset(new ConstantTexture<Float>(0.f)); std::shared_ptr<Texture<Float>> shadowAlphaTex; std::string shadowAlphaTexName = params.FindTexture("shadowalpha"); if (shadowAlphaTexName != "") { if (floatTextures->find(shadowAlphaTexName) != floatTextures->end()) shadowAlphaTex = (*floatTextures)[shadowAlphaTexName]; else Error( "Couldn't find float texture \"%s\" for \"shadowalpha\" " "parameter", shadowAlphaTexName.c_str()); } else if (params.FindOneFloat("shadowalpha", 1.f) == 0.f) shadowAlphaTex.reset(new ConstantTexture<Float>(0.f)); return CreateTriangleMesh(o2w, w2o, reverseOrientation, nvi / 3, vi, npi, P, S, N, uvs, alphaTex, shadowAlphaTex); }