blob: 265f685894310812f3e5400ea144040029281bfb [file] [log] [blame]
#ifndef VEC3_H
#define VEC3_H
//==============================================================================================
// Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy (see file COPYING.txt) of the CC0 Public
// Domain Dedication along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
//
// The original source code is from
// https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek
//
// Changes to the original code follow the following license.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//==============================================================================================
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
using std::fabs;
using std::sqrt;
using std::string;
class vec3 {
public:
double e[3];
__host__ __device__ vec3() : e{0, 0, 0} {}
__host__ __device__ vec3(double e0, double e1, double e2) : e{e0, e1, e2} {}
__host__ __device__ double x() const { return e[0]; }
__host__ __device__ double y() const { return e[1]; }
__host__ __device__ double z() const { return e[2]; }
__host__ __device__ vec3 operator-() const {
return vec3(-e[0], -e[1], -e[2]);
}
__host__ __device__ double operator[](int i) const { return e[i]; }
__host__ __device__ double &operator[](int i) { return e[i]; }
__host__ __device__ vec3 &operator+=(const vec3 &v) {
e[0] += v.e[0];
e[1] += v.e[1];
e[2] += v.e[2];
return *this;
}
__host__ __device__ vec3 &operator*=(double t) {
e[0] *= t;
e[1] *= t;
e[2] *= t;
return *this;
}
__host__ __device__ vec3 &operator/=(double t) { return *this *= 1 / t; }
__host__ __device__ double length() const { return sqrt(length_squared()); }
__host__ __device__ double length_squared() const {
return e[0] * e[0] + e[1] * e[1] + e[2] * e[2];
}
bool near_zero() const {
// Return true if the vector is close to zero in all dimensions.
auto s = 1e-8;
return (fabs(e[0]) < s) && (fabs(e[1]) < s) && (fabs(e[2]) < s);
}
static __host__ __device__ vec3 random(unsigned &rnd) {
auto x = random_double(rnd);
auto y = random_double(rnd);
auto z = random_double(rnd);
return vec3(x, y, z);
}
static __host__ __device__ vec3 random(double min, double max,
unsigned &rnd) {
auto x = random_double(min, max, rnd);
auto y = random_double(min, max, rnd);
auto z = random_double(min, max, rnd);
return vec3(x, y, z);
}
std::string toString() const {
std::ostringstream oss;
oss << "(" << e[0] << ", " << e[1] << ", " << e[2] << ")";
return oss.str();
}
};
// point3 is just an alias for vec3, but useful for geometric clarity in the code.
using point3 = vec3;
// Vector Utility Functions
inline std::ostream& operator<<(std::ostream &out, const vec3 &v) {
return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
}
inline __host__ __device__ vec3 operator+(const vec3 &u, const vec3 &v) {
return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
}
inline __host__ __device__ vec3 operator-(const vec3 &u, const vec3 &v) {
return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
}
inline __host__ __device__ vec3 operator*(const vec3 &u, const vec3 &v) {
return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
}
inline __host__ __device__ vec3 operator*(double t, const vec3 &v) {
return vec3(t * v.e[0], t * v.e[1], t * v.e[2]);
}
inline __host__ __device__ vec3 operator*(const vec3 &v, double t) {
return t * v;
}
inline __host__ __device__ vec3 operator/(vec3 v, double t) {
return (1 / t) * v;
}
inline __host__ __device__ double dot(const vec3 &u, const vec3 &v) {
return u.e[0] * v.e[0] + u.e[1] * v.e[1] + u.e[2] * v.e[2];
}
inline __host__ __device__ vec3 cross(const vec3 &u, const vec3 &v) {
return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
u.e[2] * v.e[0] - u.e[0] * v.e[2],
u.e[0] * v.e[1] - u.e[1] * v.e[0]);
}
inline __host__ __device__ vec3 unit_vector(vec3 v) { return v / v.length(); }
inline __host__ __device__ vec3 random_in_unit_disk(unsigned &rnd) {
while (true) {
auto x = random_double(-1, 1, rnd);
auto y = random_double(-1, 1, rnd);
auto p = vec3(x, y, 0);
if (p.length_squared() < 1)
return p;
}
}
inline __host__ __device__ vec3 random_in_unit_sphere(unsigned &rnd) {
while (true) {
auto p = vec3::random(-1, 1, rnd);
if (p.length_squared() < 1)
return p;
}
}
inline __host__ __device__ vec3 random_unit_vector(unsigned &rnd) {
return unit_vector(random_in_unit_sphere(rnd));
}
inline __host__ __device__ vec3 random_on_hemisphere(const vec3 &normal,
unsigned &rnd) {
vec3 on_unit_sphere = random_unit_vector(rnd);
if (dot(on_unit_sphere, normal) > 0.0) // In the same hemisphere as the normal
return on_unit_sphere;
else
return -on_unit_sphere;
}
inline __host__ __device__ vec3 reflect(const vec3 &v, const vec3 &n) {
return v - 2 * dot(v, n) * n;
}
inline __host__ __device__ vec3 refract(const vec3 &uv, const vec3 &n,
double etai_over_etat) {
auto 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;
}
#endif