You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
6.7 KiB

#include <cfloat>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>
#include <limits>
#include <vector>
#include "geo.h"
#include "ray.h"
#include "vec3.h"
float MAX(float a, float b) { return (a > b) ? a : b; }
using namespace std;
int max_step = 5;
vec3 shading(vec3 &lightsource, vec3 &intensity, hit_record ht, vec3 kd, const vector<sphere> &list) {
/*
define L, N by yourself
*/
vec3 L = lightsource - ht.p;
vec3 N = ht.nv;
ray shadowRay(ht.p, L);
int intersect = -1;
hit_record rec;
float closest = FLT_MAX;
/*
To-do:
To find whether the shadowRay hit other object,
you should run the function "hit" of all the hitable you created
*/
for (int i = 0; i < list.size(); i++) {
if (list[i].hit(shadowRay, 0.001, 10000, &rec)) {
intersect += 1;
}
}
if (intersect == -1) {
return kd * intensity * MAX(0, dot(N, unit_vector(L)));
} else {
return vec3(0, 0, 0);
}
}
vec3 skybox(const ray &r) {
vec3 uni_direction = unit_vector(r.direction());
float t = 0.5 * (uni_direction.y() + 1);
return (1.0 - t) * vec3(1, 1, 1) + t * vec3(0.5, 0.7, 1.0);
}
vec3 trace(const ray &r, const vector<sphere> &list, int depth) {
if (r.direction() == vec3(0, 0, 0)) {
return vec3(0, 0, 0);
}
//cout << r.direction() << endl;
if (depth >= max_step)
return skybox(r); //or return vec3(0,0,0);
int intersect = -1;
vec3 lightsource = vec3(-10, 10, 0);
vec3 intensity = vec3(1, 1, 1);
hit_record rec;
rec.t = 10000;
rec.p = vec3(0, 0, 0);
rec.nv = vec3(0, 0, 0);
float closest = FLT_MAX;
/*
To-do:
To find the nearest object from the origin of the ray,
you should run the function "hit" of all the hitable you created
*/
//cout << "Hit" << endl;
for (int i = 0; i < list.size(); i++) {
if (list[i].hit(r, 0.0001, 1000, &rec)) {
//cout << intersect << endl;
intersect += 1;
}
}
if (intersect != -1) {
/*
To-do:
1.compute the local color by shading function
2.compute the relected color by
2.1 compute the reflected direction
2.2 define a reflected ray by rec.p and the direction in 2.1
2.3 run trace(reflected_ray,list,depth+1);
3.compute the transmitted color by
3.1 compute the transmitted direction by Snell's law
3.2 define a transmitted ray by rec.p and the direction in 3.1
3.3 run trace( transmitted_ray, list, depth+1 );
4.return the color by the parameter w_r, w_t and the 3 color you computed.
*/
//1.
vec3 L = unit_vector(lightsource - rec.p);
vec3 colour = (dot(rec.nv, L) >= 0 ? dot(rec.nv, L) : 0) * rec.kd;
//cout << rec.kd << " " << rec.wr << endl;
//return colour;
vec3 shadow = shading(lightsource, intensity, rec, rec.kd, list);
colour = 0.2 * colour + 0.8 * shadow;
if (depth >= 5) {
//return 0.5 * vec3(rec.nv.x() + 1, rec.nv.y() + 1, rec.nv.z() + 1);
return colour;
}
if (rec.wr <= 0 && rec.wt <= 0) {
return colour;
}
{
vec3 reflection = vec3(0, 0, 0);
if ((dot(r.direction(), rec.nv) / r.direction().length() * rec.nv.length()) < 0) {
if (rec.wr > 0) {
//cout << "reflection " << depth << endl;
reflection = trace(ray(rec.p, reflect(r.direction(), rec.nv)), list, (depth + 1));
}
if (rec.wt <= 0) {
//cout << "reflection " << depth << endl;
colour = reflection * rec.wr + colour * max(0.0f, (1 - rec.wr));
return colour;
}
//cout << "refraction " << depth << endl;
vec3 refraction = trace(ray(rec.p, refract(r.direction(), rec.nv, 1.5)), list, (depth + 1));
colour = reflection * rec.wr + refraction * rec.wt + colour * max(0.0f, (1 - rec.wr - rec.wt));
} else {
//cout << "refraction " << depth << endl;
vec3 refraction = trace(ray(rec.p, refract(r.direction(), rec.nv, 1.5)), list, (depth + 1));
//cout << "refraction out" << endl;
colour = refraction;
}
//cout << L << endl;
//cout << colour << endl;
//return vec3(0, 0, 0);
return colour;
}
} else {
return skybox(r);
}
}
int main() {
int width = 3840;
int height = 1920;
srand(time(NULL));
//camera and projection plane
vec3 lower_left_corner(-2, -1, -1);
vec3 origin(0, 0, 0);
vec3 horizontal(4, 0, 0);
vec3 vertical(0, 2, 0);
vec3 colorlist[8] = {vec3(0.8, 0.3, 0.3), vec3(0.3, 0.8, 0.3), vec3(0.3, 0.3, 0.8),
vec3(0.8, 0.8, 0.3), vec3(0.3, 0.8, 0.8), vec3(0.8, 0.3, 0.8),
vec3(0.8, 0.8, 0.8), vec3(0.3, 0.3, 0.3)};
//test scene with spheres
vector<sphere> hitable_list;
hitable_list.push_back(sphere(vec3(0, -100.5, -2), 100, vec3(1.0f, 1.0f, 1.0f), 0.0f, 0.0f)); //ground
hitable_list.push_back(sphere(vec3(0, 0, -2), 0.5, vec3(1.0f, 1.0f, 1.0f), 0.0f, 0.9f));
hitable_list.push_back(sphere(vec3(1, 0, -1.75), 0.5, vec3(1.0f, 1.0f, 1.0f), 0.5f, 0.0f));
hitable_list.push_back(sphere(vec3(-1, 0, -2.25), 0.5, vec3(1.0f, 0.7f, 0.3f), 0.0f, 0.0f));
for (int i = 0; i < 48; i++) {
float xr = ((float)rand() / (float)(RAND_MAX)) * 6.0f - 3.0f;
float zr = ((float)rand() / (float)(RAND_MAX)) * 3.0f - 1.5f;
int cindex = rand() % 8;
float rand_reflec = ((float)rand() / (float)(RAND_MAX));
//float rand_refrac = ((float)rand() / (float)(RAND_MAX));
hitable_list.push_back(sphere(vec3(xr, -0.4, zr - 2), 0.1, colorlist[cindex], rand_reflec, 0.0f));
}
fstream file;
file.open("ray.ppm", ios::out);
file << "P3\n"
<< width << " " << height << "\n255\n";
for (int j = height - 1; j >= 0; j--) {
cout << j << endl;
for (int i = 0; i < width; i++) {
//cout << j << " " << i << endl;
float u = float(i) / float(width);
float v = float(j) / float(height);
ray r(origin, lower_left_corner + u * horizontal + v * vertical);
vec3 c = trace(r, hitable_list, 0);
file << min(255, (int)(c.r() * 255)) << " "
<< min(255, (int)(c.g() * 255)) << " "
<< min(255, (int)(c.b() * 255)) << endl;
}
}
return 0;
}