/******************************************************************/ /* 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 #include #include "boundedVolumeNode.h" #include "random_number.h" boundedVolumeNode::boundedVolumeNode(const std::vector>::iterator& start, const std::vector>::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& 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& 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(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(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; } }