/******************************************************************/ /* 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 "boundedCompound.h" #include "intersector_factory_base.h" ///////////////// // Constructor // ///////////////// boundedCompound::boundedCompound(void) : boundedPrimitive() { _transform = transformation3d(); _intersector = nullptr; } boundedCompound::boundedCompound(const transformation3d& transform, const std::shared_ptr& shader) : boundedPrimitive(boundingBox(), shader) { _transform = transform; _intersector = nullptr; } ///////////// // Methods // ///////////// intersectionPoint boundedCompound::intersect(const ray& r) const { // sanity check assert(_intersector); // inverse transform ray ray transformedRay = inverseTransform(r, _transform); // pass intersection computation to _intersector intersectionPoint ip = _intersector->intersect( transformedRay ); // if no shader, insert current shader if(!ip.hasShader()) ip.setShader(_shader); // transform the intersection point ip.transform(_transform); // Done. return ip; } float boundedCompound::area(void) const { float total_area = 0.0f; for_each(compounds().begin(), compounds().end(), [&](const std::shared_ptr& prim) { total_area += prim->area(); }); // Done. return total_area; } surfaceSample boundedCompound::sample(float r1, float r2) const { float total_area = area(); auto primItr = compounds().begin(); // sample compounds (proportional to area) float prim_area = (*primItr)->area(); float residual = r1*total_area; while(residual > prim_area && std::next(primItr) != compounds().end()) { residual -= prim_area; primItr++; prim_area = (*primItr)->area(); } // rescale the random variable r1 = std::min(residual / prim_area, 1.0f); // sample point in triangle (and adjust pdf to include the above selection) surfaceSample sample = (*primItr)->sample(r1, r2) * (prim_area / total_area); // apply transformation sample.transform(_transform); // Done. return sample; } void boundedCompound::initialize(const intersector_factory_base& ifb) { // create the _intersector _intersector = ifb(*this); } void boundedCompound::initializeBoundingBox(void) { // compute the bounding box in world coordinates _bb = boundingBox(); for_each(compounds().begin(), compounds().end(), [&](const std::shared_ptr& prim) { _bb += transform(prim->boundingbox(), _transform); }); } bool boundedCompound::hasShader(void) const { // check if this has a shader if(boundedPrimitive::hasShader()) return true; // check if each child has a shader for(auto itr = compounds().begin(); itr != compounds().end(); itr++) { if(!(*itr)->hasShader()) return false; } // Done. return true; } void boundedCompound::_print(std::ostream& s) const { s << "boundedCompound (" << _bb << ", " << compounds().size() << " compounds)"; }