|
Blender
V2.59
|
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