BBox3fa SceneTriangle1v::update(char* prim, size_t num, void* geom) const { BBox3fa bounds = empty; Scene* scene = (Scene*) geom; for (size_t j=0; j<num; j++) { Triangle1v& dst = ((Triangle1v*) prim)[j]; const unsigned geomID = dst.geomID(); const unsigned primID = dst.primID(); const TriangleMesh* mesh = scene->getTriangleMesh(geomID); const TriangleMesh::Triangle& tri = mesh->triangle(primID); const Vec3fa v0 = mesh->vertex(tri.v[0]); const Vec3fa v1 = mesh->vertex(tri.v[1]); const Vec3fa v2 = mesh->vertex(tri.v[2]); new (&dst) Triangle1v(v0,v1,v2,geomID,primID,mesh->mask); bounds.extend(merge(BBox3fa(v0),BBox3fa(v1),BBox3fa(v2))); } return bounds; }
std::pair<BBox3fa,BBox3fa> Triangle1vMBType::update2(char* prim, size_t num, void* geom) const { BBox3fa bounds0 = empty, bounds1 = empty; for (size_t j=0; j<num; j++) { const Triangle1vMB& tri = ((Triangle1vMB*) prim)[j]; bounds0.extend(merge(BBox3fa(tri.v0),BBox3fa(tri.v1),BBox3fa(tri.v2))); bounds1.extend(merge(BBox3fa(tri.v0+tri.d0),BBox3fa(tri.v1+tri.d1),BBox3fa(tri.v2+tri.d2))); } return std::pair<BBox3fa,BBox3fa>(bounds0,bounds1); }
BBox3fa BVHNRefitter<N>::refit_toplevel(NodeRef& ref, size_t &subtrees, const BBox3fa *const subTreeBounds, const size_t depth) { if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH) { assert(subtrees < MAX_NUM_SUB_TREES); assert(subTrees[subtrees] == ref); return subTreeBounds[subtrees++]; } if (ref.isAlignedNode()) { AlignedNode* node = ref.alignedNode(); BBox3fa bounds[N]; for (size_t i=0; i<N; i++) { NodeRef& child = node->child(i); if (unlikely(child == BVH::emptyNode)) bounds[i] = BBox3fa(empty); else bounds[i] = refit_toplevel(child,subtrees,subTreeBounds,depth+1); } BBox3vf<N> boundsT = transpose<N>(bounds); /* set new bounds */ node->lower_x = boundsT.lower.x; node->lower_y = boundsT.lower.y; node->lower_z = boundsT.lower.z; node->upper_x = boundsT.upper.x; node->upper_y = boundsT.upper.y; node->upper_z = boundsT.upper.z; return merge<N>(bounds); } else return leafBounds.leafBounds(ref); }
BBox3fa BVHNRefitter<N>::recurse_bottom(NodeRef& ref) { /* this is a leaf node */ if (unlikely(ref.isLeaf())) return leafBounds.leafBounds(ref); /* recurse if this is an internal node */ AlignedNode* node = ref.alignedNode(); /* enable exclusive prefetch for >= AVX platforms */ #if defined(__AVX__) ref.prefetchW(); #endif BBox3fa bounds[N]; for (size_t i=0; i<N; i++) if (unlikely(node->child(i) == BVH::emptyNode)) { bounds[i] = BBox3fa(empty); } else bounds[i] = recurse_bottom(node->child(i)); /* AOS to SOA transform */ BBox3vf<N> boundsT = transpose<N>(bounds); /* set new bounds */ node->lower_x = boundsT.lower.x; node->lower_y = boundsT.lower.y; node->lower_z = boundsT.lower.z; node->upper_x = boundsT.upper.x; node->upper_y = boundsT.upper.y; node->upper_z = boundsT.upper.z; return merge<N>(bounds); }
BBox3fa TriangleMeshTriangle1v::update(char* prim_i, size_t num, void* geom) const { BBox3fa bounds = empty; const TriangleMesh* mesh = (const TriangleMesh*) geom; Triangle1v* prim = (Triangle1v*) prim_i; if (num == -1) { while (true) { const unsigned geomID = prim->geomID<1>(); const unsigned primID = prim->primID<1>(); const TriangleMesh::Triangle& tri = mesh->triangle(primID); const Vec3fa v0 = mesh->vertex(tri.v[0]); const Vec3fa v1 = mesh->vertex(tri.v[1]); const Vec3fa v2 = mesh->vertex(tri.v[2]); const bool last = prim->last(); new (prim) Triangle1v(v0,v1,v2,geomID,primID,mesh->mask,last); bounds.extend(merge(BBox3fa(v0),BBox3fa(v1),BBox3fa(v2))); if (last) break; prim++; } } else { for (size_t i=0; i<num; i++, prim++) { const unsigned geomID = prim->geomID<0>(); const unsigned primID = prim->primID<0>(); const TriangleMesh::Triangle& tri = mesh->triangle(primID); const Vec3fa v0 = mesh->vertex(tri.v[0]); const Vec3fa v1 = mesh->vertex(tri.v[1]); const Vec3fa v2 = mesh->vertex(tri.v[2]); new (prim) Triangle1v(v0,v1,v2,geomID,primID,mesh->mask,false); bounds.extend(merge(BBox3fa(v0),BBox3fa(v1),BBox3fa(v2))); } } return bounds; }
std::pair<BBox3fa,BBox3fa> TriangleMeshTriangle1vMB::update2(char* prim_i, size_t num, void* geom) const { BBox3fa bounds0 = empty, bounds1 = empty; Triangle1vMB* prim = (Triangle1vMB*) prim_i; if (num == -1) { while (true) { bounds0.extend(merge(BBox3fa(prim->v0),BBox3fa(prim->v1),BBox3fa(prim->v2))); bounds1.extend(merge(BBox3fa(prim->v0+prim->d0),BBox3fa(prim->v1+prim->d1),BBox3fa(prim->v2+prim->d2))); const bool last = prim->last(); if (last) break; prim++; } } else { for (size_t i=0; i<num; i++, prim++) { bounds0.extend(merge(BBox3fa(prim->v0),BBox3fa(prim->v1),BBox3fa(prim->v2))); bounds1.extend(merge(BBox3fa(prim->v0+prim->d0),BBox3fa(prim->v1+prim->d1),BBox3fa(prim->v2+prim->d2))); } } return std::pair<BBox3fa,BBox3fa>(bounds0,bounds1); }
void build_morton(vector_t<PrimRef>& prims, isa::PrimInfo& pinfo) { size_t N = pinfo.size(); /* array for morton builder */ vector_t<isa::MortonID32Bit> morton_src(N); vector_t<isa::MortonID32Bit> morton_tmp(N); for (size_t i=0; i<N; i++) morton_src[i].index = i; /* fast allocator that supports thread local operation */ FastAllocator allocator; 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(); // FIXME: dont use morton_src, should be input 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; } }
static void parseCommandLine(Ref<ParseStream> cin, const FileName& path) { while (true) { std::string tag = cin->getString(); if (tag == "") return; /* parse command line parameters from a file */ else if (tag == "-c") { FileName file = path + cin->getFileName(); parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); } /* load model */ else if (tag == "-i") { g_scene->add(SceneGraph::load(path + cin->getFileName())); } /* convert triangles to quads */ else if (tag == "-convert-triangles-to-quads") { g_scene->triangles_to_quads(); } /* convert to subdivs */ else if (tag == "-convert-to-subdivs") { g_scene->triangles_to_quads(); g_scene->quads_to_subdivs(); } /* convert bezier to lines */ else if (tag == "-convert-bezier-to-lines") { g_scene->bezier_to_lines(); } /* load terrain */ else if (tag == "-terrain") { Ref<Image> tex = loadImage(path + cin->getFileName()); const Vec3fa lower = cin->getVec3fa(); const Vec3fa upper = cin->getVec3fa(); g_height_field = new HeightField(tex,BBox3fa(lower,upper)); g_scene->add(g_height_field->geometry()); } /* distribute model */ else if (tag == "-distribute") { Ref<SceneGraph::Node> object = SceneGraph::load(path + cin->getFileName()); Ref<Image> distribution = loadImage(path + cin->getFileName()); const float minDistance = cin->getFloat(); const size_t N = cin->getInt(); Ref<Instantiator> instantiator = new Instantiator(g_height_field,object,distribution,minDistance,N); instantiator->instantiate(g_scene); } /* instantiate model a single time */ else if (tag == "-instantiate") { Ref<SceneGraph::Node> object = SceneGraph::load(path + cin->getFileName()); const float px = cin->getFloat(); const float py = cin->getFloat(); const Vec2f p(px,py); const float angle = cin->getFloat()/180.0f*float(pi); const AffineSpace3fa space = g_height_field->get(p)*AffineSpace3fa::rotate(Vec3fa(0,1,0),angle); g_scene->add(new SceneGraph::TransformNode(space,object)); } /* enable texture embedding */ else if (tag == "-embed-textures") { embedTextures = true; } /* enable texture referencing */ else if (tag == "-reference-textures") { embedTextures = false; } /* output filename */ else if (tag == "-o") { SceneGraph::store(g_scene.dynamicCast<SceneGraph::Node>(),path + cin->getFileName(),embedTextures); } /* skip unknown command line parameter */ else { std::cerr << "unknown command line parameter: " << tag << " "; while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; std::cerr << std::endl; } } }