Blender  V2.59
rayobject.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: rayobject.cpp 35233 2011-02-27 19:31:27Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): André Pinto.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <assert.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "BLI_math.h"
00040 #include "BLI_utildefines.h"
00041 
00042 #include "DNA_material_types.h"
00043 
00044 #include "rayintersection.h"
00045 #include "rayobject.h"
00046 #include "raycounter.h"
00047 #include "render_types.h"
00048 
00049 /* RayFace
00050 
00051    note we force always inline here, because compiler refuses to otherwise
00052    because function is too long. Since this is code that is called billions
00053    of times we really do want to inline. */
00054 
00055 MALWAYS_INLINE RayObject* rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
00056 {
00057         rayface->ob = ob;
00058         rayface->face = face;
00059 
00060         copy_v3_v3(rayface->v1, v1);
00061         copy_v3_v3(rayface->v2, v2);
00062         copy_v3_v3(rayface->v3, v3);
00063 
00064         if(v4)
00065         {
00066                 copy_v3_v3(rayface->v4, v4);
00067                 rayface->quad = 1;
00068         }
00069         else
00070         {
00071                 rayface->quad = 0;
00072         }
00073 
00074         return RE_rayobject_unalignRayFace(rayface);
00075 }
00076 
00077 MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
00078 {
00079         rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0);
00080 
00081         if(obi->transform_primitives)
00082         {
00083                 mul_m4_v3(obi->mat, rayface->v1);
00084                 mul_m4_v3(obi->mat, rayface->v2);
00085                 mul_m4_v3(obi->mat, rayface->v3);
00086 
00087                 if(RE_rayface_isQuad(rayface))
00088                         mul_m4_v3(obi->mat, rayface->v4);
00089         }
00090 }
00091 
00092 RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
00093 {
00094         return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0);
00095 }
00096 
00097 /* VlakPrimitive */
00098 
00099 RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
00100 {
00101         face->ob = obi;
00102         face->face = vlr;
00103 
00104         return RE_rayobject_unalignVlakPrimitive(face);
00105 }
00106 
00107 /* Checks for ignoring faces or materials */
00108 
00109 MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
00110 {
00111         /* for baking selected to active non-traceable materials might still
00112          * be in the raytree */
00113         if(!(vlr->flag & R_TRACEBLE))
00114                 return 0;
00115 
00116         /* I know... cpu cycle waste, might do smarter once */
00117         if(is->mode==RE_RAY_MIRROR)
00118                 return !(vlr->mat->mode & MA_ONLYCAST);
00119         else
00120                 return (is->lay & obi->lay);
00121 }
00122 
00123 MALWAYS_INLINE int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
00124 {
00125         /* solid material types only */
00126         if (vlr->mat->material_type == MA_TYPE_SURFACE)
00127                 return 1;
00128         else
00129                 return 0;
00130 }
00131 
00132 MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
00133 {
00134         return (obi->obr->ob != is->userdata);
00135 }
00136 
00137 /* Ray Triangle/Quad Intersection */
00138 
00139 MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
00140 {
00141         float co1[3], co2[3], co3[3], co4[3];
00142         float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
00143         int quad;
00144 
00145         quad= RE_rayface_isQuad(face);
00146 
00147         copy_v3_v3(co1, face->v1);
00148         copy_v3_v3(co2, face->v2);
00149         copy_v3_v3(co3, face->v3);
00150 
00151         copy_v3_v3(r, dir);
00152 
00153         /* intersect triangle */
00154         sub_v3_v3v3(t0, co3, co2);
00155         sub_v3_v3v3(t1, co3, co1);
00156 
00157         cross_v3_v3v3(x, r, t1);
00158         divdet= dot_v3v3(t0, x);
00159 
00160         sub_v3_v3v3(m, start, co3);
00161         det1= dot_v3v3(m, x);
00162         
00163         if(divdet != 0.0f) {
00164                 divdet= 1.0f/divdet;
00165                 v= det1*divdet;
00166 
00167                 if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
00168                         float cros[3];
00169 
00170                         cross_v3_v3v3(cros, m, t0);
00171                         u= divdet*dot_v3v3(cros, r);
00172 
00173                         if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
00174                                 l= divdet*dot_v3v3(cros, t1);
00175 
00176                                 /* check if intersection is within ray length */
00177                                 if(l > -RE_RAYTRACE_EPSILON && l < *lambda) {
00178                                         uv[0]= u;
00179                                         uv[1]= v;
00180                                         *lambda= l;
00181                                         return 1;
00182                                 }
00183                         }
00184                 }
00185         }
00186 
00187         /* intersect second triangle in quad */
00188         if(quad) {
00189                 copy_v3_v3(co4, face->v4);
00190                 sub_v3_v3v3(t0, co3, co4);
00191                 divdet= dot_v3v3(t0, x);
00192 
00193                 if(divdet != 0.0f) {
00194                         divdet= 1.0f/divdet;
00195                         v = det1*divdet;
00196                         
00197                         if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
00198                                 float cros[3];
00199 
00200                                 cross_v3_v3v3(cros, m, t0);
00201                                 u= divdet*dot_v3v3(cros, r);
00202         
00203                                 if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
00204                                         l= divdet*dot_v3v3(cros, t1);
00205                                         
00206                                         if(l >- RE_RAYTRACE_EPSILON && l < *lambda) {
00207                                                 uv[0]= u;
00208                                                 uv[1]= -(1.0f + v + u);
00209                                                 *lambda= l;
00210                                                 return 2;
00211                                         }
00212                                 }
00213                         }
00214                 }
00215         }
00216 
00217         return 0;
00218 }
00219 
00220 /* Simpler yes/no Ray Triangle/Quad Intersection */
00221 
00222 MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
00223 {
00224         float co1[3], co2[3], co3[3], co4[3];
00225         float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
00226         int quad;
00227 
00228         quad= RE_rayface_isQuad(face);
00229 
00230         copy_v3_v3(co1, face->v1);
00231         copy_v3_v3(co2, face->v2);
00232         copy_v3_v3(co3, face->v3);
00233 
00234         negate_v3_v3(r, dir); /* note, different than above function */
00235 
00236         /* intersect triangle */
00237         sub_v3_v3v3(t0, co3, co2);
00238         sub_v3_v3v3(t1, co3, co1);
00239 
00240         cross_v3_v3v3(x, r, t1);
00241         divdet= dot_v3v3(t0, x);
00242 
00243         sub_v3_v3v3(m, start, co3);
00244         det1= dot_v3v3(m, x);
00245         
00246         if(divdet != 0.0f) {
00247                 divdet= 1.0f/divdet;
00248                 v= det1*divdet;
00249 
00250                 if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
00251                         float cros[3];
00252 
00253                         cross_v3_v3v3(cros, m, t0);
00254                         u= divdet*dot_v3v3(cros, r);
00255 
00256                         if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
00257                                 return 1;
00258                 }
00259         }
00260 
00261         /* intersect second triangle in quad */
00262         if(quad) {
00263                 copy_v3_v3(co4, face->v4);
00264                 sub_v3_v3v3(t0, co3, co4);
00265                 divdet= dot_v3v3(t0, x);
00266 
00267                 if(divdet != 0.0f) {
00268                         divdet= 1.0f/divdet;
00269                         v = det1*divdet;
00270                         
00271                         if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
00272                                 float cros[3];
00273 
00274                                 cross_v3_v3v3(cros, m, t0);
00275                                 u= divdet*dot_v3v3(cros, r);
00276         
00277                                 if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
00278                                         return 2;
00279                         }
00280                 }
00281         }
00282 
00283         return 0;
00284 }
00285 
00286 /* RayFace intersection with checks and neighbour verifaction included,
00287    Isect is modified if the face is hit. */
00288 
00289 MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
00290 {
00291         float dist, uv[2];
00292         int ok= 0;
00293         
00294         /* avoid self-intersection */
00295         if(is->orig.ob == face->ob && is->orig.face == face->face)
00296                 return 0;
00297                 
00298         /* check if we should intersect this face */
00299         if(is->check == RE_CHECK_VLR_RENDER)
00300         {
00301                 if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
00302                         return 0;
00303         }
00304         else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL)
00305         {
00306                 if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
00307                         return 0;
00308                 if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
00309                         return 0;
00310         }
00311         else if(is->check == RE_CHECK_VLR_BAKE) {
00312                 if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
00313                         return 0;
00314         }
00315 
00316         /* ray counter */
00317         RE_RC_COUNT(is->raycounter->faces.test);
00318 
00319         dist= is->dist;
00320         ok= isec_tri_quad(is->start, is->dir, face, uv, &dist);
00321 
00322         if(ok) {
00323         
00324                 /* when a shadow ray leaves a face, it can be little outside the edges
00325                    of it, causing intersection to be detected in its neighbour face */
00326                 if(is->skip & RE_SKIP_VLR_NEIGHBOUR)
00327                 {
00328                         if(dist < 0.1f && is->orig.ob == face->ob)
00329                         {
00330                                 VlakRen * a = (VlakRen*)is->orig.face;
00331                                 VlakRen * b = (VlakRen*)face->face;
00332 
00333                                 /* so there's a shared edge or vertex, let's intersect ray with
00334                                    face itself, if that's true we can safely return 1, otherwise
00335                                    we assume the intersection is invalid, 0 */
00336                                 if(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1
00337                                 || a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2
00338                                 || a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3
00339                                 || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) {
00340                                         /* create RayFace from original face, transformed if necessary */
00341                                         RayFace origface;
00342                                         ObjectInstanceRen *ob= (ObjectInstanceRen*)is->orig.ob;
00343                                         rayface_from_vlak(&origface, ob, (VlakRen*)is->orig.face);
00344 
00345                                         if(!isec_tri_quad_neighbour(is->start, is->dir, &origface))
00346                                         {
00347                                                 return 0;
00348                                         }
00349                                 }
00350                         }
00351                 }
00352 
00353                 RE_RC_COUNT(is->raycounter->faces.hit);
00354 
00355                 is->isect= ok;  // which half of the quad
00356                 is->dist= dist;
00357                 is->u= uv[0]; is->v= uv[1];
00358 
00359                 is->hit.ob   = face->ob;
00360                 is->hit.face = face->face;
00361 #ifdef RT_USE_LAST_HIT
00362                 is->last_hit = hit_obj;
00363 #endif
00364                 return 1;
00365         }
00366 
00367         return 0;
00368 }
00369 
00370 /* Intersection */
00371 
00372 int RE_rayobject_raycast(RayObject *r, Isect *isec)
00373 {
00374         int i;
00375 
00376         RE_RC_COUNT(isec->raycounter->raycast.test);
00377 
00378         /* setup vars used on raycast */
00379         for(i=0; i<3; i++)
00380         {
00381                 isec->idot_axis[i]              = 1.0f / isec->dir[i];
00382                 
00383                 isec->bv_index[2*i]             = isec->idot_axis[i] < 0.0 ? 1 : 0;
00384                 isec->bv_index[2*i+1]   = 1 - isec->bv_index[2*i];
00385                 
00386                 isec->bv_index[2*i]             = i+3*isec->bv_index[2*i];
00387                 isec->bv_index[2*i+1]   = i+3*isec->bv_index[2*i+1];
00388         }
00389 
00390 #ifdef RT_USE_LAST_HIT  
00391         /* last hit heuristic */
00392         if(isec->mode==RE_RAY_SHADOW && isec->last_hit)
00393         {
00394                 RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
00395                 
00396                 if(RE_rayobject_intersect(isec->last_hit, isec))
00397                 {
00398                         RE_RC_COUNT(isec->raycounter->raycast.hit);
00399                         RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit);
00400                         return 1;
00401                 }
00402         }
00403 #endif
00404 
00405 #ifdef RT_USE_HINT
00406         isec->hit_hint = 0;
00407 #endif
00408 
00409         if(RE_rayobject_intersect(r, isec))
00410         {
00411                 RE_RC_COUNT(isec->raycounter->raycast.hit);
00412 
00413 #ifdef RT_USE_HINT
00414                 isec->hint = isec->hit_hint;
00415 #endif
00416                 return 1;
00417         }
00418 
00419         return 0;
00420 }
00421 
00422 int RE_rayobject_intersect(RayObject *r, Isect *i)
00423 {
00424         if(RE_rayobject_isRayFace(r))
00425         {
00426                 return intersect_rayface(r, (RayFace*) RE_rayobject_align(r), i);
00427         }
00428         else if(RE_rayobject_isVlakPrimitive(r))
00429         {
00430                 //TODO optimize (useless copy to RayFace to avoid duplicate code)
00431                 VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r);
00432                 RayFace nface;
00433                 rayface_from_vlak(&nface, face->ob, face->face);
00434 
00435                 return intersect_rayface(r, &nface, i);
00436         }
00437         else if(RE_rayobject_isRayAPI(r))
00438         {
00439                 r = RE_rayobject_align(r);
00440                 return r->api->raycast(r, i);
00441         }
00442         else {
00443                 assert(0);
00444         return 0;
00445         }
00446 }
00447 
00448 /* Building */
00449 
00450 void RE_rayobject_add(RayObject *r, RayObject *o)
00451 {
00452         r = RE_rayobject_align(r);
00453         return r->api->add(r, o);
00454 }
00455 
00456 void RE_rayobject_done(RayObject *r)
00457 {
00458         r = RE_rayobject_align(r);
00459         r->api->done(r);
00460 }
00461 
00462 void RE_rayobject_free(RayObject *r)
00463 {
00464         r = RE_rayobject_align(r);
00465         r->api->free(r);
00466 }
00467 
00468 float RE_rayobject_cost(RayObject *r)
00469 {
00470         if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r))
00471         {
00472                 return 1.0f;
00473         }
00474         else if(RE_rayobject_isRayAPI(r))
00475         {
00476                 r = RE_rayobject_align(r);
00477                 return r->api->cost(r);
00478         }
00479         else {
00480                 assert(0);
00481                 return 1.0f;
00482         }
00483 }
00484 
00485 /* Bounding Boxes */
00486 
00487 void RE_rayobject_merge_bb(RayObject *r, float *min, float *max)
00488 {
00489         if(RE_rayobject_isRayFace(r))
00490         {
00491                 RayFace *face = (RayFace*) RE_rayobject_align(r);
00492                 
00493                 DO_MINMAX(face->v1, min, max);
00494                 DO_MINMAX(face->v2, min, max);
00495                 DO_MINMAX(face->v3, min, max);
00496                 if(RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max);
00497         }
00498         else if(RE_rayobject_isVlakPrimitive(r))
00499         {
00500                 VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r);
00501                 RayFace nface;
00502                 rayface_from_vlak(&nface, face->ob, face->face);
00503 
00504                 DO_MINMAX(nface.v1, min, max);
00505                 DO_MINMAX(nface.v2, min, max);
00506                 DO_MINMAX(nface.v3, min, max);
00507                 if(RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max);
00508         }
00509         else if(RE_rayobject_isRayAPI(r))
00510         {
00511                 r = RE_rayobject_align(r);
00512                 r->api->bb(r, min, max);
00513         }
00514         else
00515                 assert(0);
00516 }
00517 
00518 /* Hints */
00519 
00520 void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
00521 {
00522         if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r))
00523         {
00524                 return;
00525         }
00526         else if(RE_rayobject_isRayAPI(r))
00527         {
00528                 r = RE_rayobject_align(r);
00529                 return r->api->hint_bb(r, hint, min, max);
00530         }
00531         else
00532                 assert(0);
00533 }
00534 
00535 /* RayObjectControl */
00536 
00537 int RE_rayobjectcontrol_test_break(RayObjectControl *control)
00538 {
00539         if(control->test_break)
00540                 return control->test_break(control->data);
00541 
00542         return 0;
00543 }
00544 
00545 void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break)
00546 {
00547         if(RE_rayobject_isRayAPI(r))
00548         {
00549                 r = RE_rayobject_align(r);
00550                 r->control.data = data;
00551                 r->control.test_break = test_break;
00552         }
00553 }
00554