summaryrefslogtreecommitdiff
path: root/hw6/src/boundedCompound.cpp
blob: c37ca0f87f53d157e1f3fbef5a6f10aff1c6df77 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/******************************************************************/
/* 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 "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<const shader_base>& 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<const boundedPrimitive>& 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<const boundedPrimitive>& 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)";
}