|
Blender
V2.59
|
00001 /* 00002 * $Id: MOD_uvproject.c 38888 2011-08-01 05:25:30Z campbellbarton $ 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) 2005 by the Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * Contributor(s): Daniel Dunbar 00024 * Ton Roosendaal, 00025 * Ben Batt, 00026 * Brecht Van Lommel, 00027 * Campbell Barton 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 * 00031 */ 00032 00038 /* UV Project modifier: Generates UVs projected from an object */ 00039 00040 #include "DNA_meshdata_types.h" 00041 #include "DNA_camera_types.h" 00042 #include "DNA_object_types.h" 00043 00044 #include "BLI_math.h" 00045 #include "BLI_string.h" 00046 #include "BLI_uvproject.h" 00047 #include "BLI_utildefines.h" 00048 00049 00050 #include "BKE_DerivedMesh.h" 00051 00052 #include "MOD_modifiertypes.h" 00053 #include "MOD_util.h" 00054 00055 #include "MEM_guardedalloc.h" 00056 #include "depsgraph_private.h" 00057 00058 static void initData(ModifierData *md) 00059 { 00060 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00061 int i; 00062 00063 for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) 00064 umd->projectors[i] = NULL; 00065 umd->image = NULL; 00066 umd->flags = 0; 00067 umd->num_projectors = 1; 00068 umd->aspectx = umd->aspecty = 1.0f; 00069 umd->scalex = umd->scaley = 1.0f; 00070 } 00071 00072 static void copyData(ModifierData *md, ModifierData *target) 00073 { 00074 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00075 UVProjectModifierData *tumd = (UVProjectModifierData*) target; 00076 int i; 00077 00078 for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) 00079 tumd->projectors[i] = umd->projectors[i]; 00080 tumd->image = umd->image; 00081 tumd->flags = umd->flags; 00082 tumd->num_projectors = umd->num_projectors; 00083 tumd->aspectx = umd->aspectx; 00084 tumd->aspecty = umd->aspecty; 00085 tumd->scalex = umd->scalex; 00086 tumd->scaley = umd->scaley; 00087 BLI_strncpy(tumd->uvlayer_name, umd->uvlayer_name, sizeof(umd->uvlayer_name)); 00088 } 00089 00090 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md)) 00091 { 00092 CustomDataMask dataMask = 0; 00093 00094 /* ask for UV coordinates */ 00095 dataMask |= CD_MASK_MTFACE; 00096 00097 return dataMask; 00098 } 00099 00100 static void foreachObjectLink(ModifierData *md, Object *ob, 00101 ObjectWalkFunc walk, void *userData) 00102 { 00103 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00104 int i; 00105 00106 for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) 00107 walk(userData, ob, &umd->projectors[i]); 00108 } 00109 00110 static void foreachIDLink(ModifierData *md, Object *ob, 00111 IDWalkFunc walk, void *userData) 00112 { 00113 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00114 00115 walk(userData, ob, (ID **)&umd->image); 00116 00117 foreachObjectLink(md, ob, (ObjectWalkFunc)walk, 00118 userData); 00119 } 00120 00121 static void updateDepgraph(ModifierData *md, DagForest *forest, 00122 struct Scene *UNUSED(scene), 00123 Object *UNUSED(ob), 00124 DagNode *obNode) 00125 { 00126 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00127 int i; 00128 00129 for(i = 0; i < umd->num_projectors; ++i) { 00130 if(umd->projectors[i]) { 00131 DagNode *curNode = dag_get_node(forest, umd->projectors[i]); 00132 00133 dag_add_relation(forest, curNode, obNode, 00134 DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier"); 00135 } 00136 } 00137 } 00138 00139 typedef struct Projector { 00140 Object *ob; /* object this projector is derived from */ 00141 float projmat[4][4]; /* projection matrix */ 00142 float normal[3]; /* projector normal in world space */ 00143 void *uci; /* optional uv-project info (panorama projection) */ 00144 } Projector; 00145 00146 static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, 00147 Object *ob, DerivedMesh *dm) 00148 { 00149 float (*coords)[3], (*co)[3]; 00150 MTFace *tface; 00151 int i, numVerts, numFaces; 00152 Image *image = umd->image; 00153 MFace *mface, *mf; 00154 int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0); 00155 Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; 00156 int num_projectors = 0; 00157 float aspect; 00158 char uvname[32]; 00159 float aspx= umd->aspectx ? umd->aspectx : 1.0f; 00160 float aspy= umd->aspecty ? umd->aspecty : 1.0f; 00161 float scax= umd->scalex ? umd->scalex : 1.0f; 00162 float scay= umd->scaley ? umd->scaley : 1.0f; 00163 int free_uci= 0; 00164 00165 aspect = aspx / aspy; 00166 00167 for(i = 0; i < umd->num_projectors; ++i) 00168 if(umd->projectors[i]) 00169 projectors[num_projectors++].ob = umd->projectors[i]; 00170 00171 if(num_projectors == 0) return dm; 00172 00173 /* make sure there are UV layers available */ 00174 00175 if(!CustomData_has_layer(&dm->faceData, CD_MTFACE)) return dm; 00176 00177 /* make sure we're using an existing layer */ 00178 validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname); 00179 00180 /* calculate a projection matrix and normal for each projector */ 00181 for(i = 0; i < num_projectors; ++i) { 00182 float tmpmat[4][4]; 00183 float offsetmat[4][4]; 00184 Camera *cam = NULL; 00185 /* calculate projection matrix */ 00186 invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); 00187 00188 projectors[i].uci= NULL; 00189 00190 if(projectors[i].ob->type == OB_CAMERA) { 00191 00192 cam = (Camera *)projectors[i].ob->data; 00193 if(cam->flag & CAM_PANORAMA) { 00194 projectors[i].uci= project_camera_info(projectors[i].ob, NULL, aspx, aspy); 00195 project_camera_info_scale(projectors[i].uci, scax, scay); 00196 free_uci= 1; 00197 } 00198 else { 00199 float scale= (cam->type == CAM_PERSP) ? cam->clipsta * 32.0f / cam->lens : cam->ortho_scale; 00200 float xmax, xmin, ymax, ymin; 00201 00202 if(aspect > 1.0f) { 00203 xmax = 0.5f * scale; 00204 ymax = xmax / aspect; 00205 } else { 00206 ymax = 0.5f * scale; 00207 xmax = ymax * aspect; 00208 } 00209 xmin = -xmax; 00210 ymin = -ymax; 00211 00212 /* scale the matrix */ 00213 xmin *= scax; 00214 xmax *= scax; 00215 ymin *= scay; 00216 ymax *= scay; 00217 00218 if(cam->type == CAM_PERSP) { 00219 float perspmat[4][4]; 00220 perspective_m4( perspmat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend); 00221 mul_m4_m4m4(tmpmat, projectors[i].projmat, perspmat); 00222 } else { /* if(cam->type == CAM_ORTHO) */ 00223 float orthomat[4][4]; 00224 orthographic_m4( orthomat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend); 00225 mul_m4_m4m4(tmpmat, projectors[i].projmat, orthomat); 00226 } 00227 } 00228 } else { 00229 copy_m4_m4(tmpmat, projectors[i].projmat); 00230 } 00231 00232 unit_m4(offsetmat); 00233 mul_mat3_m4_fl(offsetmat, 0.5); 00234 offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; 00235 00236 if (cam) { 00237 if (aspx == aspy) { 00238 offsetmat[3][0] -= cam->shiftx; 00239 offsetmat[3][1] -= cam->shifty; 00240 } else if (aspx < aspy) { 00241 offsetmat[3][0] -=(cam->shiftx * aspy/aspx); 00242 offsetmat[3][1] -= cam->shifty; 00243 } else { 00244 offsetmat[3][0] -= cam->shiftx; 00245 offsetmat[3][1] -=(cam->shifty * aspx/aspy); 00246 } 00247 } 00248 00249 mul_m4_m4m4(projectors[i].projmat, tmpmat, offsetmat); 00250 00251 /* calculate worldspace projector normal (for best projector test) */ 00252 projectors[i].normal[0] = 0; 00253 projectors[i].normal[1] = 0; 00254 projectors[i].normal[2] = 1; 00255 mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); 00256 } 00257 00258 /* make sure we are not modifying the original UV layer */ 00259 tface = CustomData_duplicate_referenced_layer_named(&dm->faceData, 00260 CD_MTFACE, uvname); 00261 00262 00263 numVerts = dm->getNumVerts(dm); 00264 00265 coords = MEM_callocN(sizeof(*coords) * numVerts, 00266 "uvprojectModifier_do coords"); 00267 dm->getVertCos(dm, coords); 00268 00269 /* convert coords to world space */ 00270 for(i = 0, co = coords; i < numVerts; ++i, ++co) 00271 mul_m4_v3(ob->obmat, *co); 00272 00273 /* if only one projector, project coords to UVs */ 00274 if(num_projectors == 1 && projectors[0].uci==NULL) 00275 for(i = 0, co = coords; i < numVerts; ++i, ++co) 00276 mul_project_m4_v3(projectors[0].projmat, *co); 00277 00278 mface = dm->getFaceArray(dm); 00279 numFaces = dm->getNumFaces(dm); 00280 00281 /* apply coords as UVs, and apply image if tfaces are new */ 00282 for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) { 00283 if(override_image || !image || tface->tpage == image) { 00284 if(num_projectors == 1) { 00285 if(projectors[0].uci) { 00286 project_from_camera(tface->uv[0], coords[mf->v1], projectors[0].uci); 00287 project_from_camera(tface->uv[1], coords[mf->v2], projectors[0].uci); 00288 project_from_camera(tface->uv[2], coords[mf->v3], projectors[0].uci); 00289 if(mf->v3) 00290 project_from_camera(tface->uv[3], coords[mf->v4], projectors[0].uci); 00291 } 00292 else { 00293 /* apply transformed coords as UVs */ 00294 tface->uv[0][0] = coords[mf->v1][0]; 00295 tface->uv[0][1] = coords[mf->v1][1]; 00296 tface->uv[1][0] = coords[mf->v2][0]; 00297 tface->uv[1][1] = coords[mf->v2][1]; 00298 tface->uv[2][0] = coords[mf->v3][0]; 00299 tface->uv[2][1] = coords[mf->v3][1]; 00300 if(mf->v4) { 00301 tface->uv[3][0] = coords[mf->v4][0]; 00302 tface->uv[3][1] = coords[mf->v4][1]; 00303 } 00304 } 00305 } else { 00306 /* multiple projectors, select the closest to face normal 00307 * direction 00308 */ 00309 float co1[3], co2[3], co3[3], co4[3]; 00310 float face_no[3]; 00311 int j; 00312 Projector *best_projector; 00313 float best_dot; 00314 00315 copy_v3_v3(co1, coords[mf->v1]); 00316 copy_v3_v3(co2, coords[mf->v2]); 00317 copy_v3_v3(co3, coords[mf->v3]); 00318 00319 /* get the untransformed face normal */ 00320 if(mf->v4) { 00321 copy_v3_v3(co4, coords[mf->v4]); 00322 normal_quad_v3(face_no, co1, co2, co3, co4); 00323 } else { 00324 normal_tri_v3(face_no, co1, co2, co3); 00325 } 00326 00327 /* find the projector which the face points at most directly 00328 * (projector normal with largest dot product is best) 00329 */ 00330 best_dot = dot_v3v3(projectors[0].normal, face_no); 00331 best_projector = &projectors[0]; 00332 00333 for(j = 1; j < num_projectors; ++j) { 00334 float tmp_dot = dot_v3v3(projectors[j].normal, 00335 face_no); 00336 if(tmp_dot > best_dot) { 00337 best_dot = tmp_dot; 00338 best_projector = &projectors[j]; 00339 } 00340 } 00341 00342 if(best_projector->uci) { 00343 project_from_camera(tface->uv[0], coords[mf->v1], best_projector->uci); 00344 project_from_camera(tface->uv[1], coords[mf->v2], best_projector->uci); 00345 project_from_camera(tface->uv[2], coords[mf->v3], best_projector->uci); 00346 if(mf->v3) 00347 project_from_camera(tface->uv[3], coords[mf->v4], best_projector->uci); 00348 } 00349 else { 00350 mul_project_m4_v3(best_projector->projmat, co1); 00351 mul_project_m4_v3(best_projector->projmat, co2); 00352 mul_project_m4_v3(best_projector->projmat, co3); 00353 if(mf->v4) 00354 mul_project_m4_v3(best_projector->projmat, co4); 00355 00356 /* apply transformed coords as UVs */ 00357 tface->uv[0][0] = co1[0]; 00358 tface->uv[0][1] = co1[1]; 00359 tface->uv[1][0] = co2[0]; 00360 tface->uv[1][1] = co2[1]; 00361 tface->uv[2][0] = co3[0]; 00362 tface->uv[2][1] = co3[1]; 00363 if(mf->v4) { 00364 tface->uv[3][0] = co4[0]; 00365 tface->uv[3][1] = co4[1]; 00366 } 00367 } 00368 } 00369 } 00370 00371 if(override_image) { 00372 tface->mode = TF_TEX; 00373 tface->tpage = image; 00374 } 00375 } 00376 00377 MEM_freeN(coords); 00378 00379 if(free_uci) { 00380 int j; 00381 for(j = 0; j < num_projectors; ++j) { 00382 if(projectors[j].uci) { 00383 MEM_freeN(projectors[j].uci); 00384 } 00385 } 00386 } 00387 return dm; 00388 } 00389 00390 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, 00391 DerivedMesh *derivedData, 00392 int UNUSED(useRenderParams), 00393 int UNUSED(isFinalCalc)) 00394 { 00395 DerivedMesh *result; 00396 UVProjectModifierData *umd = (UVProjectModifierData*) md; 00397 00398 result = uvprojectModifier_do(umd, ob, derivedData); 00399 00400 return result; 00401 } 00402 00403 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob, 00404 struct EditMesh *UNUSED(editData), 00405 DerivedMesh *derivedData) 00406 { 00407 return applyModifier(md, ob, derivedData, 0, 1); 00408 } 00409 00410 00411 ModifierTypeInfo modifierType_UVProject = { 00412 /* name */ "UVProject", 00413 /* structName */ "UVProjectModifierData", 00414 /* structSize */ sizeof(UVProjectModifierData), 00415 /* type */ eModifierTypeType_Nonconstructive, 00416 /* flags */ eModifierTypeFlag_AcceptsMesh 00417 | eModifierTypeFlag_SupportsMapping 00418 | eModifierTypeFlag_SupportsEditmode 00419 | eModifierTypeFlag_EnableInEditmode, 00420 00421 /* copyData */ copyData, 00422 /* deformVerts */ NULL, 00423 /* deformMatrices */ NULL, 00424 /* deformVertsEM */ NULL, 00425 /* deformMatricesEM */ NULL, 00426 /* applyModifier */ applyModifier, 00427 /* applyModifierEM */ applyModifierEM, 00428 /* initData */ initData, 00429 /* requiredDataMask */ requiredDataMask, 00430 /* freeData */ NULL, 00431 /* isDisabled */ NULL, 00432 /* updateDepgraph */ updateDepgraph, 00433 /* dependsOnTime */ NULL, 00434 /* dependsOnNormals */ NULL, 00435 /* foreachObjectLink */ foreachObjectLink, 00436 /* foreachIDLink */ foreachIDLink, 00437 };