Skip to content

Instantly share code, notes, and snippets.

@apsicle
Created October 4, 2016 02:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apsicle/0f19a8ca3858237aecb371c139cd8fce to your computer and use it in GitHub Desktop.
Save apsicle/0f19a8ca3858237aecb371c139cd8fce to your computer and use it in GitHub Desktop.
#include "Light.hpp"
#include <cmath>
void Light::set (double x, double y, double z) {
this -> loc.set(x, y, z);
}
Light::Light(void) {
set(5, 10, 0);
}
Light::Light(double x, double y, double z) {
set(x, y, z);
}
COLOR_T Light::illuminate(RAY_T ray, COLOR_T surface_col, Vector int_pt, Vector normal) {
COLOR_T col;
//Ambient
col.R = surface_col.R * 0.1;
col.G = surface_col.G * 0.1;
col.B = surface_col.B * 0.1;
//Diffuse
Vector L;
L = loc - int_pt;
L.normalize();
double dotted = L.dot(normal);
if(dotted > 0) {
col.R += dotted * surface_col.R;
col.G += dotted * surface_col.G;
col.B += dotted * surface_col.B;
//Specular
Vector R = L - (normal * (normal.dot(L)) * 2);
R.normalize();
double dot2 = R.dot(ray.dir);
if(dot2 > 0) {
col.R += pow(dot2, 200);
col.G += pow(dot2, 200);
col.B += pow(dot2, 200);
}
}
return col;
}
#ifndef LIGHT_HPP_
#define LIGHT_HPP_
#include "Vector.hpp"
#include "rt.hpp"
class Light {
private:
Vector loc;
public:
Light(void);
Light(double, double, double);
void set(double, double, double);
COLOR_T illuminate(RAY_T ray, COLOR_T surface_col, Vector int_pt, Vector normal);
};
#endif
#ifndef OBJ_HPP_
#define OBJ_HPP_
#include "rt.hpp"
#include "Sphere.hpp"
typedef struct OBJ {
//The node class. Contains sphere
Sphere sphere;
COLOR_T color;
struct OBJ *next;
} OBJ_T;
#endif
#include <iostream>
#include <cstdio>
#include <cmath>
#include "rt.hpp"
#include "obj.hpp"
#include "Light.hpp"
#include "Sphere.hpp"
#include "Vector.hpp"
/* Author: Ryan Yan
* Date: 04/24/16
*
* Description: This is a raytracing program. This produces a 2-d graphical depiction of
* spheres based on information in a formatted text file from the vantage point of a viewer behind a canvas.
* This works with the input files sphere.txt and spheres.txt.
*/
void read_objs (OBJ_T** list) {
//This function takes a declared linked list, and reads in stdinput (redirected from console) of spheres or sphere.txt
//Declare vars
double x, y, z;
double radius;
Sphere input_sphere;
COLOR_T color;
//Scan in series of 7 floats describing a sphere (formatted in spheres.txt)
while(std::cin >> x >> y >> z >> radius >> color.R >> color.G >> color.B != NULL) {
OBJ_T * node = new OBJ_T; //allocate memory for new node object.
input_sphere.set(Vector(x, y, z), radius); //create sphere based on inputs
node->sphere = input_sphere;
node->color = color;
node->next = *list; //add node (containing sphere) to head of linked list and change head pointer.
*list = node;
}
}
COLOR_T Trace (RAY_T ray, OBJ_T* list, Light light) {
//Iterates through the linked list of nodes (spheres) and finds the color associated with the sphere closest to the viewer.
//Trace is called in the main loop on each pixel in order to color it.
//Declare vars
OBJ_T* mylist = list;
double min_t;
double t;
t = min_t = 1000;
OBJ_T* closest_obj = NULL;
OBJ_T* curr_obj = NULL;
Vector closest_int_pt;
Vector curr_int_pt;
Vector closest_normal;
Vector curr_normal;
COLOR_T color = {0,0,0}; //If we find no intersections, default to black
for(curr_obj = list; curr_obj != NULL; curr_obj = curr_obj -> next){ //Search through linked list for closest visible sphere
if (curr_obj->sphere.intersect(ray, t, curr_int_pt, curr_normal)) {
if (t < min_t) { //This loop finds the closest sphere
closest_obj = curr_obj;
closest_int_pt = curr_int_pt;
closest_normal = curr_normal;
min_t = t;
}
}
mylist = mylist -> next;
}
if(closest_obj != NULL){
color = light.illuminate(ray, closest_obj -> color, closest_int_pt, closest_normal); //colors in the closest sphere
}
return color;
}
int main() {
//Set vars
int maxy = 1000, maxx = 1000;
double y, x;
Vector origin(0,0,0);
double t;
COLOR_T pixel;
Light light;
light.set(5, 10, 0);
//Write ppm header.
std::cout << "P6\n" << maxx << "\n" << maxy << "\n255\n";
//Create a linked list, setting sentinel node.
OBJ_T* mylist = new OBJ_T;
mylist -> next = NULL;
read_objs (&mylist);
//Write image data by looping through pixels and checking intersections with all spheres
for (y = maxy; y > 0; y--) {
for (x = 0; x < maxx; x++) {
//Set ray
Vector dir(-0.5 + (x / 1000), -0.5 + (y / 1000), 1);
dir.normalize();
RAY_T ray = {origin, dir};
//Set pixel color with cast and multiply by 255. We use a number from 0 to 1 multiplied by 255 for extra precision.
pixel = Trace(ray, mylist, light);
if(pixel.R > 1.0) {
pixel.R = 1.0;
}
if(pixel.G > 1.0) {
pixel.G = 1.0;
}
if(pixel.B > 1.0) {
pixel.B = 1.0;
}
pixel.R = pixel.R * 255;
pixel.G = pixel.G * 255;
pixel.B = pixel.B * 255;
//Print out pixels as characters to the ppm.
std::cout << (unsigned char) pixel.R << (unsigned char) pixel.G << (unsigned char) pixel.B;
}
}
//delete the dynamically allocated memory by iterating through the linked list
OBJ_T* curr;
while (mylist != NULL) {
curr = mylist;
mylist = mylist -> next;
delete(curr);
}
//Always return 0, kids.
return 0;
}
#ifndef RT_HPP_
#define RT_HPP_
#include "Vector.hpp"
/* Author: Ryan Yan
* Date: 04/24/16
*
* Description: This is a raytracing program. This header file defines several useful structures
*/
typedef struct RAY {
//An infinite length Vector
Vector origin;
Vector dir;
} RAY_T;
typedef struct COLOR {
//For pixel shading
double R;
double G;
double B;
} COLOR_T;
#endif
#include "Sphere.hpp"
#include "rt.hpp"
#include <iostream>
#include <cmath>
void Sphere::set (Vector ctr, double radius) {
this -> ctr = ctr;
this -> radius = radius;
}
bool Sphere::intersect (RAY_T ray, double &t, Vector &int_pt, Vector &normal) {
//Passed in a ray, a sphere, and the previously held minimum distance t.
//Returns 1 when found intersection and 0 when not. Sets t to minimum of the roots (intersections) when found.
//Declare vars
Vector origin = ray.origin;
Vector dir = ray.dir;
//Analytical solution to the intersection of a ray and a sphere in 3 dimensions. We can write a parametric equation
//of the normalized Vector representing the ray, and solve a quadratic equation for the distance t between the origin
//of the ray and the intersection.
double A = 1;
double B = dir.dot(origin - ctr) * 2;
double C = (origin - ctr).dot(origin - ctr) - radius*radius;
double discriminant = B*B - 4*A*C;
if(discriminant <= 0) {
//no real roots, so exit w/o finding intersection.
return 0;
}
else {
double root1 = (-B + std::sqrt(discriminant)) / 2;
double root2 = (-B - std::sqrt(discriminant)) / 2;
if (root1 <= 0 && root2 <= 0) {
return 0; //both negative roots means we're in front of the image, so we can't see it.
}
else if (root1 <= root2) {
//We return the smaller root (minimum distance)
t = root1;
int_pt = origin + (dir * t);
normal = (int_pt - ctr) / radius;
return 1;
}
else {
t = root2;
int_pt = origin + (dir * t);
normal = (int_pt - ctr) / radius;
return 1;
}
}
}
#ifndef SPHERE_HPP_
#define SPHERE_HPP_
#include "rt.hpp"
#include "Vector.hpp"
class Sphere {
//Sphere class. Center, radius, check intersection.
private:
Vector ctr;
double radius;
public:
void set (Vector, double);
bool intersect (RAY_T ray, double &t, Vector &int_pt, Vector &normal);
};
#endif
0.0 0.0 10.0
2.0
1.0 0.0 0.0
-3.0 -3.0 6.0
3.5
1.0 0.0 1.0
1.8 -1.3 6.0
0.9
0.7 1.0 0.3
-0.6 -0.9 3.0
0.25
0.0 0.0 0.6
3.0 2.5 12.0
2.8
0.6 0.5 0.8
-2.0 2.0 4.0
1.0
0.2 0.5 0.2
-0.55 0.7 2.0
0.1
0.9 0.9 0.1
2.0 0.9 7.0
0.07
0.6 1.0 1.0
#include <cmath>
#include <iostream>
#include "Vector.hpp"
/* Author: Ryan Yan
* Date: 04/11/16
*
* Description: This is a raytracing program. This file defines several useful functions on vectors
*/
Vector::Vector (double x, double y, double z) {
set(x, y, z);
}
Vector::Vector (void) {
set(0, 0, 0);
}
void Vector::set (double x, double y, double z) {
this -> x = x;
this -> y = y;
this -> z = z;
}
Vector Vector::add(Vector v){
Vector rv;
rv.x = x + v.x;
rv.y = y + v.y;
rv.z = z + v.z;
return rv;
}
Vector Vector::operator + (Vector v) {
return this -> add(v);
}
Vector Vector::subtract(Vector v){
Vector rv;
rv.x = x - v.x;
rv.y = y - v.y;
rv.z = z - v.z;
return rv;
}
Vector Vector::operator - (Vector v){
return this -> subtract(v);
}
Vector Vector::mult(Vector v){
Vector rv;
rv.x = x * v.x;
rv.y = y * v.y;
rv.z = z * v.z;
return rv;
}
Vector Vector::operator * (Vector v) {
return this -> mult(v);
}
Vector Vector::scalar_mult(double d) {
Vector rv;
rv.x = d * x;
rv.y = d * y;
rv.z = d * z;
return rv;
}
Vector Vector::operator * (double d) {
return this -> scalar_mult(d);
}
Vector Vector::scalar_divide(double d) {
Vector rv;
rv.x = x / d;
rv.y = y / d;
rv.z = z / d;
return rv;
}
Vector Vector::operator / (double d) {
return this -> scalar_divide(d);
}
double Vector::sum_components (void) {
return x + y + z;
}
double Vector::length (void) {
return std::sqrt(x*x + y*y + z*z);
}
void Vector::normalize (void) {
//Normalizing the vector normalizes each component such that the length of the vector is 1.
double magnitude = length();
this -> x = x / magnitude;
this -> y = y / magnitude;
this -> z = z / magnitude;
}
double Vector::dot (Vector v) {
//Sum of elementwise products of two vectors.
double sum = mult(v).sum_components();
return sum;
}
void Vector::print (void) {
std::cout << "x: " << this -> x << "\ny: " << this -> y << "\nz: " << this -> z << "\n";
}
/*
int main() {
Vector test;
Vector test1;
Vector test2;
test.print();
test2 = test.add(Vector (2,3,4));
test2.print();
test1.set(1,1,1);
std::cout << test1.dot(test2);
test2.print();
std::cout << test2.length();
test2.normalize();
test2.print();
(test1 / 4).print();
(test1 * 2).print();
return 0;
}*/
#ifndef VECTOR_HPP_
#define VECTOR_HPP_
/* Author: Ryan Yan
* Date: 04/11/16
* This header file defines the vector structure
*/
class Vector {
//Magnitude and direction.
private:
double x;
double y;
double z;
public:
Vector(void);
Vector(double x, double y, double z);
void set(double x, double y, double z);
Vector add(Vector);
Vector operator+(Vector);
Vector subtract(Vector);
Vector operator-(Vector);
Vector mult(Vector);
Vector operator*(Vector);
Vector scalar_mult(double);
Vector operator*(double);
Vector scalar_divide(double);
Vector operator/(double);
double sum_components(void);
double length(void);
double dot (Vector);
void normalize (void);
void print(void);
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment