diff options
Diffstat (limited to 'source/blender/render/intern/raytrace/rayobject.cpp')
-rw-r--r-- | source/blender/render/intern/raytrace/rayobject.cpp | 644 |
1 files changed, 295 insertions, 349 deletions
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index 84ec56e131a..dd4932f0bd9 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -26,127 +26,86 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #include <assert.h> -#include "BKE_utildefines.h" +#include "MEM_guardedalloc.h" + #include "BLI_math.h" +#include "BLI_utildefines.h" + #include "DNA_material_types.h" -#include "RE_raytrace.h" -#include "render_types.h" +#include "rayintersection.h" #include "rayobject.h" #include "raycounter.h" +#include "render_types.h" -/* - * Determines the distance that the ray must travel to hit the bounding volume of the given node - * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe - * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9] - */ -int RE_rayobject_bb_intersect_test(const Isect *isec, const float *_bb) -{ - const float *bb = _bb; - - float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; - float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; - float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; - float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; - float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; - float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; - - RE_RC_COUNT(isec->raycounter->bb.test); - - if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; - if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0; - if(t1x > isec->labda || t1y > isec->labda || t1z > isec->labda) return 0; - RE_RC_COUNT(isec->raycounter->bb.hit); - - return 1; -} +/* RayFace + note we force always inline here, because compiler refuses to otherwise + because function is too long. Since this is code that is called billions + of times we really do want to inline. */ -/* only for self-intersecting test with current render face (where ray left) */ -static int intersection2(VlakRen *face, float r0, float r1, float r2, float rx1, float ry1, float rz1) +MALWAYS_INLINE RayObject* rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4) { - float co1[3], co2[3], co3[3], co4[3]; - float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22; - float m0, m1, m2, divdet, det, det1; - float u1, v, u2; + rayface->ob = ob; + rayface->face = face; - VECCOPY(co1, face->v1->co); - VECCOPY(co2, face->v2->co); - if(face->v4) + copy_v3_v3(rayface->v1, v1); + copy_v3_v3(rayface->v2, v2); + copy_v3_v3(rayface->v3, v3); + + if(v4) { - VECCOPY(co3, face->v4->co); - VECCOPY(co4, face->v3->co); + copy_v3_v3(rayface->v4, v4); + rayface->quad = 1; } else { - VECCOPY(co3, face->v3->co); + rayface->quad = 0; } - t00= co3[0]-co1[0]; - t01= co3[1]-co1[1]; - t02= co3[2]-co1[2]; - t10= co3[0]-co2[0]; - t11= co3[1]-co2[1]; - t12= co3[2]-co2[2]; - - x0= t11*r2-t12*r1; - x1= t12*r0-t10*r2; - x2= t10*r1-t11*r0; - - divdet= t00*x0+t01*x1+t02*x2; + return RE_rayobject_unalignRayFace(rayface); +} - m0= rx1-co3[0]; - m1= ry1-co3[1]; - m2= rz1-co3[2]; - det1= m0*x0+m1*x1+m2*x2; - - if(divdet!=0.0f) { - u1= det1/divdet; +MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0); - if(u1<ISECT_EPSILON) { - det= t00*(m1*r2-m2*r1); - det+= t01*(m2*r0-m0*r2); - det+= t02*(m0*r1-m1*r0); - v= det/divdet; + if(obi->transform_primitives) + { + mul_m4_v3(obi->mat, rayface->v1); + mul_m4_v3(obi->mat, rayface->v2); + mul_m4_v3(obi->mat, rayface->v3); - if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) { - return 1; - } - } + if(RE_rayface_isQuad(rayface)) + mul_m4_v3(obi->mat, rayface->v4); } +} - if(face->v4) { +RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0); +} - t20= co3[0]-co4[0]; - t21= co3[1]-co4[1]; - t22= co3[2]-co4[2]; +/* VlakPrimitive */ - divdet= t20*x0+t21*x1+t22*x2; - if(divdet!=0.0f) { - u2= det1/divdet; - - if(u2<ISECT_EPSILON) { - det= t20*(m1*r2-m2*r1); - det+= t21*(m2*r0-m0*r2); - det+= t22*(m0*r1-m1*r0); - v= det/divdet; - - if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) { - return 2; - } - } - } - } - return 0; +RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr) +{ + face->ob = obi; + face->face = vlr; + + return RE_rayobject_unalignVlakPrimitive(face); } -static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr) +/* Checks for ignoring faces or materials */ + +MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr) { /* for baking selected to active non-traceable materials might still * be in the raytree */ - if(!(vlr->mat->mode & MA_TRACEBLE)) + if(!(vlr->flag & R_TRACEBLE)) return 0; /* I know... cpu cycle waste, might do smarter once */ @@ -156,7 +115,7 @@ static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen return (is->lay & obi->lay); } -static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) +MALWAYS_INLINE int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) { /* solid material types only */ if (vlr->mat->material_type == MA_TYPE_SURFACE) @@ -165,168 +124,223 @@ static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, V return 0; } -static inline int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) +MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) { return (obi->obr->ob != is->userdata); } -static inline int rayface_check_cullface(RayFace *face, Isect *is) -{ - float nor[3]; - - /* don't intersect if the ray faces along the face normal */ - if(face->quad) normal_quad_v3( nor,face->v1, face->v2, face->v3, face->v4); - else normal_tri_v3( nor,face->v1, face->v2, face->v3); +/* Ray Triangle/Quad Intersection */ - return (INPR(nor, is->vec) < 0); -} - -/* ray - triangle or quad intersection */ -/* this function shall only modify Isect if it detects an hit */ -static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) +MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda) { - float co1[3],co2[3],co3[3],co4[3]={0}; - float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2; - float m0, m1, m2, divdet, det1; - float labda, u, v; - short ok=0; - - if(is->orig.ob == face->ob && is->orig.face == face->face) - return 0; - - /* check if we should intersect this face */ - if(is->skip & RE_SKIP_VLR_RENDER_CHECK) - { - if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - } - else if(is->skip & RE_SKIP_VLR_NON_SOLID_MATERIAL) - { - if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) - return 0; - } - else if(is->skip & RE_SKIP_VLR_BAKE_CHECK) { - if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - } + float co1[3], co2[3], co3[3], co4[3]; + float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l; + int quad; - if(is->skip & RE_SKIP_CULLFACE) - { - if(rayface_check_cullface(face, is) == 0) - return 0; - } + quad= RE_rayface_isQuad(face); - RE_RC_COUNT(is->raycounter->faces.test); + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); - //Load coords - VECCOPY(co1, face->v1); - VECCOPY(co2, face->v2); - if(RE_rayface_isQuad(face)) - { - VECCOPY(co3, face->v4); - VECCOPY(co4, face->v3); - } - else - { - VECCOPY(co3, face->v3); - } + copy_v3_v3(r, dir); - t00= co3[0]-co1[0]; - t01= co3[1]-co1[1]; - t02= co3[2]-co1[2]; - t10= co3[0]-co2[0]; - t11= co3[1]-co2[1]; - t12= co3[2]-co2[2]; - - r0= is->vec[0]; - r1= is->vec[1]; - r2= is->vec[2]; - - x0= t12*r1-t11*r2; - x1= t10*r2-t12*r0; - x2= t11*r0-t10*r1; + /* intersect triangle */ + sub_v3_v3v3(t0, co3, co2); + sub_v3_v3v3(t1, co3, co1); - divdet= t00*x0+t01*x1+t02*x2; + cross_v3_v3v3(x, r, t1); + divdet= dot_v3v3(t0, x); - m0= is->start[0]-co3[0]; - m1= is->start[1]-co3[1]; - m2= is->start[2]-co3[2]; - det1= m0*x0+m1*x1+m2*x2; + sub_v3_v3v3(m, start, co3); + det1= dot_v3v3(m, x); - if(divdet!=0.0f) { - + if(divdet != 0.0f) { divdet= 1.0f/divdet; - u= det1*divdet; - if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) { - float cros0, cros1, cros2; - - cros0= m1*t02-m2*t01; - cros1= m2*t00-m0*t02; - cros2= m0*t01-m1*t00; - v= divdet*(cros0*r0 + cros1*r1 + cros2*r2); + v= det1*divdet; - if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) { - labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; - if(labda>-ISECT_EPSILON && labda<is->labda) { - ok= 1; + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { + l= divdet*dot_v3v3(cros, t1); + + /* check if intersection is within ray length */ + if(l > -RE_RAYTRACE_EPSILON && l < *lambda) { + uv[0]= u; + uv[1]= v; + *lambda= l; + return 1; } } } } - if(ok==0 && RE_rayface_isQuad(face)) { - - t20= co3[0]-co4[0]; - t21= co3[1]-co4[1]; - t22= co3[2]-co4[2]; + /* intersect second triangle in quad */ + if(quad) { + copy_v3_v3(co4, face->v4); + sub_v3_v3v3(t0, co3, co4); + divdet= dot_v3v3(t0, x); - divdet= t20*x0+t21*x1+t22*x2; - if(divdet!=0.0f) { + if(divdet != 0.0f) { divdet= 1.0f/divdet; - u = det1*divdet; + v = det1*divdet; - if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) { - float cros0, cros1, cros2; - cros0= m1*t22-m2*t21; - cros1= m2*t20-m0*t22; - cros2= m0*t21-m1*t20; - v= divdet*(cros0*r0 + cros1*r1 + cros2*r2); + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); - if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) { - labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { + l= divdet*dot_v3v3(cros, t1); - if(labda>-ISECT_EPSILON && labda<is->labda) { - ok= 2; + if(l >- RE_RAYTRACE_EPSILON && l < *lambda) { + uv[0]= u; + uv[1]= -(1.0f + v + u); + *lambda= l; + return 2; } } } } } + return 0; +} + +/* Simpler yes/no Ray Triangle/Quad Intersection */ + +MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face) +{ + float co1[3], co2[3], co3[3], co4[3]; + float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1; + int quad; + + quad= RE_rayface_isQuad(face); + + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); + + negate_v3_v3(r, dir); /* note, different than above function */ + + /* intersect triangle */ + sub_v3_v3v3(t0, co3, co2); + sub_v3_v3v3(t1, co3, co1); + + cross_v3_v3v3(x, r, t1); + divdet= dot_v3v3(t0, x); + + sub_v3_v3v3(m, start, co3); + det1= dot_v3v3(m, x); + + if(divdet != 0.0f) { + divdet= 1.0f/divdet; + v= det1*divdet; + + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) + return 1; + } + } + + /* intersect second triangle in quad */ + if(quad) { + copy_v3_v3(co4, face->v4); + sub_v3_v3v3(t0, co3, co4); + divdet= dot_v3v3(t0, x); + + if(divdet != 0.0f) { + divdet= 1.0f/divdet; + v = det1*divdet; + + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) + return 2; + } + } + } + + return 0; +} + +/* RayFace intersection with checks and neighbour verifaction included, + Isect is modified if the face is hit. */ + +MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) +{ + float dist, uv[2]; + int ok= 0; + + /* avoid self-intersection */ + if(is->orig.ob == face->ob && is->orig.face == face->face) + return 0; + + /* check if we should intersect this face */ + if(is->check == RE_CHECK_VLR_RENDER) + { + if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) + { + if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + else if(is->check == RE_CHECK_VLR_BAKE) { + if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + + /* ray counter */ + RE_RC_COUNT(is->raycounter->faces.test); + + dist= is->dist; + ok= isec_tri_quad(is->start, is->dir, face, uv, &dist); + if(ok) { - /* when a shadow ray leaves a face, it can be little outside the edges of it, causing - intersection to be detected in its neighbour face */ + /* when a shadow ray leaves a face, it can be little outside the edges + of it, causing intersection to be detected in its neighbour face */ if(is->skip & RE_SKIP_VLR_NEIGHBOUR) { - if(labda < 0.1f && is->orig.ob == face->ob) + if(dist < 0.1f && is->orig.ob == face->ob) { VlakRen * a = (VlakRen*)is->orig.face; VlakRen * b = (VlakRen*)face->face; - /* so there's a shared edge or vertex, let's intersect ray with face - itself, if that's true we can safely return 1, otherwise we assume - the intersection is invalid, 0 */ + /* so there's a shared edge or vertex, let's intersect ray with + face itself, if that's true we can safely return 1, otherwise + we assume the intersection is invalid, 0 */ if(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1 || a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2 || a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3 - || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) - if(!intersection2((VlakRen*)a, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2])) - { - return 0; + || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) { + /* create RayFace from original face, transformed if necessary */ + RayFace origface; + ObjectInstanceRen *ob= (ObjectInstanceRen*)is->orig.ob; + rayface_from_vlak(&origface, ob, (VlakRen*)is->orig.face); + + if(!isec_tri_quad_neighbour(is->start, is->dir, &origface)) + { + return 0; + } } } } @@ -334,8 +348,8 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) RE_RC_COUNT(is->raycounter->faces.hit); is->isect= ok; // which half of the quad - is->labda= labda; - is->u= u; is->v= v; + is->dist= dist; + is->u= uv[0]; is->v= uv[1]; is->hit.ob = face->ob; is->hit.face = face->face; @@ -348,51 +362,18 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) return 0; } -RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) -{ - return RE_rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0 ); -} - -RayObject* RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4) -{ - rayface->ob = ob; - rayface->face = face; - - VECCOPY(rayface->v1, v1); - VECCOPY(rayface->v2, v2); - VECCOPY(rayface->v3, v3); - if(v4) - { - VECCOPY(rayface->v4, v4); - rayface->quad = 1; - } - else - { - rayface->quad = 0; - } - - return RE_rayobject_unalignRayFace(rayface); -} - -RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr) -{ - face->ob = obi; - face->face = vlr; - return RE_rayobject_unalignVlakPrimitive(face); -} - +/* Intersection */ int RE_rayobject_raycast(RayObject *r, Isect *isec) { int i; + RE_RC_COUNT(isec->raycounter->raycast.test); - /* Setup vars used on raycast */ - isec->dist = len_v3(isec->vec); - + /* setup vars used on raycast */ for(i=0; i<3; i++) { - isec->idot_axis[i] = 1.0f / isec->vec[i]; + isec->idot_axis[i] = 1.0f / isec->dir[i]; isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0; isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i]; @@ -402,7 +383,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) } #ifdef RT_USE_LAST_HIT - /* Last hit heuristic */ + /* last hit heuristic */ if(isec->mode==RE_RAY_SHADOW && isec->last_hit) { RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test); @@ -429,6 +410,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) #endif return 1; } + return 0; } @@ -443,98 +425,92 @@ int RE_rayobject_intersect(RayObject *r, Isect *i) //TODO optimize (useless copy to RayFace to avoid duplicate code) VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r); RayFace nface; - RE_rayface_from_vlak(&nface, face->ob, face->face); - - if(face->ob->transform_primitives) - { - mul_m4_v3(face->ob->mat, nface.v1); - mul_m4_v3(face->ob->mat, nface.v2); - mul_m4_v3(face->ob->mat, nface.v3); - if(RE_rayface_isQuad(&nface)) - mul_m4_v3(face->ob->mat, nface.v4); - } + rayface_from_vlak(&nface, face->ob, face->face); return intersect_rayface(r, &nface, i); } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - return r->api->raycast( r, i ); + r = RE_rayobject_align(r); + return r->api->raycast(r, i); + } + else { + assert(0); + return 0; } - else assert(0); - return 0; /* wont reach this, quiet compilers */ } +/* Building */ + void RE_rayobject_add(RayObject *r, RayObject *o) { - r = RE_rayobject_align( r ); - return r->api->add( r, o ); + r = RE_rayobject_align(r); + return r->api->add(r, o); } void RE_rayobject_done(RayObject *r) { - r = RE_rayobject_align( r ); - r->api->done( r ); + r = RE_rayobject_align(r); + r->api->done(r); } void RE_rayobject_free(RayObject *r) { - r = RE_rayobject_align( r ); - r->api->free( r ); + r = RE_rayobject_align(r); + r->api->free(r); +} + +float RE_rayobject_cost(RayObject *r) +{ + if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) + { + return 1.0f; + } + else if(RE_rayobject_isRayAPI(r)) + { + r = RE_rayobject_align(r); + return r->api->cost(r); + } + else { + assert(0); + return 1.0f; + } } +/* Bounding Boxes */ + void RE_rayobject_merge_bb(RayObject *r, float *min, float *max) { if(RE_rayobject_isRayFace(r)) { RayFace *face = (RayFace*) RE_rayobject_align(r); - DO_MINMAX( face->v1, min, max ); - DO_MINMAX( face->v2, min, max ); - DO_MINMAX( face->v3, min, max ); - if(RE_rayface_isQuad(face)) DO_MINMAX( face->v4, min, max ); + DO_MINMAX(face->v1, min, max); + DO_MINMAX(face->v2, min, max); + DO_MINMAX(face->v3, min, max); + if(RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max); } else if(RE_rayobject_isVlakPrimitive(r)) { VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r); RayFace nface; - RE_rayface_from_vlak(&nface, face->ob, face->face); - - if(face->ob->transform_primitives) - { - mul_m4_v3(face->ob->mat, nface.v1); - mul_m4_v3(face->ob->mat, nface.v2); - mul_m4_v3(face->ob->mat, nface.v3); - if(RE_rayface_isQuad(&nface)) - mul_m4_v3(face->ob->mat, nface.v4); - } + rayface_from_vlak(&nface, face->ob, face->face); - DO_MINMAX( nface.v1, min, max ); - DO_MINMAX( nface.v2, min, max ); - DO_MINMAX( nface.v3, min, max ); - if(RE_rayface_isQuad(&nface)) DO_MINMAX( nface.v4, min, max ); + DO_MINMAX(nface.v1, min, max); + DO_MINMAX(nface.v2, min, max); + DO_MINMAX(nface.v3, min, max); + if(RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max); } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - r->api->bb( r, min, max ); + r = RE_rayobject_align(r); + r->api->bb(r, min, max); } - else assert(0); + else + assert(0); } -float RE_rayobject_cost(RayObject *r) -{ - if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) - { - return 1.0; - } - else if(RE_rayobject_isRayAPI(r)) - { - r = RE_rayobject_align( r ); - return r->api->cost( r ); - } - else assert(0); -} +/* Hints */ void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max) { @@ -544,60 +520,30 @@ void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max) } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - return r->api->hint_bb( r, hint, min, max ); + r = RE_rayobject_align(r); + return r->api->hint_bb(r, hint, min, max); } - else assert(0); + else + assert(0); } +/* RayObjectControl */ + int RE_rayobjectcontrol_test_break(RayObjectControl *control) { if(control->test_break) - return control->test_break( control->data ); + return control->test_break(control->data); return 0; } - -/* - * Empty raytree - */ -static int RE_rayobject_empty_intersect(RayObject *o, Isect *is) +void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break) { - return 0; -} - -static void RE_rayobject_empty_free(RayObject *o) -{ -} - -static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max) -{ - return; -} - -static float RE_rayobject_empty_cost(RayObject *o) -{ - return 0.0; + if(RE_rayobject_isRayAPI(r)) + { + r = RE_rayobject_align(r); + r->control.data = data; + r->control.test_break = test_break; + } } -static void RE_rayobject_empty_hint_bb(RayObject *o, RayHint *hint, float *min, float *max) -{} - -static RayObjectAPI empty_api = -{ - RE_rayobject_empty_intersect, - NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob); - NULL, //static void RE_rayobject_instance_done(RayObject *o); - RE_rayobject_empty_free, - RE_rayobject_empty_bb, - RE_rayobject_empty_cost, - RE_rayobject_empty_hint_bb -}; - -static RayObject empty_raytree = { &empty_api, {0, 0} }; - -RayObject *RE_rayobject_empty_create() -{ - return RE_rayobject_unalignRayAPI( &empty_raytree ); -} |