113 if (R_dot_V > 0) |
114 if (R_dot_V > 0) |
114 I += mat.specular * light.colour * powf(R_dot_V, mat.shininess); |
115 I += mat.specular * light.colour * powf(R_dot_V, mat.shininess); |
115 return I; |
116 return I; |
116 } |
117 } |
117 |
118 |
|
119 Colour Raytracer::shader_evalulate(Ray &ray, int depth, Shape *origin_shape, |
|
120 Float nearest_distance, Shape *nearest_shape) |
|
121 { |
|
122 Colour col = Colour(); |
|
123 Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection |
|
124 Vector3 normal = nearest_shape->normal(P); |
|
125 bool from_inside = false; |
|
126 |
|
127 // make shapes double sided |
|
128 if (dot(normal, ray.dir) > 0.0) |
|
129 { |
|
130 normal = - normal; |
|
131 from_inside = true; |
|
132 } |
|
133 |
|
134 col = PhongShader_ambient(*nearest_shape->material, P); |
|
135 |
|
136 vector<Light*>::iterator light; |
|
137 for (light = lights.begin(); light != lights.end(); light++) { |
|
138 Vector3 jo, L = (*light)->pos - P; // direction vector to light |
|
139 L.normalize(); |
|
140 Float L_dot_N = dot(L, normal); |
|
141 if (L_dot_N > 0) { |
|
142 // test if this light is occluded (sharp shadows) |
|
143 if ((*light)->cast_shadows) { |
|
144 Ray shadow_ray = Ray(P, L); |
|
145 Float dist = FLT_MAX; |
|
146 if (top->nearest_intersection(nearest_shape, shadow_ray, dist)) |
|
147 continue; |
|
148 } |
|
149 |
|
150 // shading function |
|
151 Vector3 R = L - 2.0 * L_dot_N * normal; |
|
152 col += PhongShader_calculate(*nearest_shape->material, |
|
153 P, normal, R, ray.dir, **light); |
|
154 } |
|
155 } |
|
156 |
|
157 if (depth < max_depth) |
|
158 { |
|
159 Colour trans_col, refl_col; |
|
160 Float trans = nearest_shape->material->transmissivity; |
|
161 Float refl = nearest_shape->material->reflectivity; |
|
162 const Float cos_i = - dot(normal, ray.dir); |
|
163 |
|
164 // reflection |
|
165 if (refl > 0.01) |
|
166 { |
|
167 Vector3 newdir = ray.dir + 2.0 * cos_i * normal; |
|
168 Ray newray = Ray(P, newdir); |
|
169 refl_col = raytrace(newray, depth + 1, nearest_shape); |
|
170 } |
|
171 |
|
172 // refraction |
|
173 if (trans > 0.01) |
|
174 { |
|
175 Float n, n1, n2; |
|
176 if (from_inside) |
|
177 { |
|
178 n1 = nearest_shape->material->refract_index; |
|
179 n2 = 1.0; |
|
180 n = n1; |
|
181 } |
|
182 else |
|
183 { |
|
184 n1 = 1.0; |
|
185 n2 = nearest_shape->material->refract_index; |
|
186 n = 1.0 / n2; |
|
187 } |
|
188 const Float sin2_t = n*n * (1 - cos_i*cos_i); |
|
189 if (sin2_t >= 1.0) |
|
190 { |
|
191 // totally reflected |
|
192 refl += trans; |
|
193 trans = 0; |
|
194 } |
|
195 else |
|
196 { |
|
197 const Float cos_t = sqrtf(1 - sin2_t); |
|
198 const Float Rdiv = 1.0/(n1*cos_i + n2*cos_t); |
|
199 const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv; |
|
200 const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv; |
|
201 const Float R = (Rper*Rper + Rpar*Rpar)/2; |
|
202 refl += R*trans; |
|
203 trans = (1-R)*trans; |
|
204 Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal; |
|
205 Ray newray = Ray(P + 0.001*newdir, newdir); |
|
206 trans_col = raytrace(newray, depth + 1, NULL); |
|
207 } |
|
208 } |
|
209 col = (1-refl-trans)*col + refl*refl_col + trans*trans_col; |
|
210 } |
|
211 |
|
212 // ambient occlusion |
|
213 if (!from_inside && ao_samples) |
|
214 { |
|
215 Float miss = 0; |
|
216 for (int i = 0; i < ao_samples; i++) { |
|
217 Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
|
218 Ray ao_ray = Ray(P, dir); |
|
219 Float dist = ao_distance; |
|
220 Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist); |
|
221 if (shape_in_way == NULL) |
|
222 miss += 1.0; |
|
223 else |
|
224 miss += dist / ao_distance; |
|
225 } |
|
226 Float ao_intensity = miss / ao_samples; |
|
227 col = col * ao_intensity; |
|
228 } |
|
229 |
|
230 return col; |
|
231 } |
|
232 |
118 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape) |
233 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape) |
119 { |
234 { |
120 Float nearest_distance = Inf; |
235 Float nearest_distance = Inf; |
121 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
236 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
122 |
237 |
123 if (nearest_shape == NULL) { |
238 if (nearest_shape == NULL) |
|
239 { |
124 return bg_colour; |
240 return bg_colour; |
125 } else { |
241 } |
126 Colour col = Colour(); |
242 else |
127 Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection |
243 { |
128 Vector3 normal = nearest_shape->normal(P); |
244 return shader_evalulate(ray, depth, origin_shape, nearest_distance, nearest_shape); |
129 bool from_inside = false; |
245 } |
130 |
246 } |
131 // make shapes double sided |
247 |
132 if (dot(normal, ray.dir) > 0.0) |
248 void Raytracer::raytracePacket(Ray *rays, Colour *results) |
133 { |
249 { |
134 normal = - normal; |
250 Float nearest_distances[4] = {Inf,Inf,Inf,Inf}; |
135 from_inside = true; |
251 Shape *nearest_shapes[4]; |
136 } |
252 static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL}; |
137 |
253 top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes); |
138 col = PhongShader_ambient(*nearest_shape->material, P); |
254 |
139 |
255 for (int i = 0; i < 4; i++) |
140 vector<Light*>::iterator light; |
256 if (nearest_shapes[i] == NULL) |
141 for (light = lights.begin(); light != lights.end(); light++) { |
257 results[i] = bg_colour; |
142 Vector3 jo, L = (*light)->pos - P; // direction vector to light |
258 else |
143 L.normalize(); |
259 results[i] = shader_evalulate(rays[i], 0, NULL, |
144 Float L_dot_N = dot(L, normal); |
260 nearest_distances[i], nearest_shapes[i]); |
145 if (L_dot_N > 0) { |
|
146 // test if this light is occluded (sharp shadows) |
|
147 if ((*light)->cast_shadows) { |
|
148 Ray shadow_ray = Ray(P, L); |
|
149 Float dist = FLT_MAX; |
|
150 if (top->nearest_intersection(nearest_shape, shadow_ray, dist)) |
|
151 continue; |
|
152 } |
|
153 |
|
154 // shading function |
|
155 Vector3 R = L - 2.0 * L_dot_N * normal; |
|
156 col += PhongShader_calculate(*nearest_shape->material, |
|
157 P, normal, R, ray.dir, **light); |
|
158 } |
|
159 } |
|
160 |
|
161 if (depth < max_depth) |
|
162 { |
|
163 Colour trans_col, refl_col; |
|
164 Float trans = nearest_shape->material->transmissivity; |
|
165 Float refl = nearest_shape->material->reflectivity; |
|
166 const Float cos_i = - dot(normal, ray.dir); |
|
167 |
|
168 // reflection |
|
169 if (refl > 0.01) |
|
170 { |
|
171 Vector3 newdir = ray.dir + 2.0 * cos_i * normal; |
|
172 Ray newray = Ray(P, newdir); |
|
173 refl_col = raytrace(newray, depth + 1, nearest_shape); |
|
174 } |
|
175 |
|
176 // refraction |
|
177 if (trans > 0.01) |
|
178 { |
|
179 Float n, n1, n2; |
|
180 if (from_inside) |
|
181 { |
|
182 n1 = nearest_shape->material->refract_index; |
|
183 n2 = 1.0; |
|
184 n = n1; |
|
185 } |
|
186 else |
|
187 { |
|
188 n1 = 1.0; |
|
189 n2 = nearest_shape->material->refract_index; |
|
190 n = 1.0 / n2; |
|
191 } |
|
192 const Float sin2_t = n*n * (1 - cos_i*cos_i); |
|
193 if (sin2_t >= 1.0) |
|
194 { |
|
195 // totally reflected |
|
196 refl += trans; |
|
197 trans = 0; |
|
198 } |
|
199 else |
|
200 { |
|
201 const Float cos_t = sqrtf(1 - sin2_t); |
|
202 const Float Rdiv = 1.0/(n1*cos_i + n2*cos_t); |
|
203 const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv; |
|
204 const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv; |
|
205 const Float R = (Rper*Rper + Rpar*Rpar)/2; |
|
206 refl += R*trans; |
|
207 trans = (1-R)*trans; |
|
208 Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal; |
|
209 Ray newray = Ray(P + 0.001*newdir, newdir); |
|
210 trans_col = raytrace(newray, depth + 1, NULL); |
|
211 } |
|
212 } |
|
213 col = (1-refl-trans)*col + refl*refl_col + trans*trans_col; |
|
214 } |
|
215 |
|
216 // ambient occlusion |
|
217 if (!from_inside && ao_samples) |
|
218 { |
|
219 Float miss = 0; |
|
220 for (int i = 0; i < ao_samples; i++) { |
|
221 Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
|
222 Ray ao_ray = Ray(P, dir); |
|
223 Float dist = ao_distance; |
|
224 Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist); |
|
225 if (shape_in_way == NULL) |
|
226 miss += 1.0; |
|
227 else |
|
228 miss += dist / ao_distance; |
|
229 } |
|
230 Float ao_intensity = miss / ao_samples; |
|
231 col = col * ao_intensity; |
|
232 } |
|
233 |
|
234 return col; |
|
235 } |
|
236 } |
261 } |
237 |
262 |
238 void *Raytracer::raytrace_worker(void *d) |
263 void *Raytracer::raytrace_worker(void *d) |
239 { |
264 { |
240 static const int my_queue_size = 256; |
265 static const int my_queue_size = 256; |
241 Raytracer *rt = (Raytracer*)d; |
266 Raytracer *rt = (Raytracer*)d; |
242 Sample my_queue[my_queue_size]; |
267 Sample my_queue[my_queue_size]; |
243 Colour my_colours[my_queue_size]; |
268 Colour my_colours[my_queue_size]; |
244 int my_count; |
269 int my_count; |
245 Ray ray; |
270 Ray ray, rays[4]; |
|
271 const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples()); |
246 for (;;) |
272 for (;;) |
247 { |
273 { |
248 pthread_mutex_lock(&rt->sample_queue_mutex); |
274 pthread_mutex_lock(&rt->sample_queue_mutex); |
249 while (rt->sample_queue_count == 0) |
275 while (rt->sample_queue_count == 0) |
250 { |
276 { |