65 q = atan2f(normal.y, normal.x); |
65 q = atan2f(normal.y, normal.x); |
66 x = xx*cos(q) - yy*sin(q); |
66 x = xx*cos(q) - yy*sin(q); |
67 y = xx*sin(q) + yy*cos(q); |
67 y = xx*sin(q) + yy*cos(q); |
68 z = zz; |
68 z = zz; |
69 |
69 |
70 return Vector3(x, y, z); |
70 return Vector(x, y, z); |
71 } |
|
72 |
|
73 // ---- tyto dve funkce budou v budouci verzi metody objektu PhongShader |
|
74 |
|
75 // calculate shader function |
|
76 // P is point of intersection, N normal in this point |
|
77 Colour PhongShader_ambient(const Material &mat, const Vector3 &P) |
|
78 { |
|
79 Colour col; |
|
80 if (mat.texture) |
|
81 col = mat.texture->evaluate(P); |
|
82 else |
|
83 col = mat.colour; |
|
84 |
|
85 // ambient |
|
86 return mat.ambient * col; |
|
87 } |
71 } |
88 |
72 |
89 /* |
73 /* |
90 P is point of intersection, |
74 P is point of intersection, |
91 N normal in this point, |
75 N normal in this point, |
92 R direction of reflected ray, |
76 R direction of reflected ray, |
93 V direction to the viewer |
77 V direction to the viewer |
94 */ |
78 */ |
95 Colour PhongShader_calculate(const Material &mat, |
79 Colour Raytracer::PhongShader(const Shape *shape, |
96 const Vector3 &P, const Vector3 &N, const Vector3 &R, const Vector3 &V, |
80 const Vector &P, const Vector &N, const Vector &V) |
97 const Light &light) |
81 { |
98 { |
82 Colour col, acc; |
99 Colour I = Colour(); |
83 Material * const &mat = shape->material; |
100 Vector3 L = light.pos - P; |
84 |
101 L.normalize(); |
85 if (mat->texture) |
102 Float L_dot_N = dot(L, N); |
86 col = mat->texture->evaluate(P); |
103 Float R_dot_V = dot(R, V); |
|
104 |
|
105 Colour col; |
|
106 if (mat.texture) |
|
107 col = mat.texture->evaluate(P); |
|
108 else |
87 else |
109 col = mat.colour; |
88 col = mat->colour; |
110 |
89 |
111 // diffuse |
90 // ambient |
112 I = mat.diffuse * col * light.colour * L_dot_N; |
91 acc = mat->ambient * col; |
113 |
|
114 // specular |
|
115 if (R_dot_V > 0) |
|
116 I += mat.specular * light.colour * powf(R_dot_V, mat.shininess); |
|
117 return I; |
|
118 } |
|
119 |
|
120 Colour Raytracer::shader_evalulate(const Ray &ray, int depth, Shape *origin_shape, |
|
121 Float nearest_distance, Shape *nearest_shape) |
|
122 { |
|
123 Colour col = Colour(); |
|
124 Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection |
|
125 Vector3 normal = nearest_shape->normal(P); |
|
126 bool from_inside = false; |
|
127 |
|
128 // make shapes double sided |
|
129 if (dot(normal, ray.dir) > 0.0) |
|
130 { |
|
131 normal = - normal; |
|
132 from_inside = true; |
|
133 } |
|
134 |
|
135 col = PhongShader_ambient(*nearest_shape->material, P); |
|
136 |
92 |
137 vector<Light*>::iterator light; |
93 vector<Light*>::iterator light; |
138 for (light = lights.begin(); light != lights.end(); light++) { |
94 for (light = lights.begin(); light != lights.end(); light++) |
139 Vector3 jo, L = (*light)->pos - P; // direction vector to light |
95 { |
140 L.normalize(); |
96 const Vector L = normalize((*light)->pos - P); // direction vector to light |
141 Float L_dot_N = dot(L, normal); |
97 const Float L_dot_N = dot(L, N); |
142 if (L_dot_N > 0) { |
98 if (L_dot_N > 0) |
|
99 { |
143 // test if this light is occluded (sharp shadows) |
100 // test if this light is occluded (sharp shadows) |
144 if ((*light)->cast_shadows) { |
101 if ((*light)->cast_shadows) { |
145 Ray shadow_ray = Ray(P, L); |
102 const Ray shadow_ray = Ray(P, L); |
146 Float dist = FLT_MAX; |
103 Float dist = FLT_MAX; |
147 if (top->nearest_intersection(nearest_shape, shadow_ray, dist)) |
104 if (top->nearest_intersection(shape, shadow_ray, dist)) |
148 continue; |
105 continue; |
149 } |
106 } |
150 |
107 |
151 // shading function |
108 const Vector R = L - 2.0 * L_dot_N * N; |
152 Vector3 R = L - 2.0 * L_dot_N * normal; |
109 const Float R_dot_V = dot(R, V); |
153 col += PhongShader_calculate(*nearest_shape->material, |
110 |
154 P, normal, R, ray.dir, **light); |
111 // diffuse |
155 } |
112 acc += mat->diffuse * col * (*light)->colour * L_dot_N; |
156 } |
113 |
157 |
114 // specular |
|
115 if (R_dot_V > 0) |
|
116 acc += mat->specular * (*light)->colour * powf(R_dot_V, mat->shininess); |
|
117 } |
|
118 } |
|
119 |
|
120 return acc; |
|
121 } |
|
122 |
|
123 #ifndef NO_SSE |
|
124 VectorPacket Raytracer::PhongShader_packet(const Shape **shapes, |
|
125 const VectorPacket &P, const VectorPacket &N, const VectorPacket &V) |
|
126 { |
|
127 VectorPacket acc, colour; |
|
128 union { __m128 ambient; float ambient_f[4]; }; |
|
129 union { __m128 diffuse; float diffuse_f[4]; }; |
|
130 union { __m128 specular; float specular_f[4]; }; |
|
131 union { __m128 shininess; float shininess_f[4]; }; |
|
132 |
|
133 for (int i = 0; i < 4; i++) |
|
134 if (shapes[i] == NULL) |
|
135 { |
|
136 ambient_f[i] = 0; |
|
137 diffuse_f[i] = 0; |
|
138 specular_f[i] = 0; |
|
139 shininess_f[i] = 0; |
|
140 } |
|
141 else |
|
142 { |
|
143 Material * const &mat = shapes[i]->material; |
|
144 if (mat->texture) |
|
145 colour.setVector(i, mat->texture->evaluate(P.getVector(i))); |
|
146 else |
|
147 colour.setVector(i, mat->colour); |
|
148 ambient_f[i] = mat->ambient; |
|
149 diffuse_f[i] = mat->diffuse; |
|
150 specular_f[i] = mat->specular; |
|
151 shininess_f[i] = mat->shininess; |
|
152 } |
|
153 |
|
154 // ambient |
|
155 acc = colour * ambient; |
|
156 |
|
157 Shape **shadow_shapes; |
|
158 vector<Light*>::iterator light; |
|
159 for (light = lights.begin(); light != lights.end(); light++) |
|
160 { |
|
161 // direction vector to light |
|
162 VectorPacket L = VectorPacket((*light)->pos) - P; |
|
163 L.normalize(); |
|
164 const __m128 L_dot_N = dot(L, N); |
|
165 __m128 valid = _mm_cmpgt_ps(L_dot_N, mZero); |
|
166 |
|
167 // test if this light is occluded (sharp shadows) |
|
168 if ((*light)->cast_shadows) |
|
169 { |
|
170 const RayPacket shadow_rays = RayPacket(P, L); |
|
171 union { __m128 dists; float dists_f[4]; }; |
|
172 dists = mInf; |
|
173 top->packet_intersection(shapes, shadow_rays, |
|
174 dists_f, shadow_shapes); |
|
175 valid = _mm_and_ps(valid, _mm_cmpeq_ps(dists, mInf)); |
|
176 } |
|
177 |
|
178 const VectorPacket R = L - N * _mm_mul_ps(mTwo, L_dot_N); |
|
179 const __m128 R_dot_V = dot(R, V); |
|
180 |
|
181 // diffuse |
|
182 acc.selectiveAdd(valid, |
|
183 colour * VectorPacket((*light)->colour) * _mm_mul_ps(diffuse, L_dot_N)); |
|
184 |
|
185 // specular |
|
186 valid = _mm_and_ps(valid, _mm_cmpgt_ps(R_dot_V, mZero)); |
|
187 __m128 spec = _mm_mul_ps(_mm_mul_ps(specular, _mm_set_ps1((*light)->colour.r)), |
|
188 _mm_fastpow(R_dot_V, shininess)); |
|
189 acc.selectiveAdd(valid, spec); |
|
190 } |
|
191 return acc; |
|
192 } |
|
193 #endif |
|
194 |
|
195 void Raytracer::lightScatter(const Ray &ray, const Shape *shape, int depth, |
|
196 const Vector &P, const Vector &normal, bool from_inside, Colour &col) |
|
197 { |
158 if (depth < max_depth) |
198 if (depth < max_depth) |
159 { |
199 { |
160 Colour trans_col, refl_col; |
200 Colour trans_col, refl_col; |
161 Float trans = nearest_shape->material->transmissivity; |
201 Float trans = shape->material->transmissivity; |
162 Float refl = nearest_shape->material->reflectivity; |
202 Float refl = shape->material->reflectivity; |
163 const Float cos_i = - dot(normal, ray.dir); |
203 const Float cos_i = - dot(normal, ray.dir); |
164 |
204 |
165 // reflection |
205 // reflection |
166 if (refl > 0.01) |
206 if (refl > 0.01) |
167 { |
207 { |
168 Vector3 newdir = ray.dir + 2.0 * cos_i * normal; |
208 Vector newdir = ray.dir + 2.0 * cos_i * normal; |
169 Ray newray = Ray(P, newdir); |
209 Ray newray = Ray(P, newdir); |
170 refl_col = raytrace(newray, depth + 1, nearest_shape); |
210 refl_col = raytrace(newray, depth + 1, shape); |
171 } |
211 } |
172 |
212 |
173 // refraction |
213 // refraction |
174 if (trans > 0.01) |
214 if (trans > 0.01) |
175 { |
215 { |
176 Float n, n1, n2; |
216 Float n, n1, n2; |
177 if (from_inside) |
217 if (from_inside) |
178 { |
218 { |
179 n1 = nearest_shape->material->refract_index; |
219 n1 = shape->material->refract_index; |
180 n2 = 1.0; |
220 n2 = 1.0; |
181 n = n1; |
221 n = n1; |
182 } |
222 } |
183 else |
223 else |
184 { |
224 { |
185 n1 = 1.0; |
225 n1 = 1.0; |
186 n2 = nearest_shape->material->refract_index; |
226 n2 = shape->material->refract_index; |
187 n = 1.0 / n2; |
227 n = 1.0 / n2; |
188 } |
228 } |
189 const Float sin2_t = n*n * (1 - cos_i*cos_i); |
229 const Float sin2_t = n*n * (1 - cos_i*cos_i); |
190 if (sin2_t >= 1.0) |
230 if (sin2_t >= 1.0) |
191 { |
231 { |
200 const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv; |
240 const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv; |
201 const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv; |
241 const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv; |
202 const Float R = (Rper*Rper + Rpar*Rpar)/2; |
242 const Float R = (Rper*Rper + Rpar*Rpar)/2; |
203 refl += R*trans; |
243 refl += R*trans; |
204 trans = (1-R)*trans; |
244 trans = (1-R)*trans; |
205 Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal; |
245 Vector newdir = n * ray.dir + (n*cos_i - cos_t) * normal; |
206 Ray newray = Ray(P + 0.001*newdir, newdir); |
246 Ray newray = Ray(P + 0.001*newdir, newdir); |
207 trans_col = raytrace(newray, depth + 1, NULL); |
247 trans_col = raytrace(newray, depth + 1, NULL); |
208 } |
248 } |
209 } |
249 } |
210 col = (1-refl-trans)*col + refl*refl_col + trans*trans_col; |
250 col = (1-refl-trans)*col + refl*refl_col + trans*trans_col; |
211 } |
251 } |
212 |
252 |
213 // ambient occlusion |
253 // ambient occlusion |
214 if (!from_inside && ao_samples) |
254 if (ao_samples && !from_inside) |
215 { |
255 { |
216 Float miss = 0; |
256 Float miss = 0; |
217 for (int i = 0; i < ao_samples; i++) { |
257 for (int i = 0; i < ao_samples; i++) |
218 Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
258 { |
|
259 Vector dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
219 Ray ao_ray = Ray(P, dir); |
260 Ray ao_ray = Ray(P, dir); |
220 Float dist = ao_distance; |
261 Float dist = ao_distance; |
221 Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist); |
262 Shape *shape_in_way = top->nearest_intersection(shape, ao_ray, dist); |
222 if (shape_in_way == NULL) |
263 if (shape_in_way == NULL) |
223 miss += 1.0; |
264 miss += 1.0; |
224 else |
265 else |
225 miss += dist / ao_distance; |
266 miss += dist / ao_distance; |
226 } |
267 } |
227 Float ao_intensity = miss / ao_samples; |
268 Float ao_intensity = miss / ao_samples; |
228 col = col * ao_intensity; |
269 col = col * ao_intensity; |
229 } |
270 } |
230 |
271 } |
231 return col; |
272 |
232 } |
273 Colour Raytracer::raytrace(Ray &ray, int depth, const Shape *origin_shape) |
233 |
|
234 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape) |
|
235 { |
274 { |
236 Float nearest_distance = Inf; |
275 Float nearest_distance = Inf; |
237 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
276 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
238 |
277 |
239 if (nearest_shape == NULL) |
278 if (nearest_shape == NULL) |
240 return bg_colour; |
279 return bg_colour; |
241 else |
280 else |
242 return shader_evalulate(ray, depth, origin_shape, nearest_distance, nearest_shape); |
281 { |
243 } |
282 const Vector P = ray.o + ray.dir * nearest_distance; // point of intersection |
244 |
283 Vector normal = nearest_shape->normal(P); |
|
284 bool from_inside = false; |
|
285 |
|
286 // make shapes double sided |
|
287 if (dot(normal, ray.dir) > 0.0) |
|
288 { |
|
289 normal = - normal; |
|
290 from_inside = true; |
|
291 } |
|
292 |
|
293 // shading function |
|
294 Colour col = PhongShader(nearest_shape, P, normal, ray.dir); |
|
295 lightScatter(ray, nearest_shape, depth, P, normal, from_inside, col); |
|
296 return col; |
|
297 } |
|
298 } |
|
299 |
|
300 #ifndef NO_SSE |
245 void Raytracer::raytracePacket(RayPacket &rays, Colour *results) |
301 void Raytracer::raytracePacket(RayPacket &rays, Colour *results) |
246 { |
302 { |
247 Float nearest_distances[4] = {Inf,Inf,Inf,Inf}; |
303 union { |
|
304 float nearest_distances[4]; |
|
305 __m128 m_nearest_distances; |
|
306 }; |
|
307 __m128 mask; |
248 Shape *nearest_shapes[4]; |
308 Shape *nearest_shapes[4]; |
249 static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL}; |
309 static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL}; |
|
310 m_nearest_distances = mInf; |
|
311 mask = mAllSet; |
|
312 |
250 top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes); |
313 top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes); |
251 |
314 |
|
315 mask = _mm_cmpneq_ps(m_nearest_distances, mInf); |
|
316 if (!_mm_movemask_ps(mask)) |
|
317 { |
|
318 for (int i = 0; i < 4; i++) |
|
319 results[i] = bg_colour; |
|
320 return; |
|
321 } |
|
322 |
|
323 const VectorPacket P = rays.o + rays.dir * m_nearest_distances; // point of intersection |
|
324 |
|
325 VectorPacket normal; |
252 for (int i = 0; i < 4; i++) |
326 for (int i = 0; i < 4; i++) |
253 if (nearest_shapes[i] == NULL) |
327 if (nearest_shapes[i] != NULL) |
|
328 normal.setVector(i, nearest_shapes[i]->normal(P.getVector(i))); |
|
329 |
|
330 // make shapes double sided |
|
331 __m128 from_inside = _mm_cmpgt_ps(dot(normal, rays.dir), mZero); |
|
332 normal.mx = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.mx)), |
|
333 _mm_andnot_ps(from_inside, normal.mx)); |
|
334 normal.my = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.my)), |
|
335 _mm_andnot_ps(from_inside, normal.my)); |
|
336 normal.mz = _mm_or_ps(_mm_and_ps(from_inside, _mm_sub_ps(mZero, normal.mz)), |
|
337 _mm_andnot_ps(from_inside, normal.mz)); |
|
338 |
|
339 // shading function |
|
340 VectorPacket pres = |
|
341 PhongShader_packet(const_cast<const Shape**>(nearest_shapes), P, normal, rays.dir); |
|
342 //pres.mx = _mm_or_ps(_mm_and_ps(mask, pres.mx), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.r))); |
|
343 //pres.my = _mm_or_ps(_mm_and_ps(mask, pres.my), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.g))); |
|
344 //pres.mz = _mm_or_ps(_mm_and_ps(mask, pres.mz), _mm_andnot_ps(mask, _mm_set_ps1(bg_colour.b))); |
|
345 |
|
346 for (int i = 0; i < 4; i++) |
|
347 if (nearest_shapes[i] != NULL) |
|
348 { |
|
349 results[i] = pres.getVector(i); |
|
350 lightScatter(rays[i], nearest_shapes[i], 0, |
|
351 P.getVector(i), normal.getVector(i), (_mm_movemask_ps(from_inside)>>i)&1, |
|
352 results[i]); |
|
353 } |
|
354 else |
254 results[i] = bg_colour; |
355 results[i] = bg_colour; |
255 else |
356 } |
256 results[i] = shader_evalulate(rays[i], 0, NULL, |
357 #endif |
257 nearest_distances[i], nearest_shapes[i]); |
|
258 } |
|
259 |
358 |
260 void *Raytracer::raytrace_worker(void *d) |
359 void *Raytracer::raytrace_worker(void *d) |
261 { |
360 { |
262 static const int my_queue_size = 256; |
361 static const int my_queue_size = 256; |
263 Raytracer *rt = (Raytracer*)d; |
362 Raytracer *rt = (Raytracer*)d; |
264 Sample my_queue[my_queue_size]; |
363 Sample my_queue[my_queue_size]; |
265 Colour my_colours[my_queue_size]; |
364 Colour my_colours[my_queue_size]; |
266 int my_count; |
365 int my_count; |
267 Ray ray; |
366 Ray ray; |
|
367 #ifndef NO_SSE |
268 RayPacket rays; |
368 RayPacket rays; |
269 const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples()); |
369 const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples()); |
|
370 #endif |
270 for (;;) |
371 for (;;) |
271 { |
372 { |
272 pthread_mutex_lock(&rt->sample_queue_mutex); |
373 pthread_mutex_lock(&rt->sample_queue_mutex); |
273 while (rt->sample_queue_count == 0) |
374 while (rt->sample_queue_count == 0) |
274 { |
375 { |