/******************************************************************/
/* 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 << "}";
}