clray
view src/dbgray.cc @ 54:6a30f27fa1e6
separated the OpenGL visualization and added a CPU raytracing mode
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 10 Sep 2010 16:47:00 +0100 |
parents | |
children | df239a52a091 |
line source
1 #include <string.h>
2 #include <assert.h>
3 #include "rt.h"
4 #include "ogl.h"
5 #include "vector.h"
6 #include "timer.h"
8 struct SurfPoint {
9 float t;
10 Vector3 pos, norm;
11 const Face *face;
12 };
14 static void trace_ray(float *pixel, const Ray &ray, int iter, float energy = 1.0f);
15 static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy = 1.0f);
16 static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret);
17 static bool ray_aabb_test(const Ray &ray, const AABBox &aabb);
18 static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp);
19 static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm);
20 static void transform(float *res, const float *v, const float *xform);
21 static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform);
23 static int xsz, ysz;
24 static float *fb;
25 static unsigned int tex;
26 static Scene *scn;
27 static const Ray *prim_rays;
30 bool init_dbg_renderer(int width, int height, Scene *scene, unsigned int texid)
31 {
32 try {
33 fb = new float[3 * width * height];
34 }
35 catch(...) {
36 return false;
37 }
39 xsz = width;
40 ysz = height;
41 tex = texid;
42 scn = scene;
43 return true;
44 }
46 void destroy_dbg_renderer()
47 {
48 delete [] fb;
49 delete [] prim_rays;
50 }
52 void dbg_set_primary_rays(const Ray *rays)
53 {
54 prim_rays = rays;
55 }
57 void dbg_render(const float *xform, const float *invtrans_xform, int num_threads)
58 {
59 unsigned long t0 = get_msec();
61 int iter = get_render_option_int(ROPT_ITER);
63 int offs = 0;
64 for(int i=0; i<ysz; i++) {
65 for(int j=0; j<xsz; j++) {
66 Ray ray = prim_rays[offs];
67 transform_ray(&ray, xform, invtrans_xform);
69 trace_ray(fb + offs * 3, ray, iter, 1.0);
70 offs++;
71 }
72 }
74 glPushAttrib(GL_TEXTURE_BIT);
75 glBindTexture(GL_TEXTURE_2D, tex);
76 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, fb);
77 glPopAttrib();
79 printf("rendered in %lu msec\n", get_msec() - t0);
80 }
82 static void trace_ray(float *pixel, const Ray &ray, int iter, float energy)
83 {
84 SurfPoint sp;
86 if(find_intersection(ray, scn, scn->kdtree, &sp)) {
87 shade(pixel, ray, sp, iter, energy);
88 } else {
89 pixel[0] = pixel[1] = pixel[2] = 0.05f;
90 }
91 }
93 #define MAX(a, b) ((a) > (b) ? (a) : (b))
95 static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy)
96 {
97 const Material *mat = scn->get_materials() + sp.face->matid;
99 bool cast_shadows = get_render_option_bool(ROPT_SHAD);
100 Vector3 raydir(ray.dir);
101 Vector3 norm = sp.norm;
103 if(dot(raydir, norm) >= 0.0) {
104 norm = -norm;
105 }
107 float dcol[3] = {0, 0, 0};
108 float scol[3] = {0, 0, 0};
110 for(int i=0; i<scn->get_num_lights(); i++) {
111 Vector3 lpos(scn->lights[i].pos);
112 Vector3 ldir = lpos - sp.pos;
114 Ray shadowray;
115 shadowray.origin[0] = sp.pos.x;
116 shadowray.origin[1] = sp.pos.y;
117 shadowray.origin[2] = sp.pos.z;
118 shadowray.dir[0] = ldir.x;
119 shadowray.dir[1] = ldir.y;
120 shadowray.dir[2] = ldir.z;
122 if(!cast_shadows || !find_intersection(shadowray, scn, scn->kdtree, 0)) {
124 ldir.normalize();
126 Vector3 vdir = -raydir / RAY_MAG;
127 Vector3 vref = reflect(vdir, norm);
129 float ndotl = dot(ldir, norm);
130 float diff = MAX(ndotl, 0.0f);
132 dcol[0] += mat->kd[0] * diff;
133 dcol[1] += mat->kd[1] * diff;
134 dcol[2] += mat->kd[2] * diff;
136 float ldotvr = dot(ldir, vref);
137 float spec = pow(MAX(ldotvr, 0.0f), mat->spow);
139 scol[0] += mat->ks[0] * spec;
140 scol[1] += mat->ks[1] * spec;
141 scol[2] += mat->ks[2] * spec;
142 }
143 }
145 float refl_color[3];
146 refl_color[0] = mat->ks[0] * mat->kr;
147 refl_color[1] = mat->ks[1] * mat->kr;
148 refl_color[2] = mat->ks[2] * mat->kr;
150 energy *= (refl_color[0] + refl_color[1] + refl_color[2]) / 3.0;
151 if(iter >= 0 && energy > MIN_ENERGY) {
152 Vector3 rdir = reflect(-raydir, norm);
154 Ray refl;
155 refl.origin[0] = sp.pos.x;
156 refl.origin[1] = sp.pos.y;
157 refl.origin[2] = sp.pos.z;
158 refl.dir[0] = rdir.x;
159 refl.dir[1] = rdir.y;
160 refl.dir[2] = rdir.z;
162 float rcol[3];
163 trace_ray(rcol, refl, iter - 1, energy);
164 scol[0] += rcol[0] * mat->ks[0] * mat->kr;
165 scol[1] += rcol[1] * mat->ks[1] * mat->kr;
166 scol[2] += rcol[2] * mat->ks[2] * mat->kr;
167 }
169 pixel[0] = dcol[0] + scol[0];
170 pixel[1] = dcol[1] + scol[1];
171 pixel[2] = dcol[2] + scol[2];
172 }
174 static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret)
175 {
176 if(!ray_aabb_test(ray, kd->aabb)) {
177 return false;
178 }
180 SurfPoint sp, sptmp;
181 if(!spret) {
182 spret = &sptmp;
183 }
185 spret->t = RAY_MAG;
186 spret->face = 0;
188 if(kd->left) {
189 assert(kd->right);
191 bool found = find_intersection(ray, scn, kd->left, spret);
192 if(find_intersection(ray, scn, kd->right, &sp)) {
193 if(!found || sp.t < spret->t) {
194 *spret = sp;
195 }
196 found = true;
197 }
198 return found;
199 }
201 const Face *faces = scn->get_face_buffer();
203 for(size_t i=0; i<kd->face_idx.size(); i++) {
204 if(ray_triangle_test(ray, faces + kd->face_idx[i], &sp) && sp.t < spret->t) {
205 *spret = sp;
206 }
207 }
208 return spret->face != 0;
209 }
211 static bool ray_aabb_test(const Ray &ray, const AABBox &aabb)
212 {
213 if(ray.origin[0] >= aabb.min[0] && ray.origin[1] >= aabb.min[1] && ray.origin[2] >= aabb.min[2] &&
214 ray.origin[0] < aabb.max[0] && ray.origin[1] < aabb.max[1] && ray.origin[2] < aabb.max[2]) {
215 return true;
216 }
218 float bbox[][3] = {
219 {aabb.min[0], aabb.min[1], aabb.min[2]},
220 {aabb.max[0], aabb.max[1], aabb.max[2]}
221 };
223 int xsign = (int)(ray.dir[0] < 0.0);
224 float invdirx = 1.0 / ray.dir[0];
225 float tmin = (bbox[xsign][0] - ray.origin[0]) * invdirx;
226 float tmax = (bbox[1 - xsign][0] - ray.origin[0]) * invdirx;
228 int ysign = (int)(ray.dir[1] < 0.0);
229 float invdiry = 1.0 / ray.dir[1];
230 float tymin = (bbox[ysign][1] - ray.origin[1]) * invdiry;
231 float tymax = (bbox[1 - ysign][1] - ray.origin[1]) * invdiry;
233 if(tmin > tymax || tymin > tmax) {
234 return false;
235 }
237 if(tymin > tmin) tmin = tymin;
238 if(tymax < tmax) tmax = tymax;
240 int zsign = (int)(ray.dir[2] < 0.0);
241 float invdirz = 1.0 / ray.dir[2];
242 float tzmin = (bbox[zsign][2] - ray.origin[2]) * invdirz;
243 float tzmax = (bbox[1 - zsign][2] - ray.origin[2]) * invdirz;
245 if(tmin > tzmax || tzmin > tmax) {
246 return false;
247 }
249 return tmin < 1.0 && tmax > 0.0;
251 }
253 static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp)
254 {
255 Vector3 origin = ray.origin;
256 Vector3 dir = ray.dir;
257 Vector3 norm = face->normal;
259 float ndotdir = dot(dir, norm);
261 if(fabs(ndotdir) <= EPSILON) {
262 return false;
263 }
265 Vector3 pt = face->v[0].pos;
266 Vector3 vec = pt - origin;
268 float ndotvec = dot(norm, vec);
269 float t = ndotvec / ndotdir;
271 if(t < EPSILON || t > 1.0) {
272 return false;
273 }
274 pt = origin + dir * t;
277 Vector3 bc = calc_bary(pt, face, norm);
278 float bc_sum = bc.x + bc.y + bc.z;
280 if(bc_sum < 1.0 - EPSILON || bc_sum > 1.0 + EPSILON) {
281 return false;
282 }
284 Vector3 n0(face->v[0].normal);
285 Vector3 n1(face->v[1].normal);
286 Vector3 n2(face->v[2].normal);
288 sp->t = t;
289 sp->pos = pt;
290 sp->norm = n0 * bc.x + n1 * bc.y + n2 * bc.z;
291 sp->norm.normalize();
292 sp->face = face;
293 return true;
294 }
296 static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm)
297 {
298 Vector3 bc(0.0f, 0.0f, 0.0f);
300 Vector3 v1 = Vector3(face->v[1].pos) - Vector3(face->v[0].pos);
301 Vector3 v2 = Vector3(face->v[2].pos) - Vector3(face->v[0].pos);
302 Vector3 xv1v2 = cross(v1, v2);
304 float area = fabs(dot(xv1v2, norm)) * 0.5;
305 if(area < EPSILON) {
306 return bc;
307 }
309 Vector3 pv0 = face->v[0].pos - pt;
310 Vector3 pv1 = face->v[1].pos - pt;
311 Vector3 pv2 = face->v[2].pos - pt;
313 // calculate the area of each sub-triangle
314 Vector3 x12 = cross(pv1, pv2);
315 Vector3 x20 = cross(pv2, pv0);
316 Vector3 x01 = cross(pv0, pv1);
318 float a0 = fabs(dot(x12, norm)) * 0.5;
319 float a1 = fabs(dot(x20, norm)) * 0.5;
320 float a2 = fabs(dot(x01, norm)) * 0.5;
322 bc.x = a0 / area;
323 bc.y = a1 / area;
324 bc.z = a2 / area;
325 return bc;
327 }
329 static void transform(float *res, const float *v, const float *xform)
330 {
331 float tmp[3];
332 tmp[0] = v[0] * xform[0] + v[1] * xform[4] + v[2] * xform[8] + xform[12];
333 tmp[1] = v[0] * xform[1] + v[1] * xform[5] + v[2] * xform[9] + xform[13];
334 tmp[2] = v[0] * xform[2] + v[1] * xform[6] + v[2] * xform[10] + xform[14];
335 memcpy(res, tmp, sizeof tmp);
336 }
338 static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform)
339 {
340 transform(ray->origin, ray->origin, xform);
341 transform(ray->dir, ray->dir, invtrans_xform);
342 }