clray
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/dbgray.cc Fri Sep 10 16:47:00 2010 +0100 1.3 @@ -0,0 +1,342 @@ 1.4 +#include <string.h> 1.5 +#include <assert.h> 1.6 +#include "rt.h" 1.7 +#include "ogl.h" 1.8 +#include "vector.h" 1.9 +#include "timer.h" 1.10 + 1.11 +struct SurfPoint { 1.12 + float t; 1.13 + Vector3 pos, norm; 1.14 + const Face *face; 1.15 +}; 1.16 + 1.17 +static void trace_ray(float *pixel, const Ray &ray, int iter, float energy = 1.0f); 1.18 +static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy = 1.0f); 1.19 +static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret); 1.20 +static bool ray_aabb_test(const Ray &ray, const AABBox &aabb); 1.21 +static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp); 1.22 +static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm); 1.23 +static void transform(float *res, const float *v, const float *xform); 1.24 +static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform); 1.25 + 1.26 +static int xsz, ysz; 1.27 +static float *fb; 1.28 +static unsigned int tex; 1.29 +static Scene *scn; 1.30 +static const Ray *prim_rays; 1.31 + 1.32 + 1.33 +bool init_dbg_renderer(int width, int height, Scene *scene, unsigned int texid) 1.34 +{ 1.35 + try { 1.36 + fb = new float[3 * width * height]; 1.37 + } 1.38 + catch(...) { 1.39 + return false; 1.40 + } 1.41 + 1.42 + xsz = width; 1.43 + ysz = height; 1.44 + tex = texid; 1.45 + scn = scene; 1.46 + return true; 1.47 +} 1.48 + 1.49 +void destroy_dbg_renderer() 1.50 +{ 1.51 + delete [] fb; 1.52 + delete [] prim_rays; 1.53 +} 1.54 + 1.55 +void dbg_set_primary_rays(const Ray *rays) 1.56 +{ 1.57 + prim_rays = rays; 1.58 +} 1.59 + 1.60 +void dbg_render(const float *xform, const float *invtrans_xform, int num_threads) 1.61 +{ 1.62 + unsigned long t0 = get_msec(); 1.63 + 1.64 + int iter = get_render_option_int(ROPT_ITER); 1.65 + 1.66 + int offs = 0; 1.67 + for(int i=0; i<ysz; i++) { 1.68 + for(int j=0; j<xsz; j++) { 1.69 + Ray ray = prim_rays[offs]; 1.70 + transform_ray(&ray, xform, invtrans_xform); 1.71 + 1.72 + trace_ray(fb + offs * 3, ray, iter, 1.0); 1.73 + offs++; 1.74 + } 1.75 + } 1.76 + 1.77 + glPushAttrib(GL_TEXTURE_BIT); 1.78 + glBindTexture(GL_TEXTURE_2D, tex); 1.79 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, fb); 1.80 + glPopAttrib(); 1.81 + 1.82 + printf("rendered in %lu msec\n", get_msec() - t0); 1.83 +} 1.84 + 1.85 +static void trace_ray(float *pixel, const Ray &ray, int iter, float energy) 1.86 +{ 1.87 + SurfPoint sp; 1.88 + 1.89 + if(find_intersection(ray, scn, scn->kdtree, &sp)) { 1.90 + shade(pixel, ray, sp, iter, energy); 1.91 + } else { 1.92 + pixel[0] = pixel[1] = pixel[2] = 0.05f; 1.93 + } 1.94 +} 1.95 + 1.96 +#define MAX(a, b) ((a) > (b) ? (a) : (b)) 1.97 + 1.98 +static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy) 1.99 +{ 1.100 + const Material *mat = scn->get_materials() + sp.face->matid; 1.101 + 1.102 + bool cast_shadows = get_render_option_bool(ROPT_SHAD); 1.103 + Vector3 raydir(ray.dir); 1.104 + Vector3 norm = sp.norm; 1.105 + 1.106 + if(dot(raydir, norm) >= 0.0) { 1.107 + norm = -norm; 1.108 + } 1.109 + 1.110 + float dcol[3] = {0, 0, 0}; 1.111 + float scol[3] = {0, 0, 0}; 1.112 + 1.113 + for(int i=0; i<scn->get_num_lights(); i++) { 1.114 + Vector3 lpos(scn->lights[i].pos); 1.115 + Vector3 ldir = lpos - sp.pos; 1.116 + 1.117 + Ray shadowray; 1.118 + shadowray.origin[0] = sp.pos.x; 1.119 + shadowray.origin[1] = sp.pos.y; 1.120 + shadowray.origin[2] = sp.pos.z; 1.121 + shadowray.dir[0] = ldir.x; 1.122 + shadowray.dir[1] = ldir.y; 1.123 + shadowray.dir[2] = ldir.z; 1.124 + 1.125 + if(!cast_shadows || !find_intersection(shadowray, scn, scn->kdtree, 0)) { 1.126 + 1.127 + ldir.normalize(); 1.128 + 1.129 + Vector3 vdir = -raydir / RAY_MAG; 1.130 + Vector3 vref = reflect(vdir, norm); 1.131 + 1.132 + float ndotl = dot(ldir, norm); 1.133 + float diff = MAX(ndotl, 0.0f); 1.134 + 1.135 + dcol[0] += mat->kd[0] * diff; 1.136 + dcol[1] += mat->kd[1] * diff; 1.137 + dcol[2] += mat->kd[2] * diff; 1.138 + 1.139 + float ldotvr = dot(ldir, vref); 1.140 + float spec = pow(MAX(ldotvr, 0.0f), mat->spow); 1.141 + 1.142 + scol[0] += mat->ks[0] * spec; 1.143 + scol[1] += mat->ks[1] * spec; 1.144 + scol[2] += mat->ks[2] * spec; 1.145 + } 1.146 + } 1.147 + 1.148 + float refl_color[3]; 1.149 + refl_color[0] = mat->ks[0] * mat->kr; 1.150 + refl_color[1] = mat->ks[1] * mat->kr; 1.151 + refl_color[2] = mat->ks[2] * mat->kr; 1.152 + 1.153 + energy *= (refl_color[0] + refl_color[1] + refl_color[2]) / 3.0; 1.154 + if(iter >= 0 && energy > MIN_ENERGY) { 1.155 + Vector3 rdir = reflect(-raydir, norm); 1.156 + 1.157 + Ray refl; 1.158 + refl.origin[0] = sp.pos.x; 1.159 + refl.origin[1] = sp.pos.y; 1.160 + refl.origin[2] = sp.pos.z; 1.161 + refl.dir[0] = rdir.x; 1.162 + refl.dir[1] = rdir.y; 1.163 + refl.dir[2] = rdir.z; 1.164 + 1.165 + float rcol[3]; 1.166 + trace_ray(rcol, refl, iter - 1, energy); 1.167 + scol[0] += rcol[0] * mat->ks[0] * mat->kr; 1.168 + scol[1] += rcol[1] * mat->ks[1] * mat->kr; 1.169 + scol[2] += rcol[2] * mat->ks[2] * mat->kr; 1.170 + } 1.171 + 1.172 + pixel[0] = dcol[0] + scol[0]; 1.173 + pixel[1] = dcol[1] + scol[1]; 1.174 + pixel[2] = dcol[2] + scol[2]; 1.175 +} 1.176 + 1.177 +static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret) 1.178 +{ 1.179 + if(!ray_aabb_test(ray, kd->aabb)) { 1.180 + return false; 1.181 + } 1.182 + 1.183 + SurfPoint sp, sptmp; 1.184 + if(!spret) { 1.185 + spret = &sptmp; 1.186 + } 1.187 + 1.188 + spret->t = RAY_MAG; 1.189 + spret->face = 0; 1.190 + 1.191 + if(kd->left) { 1.192 + assert(kd->right); 1.193 + 1.194 + bool found = find_intersection(ray, scn, kd->left, spret); 1.195 + if(find_intersection(ray, scn, kd->right, &sp)) { 1.196 + if(!found || sp.t < spret->t) { 1.197 + *spret = sp; 1.198 + } 1.199 + found = true; 1.200 + } 1.201 + return found; 1.202 + } 1.203 + 1.204 + const Face *faces = scn->get_face_buffer(); 1.205 + 1.206 + for(size_t i=0; i<kd->face_idx.size(); i++) { 1.207 + if(ray_triangle_test(ray, faces + kd->face_idx[i], &sp) && sp.t < spret->t) { 1.208 + *spret = sp; 1.209 + } 1.210 + } 1.211 + return spret->face != 0; 1.212 +} 1.213 + 1.214 +static bool ray_aabb_test(const Ray &ray, const AABBox &aabb) 1.215 +{ 1.216 + if(ray.origin[0] >= aabb.min[0] && ray.origin[1] >= aabb.min[1] && ray.origin[2] >= aabb.min[2] && 1.217 + ray.origin[0] < aabb.max[0] && ray.origin[1] < aabb.max[1] && ray.origin[2] < aabb.max[2]) { 1.218 + return true; 1.219 + } 1.220 + 1.221 + float bbox[][3] = { 1.222 + {aabb.min[0], aabb.min[1], aabb.min[2]}, 1.223 + {aabb.max[0], aabb.max[1], aabb.max[2]} 1.224 + }; 1.225 + 1.226 + int xsign = (int)(ray.dir[0] < 0.0); 1.227 + float invdirx = 1.0 / ray.dir[0]; 1.228 + float tmin = (bbox[xsign][0] - ray.origin[0]) * invdirx; 1.229 + float tmax = (bbox[1 - xsign][0] - ray.origin[0]) * invdirx; 1.230 + 1.231 + int ysign = (int)(ray.dir[1] < 0.0); 1.232 + float invdiry = 1.0 / ray.dir[1]; 1.233 + float tymin = (bbox[ysign][1] - ray.origin[1]) * invdiry; 1.234 + float tymax = (bbox[1 - ysign][1] - ray.origin[1]) * invdiry; 1.235 + 1.236 + if(tmin > tymax || tymin > tmax) { 1.237 + return false; 1.238 + } 1.239 + 1.240 + if(tymin > tmin) tmin = tymin; 1.241 + if(tymax < tmax) tmax = tymax; 1.242 + 1.243 + int zsign = (int)(ray.dir[2] < 0.0); 1.244 + float invdirz = 1.0 / ray.dir[2]; 1.245 + float tzmin = (bbox[zsign][2] - ray.origin[2]) * invdirz; 1.246 + float tzmax = (bbox[1 - zsign][2] - ray.origin[2]) * invdirz; 1.247 + 1.248 + if(tmin > tzmax || tzmin > tmax) { 1.249 + return false; 1.250 + } 1.251 + 1.252 + return tmin < 1.0 && tmax > 0.0; 1.253 + 1.254 +} 1.255 + 1.256 +static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp) 1.257 +{ 1.258 + Vector3 origin = ray.origin; 1.259 + Vector3 dir = ray.dir; 1.260 + Vector3 norm = face->normal; 1.261 + 1.262 + float ndotdir = dot(dir, norm); 1.263 + 1.264 + if(fabs(ndotdir) <= EPSILON) { 1.265 + return false; 1.266 + } 1.267 + 1.268 + Vector3 pt = face->v[0].pos; 1.269 + Vector3 vec = pt - origin; 1.270 + 1.271 + float ndotvec = dot(norm, vec); 1.272 + float t = ndotvec / ndotdir; 1.273 + 1.274 + if(t < EPSILON || t > 1.0) { 1.275 + return false; 1.276 + } 1.277 + pt = origin + dir * t; 1.278 + 1.279 + 1.280 + Vector3 bc = calc_bary(pt, face, norm); 1.281 + float bc_sum = bc.x + bc.y + bc.z; 1.282 + 1.283 + if(bc_sum < 1.0 - EPSILON || bc_sum > 1.0 + EPSILON) { 1.284 + return false; 1.285 + } 1.286 + 1.287 + Vector3 n0(face->v[0].normal); 1.288 + Vector3 n1(face->v[1].normal); 1.289 + Vector3 n2(face->v[2].normal); 1.290 + 1.291 + sp->t = t; 1.292 + sp->pos = pt; 1.293 + sp->norm = n0 * bc.x + n1 * bc.y + n2 * bc.z; 1.294 + sp->norm.normalize(); 1.295 + sp->face = face; 1.296 + return true; 1.297 +} 1.298 + 1.299 +static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm) 1.300 +{ 1.301 + Vector3 bc(0.0f, 0.0f, 0.0f); 1.302 + 1.303 + Vector3 v1 = Vector3(face->v[1].pos) - Vector3(face->v[0].pos); 1.304 + Vector3 v2 = Vector3(face->v[2].pos) - Vector3(face->v[0].pos); 1.305 + Vector3 xv1v2 = cross(v1, v2); 1.306 + 1.307 + float area = fabs(dot(xv1v2, norm)) * 0.5; 1.308 + if(area < EPSILON) { 1.309 + return bc; 1.310 + } 1.311 + 1.312 + Vector3 pv0 = face->v[0].pos - pt; 1.313 + Vector3 pv1 = face->v[1].pos - pt; 1.314 + Vector3 pv2 = face->v[2].pos - pt; 1.315 + 1.316 + // calculate the area of each sub-triangle 1.317 + Vector3 x12 = cross(pv1, pv2); 1.318 + Vector3 x20 = cross(pv2, pv0); 1.319 + Vector3 x01 = cross(pv0, pv1); 1.320 + 1.321 + float a0 = fabs(dot(x12, norm)) * 0.5; 1.322 + float a1 = fabs(dot(x20, norm)) * 0.5; 1.323 + float a2 = fabs(dot(x01, norm)) * 0.5; 1.324 + 1.325 + bc.x = a0 / area; 1.326 + bc.y = a1 / area; 1.327 + bc.z = a2 / area; 1.328 + return bc; 1.329 + 1.330 +} 1.331 + 1.332 +static void transform(float *res, const float *v, const float *xform) 1.333 +{ 1.334 + float tmp[3]; 1.335 + tmp[0] = v[0] * xform[0] + v[1] * xform[4] + v[2] * xform[8] + xform[12]; 1.336 + tmp[1] = v[0] * xform[1] + v[1] * xform[5] + v[2] * xform[9] + xform[13]; 1.337 + tmp[2] = v[0] * xform[2] + v[1] * xform[6] + v[2] * xform[10] + xform[14]; 1.338 + memcpy(res, tmp, sizeof tmp); 1.339 +} 1.340 + 1.341 +static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform) 1.342 +{ 1.343 + transform(ray->origin, ray->origin, xform); 1.344 + transform(ray->dir, ray->dir, invtrans_xform); 1.345 +}