summaryrefslogtreecommitdiff
path: root/hw2/src/triangle.cpp
diff options
context:
space:
mode:
author53hornet <53hornet@gmail.com>2019-02-02 23:33:15 -0500
committer53hornet <53hornet@gmail.com>2019-02-02 23:33:15 -0500
commitdb072ad4dc181eca5a1458656b130beb43f475bf (patch)
treea3c03c7f5497cb70503e2486662fa85cfb53415a /hw2/src/triangle.cpp
downloadcsci427-master.tar.xz
csci427-master.zip
Diffstat (limited to 'hw2/src/triangle.cpp')
-rw-r--r--hw2/src/triangle.cpp451
1 files changed, 451 insertions, 0 deletions
diff --git a/hw2/src/triangle.cpp b/hw2/src/triangle.cpp
new file mode 100644
index 0000000..1e3990e
--- /dev/null
+++ b/hw2/src/triangle.cpp
@@ -0,0 +1,451 @@
+/******************************************************************/
+/* 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 <algorithm>
+
+#include "triangle.h"
+#include "constants.h"
+
+//////////////////
+// Constructors //
+//////////////////
+triangle::triangle(void)
+{
+ _vertex_list = nullptr;
+ _normal_list = nullptr;
+ _textureCoord_list = nullptr;
+}
+
+
+//////////////////////
+// Copy Constructor //
+//////////////////////
+triangle::triangle(const triangle& t)
+ : triangle()
+{
+ // share ptr to list
+ _vertex_list = t._vertex_list;
+ _normal_list = t._normal_list;
+ _textureCoord_list = t._textureCoord_list;
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+//////////////////////
+// Move Constructor //
+//////////////////////
+triangle::triangle(triangle&& t)
+ : triangle()
+{
+ // swap list (no need to increment ref-count)
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+//////////////////////////
+// General Constructors //
+//////////////////////////
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3)
+ : triangle()
+{
+ // create a list of three vertices
+ auto vertex_list = std::make_shared<std::vector<vec3d>>(3);
+ _vertex_list = vertex_list;
+
+ // copy values
+ (*vertex_list)[0] = v1;
+ (*vertex_list)[1] = v2;
+ (*vertex_list)[2] = v3;
+
+ // set indices
+ _vertex_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list)
+ : triangle()
+{
+ // share vertex list
+ _vertex_list = vertex_list;
+
+ // copy indices
+ _vertex_idx[0] = v1_idx;
+ _vertex_idx[1] = v2_idx;
+ _vertex_idx[2] = v3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3)
+ : triangle(v1, v2, v3)
+{
+ // create a list of three normals
+ auto normal_list = std::make_shared<std::vector<vec3d>>(3);
+ _normal_list = normal_list;
+
+ // copy values
+ (*normal_list)[0] = n1;
+ (*normal_list)[1] = n2;
+ (*normal_list)[2] = n3;
+
+ // set indices
+ _normal_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list)
+{
+ // share normal list
+ _normal_list = normal_list;
+
+ // copy indices
+ _normal_idx[0] = n1_idx;
+ _normal_idx[1] = n2_idx;
+ _normal_idx[2] = n3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3)
+ : triangle(v1, v2, v3)
+{
+ // create a list of three texture coordinates
+ auto textureCoord_list = std::make_shared<std::vector<vec2d>>(3);
+ _textureCoord_list = textureCoord_list;
+
+ // copy values
+ (*textureCoord_list)[0] = t1;
+ (*textureCoord_list)[1] = t2;
+ (*textureCoord_list)[2] = t3;
+
+ // set indices
+ _textureCoord_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list)
+{
+ // share normal list
+ _textureCoord_list = texcoord_list;
+
+ // copy indices
+ _textureCoord_idx[0] = t1_idx;
+ _textureCoord_idx[1] = t2_idx;
+ _textureCoord_idx[2] = t3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3)
+ : triangle(v1, v2, v3, n1, n2, n3)
+{
+ // create a list of three texture coordinates
+ auto textureCoord_list = std::make_shared<std::vector<vec2d>>(3);
+ _textureCoord_list = textureCoord_list;
+
+ // copy values
+ (*textureCoord_list)[0] = t1;
+ (*textureCoord_list)[1] = t2;
+ (*textureCoord_list)[2] = t3;
+
+ // set indices
+ _textureCoord_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list,
+ n1_idx, n2_idx, n3_idx, normal_list)
+{
+ // share normal list
+ _textureCoord_list = texcoord_list;
+
+ // copy indices
+ _textureCoord_idx[0] = t1_idx;
+ _textureCoord_idx[1] = t2_idx;
+ _textureCoord_idx[2] = t3_idx;
+}
+
+
+
+////////////////
+// Inspectors //
+////////////////
+const vec3d& triangle::vertex(size_t index) const
+{
+ // bounds check
+ assert(_vertex_list && index < 3);
+
+ // Done.
+ return (*_vertex_list)[_vertex_idx[index]];
+}
+
+
+const vec3d& triangle::normal(size_t index) const
+{
+ // bounds check
+ assert(_normal_list && index < 3);
+
+ // Done.
+ return (*_normal_list)[_normal_idx[index]];
+}
+
+
+const vec2d& triangle::textureCoordinate(size_t index) const
+{
+ // bounds check
+ assert(_textureCoord_list && index < 3);
+
+ // Done.
+ return (*_textureCoord_list)[_textureCoord_idx[index]];
+}
+
+
+bool triangle::hasPerVertexNormals(void) const
+{
+ return (bool)(_normal_list);
+}
+
+
+bool triangle::hasPerVertexTextureCoordinates(void) const
+{
+ return (bool)(_textureCoord_list);
+}
+
+
+///////////////
+// Operators //
+///////////////
+triangle& triangle::operator=(const triangle& t)
+{
+ _assign(t);
+ return *this;
+}
+
+
+triangle& triangle::operator=(triangle&& t)
+{
+ // swap list (no need to increment ref-count)
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+
+ // Done.
+ return *this;
+}
+
+
+/////////////
+// Methods //
+/////////////
+bool triangle::intersect(const ray& r, vec3d& barycentricCoord, float& t) const
+{
+ // HW2: Implement this.
+ // Compute the intersection between the triangle (this) and the ray (r).
+ // Use the method 'vertex(i)' to access the i-th vertex of the triangle (i=[0,1,2]).
+ // Use the method 'normal()' to access the normal of the plane in which the traingle lies.
+ // Returns: bool (true if hit, false if not)
+ // barycentricCoord (fill in alpha, beta, gamma barycentric coordinates
+ // of (vertex(0), vertex(1), and vertex(2)) if hit)
+ // t (the distance at which the ray intersects => r(t) == intersection point)
+ float d, a1, a2, a3, area, alpha, beta, gamma;
+ vec3d n, q, p1, p2, p3;
+
+ d = -(vertex(0).dot(normal()));
+ t = (-((r.origin().dot(normal())) + d)) / (r.direction().dot(normal()));
+
+ if (t < 0) {return false;}
+
+ q = r.origin() + t * r.direction();
+ p1 = vertex(0);
+ p2 = vertex(1);
+ p3 = vertex(2);
+ n = (p2 - p1).cross(p3 - p1);
+ a1 = 0.5f * (p2 - q).cross(p3 - q).dot(n);
+ a2 = 0.5f * (p3 - q).cross(p1 - q).dot(n);
+ a3 = 0.5f * (p1 - q).cross(p2 - q).dot(n);
+ area = a1 + a2 + a3;
+ alpha = a1 / area;
+ beta = a2 / area;
+ gamma = a3 / area;
+
+ if (alpha < 0 || beta < 0 || gamma < 0) {return false;}
+
+ barycentricCoord = vec3d(alpha, beta, gamma);
+ return true;
+}
+
+
+boundingBox triangle::boundingbox(void) const
+{
+ boundingBox bb;
+ for(unsigned int i=0; i < 3; i++)
+ bb += vertex(i);
+ return bb;
+}
+
+
+vec3d triangle::vertex(const vec3d& barycentricCoord) const
+{
+ vec3d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += vertex(i) * barycentricCoord[i];
+ return result;
+}
+
+
+vec3d triangle::normal(void) const
+{
+ vec3d e1 = vertex(1) - vertex(0);
+ vec3d e2 = vertex(2) - vertex(0);
+ return e1.cross(e2).normalize();
+}
+
+vec3d triangle::shadingAxis(void) const
+{
+ // follow texture coordinates if defined, otherwise, return the first axis.
+ if(!_textureCoord_list) return normalize(vertex(1)-vertex(0));
+
+ // find the vector that follows the U-axis of the texture coordinates
+ // solve:
+ // [ (t1-t0) (t2-t0) ] [ delta_beta delta_gamma ]^T = [1 0]^T
+ // for delta_beta and delta_gamma.
+ vec3d v1 = vertex(1) - vertex(0);
+ vec3d v2 = vertex(2) - vertex(0);
+ vec2d t1 = textureCoordinate(1) - textureCoordinate(0);
+ vec2d t2 = textureCoordinate(2) - textureCoordinate(0);
+
+ // check special cases where U or V is aligned with a vertex
+ if( fabs(t1.v) < EPSILON ) return normalize(t1.u*v1);
+ if( fabs(t2.v) < EPSILON ) return normalize(t2.u*v2);
+
+ // compute delta_beta
+ float inv_delta_beta = t1.u - t1.v*t2.u/t2.v;
+
+ // => degenrate case
+ if(fabs(inv_delta_beta) < EPSILON) return normalize(v1);
+
+ float delta_beta = 1.0f / inv_delta_beta;
+ float delta_gamma = -delta_beta * t1.v / t2.v;
+
+ // compute U
+ return normalize( delta_beta*v1 + delta_gamma*v2 );
+}
+
+
+vec3d triangle::normal(const vec3d& barycentricCoord) const
+{
+ // sanity check
+ if(!hasPerVertexNormals()) return normal();
+
+ // interpolate
+ vec3d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += normal(i) * barycentricCoord[i];
+ return result.normalize();
+}
+
+
+vec2d triangle::textureCoordinate(const vec3d& barycentricCoord) const
+{
+ // sanity check
+ if(!hasPerVertexTextureCoordinates()) return vec2d();
+
+ // interpolate
+ vec2d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += textureCoordinate(i) * barycentricCoord[i];
+ return result;
+}
+
+
+float triangle::area(void) const
+{
+ vec3d e1 = vertex(1) - vertex(0);
+ vec3d e2 = vertex(2) - vertex(0);
+ return 0.5f * sqrt( e1.squared_length() * e2.squared_length() );
+}
+
+
+vec3d triangle::sample(float r1, float r2, vec3d& barycentricCoord, float& pdf) const
+{
+ r2 = sqrt(r2);
+
+ // compute barycentric coordinate
+ barycentricCoord.x = r1*r2;
+ barycentricCoord.y = (1.0f - r2);
+ barycentricCoord.z = 1.0f - barycentricCoord.x - barycentricCoord.y;
+
+ // compute pdf
+ pdf = 1.0f / area();
+
+ // Done.
+ return vertex(barycentricCoord);
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void triangle::_assign(const triangle& t)
+{
+ // avoid self-assign
+ if(&t == this) return;
+
+ // share ptr to list
+ _vertex_list = t._vertex_list;
+ _normal_list = t._normal_list;
+ _textureCoord_list = t._textureCoord_list;
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+void triangle::_swap(triangle& t)
+{
+ // copy list ptr
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ std::swap(_vertex_idx, t._vertex_idx);
+ std::swap(_normal_idx, t._normal_idx);
+ std::swap(_textureCoord_idx, t._textureCoord_idx);
+}