Exemple #1
0
 BVH4Statistics::BVH4Statistics (BVH4* bvh) : bvh(bvh)
 {
   numAlignedNodes = numUnalignedNodes = 0;
   numAlignedNodesMB = numUnalignedNodesMB = 0;
   numLeaves = numPrims = depth = 0;
   childrenAlignedNodes = childrenUnalignedNodes = 0;
   childrenAlignedNodesMB = childrenUnalignedNodesMB = 0;
   bvhSAH = 0.0f;
   hash = 0;
   float A = max(0.0f,halfArea(bvh->bounds));
   statistics(bvh->root,A,depth);
   bvhSAH /= halfArea(bvh->bounds);
   assert(depth <= BVH4::maxDepth);
 }
Exemple #2
0
 BVHNStatistics<N>::BVHNStatistics (BVH* bvh) : bvh(bvh)
 {
   numAlignedNodes = numUnalignedNodes = 0;
   numAlignedNodesMB = numUnalignedNodesMB = 0;
   numTransformNodes = 0;
   numLeaves = numPrims = numPrimBlocks = depth = 0;
   childrenAlignedNodes = childrenUnalignedNodes = 0;
   childrenAlignedNodesMB = childrenUnalignedNodesMB = 0;
   bvhSAH = 0.0f; leafSAH = 0.0f;
   float A = max(0.0f,halfArea(bvh->bounds));
   statistics(bvh->root,A,depth);
   bvhSAH /= halfArea(bvh->bounds);
   leafSAH /= halfArea(bvh->bounds);
   assert(depth <= BVH::maxDepth);
 }
Exemple #3
0
  void BVH2Builder::SplitTask::split()
  {
    /*! compute leaf and split cost */
    size_t N = job.size();
    float leafSAH = BVH2<Triangle4>::intCost*job.leafSAH;
    float splitSAH = BVH2<Triangle4>::travCost*halfArea(job.geomBounds)+BVH2<Triangle4>::intCost*job.splitSAH;

    /*! make leaf node when threshold reached or SAH tells us */
    if (N <= 1 || depth > BVH2<Triangle4>::maxDepth || (N <= BVH2<Triangle4>::maxLeafSize && leafSAH < splitSAH)) {
      this->nodeID = parent->bvh->createLeaf(parent->prims,parent->triangles,parent->globalAllocPrimitives(blocks(N)),job.start(),N);
      delete this;
      return;
    }

    /*! perform split */
    ObjectBinning<2> left,right;
    job.split(parent->prims,left,right);

    /*! create an inner node */
    int nodeID = (int)parent->globalAllocNodes(1);
    this->nodeID = BVH2<Triangle4>::id2offset(nodeID);
    BVH2<Triangle4>::Node& node = parent->bvh->nodes[nodeID].clear();
    node.set(0,left .geomBounds,0);
    node.set(1,right.geomBounds,0);
    parent->recurse(node.child[0],depth+1,left );
    parent->recurse(node.child[1],depth+1,right);
    delete this;
  }
