cpp-raytracer/vec3.hpp
2021-08-29 21:24:17 +02:00

217 lines
4.4 KiB
C++

#ifndef VEC3_H
#define VEC3_H
#include "rtweekend.hpp"
struct vec3 {
/* Members */
float x;
float y;
float z;
// Constructor proper. Values default to 0
vec3(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
/* Overriden operators */
// - operator. Not to be confused with substraction
vec3 operator-() const
{
return vec3(-x, -y, -z);
}
// Straightforward vector sum
vec3& operator+=(const vec3 &v)
{
this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
// Scalar multiplication
vec3& operator*=(const float t)
{
x *= t;
y *= t;
z *= t;
return *this;
}
// Division by a scalar t
vec3& operator/=(const float t)
{
x /= t;
y /= t;
z /= t;
return *this;
}
/* Methods */
float length() const
{
return sqrt(x*x + y*y + z*z);
}
// Length squared, useful for some calculations
float length_squared() const
{
return x*x + y*y + z*z;
}
// Get a vec3 with random components in the range [0,1)
inline static vec3 random()
{
return vec3(random_float(), random_float(), random_float());
}
// Get a vec3 with random components in the range [min, max)
inline static vec3 random(float min, float max)
{
return vec3(random_float(min, max), random_float(min, max), random_float(min, max));
}
// Check if all vector components are near zero
bool near_zero() const
{
float s = 1e-8;
return (fabs(x) < s) && (fabs(y) < s) && (fabs(z) < s);
}
};
/* Type aliases */
typedef vec3 point3;
typedef vec3 color;
/* More overloads */
inline bool operator==(const vec3 &u, const vec3 &v)
{
return u.x == v.x && u.y == v.y && u.z == v.z;
}
// Straightforward vector sum
inline vec3 operator+(const vec3 &u, const vec3 &v)
{
return vec3(u.x + v.x,
u.y + v.y,
u.z + v.z);
}
// Straightforward vector difference
inline vec3 operator-(const vec3 &u, const vec3 &v)
{
return vec3(u.x - v.x,
u.y - v.y,
u.z - v.z);
}
// Hadamard product
inline vec3 operator*(const vec3 &u, const vec3 &v)
{
return vec3(u.x * v.x,
u.y * v.y,
u.z * v.z);
}
// Scalar product
inline vec3 operator*(float t,const vec3 &v)
{
return vec3(t*v.x, t*v.y, t*v.z);
}
inline vec3 operator*(const vec3 &v, float t)
{
return t * v;
}
// Vector division by scalar. Note that we redefine it as multiplying by 1/t to avoid division by 0
inline vec3 operator/(vec3 v, float t)
{
return 1/t * v;
}
// Straightforward dot product
inline float dot(const vec3 &u, const vec3 &v)
{
return u.x*v.x + u.y*v.y + u.z*v.z;
}
// Cross product between two vectors
inline vec3 cross(const vec3 &u, const vec3 &v)
{
return vec3(u.y * v.z - u.z * v.y,
u.z * v.x - u.x * v.z,
u.x * v.y - u.y * v.x);
}
// Normalize vector so its length = 1
inline vec3 normalize(const vec3 v)
{
return v / v.length();
}
// Returns a vec3 of random components between [-1,1) that is inside a unit sphere
vec3 random_in_unit_sphere()
{
// Iterate until we find a vector with length < 1
while (true)
{
vec3 p = vec3::random(-1,1);
if (p.length_squared() >= 1)
continue;
return p;
}
}
// Returns a normalized version of the above vector
vec3 random_unit_vector()
{
return normalize(random_in_unit_sphere());
}
vec3 random_in_hemisphere(const vec3& normal)
{
vec3 in_unit_sphere = random_in_unit_sphere();
if (dot(in_unit_sphere, normal) > 0.0)
return in_unit_sphere;
else
return -in_unit_sphere;
}
// Reflect like a metallic material
vec3 reflect(const vec3& v, const vec3 n)
{
return v - 2*dot(v,n)*n;
}
vec3 refract(const vec3& uv, const vec3& n, float etai_over_etat)
{
float cos_theta = fmin(dot(-uv, n), 1.0);
vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n);
vec3 r_out_parallel = -sqrt(fabs(1.0 - r_out_perp.length_squared())) * n;
return r_out_perp + r_out_parallel;
}
vec3 random_in_unit_disk()
{
while (true)
{
auto p = vec3(random_float(-1,1), random_float(-1,1), 0);
if (p.length_squared() >= 1) continue;
return p;
}
}
#endif