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
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;
|
|
} |