Exemple #4
0
  void BVH2Builder<Heuristic>::SplitTask::recurse(const TaskScheduler::ThreadInfo& thread)
  {
     /*! compute leaf and split cost */
    const float leafSAH  = parent->trity.intCost*pinfo.sah();
    const float splitSAH = BVH2::travCost*halfArea(pinfo.geomBounds)+parent->trity.intCost*split.sah();
    assert(atomic_set<PrimRefBlock>::block_iterator_unsafe(prims).size() == pinfo.size());
    assert(leafSAH >= 0 && splitSAH >= 0);

    /*! create a leaf node when threshold reached or SAH tells us to stop */
    if (pinfo.size() <= 1 || depth > BVH2::maxDepth || (pinfo.size() <= parent->bvh->maxLeafTris && leafSAH <= splitSAH)) {
      dst = parent->createLeaf(thread,prims,pinfo); delete this; return;
    }

    /*! perform best found split and find new splits */
    SplitterNormal splitter(thread,&parent->alloc,parent->triangles,parent->vertices,prims,pinfo,split);

    /*! create an inner node */
    BVH2::Node* node = (BVH2::Node*) parent->bvh->alloc.malloc(thread,sizeof(BVH2::Node),1 << BVH2::alignment); node->clear();
    dst = BVH2::Base::encodeNode(node);
    node->set(1,splitter.rinfo.geomBounds,0);
    node->set(0,splitter.linfo.geomBounds,0);
    parent->recurse(thread,node->child[0],depth+1,splitter.lprims,splitter.linfo,splitter.lsplit);
    parent->recurse(thread,node->child[1],depth+1,splitter.rprims,splitter.rinfo,splitter.rsplit);
    delete this;
  }
    const StrandSplit::Split StrandSplit::find<false>(size_t threadIndex, size_t threadCount, LockStepTaskScheduler* scheduler, BezierRefList& prims)
    {
      /* first curve determines first axis */
      BezierRefList::block_iterator_unsafe i = prims;
      Vec3fa axis0 = normalize(i->p3 - i->p0);
      
      /* find 2nd axis that is most misaligned with first axis */
      float bestCos = 1.0f;
      Vec3fa axis1 = axis0;
      for (; i; i++) {
	Vec3fa axisi = i->p3 - i->p0;
	float leni = length(axisi);
	if (leni == 0.0f) continue;
	axisi /= leni;
	float cos = abs(dot(axisi,axis0));
	if (cos < bestCos) { bestCos = cos; axis1 = axisi; }
      }
      
      /* partition the two strands */
      size_t lnum = 0, rnum = 0;
      BBox3fa lbounds = empty, rbounds = empty;
      const LinearSpace3fa space0 = frame(axis0).transposed();
      const LinearSpace3fa space1 = frame(axis1).transposed();
      
      for (BezierRefList::block_iterator_unsafe i = prims; i; i++) 
      {
	BezierPrim& prim = *i;
	const Vec3fa axisi = normalize(prim.p3-prim.p0);
	const float cos0 = abs(dot(axisi,axis0));
	const float cos1 = abs(dot(axisi,axis1));
	
	if (cos0 > cos1) { lnum++; lbounds.extend(prim.bounds(space0)); }
	else             { rnum++; rbounds.extend(prim.bounds(space1)); }
      }
      
      /*! return an invalid split if we do not partition */
      if (lnum == 0 || rnum == 0) 
	return Split(inf,axis0,axis1);
      
      /*! calculate sah for the split */
      const float sah = float(lnum)*halfArea(lbounds) + float(rnum)*halfArea(rbounds);
      return Split(sah,axis0,axis1);
    }
    __forceinline SpatialSplit::Split SpatialSplit::BinInfo::best(const PrimInfo& pinfo, const Mapping& mapping, const size_t blocks_shift)
    {
      /* sweep from right to left and compute parallel prefix of merged bounds */
      ssef rAreas[BINS];
      ssei rCounts[BINS];
      ssei count = 0; BBox3fa bx = empty; BBox3fa by = empty; BBox3fa bz = empty;
      for (size_t i=BINS-1; i>0; i--)
      {
	count += numEnd[i];
	rCounts[i] = count;
	bx.extend(bounds[i][0]); rAreas[i][0] = halfArea(bx);
	by.extend(bounds[i][1]); rAreas[i][1] = halfArea(by);
	bz.extend(bounds[i][2]); rAreas[i][2] = halfArea(bz);
      }
      
      /* sweep from left to right and compute SAH */
      ssei blocks_add = (1 << blocks_shift)-1;
      ssei ii = 1; ssef vbestSAH = pos_inf; ssei vbestPos = 0;
      count = 0; bx = empty; by = empty; bz = empty;
      for (size_t i=1; i<BINS; i++, ii+=1)
      {
	count += numBegin[i-1];
	bx.extend(bounds[i-1][0]); float Ax = halfArea(bx);
	by.extend(bounds[i-1][1]); float Ay = halfArea(by);
	bz.extend(bounds[i-1][2]); float Az = halfArea(bz);
	const ssef lArea = ssef(Ax,Ay,Az,Az);
	const ssef rArea = rAreas[i];
	const ssei lCount = (count     +blocks_add) >> blocks_shift;
	const ssei rCount = (rCounts[i]+blocks_add) >> blocks_shift;
	const ssef sah = lArea*ssef(lCount) + rArea*ssef(rCount);
	vbestPos  = select(sah < vbestSAH,ii ,vbestPos);
	vbestSAH  = select(sah < vbestSAH,sah,vbestSAH);
      }
      
      /* find best dimension */
      float bestSAH = inf;
      int   bestDim = -1;
      int   bestPos = 0;
      for (size_t dim=0; dim<3; dim++) 
      {
	/* ignore zero sized dimensions */
	if (unlikely(mapping.invalid(dim)))
	  continue;

	/* test if this is a better dimension */
	if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) {
	  bestDim = dim;
	  bestPos = vbestPos[dim];
	  bestSAH = vbestSAH[dim];
	}
      }
      
      /* return invalid split if no split found */
      if (bestDim == -1) 
	return Split(inf,-1,0,mapping);
      
      /* return best found split */
      return Split(bestSAH,bestDim,bestPos,mapping);
    }
    StrandSplit::TaskFindParallel::TaskFindParallel(size_t threadIndex, size_t threadCount, LockStepTaskScheduler* scheduler, BezierRefList& prims)
    {
      /* first curve determines first axis */
      BezierRefList::block_iterator_unsafe i = prims;
      axis0 = axis1 = normalize(i->p3 - i->p0);
      
      /* parallel calculation of 2nd axis  */
      size_t numTasks = min(maxTasks,threadCount);
      scheduler->dispatchTask(threadIndex,numTasks,_task_bound_parallel,this,numTasks,"build::task_find_parallel");
      
      /* select best 2nd axis */
      float bestCos = 1.0f;
      for (size_t i=0; i<numTasks; i++) {
	if (task_cos[i] < bestCos) { bestCos = task_cos[i]; axis1 = task_axis1[i]; }
      }
      
      /* parallel calculation of unaligned bounds */
      scheduler->dispatchTask(threadIndex,numTasks,_task_bound_parallel,this,numTasks,"build::task_find_parallel");
      
      /* reduce bounds calculates by tasks */
      size_t lnum = 0; BBox3fa lbounds = empty;
      size_t rnum = 0; BBox3fa rbounds = empty;
      for (size_t i=0; i<numTasks; i++) {
	lnum += task_lnum[i]; lbounds.extend(task_lbounds[i]);
	rnum += task_rnum[i]; rbounds.extend(task_rbounds[i]);
      }
      
      /*! return an invalid split if we do not partition */
      if (lnum == 0 || rnum == 0) {
	split = Split(inf,axis0,axis1); 
	return;
      }
      
      /*! calculate sah for the split */
      const float sah = float(lnum)*halfArea(lbounds) + float(lnum)*halfArea(rbounds);
      split = Split(sah,axis0,axis1);
    }
