-
Notifications
You must be signed in to change notification settings - Fork 1
/
Ray.cu
308 lines (267 loc) · 11 KB
/
Ray.cu
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#include "Ray.h"
#define PI 3.14159f
#define BRIGHTNESS 4
#define CLIPPING_DISTANCE 999
#define EPSILON 0.001f
//REFLECTIVITY, SHADOW_DIM_FACTOR GOES FROM 0 TO 1
#define REFLECTIVITY 0.8f
#define SHADOW_DIM_FACTOR 0.9f
#define REFRACTION_BRIGHTNESS 0.8f //[0,1] higher = more prominence of reflections and refractions
#define GLASS_CLARITY 0.6f //[0,1] higher = less of original colour
#define IOR 1.5f
#define REFLECTIONAL_LIGHTING 1
#define MAXIMUM_DEPTH 5
#define USE_IMAGE_HORIZON 0
#define HORIZON_DIM_FACTOR 0.1f
/*
LIFE CYCLE OF A RAY:
starts off as an INITIAL ray and is predefined a start position and direction
the ray is then shot out, the intersection properties worked out and then,
given CLIPPING iff no intersections occur, else the vector from the point of
intersection to the lamp is calculated and if the normal of the surface blocks
the light from going to the camera then it is given a BACKSCATTER, else DIRECT
NOTE: Even if DIRECT is given to a ray, it can still encounter other objects
that might obstruct its path in future - in this case, it will be given a
BACKSCATTER when that occurs
*/
__host__ __device__ Ray::Ray(vector_t initial, Scene *scene, int MAX_BOUNCES, int BSPBVH_DEPTH){
this->BSPBVH_DEPTH = BSPBVH_DEPTH;
ray = initial;
this->scene = scene;
this->MAX_BOUNCES = MAX_BOUNCES;
pathColour.r = 0;
pathColour.g = 0;
pathColour.b = 0;
totalColour.r = 0;
totalColour.g = 0;
totalColour.b = 0;
rayNumber = 0;
rayType = INITIAL;
totalDistance = 0;
specularityHighlight = 0;
secondary = (secondaryRay_t*)malloc(MAXIMUM_DEPTH*sizeof(secondaryRay_t));
secondaryDepth = 0;
}
__host__ __device__ colour_t Ray::raytrace(void){
int rayLevel = 0;
while(rayLevel <= secondaryDepth){
if(rayLevel != 0){
ray = secondary[rayLevel-1].normalRaySecondary;
pathColour.r = 0;
pathColour.g = 0;
pathColour.b = 0;
rayNumber = 0;
rayType = INITIAL;
MAX_BOUNCES = secondary[rayLevel-1].MAX_BOUNCESSecondary;
}
while(rayType!=CLIPPING && rayNumber-1<MAX_BOUNCES){
nextRayBounce();
}
//add specularity highlights if appropiate
if(specularityHighlight>0.99){
pathColour.r *= 2-(1-specularityHighlight)*100;
pathColour.g *= 2-(1-specularityHighlight)*100;
pathColour.b *= 2-(1-specularityHighlight)*100;
specularityHighlight = 0;
}
if(rayLevel == 0){
totalColour.r += pathColour.r;
totalColour.g += pathColour.g;
totalColour.b += pathColour.b;
}else{
totalColour.r += pathColour.r*REFLECTIVITY*secondary[rayLevel-1].currentMeshReflectivitySecondary;
totalColour.g += pathColour.g*REFLECTIVITY*secondary[rayLevel-1].currentMeshReflectivitySecondary;
totalColour.b += pathColour.b*REFLECTIVITY*secondary[rayLevel-1].currentMeshReflectivitySecondary;
}
rayLevel++;
}
return totalColour;
}
__host__ __device__ void Ray::nextRayBounce(void){
rayNumber++;
Mesh* intersectedMesh;
float tMin;
if(BSPBVH_DEPTH!=0){
tMin = scene->collisionDetect(ray, &intersectedMesh);
}else{
tMin = CLIPPING_DISTANCE;
int iMin = 0;
for(int i=0; i<scene->getNumOfMeshes(); i++){
float tCurrent = scene->getMesh(i)->getIntersectionParameter(ray);
if(EPSILON<tCurrent && tCurrent<tMin && tCurrent!=0){
tMin = tCurrent;
iMin = i;
}
}
intersectedMesh = scene->getMesh(iMin);
}
colour_t intersectedMeshColour;
if(abs(tMin-CLIPPING_DISTANCE)>EPSILON){ //NOT a clipping ray
//intersectedMeshColour.r = scene->getMesh(iMin)->getColour(ray.getPosAtParameter(tMin)).r;
//intersectedMeshColour.g = scene->getMesh(iMin)->getColour(ray.getPosAtParameter(tMin)).g;
//intersectedMeshColour.b = scene->getMesh(iMin)->getColour(ray.getPosAtParameter(tMin)).b;
//intersectedMeshColour = scene->getMesh(iMin)->getColour(ray.getPosAtParameter(tMin));
intersectedMeshColour = intersectedMesh->getColour(ray.getPosAtParameter(tMin));
}else{
if(USE_IMAGE_HORIZON){
vertex_t boundingSphereIntersection = ray.getPosAtParameter(CLIPPING_DISTANCE);
vertex_t boundingSphereCentre;
boundingSphereCentre.x = 0;
boundingSphereCentre.y = 0;
boundingSphereCentre.z = 0;
vector_t r(boundingSphereCentre, boundingSphereIntersection);
vector_t s(boundingSphereCentre, boundingSphereIntersection);
s.zt = 0;
vector_t k_unit(0,0,0,0,0,1);
vector_t i_unit(0,0,0,1,0,0);
float cosine_phi = k_unit.directionDotProduct(r)/r.directionMagnitude();
float cosine_theta = i_unit.directionDotProduct(s)/s.directionMagnitude();
int x,y;
if(1){
if(s.yt>0){//theta < pi
x = 300*(1-acosf(cosine_theta)/PI);
}else{//theta >= pi
x = 300*acosf(cosine_theta)/PI;
}
y = 300*(acosf(cosine_phi))/PI;
}else{
x = 600*(cosine_theta+1)/2;
y = 300*(cosine_phi+1)/2;
}
colour_t pointColour;
pointColour.r = (scene->getTexture()[600*y+x] & 0x000000FF) >> 0;
pointColour.g = (scene->getTexture()[600*y+x] & 0x0000FF00) >> 8;
pointColour.b = (scene->getTexture()[600*y+x] & 0x00FF0000) >> 16;
pathColour.r += pointColour.r*BRIGHTNESS*HORIZON_DIM_FACTOR;
pathColour.g += pointColour.g*BRIGHTNESS*HORIZON_DIM_FACTOR;
pathColour.b += pointColour.b*BRIGHTNESS*HORIZON_DIM_FACTOR;
}else{
pathColour.r += scene->getHorizonColour().r*BRIGHTNESS*HORIZON_DIM_FACTOR;
pathColour.g += scene->getHorizonColour().g*BRIGHTNESS*HORIZON_DIM_FACTOR;
pathColour.b += scene->getHorizonColour().b*BRIGHTNESS*HORIZON_DIM_FACTOR;
}
rayType = CLIPPING;
return;
}
float distance = ray.calculateDistance(tMin);
totalDistance += distance;
float currentMeshReflectivity = intersectedMesh->getMaterial().getReflectivity();
bool isTransmission = intersectedMesh->getMaterial().getTransmission();
float isShadowed = intersectedMesh->getShadowedStatus(ray, tMin, scene->getLight());
if(rayType==BACKSCATTER){
pathColour.r += intersectedMeshColour.r*BRIGHTNESS*currentMeshReflectivity/(rayNumber*totalDistance);
pathColour.g += intersectedMeshColour.g*BRIGHTNESS*currentMeshReflectivity/(rayNumber*totalDistance);
pathColour.b += intersectedMeshColour.b*BRIGHTNESS*currentMeshReflectivity/(rayNumber*totalDistance);
}else if(rayType==DIRECT){
pathColour.r += intersectedMeshColour.r*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.g += intersectedMeshColour.g*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.b += intersectedMeshColour.b*BRIGHTNESS/(rayNumber*totalDistance);
}else if(rayType==INITIAL){
pathColour.r += intersectedMeshColour.r*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.g += intersectedMeshColour.g*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.b += intersectedMeshColour.b*BRIGHTNESS/(rayNumber*totalDistance);
}else if(rayType==TRANSMISSION){
//add nothing for now
//also needs to force TRANSMISSION off when light is exiting
isTransmission = false;
rayType = BACKSCATTER;
pathColour.r *= 1.5+2*REFRACTION_BRIGHTNESS;
pathColour.g *= 1.5+2*REFRACTION_BRIGHTNESS;
pathColour.b *= 1.5+2*REFRACTION_BRIGHTNESS;
//////////////////////////////FORCE LEAVE GLASS MATERIAL REVERSE SNELLS LAW
vertex_t pos = ray.getPosAtParameter(tMin);
vector_t transmissionRay;
vector_t normalRay = intersectedMesh->getNormal(ray.getPosAtParameter(tMin), ray);
vector_t reverseIncidence(0,0,0,-ray.xt,-ray.yt,-ray.zt);
float cosINCIDENCE = normalRay.directionDotProduct(reverseIncidence);
float normalMagnitude = normalRay.directionMagnitude();
float rayMagnitude = ray.directionMagnitude();
float hypFactor = (cosINCIDENCE + sqrt(cosINCIDENCE*cosINCIDENCE+(1/IOR)*(1/IOR)-1))/((1/IOR)*(1/IOR)-1);
transmissionRay.x0 = pos.x;
transmissionRay.y0 = pos.y;
transmissionRay.z0 = pos.z;
transmissionRay.xt = normalRay.xt/normalMagnitude + ray.xt*hypFactor/rayMagnitude;
transmissionRay.yt = normalRay.yt/normalMagnitude + ray.yt*hypFactor/rayMagnitude;
transmissionRay.zt = normalRay.zt/normalMagnitude + ray.zt*hypFactor/rayMagnitude;
ray = transmissionRay;
return;
}
//UPDATE PRIMARY LIGHTING
if(isTransmission){
rayType = TRANSMISSION;
pathColour.r -= (0.6+0.4*GLASS_CLARITY)*intersectedMeshColour.r*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.g -= (0.6+0.4*GLASS_CLARITY)*intersectedMeshColour.g*BRIGHTNESS/(rayNumber*totalDistance);
pathColour.b -= (0.6+0.4*GLASS_CLARITY)*intersectedMeshColour.b*BRIGHTNESS/(rayNumber*totalDistance);
}else if(isShadowed > 0){//backscatter by itself
rayType = BACKSCATTER;//THIS CORRESPONDS TO THE REFLECTED RAY TYPE
pathColour.r *= (1-currentMeshReflectivity/2)*(1-abs(isShadowed));
pathColour.g *= (1-currentMeshReflectivity/2)*(1-abs(isShadowed));
pathColour.b *= (1-currentMeshReflectivity/2)*(1-abs(isShadowed));
}else{//continue to light - but path can be blocked by another object
rayType = DIRECT;//THIS CORRESPONDS TO THE REFLECTED RAY TYPE
}
vector_t normalRay = intersectedMesh->getNormal(ray.getPosAtParameter(tMin), ray);
vector_t directRay;
vertex_t pos = ray.getPosAtParameter(tMin);
directRay.x0 = pos.x;
directRay.y0 = pos.y;
directRay.z0 = pos.z;
vertex_t lightPos = scene->getLight().getPos();
directRay.xt = lightPos.x - pos.x;
directRay.yt = lightPos.y - pos.y;
directRay.zt = lightPos.z - pos.z;
//////////////////////FORCE ENTER GLASS MATERIAL SNELLS LAW
vector_t transmissionRay;
vector_t reverseIncidence(0,0,0,-ray.xt,-ray.yt,-ray.zt);
float cosINCIDENCE = normalRay.directionDotProduct(reverseIncidence);
float normalMagnitude = normalRay.directionMagnitude();
float rayMagnitude = ray.directionMagnitude();
float hypFactor = (cosINCIDENCE + sqrt(cosINCIDENCE*cosINCIDENCE+IOR*IOR-1))/(IOR*IOR-1);
transmissionRay.x0 = pos.x;
transmissionRay.y0 = pos.y;
transmissionRay.z0 = pos.z;
transmissionRay.xt = normalRay.xt/normalMagnitude + ray.xt*hypFactor/rayMagnitude;
transmissionRay.yt = normalRay.yt/normalMagnitude + ray.yt*hypFactor/rayMagnitude;
transmissionRay.zt = normalRay.zt/normalMagnitude + ray.zt*hypFactor/rayMagnitude;
//SET RAY FOR NEXT SCATTER AND PREPROCESS SECONDARY LIGHTING FOR NEXT RAY
switch(rayType){
case BACKSCATTER:
{
//reestablishes the normal the the point of intersection for next ray bounce
ray = normalRay;
break;
}
case DIRECT:
{
ray = directRay;
if(REFLECTIONAL_LIGHTING && secondaryDepth < MAXIMUM_DEPTH){
secondary[secondaryDepth].currentMeshReflectivitySecondary = currentMeshReflectivity;
secondary[secondaryDepth].MAX_BOUNCESSecondary = MAX_BOUNCES-1;
secondary[secondaryDepth].normalRaySecondary = normalRay;
secondaryDepth++;
}
//SPECULARITY
specularityHighlight = normalRay.directionDotProduct(directRay)/(normalRay.directionMagnitude()*directRay.directionMagnitude());
break;
}
case TRANSMISSION:
{
ray = transmissionRay;
if(REFLECTIONAL_LIGHTING && secondaryDepth < MAXIMUM_DEPTH){
secondary[secondaryDepth].currentMeshReflectivitySecondary = currentMeshReflectivity;
secondary[secondaryDepth].MAX_BOUNCESSecondary = MAX_BOUNCES-1;
secondary[secondaryDepth].normalRaySecondary = normalRay;
secondaryDepth++;
}
//SPECULARITY
specularityHighlight = normalRay.directionDotProduct(directRay)/(normalRay.directionMagnitude()*directRay.directionMagnitude());
break;
}
default:
printf("ERROR: RAYS HAVE GONE HAYWIRE");
break;
}
}
__host__ __device__ Ray::~Ray(void){
free(secondary);
}