/******************************************************************/
/* 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 "shader_base.h"
#include "intersectionPoint.h"
/////////////////
// Constructor //
/////////////////
intersectionPoint::intersectionPoint(void)
{
_hit = false;
}
intersectionPoint::intersectionPoint(const ray& r, float rayParameter, const std::shared_ptr<const shader_base>& shader, const vec3d& normal, const vec3d& axis, const vec2d& textureCoordinate)
{
// copy
_ray = r;
_rayParameter = rayParameter;
_hit = true;
_shader = shader;
_normal = normalize(normal);
_axis = normalize(axis);
_textureCoordinate = textureCoordinate;
// compute position
_position = _ray(_rayParameter);
}
intersectionPoint::intersectionPoint(const intersectionPoint& ip)
{
_hit = ip._hit;
// copy remainder if hit
if(_hit)
{
_ray = ip._ray;
_rayParameter = ip._rayParameter;
_shader = ip._shader;
_normal = ip._normal;
_position = ip._position;
_axis = ip._axis;
_textureCoordinate = ip._textureCoordinate;
}
else _shader = nullptr;
}
///////////////
// Operators //
///////////////
intersectionPoint& intersectionPoint::operator=(const intersectionPoint& ip)
{
_assign(ip);
return *this;
}
bool intersectionPoint::operator<(const intersectionPoint& ip) const
{
// handle case where either one of the intersectionPoints is not a hit
// => assume no-hit equals a hit at infinity
if(!_hit) return false;
if(!ip._hit) return true;
// decide based on rayParameter
return _rayParameter < ip._rayParameter;
}
bool intersectionPoint::operator>(const intersectionPoint& ip) const
{
// handle case where either one of the intersectionPoints is not a hit
// => assume no-hit equals a hit at infinity
if(!_hit) return true;
if(!ip._hit) return false;
// decide based on rayParameter
return _rayParameter > ip._rayParameter;
}
bool intersectionPoint::operator<(const lightSample& ls) const
{
// handle case where this is not a hit
if(!_hit) return false;
// decide based on rayParameter
return _rayParameter < ls.distance();
}
bool intersectionPoint::operator>(const lightSample& ls) const
{
// handle case where this is not a hit
if(!_hit) return true;
// decide based on rayParameter
return _rayParameter > ls.distance();
}
////////////////
// Inspectors //
////////////////
bool intersectionPoint::isHit(void) const
{
return _hit;
}
shaderProperties intersectionPoint::getShaderProperties(void) const
{
assert(hasShader());
return _shader->properties(*this);
}
bool intersectionPoint::hasShader(void) const
{
return (_shader != nullptr);
}
float intersectionPoint::distance(const intersectionPoint& ip) const
{
// set distance to infinity of one of the two points is not a hit
if(!_hit || !ip._hit) return +LARGE;
// compute distance
return _position.distance(ip._position);
}
const vec3d& intersectionPoint::position(void) const
{
return _position;
}
const vec3d& intersectionPoint::direction(void) const
{
return _ray.direction();
}
const vec2d& intersectionPoint::textureCoordinate(void) const
{
return _textureCoordinate;
}
const vec3d& intersectionPoint::normal(void) const
{
return _normal;
}
coordinateTransformation intersectionPoint::shadingFrame(void) const
{
// transform => to global shading frame
// inverseTransform => to local shading frame
return coordinateTransformation(_normal, _axis);
}
//////////////
// Mutators //
//////////////
void intersectionPoint::transform(const transformation3d& t)
{
// sanity check
if(!_hit) return;
/// transform
_ray.transform(t);
_position = t.transformPoint(_position);
_normal = t.transformNormal(_normal);
_axis = t.transformNormal(_axis);
// recompute the ray parameter (to account for potential scaling)
_rayParameter = _ray(_position);
}
void intersectionPoint::inverseTransform(const transformation3d& t)
{
// sanity check
if(!_hit) return;
// inverse transform
_ray.inverseTransform(t);
_position = t.inverseTransformPoint(_position);
_normal = t.inverseTransformNormal(_normal);
_axis = t.inverseTransformNormal(_axis);
// recompute the ray parameter (to account for potential scaling)
_rayParameter = _ray(_position);
}
void intersectionPoint::transformShadingFrame(const transformation3d& sft)
{
// sanity check
if(!_hit) return;
// Note: shading frame transformation are defined
// with respect to the local shading frame (i.e., N=Z, axis=X)
transformation3d t = shadingFrame();
// transform
_normal = t.transformNormal( sft.transformNormal(vec3d(0.0f, 0.0f, 1.0f)) );
_axis = t.transformNormal( sft.transformNormal(vec3d(1.0f, 0.0f, 0.0f)) );
// Done.
}
void intersectionPoint::inverseTransformShadingFrame(const transformation3d& sft)
{
// sanity check
if(!_hit) return;
// Note: shading frame transformation are defined
// with respect to the local shading frame (i.e., N=Z, axis=X)
// Note: this transformation will not undo the effects of
// transformShadingFrame since the local shading frame
// is altered by the transformation (and thus the frame
// with respect to which the inverseTransformation is
// applied)
transformation3d t = shadingFrame();
// transform
_normal = t.transformNormal( sft.inverseTransformNormal(vec3d(0.0f, 0.0f, 1.0f)) );
_axis = t.transformNormal( sft.inverseTransformNormal(vec3d(1.0f, 0.0f, 0.0f)) );
// Done.
}
void intersectionPoint::setShader(const std::shared_ptr<const class shader_base>& shader)
{
_shader = shader;
}
/////////////
// Methods //
/////////////
color intersectionPoint::shade(const vec3d& out) const
{
assert(hasShader());
if(!_hit) return color(0.0f);
return _shader->shade(*this, out);
}
color intersectionPoint::shade(const lightSample& ls) const
{
assert(hasShader());
if(!_hit) return color(0.0f);
return _shader->shade(*this, ls.directionToLight()) * ls.emittance();
}
float intersectionPoint::reflectivity(void) const
{
assert(hasShader());
// get reflectivity
float albedo = _shader->reflectivity(*this);
// cannot reflect more than 100%
assert(albedo <= 1.0f);
// Done.
return albedo;
}
color intersectionPoint::reflectance(const vec3d& out) const
{
assert(hasShader());
return _shader->reflectance(*this, out);
}
brdfSample intersectionPoint::sample(float r1, float r2) const
{
assert(hasShader());
return _shader->sample(*this, r1, r2);
}
color intersectionPoint::emittance(void) const
{
assert(hasShader());
return _shader->emittance(*this);
}
/////////////////////
// Private Methods //
/////////////////////
void intersectionPoint::_assign(const intersectionPoint& ip)
{
// sanity check
if(&ip == this) return;
// copy if hit
_hit = ip._hit;
if(_hit)
{
_ray = ip._ray;
_rayParameter = ip._rayParameter;
_position = ip._position;
_normal = ip._normal;
_axis = ip._axis;
_textureCoordinate = ip._textureCoordinate;
_shader = ip._shader;
}
else _shader = nullptr;
}
void intersectionPoint::_swap(intersectionPoint& ip)
{
swap(_ray, ip._ray);
std::swap(_hit, ip._hit);
std::swap(_rayParameter, ip._rayParameter);
swap(_position, ip._position);
swap(_normal, ip._normal);
swap(_axis, ip._axis);
swap(_textureCoordinate, ip._textureCoordinate);
std::swap(_shader, ip._shader);
}