From 4d091853087e57aaf94c42dbd069ca7e3a5fa122 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mikl=C3=B3s=20T=C3=B3th?= <tothmiklostibor@gmail.com>
Date: Thu, 15 Apr 2021 19:13:10 +0200
Subject: [PATCH] reflective material and speed

---
 CMakeLists.txt |  7 +++++
 Skeleton.cpp   | 84 ++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 72 insertions(+), 19 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 639e78c..e71a1f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,13 @@ find_package(OpenGL REQUIRED)
 link_directories(${GTKMM_LIBRARY_DIRS})
 include_directories(${GTKMM_INCLUDE_DIRS})
 
+find_package(OpenMP)
+if (OPENMP_FOUND)
+    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+    set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
+endif()
+
 add_executable(Skeleton
         framework.h
         framework.cpp
diff --git a/Skeleton.cpp b/Skeleton.cpp
index 63829ab..8b60142 100644
--- a/Skeleton.cpp
+++ b/Skeleton.cpp
@@ -42,10 +42,34 @@ int objIndex[12][5]{
         {5, 6, 19, 10, 14}
 };
 
+enum MaterialType { ROUGH, REFLECTIVE };
+
 struct Material {
 	vec3 ka, kd, ks;
 	float  shininess;
-	Material(vec3 _kd, vec3 _ks, float _shininess) : ka(_kd * M_PI), kd(_kd), ks(_ks) { shininess = _shininess; }
+	vec3 F0;
+	MaterialType type;
+	Material(MaterialType t): type(t) {}
+};
+
+struct RoughMaterial: Material {
+    RoughMaterial(vec3 _kd, vec3 _ks, float _shininess): Material(ROUGH) {
+        ka = _kd * M_PI;
+        kd = _kd;
+        ks = _ks;
+        shininess = _shininess;
+    }
+};
+
+vec3 operator/(const vec3& num, const vec3& denom) {
+    return vec3(num.x / denom.x, num.y / denom.y, num.z / denom.z);
+}
+
+struct ReflectiveMaterial: Material {
+    ReflectiveMaterial(vec3 n, vec3 kappa): Material(REFLECTIVE) {
+        vec3 one(1, 1, 1);
+        F0 = ((n - one)*(n - one) + kappa*kappa) / ((n + one)*(n + one) + kappa*kappa);
+    }
 };
 
 struct Hit {
@@ -192,13 +216,15 @@ public:
 		La = vec3(0.4f, 0.4f, 0.4f);
 		vec3 lightPosition(.5, .5, 0), Le(2, 2, 2);
 		lights.push_back(new Light(lightPosition, Le));
-
-		vec3 kd(0.3f, 0.2f, 0.1f), ks(2, 2, 2);
-		Material * material = new Material(kd, ks, 50);
 		
-        objects.push_back(new Sphere(vec3(0, 0, 0), .25f, material));
-        //objects.push_back(new Pentagon(vec3(0.03, -.01, 0), vec3(0, .37, 0), vec3(-.47, .49, 0), vec3(-.73, .08, 0), vec3(-.414, -0.288, 0), material));
+		vec3 n(.17, .35, 1.5);
+		vec3 kappa(3.1, 2.7, 1.9);
+		Material* gold = new ReflectiveMaterial(n, kappa);
+        objects.push_back(new Sphere(vec3(0, 0, 0), .25f, gold));
+        //objects.push_back(new Pentagon(vec3(0.03, -.01, 0), vec3(0, .37, 0), vec3(-.47, .49, 0), vec3(-.73, .08, 0), vec3(-.414, -0.288, 0), dodekaMat));
         
+        vec3 kd(0.3f, 0.3f, .3f), ks(2, 2, 2);
+        Material* dodekaMat = new RoughMaterial(kd, ks, 50);
         for (int i = 0; i < 12; i++) {
             auto indexRow = objIndex[i];
             auto p1 = objPoints[indexRow[0]];
@@ -207,13 +233,13 @@ public:
             auto p4 = objPoints[indexRow[3]];
             auto p5 = objPoints[indexRow[4]];
             
-            objects.push_back(new Pentagon(p1, p2, p3, p4, p5, material));
+            objects.push_back(new Pentagon(p1, p2, p3, p4, p5, dodekaMat));
         }
 	}
 
 	void render(std::vector<vec4>& image) {
+#pragma omp parallel for collapse(2)
 		for (int Y = 0; Y < windowHeight; Y++) {
-#pragma omp parallel for
 			for (int X = 0; X < windowWidth; X++) {
 				vec3 color = trace(camera.getRay(X, Y));
 				image[Y * windowWidth + X] = vec4(color.x, color.y, color.z, 1);
@@ -242,19 +268,39 @@ public:
 	}
 
 	vec3 trace(Ray ray, int depth = 0) {
+        if (depth > 5) {
+            return La;
+        }
+	    
 		Hit hit = firstIntersect(ray);
 		if (hit.t < 0) return La;
-		vec3 outRadiance = hit.material->ka * La;
-		for (Light * light : lights) {
-			Ray shadowRay(hit.position + hit.normal * epsilon, light->position);
-			float cosTheta = dot(hit.normal, light->position);
-			if (cosTheta > 0 && !shadowIntersect(shadowRay)) {	// shadow computation
-				outRadiance = outRadiance + light->Le * hit.material->kd * cosTheta;
-				vec3 halfway = normalize(-ray.dir + light->position);
-				float cosDelta = dot(hit.normal, halfway);
-				if (cosDelta > 0) outRadiance = outRadiance + light->Le * hit.material->ks * powf(cosDelta, hit.material->shininess);
-			}
-		}
+		
+		vec3 outRadiance(0, 0, 0);
+		if (hit.material->type == ROUGH) {
+            outRadiance = hit.material->ka * La;
+            for (Light *light : lights) {
+                Ray shadowRay(hit.position + hit.normal * epsilon, light->position);
+                float cosTheta = dot(hit.normal, light->position);
+                if (cosTheta > 0 && !shadowIntersect(shadowRay)) {    // shadow computation
+                    outRadiance = outRadiance + light->Le * hit.material->kd * cosTheta;
+                    vec3 halfway = normalize(-ray.dir + light->position);
+                    float cosDelta = dot(hit.normal, halfway);
+                    if (cosDelta > 0) outRadiance = outRadiance + light->Le * hit.material->ks *
+                                                                  powf(cosDelta, hit.material->shininess);
+                }
+            }
+        }
+        
+        if (hit.material->type == REFLECTIVE) {
+            vec3 reflectedDir = ray.dir - hit.normal * dot(hit.normal, ray.dir) * 2.0f;
+            
+            float cosa = -dot(ray.dir, hit.normal);
+            vec3 one(1, 1, 1);
+            vec3 F = hit.material->F0 + (one - hit.material->F0) * pow(1 - cosa, 5);
+            
+            outRadiance = outRadiance + trace(Ray(hit.position + hit.normal * epsilon, reflectedDir), depth + 1) * F;
+        }
+		
 		return outRadiance;
 	}
 	
-- 
GitLab