-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUtility.cpp
More file actions
211 lines (177 loc) · 7.42 KB
/
Copy pathUtility.cpp
File metadata and controls
211 lines (177 loc) · 7.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include "Utility.h"
#include <math.h>
#include <utility>
#include <iostream>
#include <algorithm>
#define PI 3.14159265358979323846
// Returns the 2D dot product of two vectors
float Utility::dot2D(Vector v1, Vector v2) {
return (v1.getX() * v2.getX()) + (v1.getY() * v2.getY());
}
// Returns the 3D dot product of two vectors
float Utility::dot3D(Vector v1, Vector v2) {
return (v1.getX() * v2.getX()) + (v1.getY() * v2.getY()) + (v1.getZ() * v2.getZ());
}
// Returns the 4D dot product of two vectors
float Utility::dot4D(Vector v1, Vector v2) {
return (v1.getX() * v2.getX()) + (v1.getY() * v2.getY()) + (v1.getZ() * v2.getZ()) + (v1.getA() * v2.getA());
}
// Returns the 3D cross product of two vectors
Vector Utility::cross3D(Vector v1, Vector v2) {
float new_x = (v1.getY() * v2.getZ()) - (v1.getZ() * v2.getY());
float new_y = -1 * ((v1.getX() * v2.getZ()) - (v1.getZ() * v2.getX()));
float new_z = (v1.getX() * v2.getY()) - (v1.getY() * v2.getX());
return Vector(new_x, new_y, new_z);
}
// Converts Radians to Degrees
float Utility::toDegrees(float rad) {
return (rad * 180.0f) / PI;
}
// Converts Degrees to Radians
float Utility::toRadians(float deg) {
return (deg * PI) / 180.0f;
}
// Clamps a float between a specified minimum and maximums
float Utility::clamp(float value, float min, float max) {
if (value < min) {
value = min;
}
if (value > max) {
value = max;
}
return value;
}
// Attempt to solve a quadratic with given a, b, and c values
bool Utility::solveQuadratic(const float& a, const float& b, const float& c, float& x0, float& x1) {
float discr = (b * b) - (4 * a * c);
if (discr < 0) return false;
else if (discr == 0) x0 = x1 = (-0.5f * b) / a;
else { // discr > 0
float q = (b > 0) ?
-0.5f * (b + sqrtf(discr)) : // if b > 0
-0.5f * (b - sqrtf(discr)); // if b <= 0
x0 = q / a;
x1 = c / q;
}
if (x0 > x1) std::swap(x0, x1);
return true;
}
// Reflection ray cast function - used with reflection items
Vector Utility::castReflectRay(Ray ray, std::vector<Light*>* lights, std::vector<Object*>* objects, int depth) {
Vector view_dir = ray.getDirection();
view_dir.normalize3D();
Vector final_color = Vector();
IntersectInfo IsectInfo;
IsectInfo.t = 0;
// if the ray has its maximum # of times, return black
if (depth > ray.getMaxDepth()) return final_color;
for (int i = 0; i < objects->size(); i++) {
if (objects->at(i)->intersects(ray, IsectInfo)) {
switch (objects->at(i)->getShadeType()) {
case kPhong: {
IntersectInfo LightIsectInfo;
for (int l = 0; l < lights->size(); l++) {
Ray light_ray = Ray(lights->at(l)->getPosition());
Vector light_dir = IsectInfo.PHit - light_ray.getOrigin();
light_dir.normalize3D();
light_ray.setDirection(light_dir);
Vector temp_color = lights->at(l)->getColor();
//std::cout << "Light color: " << lights->at(i)->getColor().toString() << std::endl;
Vector spec = Vector();
Vector diff = Vector();
Vector reflect = getReflectionDirection(IsectInfo.NHit, light_dir);
reflect.normalize3D();
if (objects->at(i)->intersects(Ray(lights->at(l)->getPosition(), IsectInfo.PHit - lights->at(l)->getPosition()), LightIsectInfo)) {
diff = diffuse(IsectInfo.NHit, light_ray.getDirection(), lights->at(l)->getColor(), lights->at(l)->getIntensity());
spec = specular(IsectInfo.NHit, light_ray.getDirection(), reflect,
lights->at(l)->getIntensity(), objects->at(i)->getShininess(), view_dir);
temp_color = (diff * objects->at(i)->getDiffuseValue()) + (spec * objects->at(i)->getSpecularValue());
final_color += temp_color;
//std::cout << "Light " << l << " Color: " << temp_color.toString() << std::endl;
//std::cout << "New Color:" << final_color.toString() << std::endl;
}
}
break;
}
case kReflect: {
Vector reflectDir = getReflectionDirection(IsectInfo.NHit, ray.getDirection());
Ray reflectRay = Ray(IsectInfo.PHit + IsectInfo.NHit, reflectDir);
reflectRay.setMaxDepth(ray.getMaxDepth()); // make sure the new ray's max depth is the same as the starter!
final_color += castReflectRay(reflectRay, lights, objects, depth + 1) * 0.8f;
break;
}
default: {
break;
}
}
}
}
return final_color;
}
// Blend two colors and return the result
Vector Utility::blendColors(Vector color1, Vector color2, bool useA) {
Vector temp_c1 = color1;
//temp_c1.normalize3D();
Vector temp_c2 = color2;
//temp_c2.normalize3D();
//std::cout << "Blending Colors: " << temp_c1.toString() << " and " << temp_c2.toString() << std::endl;
Vector newColor = Vector((temp_c1.getX() + temp_c2.getX()) / 2.0f,
(temp_c1.getY() + temp_c2.getY()) / 2.0f,
(temp_c1.getZ() + temp_c2.getZ()) / 2.0f);
if (useA) {
float a = color1.getA() + color2.getA() * (1.0f - color1.getA());
newColor.setA(a);
}
//std::cout << "New Color: " << newColor.toString() << std::endl;
return newColor;
}
// Get the reflection direciton from a given normal and light direction
Vector Utility::getReflectionDirection(Vector surface_normal_hit, Vector light_direction) {
Vector R = ((surface_normal_hit * dot3D(surface_normal_hit, light_direction)) * 2.0f) - light_direction;
//R.normalize3D();
//std::cout << R.toString() << std::endl;
return R;
}
// Returns the diffuse color gathered from the surface normal, light direction, light color, and light intensity.
Vector Utility::diffuse(Vector surface_normal_hit, Vector light_direction, Vector light_color, float light_intensity) {
float lambert_cos = dot3D(surface_normal_hit, -light_direction);
if (lambert_cos < 0.0f) lambert_cos = 0.0f;
if (lambert_cos > 1.0f) lambert_cos = 1.0f;
//std::cout << "Lambert Cos: " << lambert_cos << std::endl;
float diffuse = lambert_cos * light_intensity;
return Vector(light_color.getX() * diffuse, light_color.getY() * diffuse, light_color.getZ() * diffuse);
}
// Returns the specular color gathered from the surface normal, light direction, reflection direction, light intensity, shininess, and view direction.
Vector Utility::specular(Vector surface_normal_hit, Vector light_direction, Vector reflect_direction, float light_intensity, float shininess, Vector view_direction) {
float specular = dot3D(view_direction, reflect_direction);
specular = clamp(specular, 0.0f, 1.0f);
//std::cout << specular << std::endl;
float spec_with_shiny = std::powf(specular, shininess);
spec_with_shiny *= light_intensity;
if(spec_with_shiny < 0.0f) std::cout << spec_with_shiny << std::endl;
return Vector(spec_with_shiny, spec_with_shiny, spec_with_shiny);
//return Vector(specular, specular, specular);
}
// Returns the refraction direction from the given incidence vector and the normal of the surface that was hit
Vector Utility::getRefractionDirection(Vector incidence_vector, Vector surface_normal_hit, float refract_index) {
float cosi = clamp(dot3D(incidence_vector, surface_normal_hit), -1, 1);
float etai = 1;
float etat = refract_index;
Vector n = surface_normal_hit;
if (cosi < 0) { // not inside surface
cosi = -cosi;
}
else { // inside surface
std::swap(etai, etat);
n = -surface_normal_hit;
}
float eta = etai / etat;
float k = 1 - eta * eta * (1 - cosi * cosi);
if (k < 0) {
return Vector();
}
else {
Vector return_val = (incidence_vector * eta) + n * (eta * cosi - sqrtf(k));
return return_val;
}
}