/******************************************************************/
/* This file is part of the homework assignments for CSCI-427/527 */
/* at The College of William & Mary and authored by Pieter Peers. */
/* No part of this file, whether altered or in original form, can */
/* be distributed or used outside the context of CSCI-427/527 */
/* without consent of either the College of William & Mary or */
/* Pieter Peers. */
/******************************************************************/
#include <cassert>
#include <algorithm>
#include "boundedVolumeNode.h"
#include "random_number.h"
boundedVolumeNode::boundedVolumeNode(const std::vector<std::shared_ptr<const boundedPrimitive>>::iterator& start, const std::vector<std::shared_ptr<const boundedPrimitive>>::iterator& end)
: _left(nullptr), _right(nullptr), boundedPrimitive()
{
assert(std::distance(start, end) > 1);
// compute the bounding box
for_each(start, end, [&](const std::shared_ptr<const boundedPrimitive>& prim)
{
_bb += prim->boundingbox();
});
// select random splitting dimension & pivot
unsigned int split = random_int(2);
float pivot = _bb.center()[split];
// partition
auto middle = std::partition(start, end, [&](const std::shared_ptr<const boundedPrimitive>& prim)
{
return prim->boundingbox().center()[split] < pivot;
});
// special case: all centers are the same.
if(start == middle) middle++;
// create _left (recurse if more than one primitive)
if(std::distance(start, middle) == 1)
_left = *start;
else
_left = std::shared_ptr<const boundedPrimitive>(new boundedVolumeNode(start, middle));
// create _right (recurse if more than one primitive)
if(std::distance(middle, end) == 1)
_right = *middle;
else
_right = std::shared_ptr<const boundedPrimitive>(new boundedVolumeNode(middle, end));
// Done.
}
intersectionPoint boundedVolumeNode::intersect(const ray& r) const
{
intersectionPoint leftIp, rightIp;
// check left child
if(_left && _left->hitBoundingBox(r))
leftIp = _left->intersect(r);
// check right child
if(_right && _right->hitBoundingBox(r))
rightIp = _right->intersect(r);
// return closest
return std::min(leftIp, rightIp);
}
float boundedVolumeNode::area(void) const
{
float total_area = 0.0f;
if(_left) total_area += _left->area();
if(_right) total_area += _right->area();
return total_area;
}
surfaceSample boundedVolumeNode::sample(float r1, float r2) const
{
if(_left && !_right) return _left->sample(r1, r2);
else if(_right && !_left) return _right->sample(r1, r2);
else
{
float area_left = _left->area();
float area_right = _right->area();
float prob_left = area_left / (area_left + area_right);
float prob_right = 1.0f - prob_left;
if(r1 <= prob_left)
return _left->sample(r1 / prob_left, r2) * prob_left;
else
return _right->sample((r1 - prob_left) / prob_right, r2) * prob_right;
}
}