Exemple #8
0
 BVHNStatistics<N>::BVHNStatistics (BVH* bvh) : bvh(bvh)
 {
   double A = max(0.0f,halfArea(bvh->getBounds()));
   if (bvh->msmblur) 
   {
     NodeRef* roots = (NodeRef*)(size_t)bvh->root;
     for (size_t i=0; i<bvh->numTimeSteps-1; i++) {
       const BBox1f t0t1(float(i+0)/float(bvh->numTimeSteps-1),
                       float(i+1)/float(bvh->numTimeSteps-1));
       stat = stat + statistics(roots[i],A,t0t1);
     }
   }
   else {
     stat = statistics(bvh->root,A,BBox1f(0.0f,1.0f));
   }
 }
Exemple #9
0
  __forceinline BVH2Builder<Heuristic>::ParallelSplitTask::ParallelSplitTask(const TaskScheduler::ThreadInfo& thread, BVH2Builder* parent, BVH2::Base*& node, size_t depth, 
                                                                             atomic_set<PrimRefBlock>& prims, const PrimInfo& pinfo, const Split& split)
    : parent(parent), dst(node), depth(depth), split(split)
  {
    /*! compute leaf and split cost */
    const float leafSAH  = parent->trity.intCost*pinfo.sah();
    const float splitSAH = BVH2::travCost*halfArea(pinfo.geomBounds)+parent->trity.intCost*split.sah();
    assert(atomic_set<PrimRefBlock>::block_iterator_unsafe(prims).size() == pinfo.size());
    assert(leafSAH >= 0 && splitSAH >= 0);

    /*! create a leaf node when threshold reached or SAH tells us to stop */
    if (pinfo.size() <= 1 || depth > BVH2::maxDepth || (pinfo.size() <= parent->bvh->maxLeafTris && leafSAH <= splitSAH)) {
      dst = parent->createLeaf(thread,prims,pinfo); delete this; return;
    }

    /*! start parallel splitting */
    new (&splitter) MultiThreadedSplitterNormal(thread,
                                                &parent->alloc,parent->triangles,parent->vertices,prims,pinfo,split,
                                                (TaskScheduler::completeFunction)_createNode,this);
  }
