-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ray.cpp
237 lines (210 loc) · 10 KB
/
Ray.cpp
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "Ray.hpp"
//***********************************************************************
// @returns Ray's direction
//***********************************************************************
Direction Ray::getDirection(){
return this->dir;
}
//***********************************************************************
// Sets the direction of this ray
// @param dir New direction for the ray
//***********************************************************************
void Ray::setDirection(Direction dir){
this->dir = dir;
}
//***********************************************************************
// Sets the origin of this ray
// @param dir New origin for the ray
//***********************************************************************
void Ray::setOrigin(Point origin){
this->origin = origin;
}
//***********************************************************************
// Finds the intersection of this ray with the shape
// @param shape Smart pointer to the shape
// @param solutions[] Array that will store the factor of the intersections (if any)
// @returns Number of intersections
//***********************************************************************
int Ray::findIntersectionWith(ShapePtr shape, float solutions[]){
return shape->findIntersectionWithLine(dir, origin, solutions);
}
//***********************************************************************
// Calculates the direct contribution of a light point
// @param scene The scene the ray is being casted at
// @param light Will be modified with the contribution of the light point
// @param destination Light point whose contribution will be calculated
// @param lastShape Smart pointer with the shape the shadow ray is being casted from
// @returns false if and only if an obstacle was found.
//***********************************************************************
bool Ray::getShadowRayResult(Scene& scene, RGB& light, LightPoint destination, ShapePtr lastShape){
ShapePtr closestShape = nullptr;
ShapePtr shape;
float solutions[2];
int nShapes = scene.shapeN();
//last shape's normal and this direction should be in the same direction (dot pruduct must be >0)
bool foundObstacle = (lastShape->getNormalAtPoint(this->origin) * this->dir <= 0);
int nIntersections;
float dist = distance(origin, destination.getLocalization());
float dist2;
for(int s = 0; s < nShapes && !foundObstacle; s++){ //Iterate through all shapes in scene
shape = scene.getShape(s);
nIntersections = findIntersectionWith(shape, solutions); //Find intersection with ray
for(int i = 0; i < nIntersections && !foundObstacle; i++){ //Loop through intersections
//safe check, in case direction is not normalized
dist2 = (solutions[i] * dir).modulus();
//foundObstacle = there was something in a distance smaller or equal to the distance to the destination,
//and larger than 0, and the collision wasn't produced with the same shape it originated
foundObstacle |= (dist >= dist2 && solutions[i] >= EPSILON);
}
}
if(!foundObstacle){
light = light + destination.getEmission() * (lastShape->getNormalAtPoint(this->origin) * this->dir) * lastShape->getMaterial().getCoefficient(DIFFUSION) / (dist * dist * M_PI);
}
return !foundObstacle;
}
//***********************************************************************
// Calculates the direct contribution of all light points
// @param scene The scene the ray is being casted at
// @param light Will be modified with the contribution of the light point
// @param origin Origin of the shadow rays
// @param lastShape Smart pointer with the shape the shadow ray is being casted from
// @returns NO_EVENT if no change was made. Otherwise, LIGHTFOUND
//***********************************************************************
Event Ray::castShadowRays(Scene& scene, RGB& light, Point origin, ShapePtr lastShape){
Ray shadowRay;
shadowRay.setOrigin(origin);
Direction d;
Point dest;
bool e = false;
for(int i = 0; i < scene.lightPN(); i++){
d = scene.getLightPoint(i).getLocalization() - origin;
d.normalize();
shadowRay.setDirection(d);
e |= shadowRay.getShadowRayResult(scene, light, scene.getLightPoint(i), lastShape);
}
return e? LIGHTFOUND : NO_EVENT;
}
//***********************************************************************
// Calculates the result of tracing a ray until it gets absorbed, finds a light or nothing was found
// @param scene The scene the ray is being casted at
// @returns The RGB tuple containing the color that was calculated
//***********************************************************************
RGB Ray::getRayResult(Scene& scene){
//Variable initializations
RGB result= RGB(0,0,0), factor = RGB(1,1,1), indirectLight= RGB(0,0,0), directLight = RGB(0,0,0), directBounce= RGB(0,0,0), preFactor= RGB(1,1,1);
float solutions[2];
int nShapes = scene.shapeN();
int nAreaLights = scene.areaLightN();
int nIntersections = 0;
float minT;
bool foundAreaLight = false;
ShapePtr closestShape;
ShapePtr shape;
ShapePtr lastShape = nullptr;
AreaLight area;
Material material;
Direction newDirection, t1, t2, normal;
Point intersection;
Direction up = scene.getCamera().getUp();
Direction left = scene.getCamera().getLeft();
bool initialized = false;
Event lastEvent = NO_EVENT, shadowEvent = NO_EVENT;
//Bounce
do{
preFactor = factor; //prefactor will always contain the throughput before the current bounce was added
closestShape = nullptr;
minT = MAX_float;
//---------------------------------------------------------------------------------------------------
//Calculate nearest intersection
for(int s = 0; s < nShapes; s++){ //Iterate through all shapes in scene
shape = scene.getShape(s);
nIntersections = findIntersectionWith(shape, solutions); //Find intersection with ray
for(int i = 0; i < nIntersections; i++){ //Loop through intersections
//If t is the smallest found AND object is not behind the origin
//AND the shape hasn't produced a reflection on the ray
if(minT > solutions[i] && solutions[i] >= EPSILON){
minT = solutions[i]; //Update minimum distance
closestShape = shape; //Update closest shape
}
}
}
//---------------------------------------------------------------------------------------------------
//Calculate intersections with Area Lights
for(int al = 0; al < nAreaLights; al++){
area = scene.getAreaLight(al);
nIntersections = area.findIntersectionWithLine(dir, origin, solutions);
if(nIntersections > 0 ){
if(minT > solutions[0] && solutions[0] >= EPSILON){
minT = solutions[0];
//Clear closest shape and set the variables to indicate we've found a light
closestShape = nullptr;
lastEvent = LIGHTFOUND;
foundAreaLight = true;
}
}
}
//---------------------------------------------------------------------------------------------------
//Get intersection results
if(foundAreaLight){
indirectLight = area.getEmission();
lastEvent = LIGHTFOUND;
}
else if(closestShape != nullptr){ //If any intersection was found with ray
lastShape = closestShape;
material = closestShape->getMaterial();
intersection = minT * dir + origin;
normal = closestShape->getNormalAtPoint(intersection);
//Calculate tangents
t1 = cross(normal, up);
if(t1.isNull()){
t1 = cross(normal, left);
}
t1.normalize();
t2 = cross(normal, t1);
t2.normalize();
//-------------------------------------------------------
//Calculate bounce light contribution
lastEvent = material.calculateRayCollision(factor,
indirectLight,
dir,
newDirection,
intersection,
normal,
t1,
t2,
initialized);
//-------------------------------------------------------
//Set the new values for the rays
setDirection(newDirection);
setOrigin(intersection);
//-------------------------------------------------------
//Next Event Estimation
if(lastEvent == DIFFUSION){
shadowEvent = castShadowRays(scene, directBounce, intersection, lastShape);
if(shadowEvent != NO_EVENT){
if(initialized){
directLight = directLight + preFactor * directBounce;
}
else{
directLight = directLight + directBounce;
}
}
}
}
}while(closestShape != nullptr && lastEvent != ABSORPTION && lastEvent != LIGHTFOUND);
//bounce when we have found something to bounce on, and neither a light source was found nor the ray was absorbed
//---------------------------------------------------------------------------------------------------
//Calculate final RGB tuple
if(lastEvent == LIGHTFOUND){
if(initialized){
result = factor * indirectLight + directLight;
}
else{
result = indirectLight + directLight;
}
}
else{
result = directLight;
}
return result;
}