/*! end current facegroup and append to mesh */ void OBJLoader::flushFaceGroup() { if (curGroup.empty()) return; if (subdivMode) { Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(curMaterial); group->add(mesh.cast<SceneGraph::Node>()); for (size_t i=0; i<v.size(); i++) mesh->positions.push_back(v[i]); for (size_t i=0; i<vn.size(); i++) mesh->normals .push_back(vn[i]); for (size_t i=0; i<vt.size(); i++) mesh->texcoords.push_back(vt[i]); for (size_t i=0; i<ec.size(); ++i) { assert(ec[i].a < v.size() && ec[i].b < v.size()); mesh->edge_creases.push_back(Vec2i(ec[i].a, ec[i].b)); mesh->edge_crease_weights.push_back(ec[i].w); } for (size_t j=0; j<curGroup.size(); j++) { const std::vector<Vertex>& face = curGroup[j]; mesh->verticesPerFace.push_back(face.size()); for (size_t i=0; i<face.size(); i++) mesh->position_indices.push_back(face[i].v); } } else { Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(curMaterial); group->add(mesh.cast<SceneGraph::Node>()); // merge three indices into one std::map<Vertex, uint32_t> vertexMap; for (size_t j=0; j<curGroup.size(); j++) { /* iterate over all faces */ const std::vector<Vertex>& face = curGroup[j]; /* triangulate the face with a triangle fan */ Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1]; for (size_t k=2; k < face.size(); k++) { i1 = i2; i2 = face[k]; uint32_t v0,v1,v2; v0 = getVertex(vertexMap, mesh, i0); v1 = getVertex(vertexMap, mesh, i1); v2 = getVertex(vertexMap, mesh, i2); assert(v0 < mesh->v.size()); assert(v1 < mesh->v.size()); assert(v2 < mesh->v.size()); mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0,v1,v2)); } } } curGroup.clear(); ec.clear(); }
void build_sah(avector<PrimRef>& prims, isa::PrimInfo& pinfo) { size_t N = pinfo.size(); /* fast allocator that supports thread local operation */ FastAllocator allocator(nullptr); for (size_t i=0; i<2; i++) { std::cout << "iteration " << i << ": building BVH over " << N << " primitives, " << std::flush; double t0 = getSeconds(); allocator.reset(); Node* root; isa::BVHBuilderBinnedSAH::build<Node*>( root, /* thread local allocator for fast allocations */ [&] () -> FastAllocator::ThreadLocal* { return allocator.threadLocal(); }, /* lambda function that creates BVH nodes */ [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, isa::BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal* alloc) -> int { assert(N <= 2); InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; for (size_t i=0; i<N; i++) { node->bounds[i] = children[i].pinfo.geomBounds; children[i].parent = (size_t*) &node->children[i]; } *current.parent = (size_t) node; return 0; }, /* lambda function that creates BVH leaves */ [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal* alloc) -> int { assert(current.prims.size() == 1); Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(prims[current.prims.begin()].ID(),prims[current.prims.begin()].bounds()); *current.parent = (size_t) node; return 0; }, /* progress monitor function */ [&] (size_t dn) { // throw an exception here to cancel the build operation }, prims.data(),pinfo,2,1024,1,1,1,1.0f,1.0f); double t1 = getSeconds(); std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; } }
int OBJLoader::fix_vn(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index)); }
void build_morton(avector<PrimRef>& prims, isa::PrimInfo& pinfo) { unsigned N = unsigned(pinfo.size()); /* array for morton builder */ avector<isa::MortonID32Bit> morton_src(N); avector<isa::MortonID32Bit> morton_tmp(N); for (unsigned i=0; i<N; i++) morton_src[i].index = i; /* fast allocator that supports thread local operation */ FastAllocator allocator(nullptr); for (size_t i=0; i<2; i++) { std::cout << "iteration " << i << ": building BVH over " << N << " primitives, " << std::flush; double t0 = getSeconds(); allocator.reset(); std::pair<Node*,BBox3fa> node_bounds = isa::bvh_builder_morton<Node*>( /* thread local allocator for fast allocations */ [&] () -> FastAllocator::ThreadLocal* { return allocator.threadLocal(); }, BBox3fa(empty), /* lambda function that allocates BVH nodes */ [&] ( isa::MortonBuildRecord<Node*>& current, isa::MortonBuildRecord<Node*>* children, size_t N, FastAllocator::ThreadLocal* alloc ) -> InnerNode* { assert(N <= 2); InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; *current.parent = node; for (size_t i=0; i<N; i++) children[i].parent = &node->children[i]; return node; }, /* lambda function that sets bounds */ [&] (InnerNode* node, const BBox3fa* bounds, size_t N) -> BBox3fa { BBox3fa res = empty; for (size_t i=0; i<N; i++) { const BBox3fa b = bounds[i]; res.extend(b); node->bounds[i] = b; } return res; }, /* lambda function that creates BVH leaves */ [&]( isa::MortonBuildRecord<Node*>& current, FastAllocator::ThreadLocal* alloc, BBox3fa& box_o) -> Node* { assert(current.size() == 1); const size_t id = morton_src[current.begin].index; const BBox3fa bounds = prims[id].bounds(); Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(id,bounds); *current.parent = node; box_o = bounds; return node; }, /* lambda that calculates the bounds for some primitive */ [&] (const isa::MortonID32Bit& morton) -> BBox3fa { return prims[morton.index].bounds(); }, /* progress monitor function */ [&] (size_t dn) { // throw an exception here to cancel the build operation }, morton_src.data(),morton_tmp.data(),prims.size(),2,1024,1,1); Node* root = node_bounds.first; double t1 = getSeconds(); std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; } }