Exemple #10
0
  int BVH2Builder::BuildTask::recurse(size_t depth, ObjectBinning<2>& job)
  {
    /*! compute leaf and split cost */
    size_t N = job.size();
    float leafSAH  = BVH2<Triangle4>::intCost*job.leafSAH;
    float splitSAH = BVH2<Triangle4>::travCost*halfArea(job.geomBounds)+BVH2<Triangle4>::intCost*job.splitSAH;

    /*! make leaf node when threshold reached or SAH tells us */
    if (N <= 1 || depth > BVH2<Triangle4>::maxDepth || (N <= BVH2<Triangle4>::maxLeafSize && leafSAH < splitSAH))
      return parent->bvh->createLeaf(parent->prims,parent->triangles,parent->threadAllocPrimitives(tid,blocks(N)),job.start(),N);

    /*! perform split */
    ObjectBinning<2> left,right;
    job.split(parent->prims,left,right);

    /*! create an inner node */
    int nodeID = (int)parent->threadAllocNodes(tid,1);
    BVH2<Triangle4>::Node& node = parent->bvh->nodes[nodeID].clear();
    node.set(0,left .geomBounds,recurse(depth+1,left ));
    node.set(1,right.geomBounds,recurse(depth+1,right));
    return BVH2<Triangle4>::id2offset(nodeID);
  }
