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)";
}
|