std::vector<std::shared_ptr<Shape>> CreateCurveShape(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { Float width = params.FindOneFloat("width", 1.f); Float width0 = params.FindOneFloat("width0", width); Float width1 = params.FindOneFloat("width1", width); int ncp; const Point3f *cp = params.FindPoint3f("P", &ncp); if (ncp != 4) { Error( "Must provide 4 control points for \"curve\" primitive. " "(Provided %d).", ncp); return std::vector<std::shared_ptr<Shape>>(); } CurveType type; std::string curveType = params.FindOneString("type", "flat"); if (curveType == "flat") type = CurveType::Flat; else if (curveType == "ribbon") type = CurveType::Ribbon; else if (curveType == "cylinder") type = CurveType::Cylinder; else { Error("Unknown curve type \"%s\". Using \"flat\".", curveType.c_str()); type = CurveType::Cylinder; } int nnorm; const Normal3f *n = params.FindNormal3f("N", &nnorm); if (n != nullptr) { if (type != CurveType::Ribbon) { Warning("Curve normals are only used with \"ribbon\" type curves."); n = nullptr; } else if (nnorm != 2) { Error( "Must provide two normals with \"N\" parameter for ribbon " "curves. " "(Provided %d).", nnorm); return std::vector<std::shared_ptr<Shape>>(); } } int sd = params.FindOneFloat("splitdepth", 2); if (type == CurveType::Ribbon && n == nullptr) { Error( "Must provide normals \"N\" at curve endpoints with ribbon " "curves."); return std::vector<std::shared_ptr<Shape>>(); } else return CreateCurve(o2w, w2o, reverseOrientation, cp, width0, width1, type, n, sd); }
std::shared_ptr<Cylinder> CreateCylinderShape(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { Float radius = params.FindOneFloat("radius", 1); Float zmin = params.FindOneFloat("zmin", -1); Float zmax = params.FindOneFloat("zmax", 1); Float phimax = params.FindOneFloat("phimax", 360); return std::make_shared<Cylinder>(o2w, w2o, reverseOrientation, radius, zmin, zmax, phimax); }
std::shared_ptr<Shape> CreateSphereShape(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { Float radius = params.FindOneFloat("radius", 1.f); Float zmin = params.FindOneFloat("zmin", -radius); Float zmax = params.FindOneFloat("zmax", radius); Float phimax = params.FindOneFloat("phimax", 360.f); return std::make_shared<Sphere>(o2w, w2o, reverseOrientation, radius, zmin, zmax, phimax); }
std::shared_ptr<Disk> CreateDiskShape(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { Float height = params.FindOneFloat("height", 0.); Float radius = params.FindOneFloat("radius", 1); Float inner_radius = params.FindOneFloat("innerradius", 0); Float phimax = params.FindOneFloat("phimax", 360); return std::make_shared<Disk>(o2w, w2o, reverseOrientation, height, radius, inner_radius, phimax); }
std::shared_ptr<Medium> MakeMedium(const std::string &name, const ParamSet ¶mSet, const Transform &medium2world) { Float sig_a_rgb[3] = {.0011f, .0024f, .014f}, sig_s_rgb[3] = {2.55f, 3.21f, 3.77f}; Spectrum sig_a = Spectrum::FromRGB(sig_a_rgb), sig_s = Spectrum::FromRGB(sig_s_rgb); std::string preset = paramSet.FindOneString("preset", ""); bool found = GetMediumScatteringProperties(preset, &sig_a, &sig_s); if (preset != "" && !found) Warning("Material preset \"%s\" not found. Using defaults.", preset.c_str()); Float scale = paramSet.FindOneFloat("scale", 1.f); Float g = paramSet.FindOneFloat("g", 0.0f); sig_a = paramSet.FindOneSpectrum("sigma_a", sig_a) * scale; sig_s = paramSet.FindOneSpectrum("sigma_s", sig_s) * scale; Medium *m = NULL; if (name == "homogeneous") { m = new HomogeneousMedium(sig_a, sig_s, g); } else if (name == "heterogeneous") { int nitems; const Float *data = paramSet.FindFloat("density", &nitems); if (!data) { Error("No \"density\" values provided for heterogeneous medium?"); return NULL; } int nx = paramSet.FindOneInt("nx", 1); int ny = paramSet.FindOneInt("ny", 1); int nz = paramSet.FindOneInt("nz", 1); Point3f p0 = paramSet.FindOnePoint3f("p0", Point3f(0.f, 0.f, 0.f)); Point3f p1 = paramSet.FindOnePoint3f("p1", Point3f(1.f, 1.f, 1.f)); if (nitems != nx * ny * nz) { Error( "GridDensityMedium has %d density values; expected nx*ny*nz = " "%d", nitems, nx * ny * nz); return NULL; } Transform data2Medium = Translate(Vector3f(p0)) * Scale(p1.x - p0.x, p1.y - p0.y, p1.z - p0.z); m = new GridDensityMedium(sig_a, sig_s, g, nx, ny, nz, medium2world * data2Medium, data); } else Warning("Medium \"%s\" unknown.", name.c_str()); paramSet.ReportUnused(); return std::shared_ptr<Medium>(m); }
NaiadFoam::NaiadFoam(const Transform *o2w, const Transform *w2o, bool ro, const ParamSet ¶ms): Shape(o2w, w2o, ro) { Nb::begin(); int nFoamEmps; const string * empStr = params.FindString("emp", &nFoamEmps); const string * bodyStr = params.FindString("body", &nFoamEmps); for (int i = 0; i < nFoamEmps; ++i) { Nb::EmpReader empReader(empStr[i].c_str(),"*"); const Nb::Body * body = empReader.ejectBody(bodyStr[i].c_str()); const Nb::ParticleShape & particle = body->constParticleShape(); bb = BBox(Point(particle.min().v[0], particle.min().v[1], particle.min().v[2]), Point(particle.max().v[0], particle.max().v[1], particle.max().v[2])); //Total amount of particles const int64_t nParticles = particle.size(); printf("Found %i particles in %s\n", nParticles, empStr[i].c_str()); //Number of blocks const int nBlocks = particle.constBlocks3f(0).block_count(); for (int64_t blockIdx = 0; blockIdx < nBlocks; ++blockIdx) { boxes.push_back(new NaiadFoamBox(o2w,w2o,ro,this,particle,blockIdx)); } } foamPlane = new std::vector<float>(441000,0); FoamInLowerBound = params.FindOneFloat("FoamInLowerBound",0.f); FoamInUpperBound = params.FindOneFloat("FoamInUpperLowerBound",255.f); FoamInGamma = params.FindOneFloat("FoamInGamma",1.f); FoamOutLowerBound = params.FindOneFloat("FoamOutUpperLowerBound",0.f); FoamOutUpperBound = params.FindOneFloat("FoamOutUpperLowerBound",255.f); printf("%f %f %f %f %f\n", FoamInLowerBound, FoamInUpperBound, FoamInGamma, FoamOutLowerBound, FoamOutUpperBound); cur = this; }
std::shared_ptr<ProjectionLight> CreateProjectionLight( const Transform &light2world, const Medium *medium, const ParamSet ¶mSet) { Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); Float fov = paramSet.FindOneFloat("fov", 45.); std::string texname = paramSet.FindOneFilename("mapname", ""); return std::make_shared<ProjectionLight>(light2world, medium, I * sc, texname, fov); }
std::shared_ptr<Shape> CreateHyperboloidShape(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { Point3f p1 = params.FindOnePoint3f("p1", Point3f(0, 0, 0)); Point3f p2 = params.FindOnePoint3f("p2", Point3f(1, 1, 1)); Float phimax = params.FindOneFloat("phimax", 360); return std::make_shared<Hyperboloid>(o2w, w2o, reverseOrientation, p1, p2, phimax); }
std::shared_ptr<SpotLight> CreateSpotLight(const Transform &l2w, const Medium *medium, const ParamSet ¶mSet) { Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0)); Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0)); Float coneangle = paramSet.FindOneFloat("coneangle", 30.); Float conedelta = paramSet.FindOneFloat("conedeltaangle", 5.); // Compute spotlight world to light transformation Point3f from = paramSet.FindOnePoint3f("from", Point3f(0, 0, 0)); Point3f to = paramSet.FindOnePoint3f("to", Point3f(0, 0, 1)); Vector3f dir = Normalize(to - from); Vector3f du, dv; CoordinateSystem(dir, &du, &dv); Transform dirToZ = Transform(Matrix4x4(du.x, du.y, du.z, 0., dv.x, dv.y, dv.z, 0., dir.x, dir.y, dir.z, 0., 0, 0, 0, 1.)); Transform light2world = l2w * Translate(Vector3f(from.x, from.y, from.z)) * Inverse(dirToZ); return std::make_shared<SpotLight>(light2world, medium, I * sc, coneangle, coneangle - conedelta); }
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); }
Filter CreateBoxFilter(const ParamSet &ps) { float xw = ps.FindOneFloat("xwidth", 0.5f); float yw = ps.FindOneFloat("ywidth", 0.5f); return Filter(xw,yw,boxFilter(xw,yw)); }
std::vector<std::shared_ptr<Shape>> CreateNURBS(const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms) { int nu = params.FindOneInt("nu", -1); if (nu == -1) { Error("Must provide number of control points \"nu\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } int uorder = params.FindOneInt("uorder", -1); if (uorder == -1) { Error("Must provide u order \"uorder\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } int nuknots, nvknots; const Float *uknots = params.FindFloat("uknots", &nuknots); if (uknots == nullptr) { Error("Must provide u knot vector \"uknots\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } if (nuknots != nu + uorder) { Error( "Number of knots in u knot vector %d doesn't match sum of " "number of u control points %d and u order %d.", nuknots, nu, uorder); return std::vector<std::shared_ptr<Shape>>(); } Float u0 = params.FindOneFloat("u0", uknots[uorder - 1]); Float u1 = params.FindOneFloat("u1", uknots[nu]); int nv = params.FindOneInt("nv", -1); if (nv == -1) { Error("Must provide number of control points \"nv\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } int vorder = params.FindOneInt("vorder", -1); if (vorder == -1) { Error("Must provide v order \"vorder\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } const Float *vknots = params.FindFloat("vknots", &nvknots); if (vknots == nullptr) { Error("Must provide v knot vector \"vknots\" with NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } if (nvknots != nv + vorder) { Error( "Number of knots in v knot vector %d doesn't match sum of " "number of v control points %d and v order %d.", nvknots, nv, vorder); return std::vector<std::shared_ptr<Shape>>(); } Float v0 = params.FindOneFloat("v0", vknots[vorder - 1]); Float v1 = params.FindOneFloat("v1", vknots[nv]); bool isHomogeneous = false; int npts; const Float *P = (const Float *)params.FindPoint3f("P", &npts); if (!P) { P = params.FindFloat("Pw", &npts); if (!P) { Error( "Must provide control points via \"P\" or \"Pw\" parameter to " "NURBS shape."); return std::vector<std::shared_ptr<Shape>>(); } if ((npts % 4) != 0) { Error( "Number of \"Pw\" control points provided to NURBS shape must " "be " "multiple of four"); return std::vector<std::shared_ptr<Shape>>(); } npts /= 4; isHomogeneous = true; } if (npts != nu * nv) { Error("NURBS shape was expecting %dx%d=%d control points, was given %d", nu, nv, nu * nv, npts); return std::vector<std::shared_ptr<Shape>>(); } // Compute NURBS dicing rates int diceu = 30, dicev = 30; std::unique_ptr<Float[]> ueval(new Float[diceu]); std::unique_ptr<Float[]> veval(new Float[dicev]); std::unique_ptr<Point3f[]> evalPs(new Point3f[diceu * dicev]); std::unique_ptr<Normal3f[]> evalNs(new Normal3f[diceu * dicev]); int i; for (i = 0; i < diceu; ++i) ueval[i] = Lerp((float)i / (float)(diceu - 1), u0, u1); for (i = 0; i < dicev; ++i) veval[i] = Lerp((float)i / (float)(dicev - 1), v0, v1); // Evaluate NURBS over grid of points memset(evalPs.get(), 0, diceu * dicev * sizeof(Point3f)); memset(evalNs.get(), 0, diceu * dicev * sizeof(Point3f)); std::unique_ptr<Point2f[]> uvs(new Point2f[diceu * dicev]); // Turn NURBS into triangles std::unique_ptr<Homogeneous3[]> Pw(new Homogeneous3[nu * nv]); if (isHomogeneous) { for (int i = 0; i < nu * nv; ++i) { Pw[i].x = P[4 * i]; Pw[i].y = P[4 * i + 1]; Pw[i].z = P[4 * i + 2]; Pw[i].w = P[4 * i + 3]; } } else { for (int i = 0; i < nu * nv; ++i) { Pw[i].x = P[3 * i]; Pw[i].y = P[3 * i + 1]; Pw[i].z = P[3 * i + 2]; Pw[i].w = 1.; } } for (int v = 0; v < dicev; ++v) { for (int u = 0; u < diceu; ++u) { uvs[(v * diceu + u)].x = ueval[u]; uvs[(v * diceu + u)].y = veval[v]; Vector3f dpdu, dpdv; Point3f pt = NURBSEvaluateSurface(uorder, uknots, nu, ueval[u], vorder, vknots, nv, veval[v], Pw.get(), &dpdu, &dpdv); evalPs[v * diceu + u].x = pt.x; evalPs[v * diceu + u].y = pt.y; evalPs[v * diceu + u].z = pt.z; evalNs[v * diceu + u] = Normal3f(Normalize(Cross(dpdu, dpdv))); } } // Generate points-polygons mesh int nTris = 2 * (diceu - 1) * (dicev - 1); std::unique_ptr<int[]> vertices(new int[3 * nTris]); int *vertp = vertices.get(); // Compute the vertex offset numbers for the triangles for (int v = 0; v < dicev - 1; ++v) { for (int u = 0; u < diceu - 1; ++u) { #define VN(u, v) ((v)*diceu + (u)) *vertp++ = VN(u, v); *vertp++ = VN(u + 1, v); *vertp++ = VN(u + 1, v + 1); *vertp++ = VN(u, v); *vertp++ = VN(u + 1, v + 1); *vertp++ = VN(u, v + 1); #undef VN } } int nVerts = diceu * dicev; return CreateTriangleMesh(o2w, w2o, reverseOrientation, nTris, vertices.get(), nVerts, evalPs.get(), nullptr, evalNs.get(), uvs.get(), nullptr); }
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); }
// NaiadMesh Method Definitions NaiadMesh::NaiadMesh(const Transform *o2w, const Transform *w2o, bool ro, const ParamSet ¶ms) : Shape(o2w, w2o, ro) { Nb::begin(); const char * empStr = params.FindOneString("emp","error").c_str(); const char * bodyStr = params.FindOneString("body","error").c_str(); Nb::EmpReader empReader(empStr,"*"); const Nb::Body * body = empReader.ejectBody(bodyStr); //Load shapes from Naiad body const Nb::TriangleShape& triangle = body->constTriangleShape(); const Nb::PointShape& point = body->constPointShape(); //Get buffers const Nb::Buffer3f& posBuf(point.constBuffer3f("position")); const Nb::Buffer3i& triIdxBuf(triangle.constBuffer3i("index")); ntris = triIdxBuf.size(); nverts = posBuf.size(); std::cout << "NaiadMesh:: Found " << nverts << " vertices." << std::endl; std::cout << "NaiadMesh:: Found " << ntris << " triangles." << std::endl; vertexIndex = new int[3 * ntris]; for (int i = 0; i < ntris; ++i) { vertexIndex[3*i ] = triIdxBuf[i].v[0]; vertexIndex[3*i + 1] = triIdxBuf[i].v[1]; vertexIndex[3*i + 2] = triIdxBuf[i].v[2]; } //memcpy(vertexIndex, &triIdxBuf[0], 3 * ntris * sizeof(int)); float dispSurface = params.FindOneFloat("disp_surface",0.f); p = new Point[nverts]; for (int i = 0; i < nverts; ++i) { Point P(posBuf[i].v[0], posBuf[i].v[1], posBuf[i].v[2]); if (dispSurface) { const Nb::Buffer3f& normalBuf(point.constBuffer3f("normal")); P.x += normalBuf[i].v[0] * dispSurface; P.y += normalBuf[i].v[1] * dispSurface; P.z += normalBuf[i].v[2] * dispSurface; } p[i] = (*ObjectToWorld)(P); #ifdef VDB if (ntris > 50000) { vdb_sample(0.1); vdb_color(0.5f, 0.8f, 1.0f); } else { vdb_sample(1.0); vdb_color(0.5f, 0.5f, 0.5f); } vdb_point(p[i].x,p[i].y,p[i].z); #endif } string uv_empStr = params.FindOneString("uv_emp","error"); if (uv_empStr != string("error")) { Nb::EmpReader empReaderUV(uv_empStr.c_str(),"*"); string uv_bodyStr = params.FindOneString("uv_body","error"); const Nb::Body * bodyUV = empReaderUV.ejectBody(uv_bodyStr.c_str()); const Nb::TriangleShape& tUV = bodyUV->constTriangleShape(); const Nb::Buffer3i& uvIdx(tUV.constBuffer3i("index")); const Nb::Buffer3f& bufU(tUV.constBuffer3f("u")); const Nb::Buffer3f& bufV(tUV.constBuffer3f("v")); uvs = new float[2*nverts]; for (int i = 0; i < uvIdx.size(); ++i) { int v0 = triIdxBuf[i].v[0]; int v1 = triIdxBuf[i].v[1]; int v2 = triIdxBuf[i].v[2]; uvs[2*v0] = bufU[i].v[0]; uvs[2*v0 + 1] = bufV[i].v[0]; uvs[2*v1] = bufU[i].v[1]; uvs[2*v1 + 1] = bufV[i].v[1]; uvs[2*v2] = bufU[i].v[2]; uvs[2*v2 + 1] = bufV[i].v[2]; } } else uvs = NULL; //No need for these parameters yet. //uvs = NULL; n = NULL; s = NULL; //For foam zbuffer foam_block = params.FindOneFloat("foam_block", 0.f); Nb::end(); }
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); }
DistanceEstimatorParams::DistanceEstimatorParams(const ParamSet ¶ms) { maxIters = params.FindOneInt("maxiters", 1000); hitEpsilon = params.FindOneFloat("hitepsilon", 1e-5f); rayEpsilonMultiplier = params.FindOneFloat("rayepsilonmultiplier", 100.f); normalEpsilon = params.FindOneFloat("normalepsilon", 1e-6f); }