Exemple #11
0
 typename BVHNStatistics<N>::Statistics BVHNStatistics<N>::statistics(NodeRef node, const double A, const BBox1f t0t1)
 {
   Statistics s;
   double dt = max(0.0f,t0t1.size());
   if (node.isAlignedNode())
   {
     AlignedNode* n = node.alignedNode();
     for (size_t i=0; i<N; i++) {
       if (n->child(i) == BVH::emptyNode) continue;
       s.statAlignedNodes.numChildren++;
       const double Ai = max(0.0f,halfArea(n->extend(i)));
       s = s + statistics(n->child(i),Ai,t0t1); 
     }
     s.statAlignedNodes.numNodes++;
     s.statAlignedNodes.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isUnalignedNode())
   {
     UnalignedNode* n = node.unalignedNode();
     for (size_t i=0; i<N; i++) {
       if (n->child(i) == BVH::emptyNode) continue;
       s.statUnalignedNodes.numChildren++;
       const double Ai = max(0.0f,halfArea(n->extend(i)));
       s = s + statistics(n->child(i),Ai,t0t1); 
     }
     s.statUnalignedNodes.numNodes++;
     s.statUnalignedNodes.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isAlignedNodeMB())
   {
     AlignedNodeMB* n = node.alignedNodeMB();
     for (size_t i=0; i<N; i++) {
       if (n->child(i) == BVH::emptyNode) continue;
       s.statAlignedNodesMB.numChildren++;
       const double Ai = max(0.0f,halfArea(n->extend0(i)));
       s = s + statistics(n->child(i),Ai,t0t1);
     }
     s.statAlignedNodesMB.numNodes++;
     s.statAlignedNodesMB.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isUnalignedNodeMB())
   {
     UnalignedNodeMB* n = node.unalignedNodeMB();
     for (size_t i=0; i<N; i++) {
       if (n->child(i) == BVH::emptyNode) continue;
       s.statUnalignedNodesMB.numChildren++;
       const double Ai = max(0.0f,halfArea(n->extend0(i)));
       s = s + statistics(n->child(i),Ai,t0t1); 
     }
     s.statUnalignedNodesMB.numNodes++;
     s.statUnalignedNodesMB.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isTransformNode())
   {
     s.statTransformNodes.numNodes++;
     s.statTransformNodes.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isQuantizedNode())
   {
     QuantizedNode* n = node.quantizedNode();
     for (size_t i=0; i<N; i++) {
       if (n->child(i) == BVH::emptyNode) continue;
       s.statQuantizedNodes.numChildren++;
       const double Ai = max(0.0f,halfArea(n->extend(i)));
       s = s + statistics(n->child(i),Ai,t0t1); 
     }
     s.statQuantizedNodes.numNodes++;
     s.statQuantizedNodes.nodeSAH += dt*A;
     s.depth++;
   }
   else if (node.isLeaf())
   {
     size_t num; const char* tri = node.leaf(num);
     if (num)
     {
       for (size_t i=0; i<num; i++) {
         s.statLeaf.numPrims += bvh->primTy.size(tri+i*bvh->primTy.bytes);
       }
       s.statLeaf.numLeaves++;
       s.statLeaf.numPrimBlocks += num;
       s.statLeaf.leafSAH += dt*A*num;
       if (num-1 < Statistics::LeafStat::NHIST) {
         s.statLeaf.numPrimBlocksHistogram[num-1]++;
       }
     }
   }
   else {
     throw std::runtime_error("not supported node type in bvh_statistics");
   }
   return s;
 } 
Exemple #12
0
  void BVHNStatistics<N>::statistics(NodeRef node, const float A, size_t& depth)
  {
    if (node.isNode())
    {
      numAlignedNodes++;
      AlignedNode* n = node.node();
      bvhSAH += A*travCostAligned;
      depth = 0;
      for (size_t i=0; i<N; i++) {
        if (n->child(i) == BVH::emptyNode) continue;
        childrenAlignedNodes++;
        const float Ai = max(0.0f,halfArea(n->extend(i)));
        size_t cdepth; statistics(n->child(i),Ai,cdepth); 
        depth=max(depth,cdepth);
      }
      depth++;
    }
    else if (node.isUnalignedNode())
    {
      numUnalignedNodes++;
      UnalignedNode* n = node.unalignedNode();
      bvhSAH += A*travCostUnaligned;
      
      depth = 0;
      for (size_t i=0; i<N; i++) {
        if (n->child(i) == BVH::emptyNode) continue;
        childrenUnalignedNodes++;
        const float Ai = max(0.0f,halfArea(n->extend(i)));
        size_t cdepth; statistics(n->child(i),Ai,cdepth); 
        depth=max(depth,cdepth);
      }
      depth++;
    }
    else if (node.isNodeMB())
    {
      numAlignedNodesMB++;
      AlignedNodeMB* n = node.nodeMB();
      bvhSAH += A*travCostAligned;
      
      depth = 0;
      for (size_t i=0; i<N; i++) {
        if (n->child(i) == BVH::emptyNode) continue;
        childrenAlignedNodesMB++;
        const float Ai = max(0.0f,halfArea(n->extend0(i)));
        size_t cdepth; statistics(n->child(i),Ai,cdepth); 
        depth=max(depth,cdepth);
      }
      depth++;
    }
    else if (node.isUnalignedNodeMB())
    {
      numUnalignedNodesMB++;
      UnalignedNodeMB* n = node.unalignedNodeMB();
      bvhSAH += A*travCostUnaligned;
      
      depth = 0;
      for (size_t i=0; i<N; i++) {
        if (n->child(i) == BVH::emptyNode) continue;
        childrenUnalignedNodesMB++;
        const float Ai = max(0.0f,halfArea(n->extend0(i)));
        size_t cdepth; statistics(n->child(i),Ai,cdepth); 
        depth=max(depth,cdepth);
      }
      depth++;
    }
    else if (node.isTransformNode())
    {
      numTransformNodes++;
      TransformNode* n = node.transformNode();
      bvhSAH += A*travCostTransform;

      depth = 0;
      const BBox3fa worldBounds = xfmBounds(n->local2world,n->localBounds);
      const float Ai = max(0.0f,halfArea(worldBounds));
      //size_t cdepth; statistics(n->child,Ai,cdepth); 
      //depth=max(depth,cdepth)+1;
    }
    else
    {
      depth = 0;
      size_t num; const char* tri = node.leaf(num);
      if (!num) return;
      
      numLeaves++;
      numPrimBlocks += num;
      for (size_t i=0; i<num; i++)
        numPrims += bvh->primTy.size(tri+i*bvh->primTy.bytes);
      
      float sah = A * intCost * num;
      leafSAH += sah;
    }
  } 
