summaryrefslogblamecommitdiff
path: root/hw6/src/compoundShader.cpp
blob: 6456fdc8f7d3674628d064fe43e23fe9fe1f230b (plain) (tree)












































































































































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