#include #include #include #include #include #include #include #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 &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 &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 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; }