Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include<vector>
- #include<iostream>
- #include <algorithm>
- #include <chrono>
- using namespace std;
- #include <glew.h>
- #include <freeglut.h>
- #include "Vec3.h"
- #include "Image.h"
- #include "Ray.h"
- #include "Sphere.h"
- #include "algebra.h"
- Light * light = new Light(Vec3f(0.f, 0.f, 0.f), Vec3f(0.8f, 0.8f, 0.8f));
- Vec3f * backgroundColor = new Vec3f(0.08f, 0.0f, 0.0209312f); //background color
- float ambientIntensity = 0.1f;
- int jumpLimit = 100;
- float phongShininessCoefficient = 1024.f;
- int xRes = 1440, yRes = 1080;
- Camera * _camera = new Camera(Vec3f(0.f, 0.f, 10.f), Vec3f(0.f, 0.f, 0.f), xRes, yRes);
- unsigned long int amount_of_intersections = 0;
- class Scene {
- public:
- vector<Sphere> spheres;
- Scene(void) {
- }
- void add(const Sphere & s) {
- spheres.push_back(s);
- //cout << "Sphere added: " << "r = " << spheres[spheres.size()-1].r << endl;
- }
- void load(char * fileName) {
- // load a file with spheres for your scene here ...
- }
- };
- void AddSpheres(Scene * scene);
- void glSetPixel(int x, int y, Vec3f & c) {
- glColor3f(c.r, c.g, c.b);
- glBegin(GL_POINTS);
- glVertex2i(x, y);
- glEnd();
- }
- class SimpleRayTracer {
- private:
- Scene * scene;
- Image * image;
- Vec3f getEyeRayDirection(int x, int y) {
- //Uses a fix camera looking along the negative z-axis
- static float z = -5.0f;
- static float sizeX = 4.0f;
- static float sizeY = 3.0f;
- static float left = -sizeX * 0.5f;
- static float bottom = -sizeY * 0.5f;
- static float dx = sizeX / float(image->getWidth());
- static float dy = sizeY / float(image->getHeight());
- return Vec3f(left + x * dx, bottom + y * dy, z).normalize();
- }
- public:
- SimpleRayTracer(Scene * scene, Image * image) {
- this->scene = scene;
- this->image = image;
- }
- void searchClosestHit(const Ray & ray, HitRec & hitRec) {
- hitRec.anyHit = false;
- hitRec.tHit = 0.f;
- hitRec.primIndex = 0;
- int closestHit = -1;
- float smallestT = 0.f;
- for (int i = 0; i < scene->spheres.size(); i++) {
- amount_of_intersections++;
- scene->spheres[i].hit(ray, hitRec);
- if (hitRec.anyHit == true)
- {
- if (hitRec.tHit < smallestT)
- {
- smallestT = hitRec.tHit;
- closestHit = i;
- }
- else if (smallestT == 0.f)
- {
- smallestT = hitRec.tHit;
- closestHit = i;
- }
- }
- }
- hitRec.tHit = smallestT;
- hitRec.primIndex = closestHit;
- }
- float clamp(const float &lo, const float &hi, const float &v)
- {
- return std::max(lo, std::min(hi, v));
- }
- Vec3f refraction(const Vec3f &I, const Vec3f &N, float refractionIndex) {
- float cosValue = clamp(-1.f, 1.f, DotProduct(I, N));
- //float cosValue = 1;
- float airRefraction = 1, sphereRefraction = refractionIndex;
- Vec3f n = N;
- float eta;
- if (cosValue < 0) { //if normal is going wrong direction we flip
- cosValue = -cosValue;
- eta = airRefraction / sphereRefraction;
- }
- else {
- swap(airRefraction, sphereRefraction);
- n = -N;
- eta = airRefraction;
- }
- float k = 1 - eta * eta * (1 - cosValue * cosValue);
- Vec3f temp;
- temp.x = eta * I.x + n.x*(eta * cosValue - sqrt(k));
- temp.y = eta * I.y + n.y*(eta * cosValue - sqrt(k));
- temp.z = eta * I.z + n.z*(eta * cosValue - sqrt(k));
- return k < 0 ? Vec3f(0.f, 0.f, 0.f) : temp;
- }
- float fresnel(const Vec3f &I, const Vec3f &N, const float &refractionIndex) {
- float cosValue = clamp(-1.f, 1.f, DotProduct(I, N));
- float airRefraction = 1.f, sphereRefraction = refractionIndex;
- if (cosValue > 0.f) {
- swap(airRefraction, sphereRefraction);
- }
- float sinValue = airRefraction / sphereRefraction * sqrtf(max(0.f, 1.f - cosValue * cosValue));
- if (sinValue >= 1.f) {
- return 1.0f;
- }
- else {
- float cost = sqrtf(max(0.f, 1.f - sinValue * sinValue));
- cosValue = fabsf(cosValue);
- float Rs = ((sphereRefraction * cosValue) - (airRefraction * cost)) / ((sphereRefraction * cosValue) + (airRefraction * cost));
- float Rp = ((airRefraction * cosValue) - (sphereRefraction * cost)) / ((airRefraction * cosValue) + (sphereRefraction * cost));
- return (Rs * Rs + Rp * Rp) / 2.f; //kr is amount of light reflected
- }
- }
- Vec3f RayCasting(Ray ray, Sphere sphere, float &t, int rayJump) {
- if (rayJump >= jumpLimit)
- {
- return Vec3f(1.0, 1.0, 1.0);
- }
- Vec3f color;
- Vec3f V = ray.d;
- Vec3f P = Vec3f(ray.o + V * t);
- Vec3f N = Vec3f(P - sphere.c);
- N = N.normalize();
- Vec3f lightDirection = Vec3f(light->getPosition() - P);
- lightDirection.normalize();
- Vec3f viewDirection = Vec3f(ray.o - P);
- viewDirection.normalize();
- Vec3f lightReflection = Vec3f(Vec3f(N) * 2 * DotProduct(lightDirection, N));
- lightReflection -= Vec3f(lightDirection);
- Vec3f viewReflection = Vec3f(Vec3f(N) * 2 * DotProduct(viewDirection, N));
- viewReflection -= Vec3f(viewDirection);
- Vec3f refractedColor = Vec3f(0.f, 0.f, 0.f);
- Ray reflectionRay;
- reflectionRay.o = P;
- reflectionRay.d = viewReflection;
- Ray shadowRay;
- shadowRay.o = P;
- shadowRay.d = lightDirection;
- HitRec hRec;
- Vec3f reflectedColor = Vec3f(0.f, 0.f, 0.f);
- Vec3f refractionDir, refractionRayOrig;
- Ray refractionRay;
- switch (sphere.type)
- {
- case Reflective:
- searchClosestHit(shadowRay, hRec); //Checks point to lightsource for shadowing spheres
- if (hRec.anyHit == true && scene->spheres[hRec.primIndex].type != Reflective_and_Refractive) //if transparent we wont shade
- {
- color = CalculateLight(sphere, P, ray, lightReflection, lightDirection, N, true); //if true we stop phong model at ambient
- }
- else
- {
- color = CalculateLight(sphere, P, ray, lightReflection, lightDirection, N, false);
- }
- color *= (1.f - sphere.reflectiveIndex);
- color += reflectedColor * sphere.reflectiveIndex;
- searchClosestHit(reflectionRay, hRec);
- if (hRec.anyHit == true)
- {
- reflectedColor = RayCasting(reflectionRay, scene->spheres[hRec.primIndex], hRec.tHit, rayJump + 1);
- if (reflectedColor.x < 0 || reflectedColor.y < 0 || reflectedColor.z < 0)
- cout << "NegativeColor!";
- color *= (1.f - sphere.reflectiveIndex);
- color += reflectedColor * sphere.reflectiveIndex;
- }
- break;
- case Reflective_and_Refractive:
- refractionDir = refraction(V, N, sphere.refractiveIndex);
- refractionDir = refractionDir.normalize();
- refractionRayOrig = (DotProduct(refractionDir, N) < 0) ?
- P - N * 0.0001 :
- P + N * 0.0001;
- refractionRay.o = refractionRayOrig;//P - N*0.0001;
- refractionRay.d = refractionDir;
- searchClosestHit(refractionRay, hRec);
- if (hRec.anyHit = true)
- {
- //Vec3f outP = (refractionRay.o + refractionRay.d*hRec.tHit);
- Vec3f outRefractionDir = refraction(refractionRayOrig, N, sphere.refractiveIndex);
- outRefractionDir = outRefractionDir.normalize();
- Vec3f outRefractionOrig = (DotProduct(outRefractionDir, N) < 0) ?
- refractionRayOrig - N * 0.0001 :
- refractionRayOrig + N * 0.0001;
- Ray outRay;
- outRay.o = outRefractionOrig;
- outRay.d = outRefractionDir;
- refractedColor = RayCasting(outRay, scene->spheres[hRec.primIndex], hRec.tHit, rayJump + 1);
- float kr = fresnel(V, N, sphere.refractiveIndex);
- color = reflectedColor * kr + refractedColor * (1.f - kr);
- }
- else
- color = reflectedColor;
- break;
- default: //for objects not reflective or refractive
- searchClosestHit(shadowRay, hRec); //Checks point to lightsource for shadowing spheres
- if (hRec.anyHit == true && scene->spheres[hRec.primIndex].type != Reflective_and_Refractive) //if transparent we wont shade
- {
- color = CalculateLight(sphere, P, ray, lightReflection, lightDirection, N, true); //if true we stop phong model at ambient
- }
- else
- {
- color = CalculateLight(sphere, P, ray, lightReflection, lightDirection, N, false);
- }break;
- }
- if (color.x < 0 || color.y < 0 || color.z < 0) //Failsafe to report if values get below 0 or cut them if they get to high and keep ratio between colours
- cout << "NegativeColor!";
- if (color.x > 1)
- {
- float diff = 1 / color.x;
- color *= diff;
- }
- if (color.y > 1)
- {
- float diff = 1 / color.y;
- color *= diff;
- }
- if (color.z > 1)
- {
- float diff = 1 / color.z;
- color *= diff;
- }
- return color;
- }
- Vec3f CalculateLight(Sphere sphere, Vec3f HitPos, Ray ray, Vec3f reflectionDir, Vec3f lightDirection, Vec3f norm, bool isShadowed)
- {
- Vec3f ambient = light->getIntensity() * ambientIntensity;
- ambient = ambient.multCoordwise(sphere.materialAmbient);
- Vec3f result = Vec3f(ambient);
- if (isShadowed)
- return result;
- float diff = max(norm.dot(lightDirection), 0.f);
- Vec3f diffuse = Vec3f(sphere.materialDiffuse) * diff;
- diffuse = diffuse.multCoordwise(light->getIntensity());
- Vec3f viewDir = Normalize(ray.o - HitPos);
- float spec = pow(max(DotProduct(reflectionDir, viewDir), 0.f), phongShininessCoefficient);
- Vec3f specular = Vec3f(sphere.materialSpecular * spec);
- specular = specular.multCoordwise(light->getIntensity());
- result += diffuse + specular;
- return result;
- }
- void fireRays(void) {
- Ray ray;
- HitRec hitRec;
- bool hit = false;
- ray.o = _camera->eyePoint; //Set the start position of the eye rays to the origin of the camera
- for (int y = 0; y < image->getHeight(); y++) {
- for (int x = 0; x < image->getWidth(); x++) {
- ray.d = getEyeRayDirection(x, y);
- hitRec.anyHit = false;
- searchClosestHit(ray, hitRec);
- if (hitRec.anyHit) {
- Vec3f color = Vec3f(0.f, 0.f, 0.f);
- color = RayCasting(ray, scene->spheres[hitRec.primIndex], hitRec.tHit, 0);
- image->setPixel(x, y, color);
- glSetPixel(x, y, color);
- }
- else {
- image->setPixel(x, y, *backgroundColor);
- glSetPixel(x, y, *backgroundColor);
- }
- }
- }
- }
- };
- SimpleRayTracer * rayTracer;
- void display(void) {
- auto start = chrono::steady_clock::now();
- amount_of_intersections = 0;
- glClear(GL_COLOR_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- rayTracer->fireRays();
- auto end = chrono::steady_clock::now();
- cout << "Number of sphere intersection tests made to render this image: " << amount_of_intersections << "\n";
- cout << "Elapsed time in nanoseconds: " << chrono::duration_cast<chrono::nanoseconds>(end - start).count() << " ns\n";
- cout << "Elapsed time in microseconds: " << chrono::duration_cast<chrono::microseconds>(end - start).count() << " microseconds\n";
- cout << "Elapsed time in milliseconds: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms\n";
- cout << "Elapsed time in seconds: " << chrono::duration_cast<chrono::seconds>(end - start).count() << " sec\n";
- glFlush();
- }
- void changeSize(int w, int h) {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluOrtho2D(0, w, 0, h);
- glViewport(0, 0, w, h);
- }
- void init(void)
- {
- glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
- glutInitWindowSize(xRes, yRes);
- glutCreateWindow("SimpleRayTracer");
- glutDisplayFunc(display);
- glutReshapeFunc(changeSize);
- //glutKeyboardFunc(keypress);
- glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
- Scene * scene = new Scene;
- AddSpheres(scene);
- Image * image = new Image(xRes, yRes);
- rayTracer = new SimpleRayTracer(scene, image);
- }
- void AddSpheres(Scene * scene)
- {
- scene->add(Sphere(Vec3f(3.78f, -3.0f, -20.0f), 3.0f)); //Orange stor
- scene->spheres[0].materialDiffuse = Vec3f(1.f, 0.3f, 0.00f);
- scene->spheres[0].materialSpecular = Vec3f(1.f, 0.5f, 0.0f);
- scene->spheres[0].materialAmbient = Vec3f(1.f, 0.3f, 0.008f);
- scene->spheres[0].reflectiveIndex = 0.f;
- scene->spheres[0].refractiveIndex = 1.f;
- scene->add(Sphere(Vec3f(-5.0f, -2.7f, -16.0f), 2.0f)); // Grön
- scene->spheres[1].materialDiffuse = Vec3f(0.2f, 0.7f, 0.2f);
- scene->spheres[1].materialSpecular = Vec3f(0.35f, 0.9f, 0.35f);
- scene->spheres[1].materialAmbient = Vec3f(0.2f, 0.7f, 0.2f);
- scene->spheres[1].reflectiveIndex = 0.f;
- scene->spheres[1].refractiveIndex = 1.f;
- scene->add(Sphere(Vec3f(3.0f, 0.0f, -17.0f), 2.0f)); //Gul
- scene->spheres[2].materialDiffuse = Vec3f(0.8f, 0.9f, 0.2f);
- scene->spheres[2].materialSpecular = Vec3f(0.84f, 0.95f, 0.3f);
- scene->spheres[2].materialAmbient = Vec3f(0.7f, 0.72f, 0.2f);
- scene->spheres[2].reflectiveIndex = 0.f;
- scene->spheres[2].refractiveIndex = 1.f;
- scene->add(Sphere(Vec3f(13.0f, 3.f, -40.0f), 15.0f)); //Gertrud
- scene->spheres[3].materialDiffuse = Vec3f(0.4f, 0.4f, 0.97f);
- scene->spheres[3].materialSpecular = Vec3f(0.5f, 0.5f, 0.97f);
- scene->spheres[3].materialAmbient = Vec3f(0.4f, 0.4f, 0.97f);
- scene->spheres[3].reflectiveIndex = 0.5f;
- scene->spheres[3].refractiveIndex = 1.f;
- scene->spheres[3].setType(Reflective);
- scene->add(Sphere(Vec3f(-6.0f, 5.0f, -27.0f), 2.0f)); //Blågrå badboll
- scene->spheres[4].materialDiffuse = Vec3f(0.13f, 0.32f, 0.39f);
- scene->spheres[4].materialSpecular = Vec3f(0.18f, 0.38f, 0.52f);
- scene->spheres[4].materialAmbient = Vec3f(0.13f, 0.32f, 0.39f);
- scene->spheres[4].reflectiveIndex = 0.38f;
- scene->spheres[4].refractiveIndex = 1.f;
- scene->spheres[4].setType(Reflective);
- scene->add(Sphere(Vec3f(4.0f, -2.f, -15.f), 1.5f)); //Röda lilla i mitten
- scene->spheres[5].materialDiffuse = Vec3f(0.87f, 0.12f, 0.12f);
- scene->spheres[5].materialSpecular = Vec3f(0.93f, 0.18f, 0.18f);
- scene->spheres[5].materialAmbient = Vec3f(0.87f, 0.12f, 0.12f);
- scene->spheres[5].reflectiveIndex = 0.5f;
- scene->spheres[5].refractiveIndex = 1.3f;
- scene->spheres[5].setType(Reflective_and_Refractive);
- scene->add(Sphere(Vec3f(-7.0f, 0.0f, -30.0f), 4.0f)); //Blänkande rosa/lila på sidan
- scene->spheres[6].materialDiffuse = Vec3f(0.7f, 0.38f, 0.78f);
- scene->spheres[6].materialSpecular = Vec3f(0.9f, 0.45f, 0.93f);
- scene->spheres[6].materialAmbient = Vec3f(0.7f, 0.38f, 0.78f);
- scene->spheres[6].reflectiveIndex = 0.99;
- scene->spheres[6].refractiveIndex = 1.f;
- scene->spheres[6].setType(Reflective);
- scene->add(Sphere(Vec3f(0.0f, -2.0f, -12.0f), 2.0f)); //Bruna i mitten
- scene->spheres[7].materialDiffuse = Vec3f(0.46f, 0.19f, 0.03f);
- scene->spheres[7].materialSpecular = Vec3f(0.5f, 0.23f, 0.08f);
- scene->spheres[7].materialAmbient = Vec3f(0.46f, 0.19f, 0.03f);
- scene->spheres[7].reflectiveIndex = 0.f;
- scene->spheres[7].refractiveIndex = 1.f;
- scene->add(Sphere(Vec3f(30.0f, 10.0f, -30.0f), 5.f)); //Lilla mörkgröna
- scene->spheres[8].materialDiffuse = Vec3f(0.f, 0.56f, 0.00f);
- scene->spheres[8].materialSpecular = Vec3f(0.f, 0.78f, 0.f);
- scene->spheres[8].materialAmbient = Vec3f(0.0f, 0.56f, 0.0f);
- scene->spheres[8].reflectiveIndex = 0.f;
- scene->spheres[8].refractiveIndex = 1.f;
- /*scene->add(Sphere(Vec3f(-4.0f, -0.5f, -15.f), 1.0f)); //transparent
- scene->spheres[9].materialDiffuse = Vec3f(0.87f, 0.12f, 0.12f);
- scene->spheres[9].materialSpecular = Vec3f(0.93f, 0.18f, 0.18f);
- scene->spheres[9].materialAmbient = Vec3f(0.87f, 0.12f, 0.12f);
- scene->spheres[9].reflectiveIndex = 0.5f;
- scene->spheres[9].refractiveIndex = 1.3f;
- scene->spheres[9].setType(Reflective_and_Refractive);*/
- }
- void main(int argc, char **argv) {
- glutInit(&argc, argv);
- init();
- glutMainLoop();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement