Blender  V2.59
MOD_uvproject.c
Go to the documentation of this file.
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 };