13 #include <malloc.h> |
13 #include <malloc.h> |
14 #include "raytracer.h" |
14 #include "raytracer.h" |
15 |
15 |
16 // Hammersley spherical point distribution |
16 // Hammersley spherical point distribution |
17 // http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html |
17 // http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html |
18 Vector3 Raytracer::SphereDistribute(int i, int n, float extent, Vector3 &normal) |
18 Vector3 Raytracer::SphereDistribute(int i, int n, Float extent, Vector3 &normal) |
19 { |
19 { |
20 float p, t, st, phi, phirad; |
20 Float p, t, st, phi, phirad; |
21 int kk; |
21 int kk; |
22 |
22 |
23 t = 0; |
23 t = 0; |
24 for (p=0.5, kk=i; kk; p*=0.5, kk>>=1) |
24 for (p=0.5, kk=i; kk; p*=0.5, kk>>=1) |
25 if (kk & 1) |
25 if (kk & 1) |
29 phi = (i + 0.5) / n; |
29 phi = (i + 0.5) / n; |
30 phirad = phi * 2.0 * M_PI; |
30 phirad = phi * 2.0 * M_PI; |
31 |
31 |
32 st = sqrt(1.0 - t*t); |
32 st = sqrt(1.0 - t*t); |
33 |
33 |
34 float x, y, z, xx, yy, zz, q; |
34 Float x, y, z, xx, yy, zz, q; |
35 x = st * cos(phirad); |
35 x = st * cos(phirad); |
36 y = st * sin(phirad); |
36 y = st * sin(phirad); |
37 z = t; |
37 z = t; |
38 |
38 |
39 // rotate against Y axis |
39 // rotate against Y axis |
73 Light &light) |
73 Light &light) |
74 { |
74 { |
75 Colour I = Colour(); |
75 Colour I = Colour(); |
76 Vector3 L = light.pos - P; |
76 Vector3 L = light.pos - P; |
77 L.normalize(); |
77 L.normalize(); |
78 float L_dot_N = dot(L, N); |
78 Float L_dot_N = dot(L, N); |
79 float R_dot_V = dot(R, V); |
79 Float R_dot_V = dot(R, V); |
80 |
80 |
81 Colour col = mat.texture.colour; //mat.texture.evaluate(P); |
81 Colour col = mat.texture.colour; //mat.texture.evaluate(P); |
82 |
82 |
83 // diffuse |
83 // diffuse |
84 I = mat.diffuse * col * light.colour * L_dot_N; |
84 I = mat.diffuse * col * light.colour * L_dot_N; |
89 return I; |
89 return I; |
90 } |
90 } |
91 |
91 |
92 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape) |
92 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape) |
93 { |
93 { |
94 float nearest_distance = FLT_MAX; //Infinity |
94 Float nearest_distance = Inf; |
95 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
95 Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance); |
96 |
96 |
97 if (nearest_shape == NULL) { |
97 if (nearest_shape == NULL) { |
98 return bg_colour; |
98 return bg_colour; |
99 } else { |
99 } else { |
104 |
104 |
105 vector<Light*>::iterator light; |
105 vector<Light*>::iterator light; |
106 for (light = lights.begin(); light != lights.end(); light++) { |
106 for (light = lights.begin(); light != lights.end(); light++) { |
107 Vector3 jo, L = (*light)->pos - P; // direction vector to light |
107 Vector3 jo, L = (*light)->pos - P; // direction vector to light |
108 L.normalize(); |
108 L.normalize(); |
109 float L_dot_N = dot(L, normal); |
109 Float L_dot_N = dot(L, normal); |
110 if (L_dot_N > 0) { |
110 if (L_dot_N > 0) { |
111 // test if this light is occluded (sharp shadows) |
111 // test if this light is occluded (sharp shadows) |
112 if ((*light)->cast_shadows) { |
112 if ((*light)->cast_shadows) { |
113 Ray shadow_ray = Ray(P, L); |
113 Ray shadow_ray = Ray(P, L); |
114 float dist = FLT_MAX; |
114 Float dist = FLT_MAX; |
115 if (top->nearest_intersection(nearest_shape, shadow_ray, dist)) |
115 if (top->nearest_intersection(nearest_shape, shadow_ray, dist)) |
116 continue; |
116 continue; |
117 } |
117 } |
118 |
118 |
119 // shading function |
119 // shading function |
135 /* ... */ |
135 /* ... */ |
136 |
136 |
137 // ambient occlusion |
137 // ambient occlusion |
138 if (ao_samples) |
138 if (ao_samples) |
139 { |
139 { |
140 float miss = 0; |
140 Float miss = 0; |
141 for (int i = 0; i < ao_samples; i++) { |
141 for (int i = 0; i < ao_samples; i++) { |
142 Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
142 Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal); |
143 Ray ao_ray = Ray(P, dir); |
143 Ray ao_ray = Ray(P, dir); |
144 float dist = ao_distance; |
144 Float dist = ao_distance; |
145 Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist); |
145 Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist); |
146 if (shape_in_way == NULL) |
146 if (shape_in_way == NULL) |
147 miss += 1.0; |
147 miss += 1.0; |
148 else |
148 else |
149 miss += dist / ao_distance; |
149 miss += dist / ao_distance; |
150 } |
150 } |
151 float ao_intensity = miss / ao_samples; |
151 Float ao_intensity = miss / ao_samples; |
152 acc = acc * ao_intensity; |
152 acc = acc * ao_intensity; |
153 } |
153 } |
154 |
154 |
155 return acc; |
155 return acc; |
156 } |
156 } |
158 |
158 |
159 static void *renderrow(void *data) |
159 static void *renderrow(void *data) |
160 { |
160 { |
161 RenderrowData *d = (RenderrowData*) data; |
161 RenderrowData *d = (RenderrowData*) data; |
162 int subsample = d->rt->getSubsample(); |
162 int subsample = d->rt->getSubsample(); |
163 float subsample2 = 1.0/(subsample*subsample); |
163 Float subsample2 = 1.0/(subsample*subsample); |
164 int ww = d->w*3; |
164 int ww = d->w*3; |
165 Vector3 dir = d->dfix; |
165 Vector3 dir = d->dfix; |
166 for (int x = 0; x < d->w; x += subsample) { |
166 for (int x = 0; x < d->w; x += subsample) { |
167 // generate a ray from eye passing through this pixel |
167 // generate a ray from eye passing through this pixel |
168 #if OVERSAMPLING |
168 #if OVERSAMPLING |
169 // 5x oversampling |
169 // 5x oversampling |
170 Colour c = Colour(); |
170 Colour c = Colour(); |
171 |
171 |
172 for (int i = 0; i < 5; i++) |
172 for (int i = 0; i < 5; i++) |
173 { |
173 { |
174 float osax[] = {0.0, -0.4, +0.4, +0.4, -0.4}; |
174 Float osax[] = {0.0, -0.4, +0.4, +0.4, -0.4}; |
175 float osay[] = {0.0, -0.4, -0.4, +0.4, +0.4}; |
175 Float osay[] = {0.0, -0.4, -0.4, +0.4, +0.4}; |
176 Vector3 tmpdir = dir + osax[i]*d->dx + osay[i]*d->dy; |
176 Vector3 tmpdir = dir + osax[i]*d->dx + osay[i]*d->dy; |
177 tmpdir.normalize(); |
177 tmpdir.normalize(); |
178 Ray ray(d->eye, tmpdir); |
178 Ray ray(d->eye, tmpdir); |
179 c += d->rt->raytrace(ray, 0, NULL); |
179 c += d->rt->raytrace(ray, 0, NULL); |
180 } |
180 } |
202 tmpdir = dir + (subsample-1)*d->dy; |
202 tmpdir = dir + (subsample-1)*d->dy; |
203 tmpdir.normalize(); |
203 tmpdir.normalize(); |
204 ray.dir = tmpdir; |
204 ray.dir = tmpdir; |
205 Colour c3 = d->rt->raytrace(ray, 0, NULL); |
205 Colour c3 = d->rt->raytrace(ray, 0, NULL); |
206 // are the colors similar? |
206 // are the colors similar? |
207 float m = (c-c2).mag2(); |
207 Float m = (c-c2).mag2(); |
208 m = max(m, (c2-c3).mag2()); |
208 m = max(m, (c2-c3).mag2()); |
209 m = max(m, (c3-c4).mag2()); |
209 m = max(m, (c3-c4).mag2()); |
210 m = max(m, (c4-c).mag2()); |
210 m = max(m, (c4-c).mag2()); |
211 if (m < 0.001) |
211 if (m < 0.001) |
212 { |
212 { |
213 // interpolate |
213 // interpolate |
214 float *i = d->iter; |
214 Float *i = d->iter; |
215 for (int x = 0; x < subsample; x++) |
215 for (int x = 0; x < subsample; x++) |
216 { |
216 { |
217 for (int y = 0; y < subsample; y++) |
217 for (int y = 0; y < subsample; y++) |
218 { |
218 { |
219 ic = c*(subsample-x)*(subsample-y)*subsample2 |
219 ic = c*(subsample-x)*(subsample-y)*subsample2 |
300 pthread_exit((void *)d); |
300 pthread_exit((void *)d); |
301 #endif |
301 #endif |
302 return (void *)d; |
302 return (void *)d; |
303 } |
303 } |
304 |
304 |
305 void Raytracer::render(int w, int h, float *buffer) |
305 void Raytracer::render(int w, int h, Float *buffer) |
306 { |
306 { |
307 if (!camera || !top || !buffer) |
307 if (!camera || !top || !buffer) |
308 return; |
308 return; |
309 |
309 |
310 RenderrowData *d; |
310 RenderrowData *d; |
311 |
311 |
312 float S = 0.5/w; |
312 Float S = 0.5/w; |
313 Vector3 dfix = camera->u*(-w/2.0*S/camera->f) |
313 Vector3 dfix = camera->u*(-w/2.0*S/camera->f) |
314 + camera->v*(h/2.0*S/camera->f) + camera->p; |
314 + camera->v*(h/2.0*S/camera->f) + camera->p; |
315 Vector3 dx = camera->u * (S/camera->f); |
315 Vector3 dx = camera->u * (S/camera->f); |
316 Vector3 dy = camera->v * (-S/camera->f); |
316 Vector3 dy = camera->v * (-S/camera->f); |
317 |
317 |
370 void Raytracer::addlight(Light *light) |
370 void Raytracer::addlight(Light *light) |
371 { |
371 { |
372 lights.push_back(light); |
372 lights.push_back(light); |
373 } |
373 } |
374 |
374 |
375 void Raytracer::ambientocclusion(int samples, float distance, float angle) |
375 void Raytracer::ambientocclusion(int samples, Float distance, Float angle) |
376 { |
376 { |
377 ao_samples = samples; |
377 ao_samples = samples; |
378 ao_distance = distance; |
378 ao_distance = distance; |
379 ao_angle = angle; |
379 ao_angle = angle; |
380 if (ao_distance == 0) |
380 if (ao_distance == 0) |