Exemple #13
0
  void BVH4Statistics::statistics(NodeRef node, const float A, size_t& depth)
  {
    if (node.isNode())
      {
	hash += 0x1234;
	numAlignedNodes++;
	AlignedNode* n = node.node();
	bvhSAH += A*BVH4::travCostAligned;
	depth = 0;
	for (size_t i=0; i<BVH4::N; i++) {
	  if (n->child(i) == BVH4::emptyNode) continue;
	  childrenAlignedNodes++;
	  const float Ai = max(0.0f,halfArea(n->extend(i)));
	  size_t cdepth; statistics(n->child(i),Ai,cdepth); 
	  depth=max(depth,cdepth);
	}
	depth++;
	hash += 0x76767*depth;
      }
    else if (node.isUnalignedNode())
      {
	hash += 0x1232344;
	numUnalignedNodes++;
	UnalignedNode* n = node.unalignedNode();
	bvhSAH += A*BVH4::travCostUnaligned;

	depth = 0;
	for (size_t i=0; i<BVH4::N; i++) {
	  if (n->child(i) == BVH4::emptyNode) continue;
	  childrenUnalignedNodes++;
	  const float Ai = max(0.0f,halfArea(n->extend(i)));
	  size_t cdepth; statistics(n->child(i),Ai,cdepth); 
	  depth=max(depth,cdepth);
	}
	depth++;
	hash += 0x76767*depth;
      }
    else if (node.isNodeMB())
      {
	hash += 0xEF343;
	numAlignedNodesMB++;
	BVH4::NodeMB* n = node.nodeMB();
	bvhSAH += A*BVH4::travCostAligned;

	depth = 0;
	for (size_t i=0; i<BVH4::N; i++) {
	  if (n->child(i) == BVH4::emptyNode) continue;
	  childrenAlignedNodesMB++;
	  const float Ai = max(0.0f,halfArea(n->extend0(i)));
	  size_t cdepth; statistics(n->child(i),Ai,cdepth); 
	  depth=max(depth,cdepth);
	}
	depth++;
	hash += 0x76767*depth;
      }
    else if (node.isUnalignedNodeMB())
      {
	hash += 0x1EEF4;
	numUnalignedNodesMB++;
	BVH4::UnalignedNodeMB* n = node.unalignedNodeMB();
	bvhSAH += A*BVH4::travCostUnaligned;

	depth = 0;
	for (size_t i=0; i<BVH4::N; i++) {
	  if (n->child(i) == BVH4::emptyNode) continue;
	  childrenUnalignedNodesMB++;
	  const float Ai = max(0.0f,halfArea(n->extend0(i)));
	  size_t cdepth; statistics(n->child(i),Ai,cdepth); 
	  depth=max(depth,cdepth);
	}
	depth++;
	hash += 0x76767*depth;
      }
    else
      {
	depth = 0;
	size_t num; const char* tri = node.leaf(num);
	hash += 0xDD776*num+0x878;
	if (!num) return;

	hash += bvh->primTy.hash(tri,num);
      
	numLeaves++;
	numPrims += num;
	float sah = A * BVH4::intCost * num;
	bvhSAH += sah;
      }
  }