summaryrefslogtreecommitdiff
path: root/hw6/src/compoundShader.cpp
blob: 6456fdc8f7d3674628d064fe43e23fe9fe1f230b (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
140
141
/******************************************************************/
/* 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 <algorithm>
#include "compoundShader.h"
#include "random_number.h"
#include <iostream> // DEBUG

//////////////////
// Constructors //
//////////////////
compoundShader::compoundShader(const std::vector<std::shared_ptr<const shader_base>>& shader_list)
  : shader_base()
{
  _compound = shader_list;
}


/////////////
// Methods //
/////////////
color compoundShader::shade(const intersectionPoint& ip, const vec3d& light_dir) const
{
  color result(0.0f, 0.0f, 0.0f);
  for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr<const shader_base>& shader)
  {
    result += shader->shade(ip, light_dir);
  });

  // Done.
  return result;
}


color compoundShader::reflectance(const intersectionPoint& ip, const vec3d& light_dir) const
{
  color result(0.0f, 0.0f, 0.0f);
  for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr<const shader_base>& shader)
  {
    result += shader->reflectance(ip, light_dir);
  });

  // Done.
  return result;
}


brdfSample compoundShader::sample(const intersectionPoint& ip, float r1, float r2) const
{
  // santiy check
  if(_compound.empty()) return brdfSample();

  // initialize
  auto currentCompound = _compound.begin();
  float pdf = 1.0f;

  // HW6: implement importance sampling of BRDF, where you select
  //      a BRDF propertional to their relative reflectivity.
  //      For example, if the compound shader has two BRDFs with
  //      an reflectivity of 20% and 40%, then the likelihood that
  //      the second BRDF is sampled is twice that of the first BRDF.
  //      Practically, you need to point the 'currentCompound' to the BRDF
  //      you want sample, and set 'pdf' to the PDF of the selection.
  // Modifies: nothing
  // Returns: brdfSample

  float cdf = 0.0f;
  float choice = random_float(1.0f) * reflectivity(ip);

  // compute cdf until it exceeds choice probability and select that compound
  while (currentCompound < _compound.end() && choice >= cdf) {
    pdf = (**currentCompound).reflectivity(ip);
    cdf += pdf;
    currentCompound++;
  }

  // move currentCompound back to selection
  currentCompound--;

  // generate sample (do not remove -- this line will produce the correct
  //  result if currentCompound and pdf are set correctly).
  return (*currentCompound)->sample(ip, r1, r2) * pdf;
}


float compoundShader::reflectivity(const intersectionPoint& ip) const
{
  // return sum of reflectivity
  float total_reflectivity = 0.0f;
  for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr<const shader_base>& shader)
  {
    total_reflectivity += shader->reflectivity(ip);
  });

  // Done.
  return total_reflectivity;
}


color compoundShader::emittance(const intersectionPoint& ip) const
{
  // return total sum of emittance
  color total_emittance;
  for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr<const shader_base>& shader)
  {
    total_emittance += shader->emittance(ip);
  });

  // Done.
  return total_emittance;
}


shaderProperties compoundShader::properties(const intersectionPoint& ip) const
{
  // if any component has a property set, then set it for the compound
  shaderProperties result(false, false);
  for(unsigned int i=0; i < _compound.size(); i++)
    result |= _compound[i]->properties(ip);

  // Done.
  return result;
}


void compoundShader::_print(std::ostream& s) const
{
  s << "Compound Shader (" << _compound.size() << " components): {";
  for(unsigned int i=0; i < _compound.size(); i++)
  {
    s << *_compound[i];
    if(i != _compound.size()-1) s << ", ";
  }
  s << "}";
}