Blender  V2.59
rayobject_instance.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: rayobject_instance.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 "rayintersection.h"
00043 #include "rayobject.h"
00044 
00045 #define RE_COST_INSTANCE (1.0f)
00046 
00047 static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
00048 static void RE_rayobject_instance_free(RayObject *o);
00049 static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
00050 static float RE_rayobject_instance_cost(RayObject *o);
00051 
00052 static void RE_rayobject_instance_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
00053 {}
00054 
00055 static RayObjectAPI instance_api =
00056 {
00057         RE_rayobject_instance_intersect,
00058         NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
00059         NULL, //static void RE_rayobject_instance_done(RayObject *o);
00060         RE_rayobject_instance_free,
00061         RE_rayobject_instance_bb,
00062         RE_rayobject_instance_cost,
00063         RE_rayobject_instance_hint_bb   
00064 };
00065 
00066 typedef struct InstanceRayObject
00067 {
00068         RayObject rayobj;
00069         RayObject *target;
00070 
00071         void *ob; //Object represented by this instance
00072         void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
00073         
00074         float global2target[4][4];
00075         float target2global[4][4];
00076         
00077 } InstanceRayObject;
00078 
00079 
00080 RayObject *RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob)
00081 {
00082         InstanceRayObject *obj= (InstanceRayObject*)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
00083         assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */       
00084         
00085         obj->rayobj.api = &instance_api;
00086         obj->target = target;
00087         obj->ob = ob;
00088         obj->target_ob = target_ob;
00089         
00090         copy_m4_m4(obj->target2global, transform);
00091         invert_m4_m4(obj->global2target, obj->target2global);
00092         
00093         return RE_rayobject_unalignRayAPI((RayObject*) obj);
00094 }
00095 
00096 static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
00097 {
00098         InstanceRayObject *obj = (InstanceRayObject*)o;
00099         float start[3], dir[3], idot_axis[3], dist;
00100         int changed = 0, i, res;
00101         
00102         // TODO - this is disabling self intersection on instances
00103         if(isec->orig.ob == obj->ob && obj->ob)
00104         {
00105                 changed = 1;
00106                 isec->orig.ob = obj->target_ob;
00107         }
00108         
00109         // backup old values
00110         copy_v3_v3(start, isec->start);
00111         copy_v3_v3(dir, isec->dir);
00112         copy_v3_v3(idot_axis, isec->idot_axis);
00113         dist = isec->dist;
00114 
00115         // transform to target coordinates system
00116         mul_m4_v3(obj->global2target, isec->start);
00117         mul_mat3_m4_v3(obj->global2target, isec->dir);
00118         isec->dist *= normalize_v3(isec->dir);
00119         
00120         // update idot_axis and bv_index
00121         for(i=0; i<3; i++)
00122         {
00123                 isec->idot_axis[i]              = 1.0f / isec->dir[i];
00124                 
00125                 isec->bv_index[2*i]             = isec->idot_axis[i] < 0.0 ? 1 : 0;
00126                 isec->bv_index[2*i+1]   = 1 - isec->bv_index[2*i];
00127                 
00128                 isec->bv_index[2*i]             = i+3*isec->bv_index[2*i];
00129                 isec->bv_index[2*i+1]   = i+3*isec->bv_index[2*i+1];
00130         }
00131 
00132         // raycast
00133         res = RE_rayobject_intersect(obj->target, isec);
00134 
00135         // map dist into original coordinate space
00136         if(res == 0)
00137         {
00138                 isec->dist = dist;
00139         }
00140         else
00141         {
00142                 // note we don't just multiply dist, because of possible
00143                 // non-uniform scaling in the transform matrix
00144                 float vec[3];
00145 
00146                 mul_v3_v3fl(vec, isec->dir, isec->dist);
00147                 mul_mat3_m4_v3(obj->target2global, vec);
00148 
00149                 isec->dist = len_v3(vec);
00150                 isec->hit.ob = obj->ob;
00151 
00152 #ifdef RT_USE_LAST_HIT  
00153                 // TODO support for last hit optimization in instances that can jump
00154                 // directly to the last hit face.
00155                 // For now it jumps directly to the last-hit instance root node.
00156                 isec->last_hit = RE_rayobject_unalignRayAPI((RayObject*) obj);
00157 #endif
00158         }
00159 
00160         // restore values
00161         copy_v3_v3(isec->start, start);
00162         copy_v3_v3(isec->dir, dir);
00163         copy_v3_v3(isec->idot_axis, idot_axis);
00164         
00165         if(changed)
00166                 isec->orig.ob = obj->ob;
00167 
00168         // restore bv_index
00169         for(i=0; i<3; i++)
00170         {
00171                 isec->bv_index[2*i]             = isec->idot_axis[i] < 0.0 ? 1 : 0;
00172                 isec->bv_index[2*i+1]   = 1 - isec->bv_index[2*i];
00173                 
00174                 isec->bv_index[2*i]             = i+3*isec->bv_index[2*i];
00175                 isec->bv_index[2*i+1]   = i+3*isec->bv_index[2*i+1];
00176         }
00177                 
00178         return res;
00179 }
00180 
00181 static void RE_rayobject_instance_free(RayObject *o)
00182 {
00183         InstanceRayObject *obj = (InstanceRayObject*)o;
00184         MEM_freeN(obj);
00185 }
00186 
00187 static float RE_rayobject_instance_cost(RayObject *o)
00188 {
00189         InstanceRayObject *obj = (InstanceRayObject*)o;
00190         return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
00191 }
00192 
00193 static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
00194 {
00195         //TODO:
00196         // *better bb.. calculated without rotations of bb
00197         // *maybe cache that better-fitted-BB at the InstanceRayObject
00198         InstanceRayObject *obj = (InstanceRayObject*)o;
00199 
00200         float m[3], M[3], t[3];
00201         int i, j;
00202         INIT_MINMAX(m, M);
00203         RE_rayobject_merge_bb(obj->target, m, M);
00204 
00205         //There must be a faster way than rotating all the 8 vertexs of the BB
00206         for(i=0; i<8; i++)
00207         {
00208                 for(j=0; j<3; j++) t[j] = i&(1<<j) ? M[j] : m[j];
00209                 mul_m4_v3(obj->target2global, t);
00210                 DO_MINMAX(t, min, max);
00211         }
00212 }
00213