/******************************************************************/ /* 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 #include "shader_base.h" #include "intersectionPoint.h" ///////////////// // Constructor // ///////////////// intersectionPoint::intersectionPoint(void) { _hit = false; } intersectionPoint::intersectionPoint(const ray& r, float rayParameter, const std::shared_ptr& 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& 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); }