Blender V2.61 - r43446

MOD_uvproject.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software  Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Daniel Dunbar
00022  *                 Ton Roosendaal,
00023  *                 Ben Batt,
00024  *                 Brecht Van Lommel,
00025  *                 Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  *
00029  */
00030 
00036 /* UV Project modifier: Generates UVs projected from an object */
00037 
00038 #include "DNA_meshdata_types.h"
00039 #include "DNA_camera_types.h"
00040 #include "DNA_object_types.h"
00041 #include "DNA_scene_types.h"
00042 
00043 #include "BLI_math.h"
00044 #include "BLI_string.h"
00045 #include "BLI_uvproject.h"
00046 #include "BLI_utildefines.h"
00047 
00048 
00049 #include "BKE_camera.h"
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[MAX_CUSTOMDATA_LAYER_NAME];
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 Maps available */
00174 
00175     if(!CustomData_has_layer(&dm->faceData, CD_MTFACE)) return dm;
00176 
00177     /* make sure we're using an existing layer */
00178     CustomData_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 sensor= camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
00200                 int sensor_fit= camera_sensor_fit(cam->sensor_fit, aspx, aspy);
00201                 float scale= (cam->type == CAM_PERSP) ? cam->clipsta * sensor / cam->lens : cam->ortho_scale;
00202                 float xmax, xmin, ymax, ymin;
00203 
00204                 if(sensor_fit==CAMERA_SENSOR_FIT_HOR) {
00205                     xmax = 0.5f * scale;
00206                     ymax = xmax / aspect;
00207                 }
00208                 else {
00209                     ymax = 0.5f * scale;
00210                     xmax = ymax * aspect;
00211                 }
00212 
00213                 xmin = -xmax;
00214                 ymin = -ymax;
00215 
00216                 /* scale the matrix */
00217                 xmin *= scax;
00218                 xmax *= scax;
00219                 ymin *= scay;
00220                 ymax *= scay;
00221 
00222                 if(cam->type == CAM_PERSP) {
00223                     float perspmat[4][4];
00224                     perspective_m4( perspmat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
00225                     mult_m4_m4m4(tmpmat, perspmat, projectors[i].projmat);
00226                 } else { /* if(cam->type == CAM_ORTHO) */
00227                     float orthomat[4][4];
00228                     orthographic_m4( orthomat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
00229                     mult_m4_m4m4(tmpmat, orthomat, projectors[i].projmat);
00230                 }
00231             }
00232         } else {
00233             copy_m4_m4(tmpmat, projectors[i].projmat);
00234         }
00235 
00236         unit_m4(offsetmat);
00237         mul_mat3_m4_fl(offsetmat, 0.5);
00238         offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
00239         
00240         if (cam) {
00241             if (aspx == aspy) { 
00242                 offsetmat[3][0] -= cam->shiftx;
00243                 offsetmat[3][1] -= cam->shifty;
00244             } else if (aspx < aspy)  {
00245                 offsetmat[3][0] -=(cam->shiftx * aspy/aspx);
00246                 offsetmat[3][1] -= cam->shifty;
00247             } else {
00248                 offsetmat[3][0] -= cam->shiftx;
00249                 offsetmat[3][1] -=(cam->shifty * aspx/aspy);
00250             }
00251         }
00252         
00253         mult_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
00254 
00255         /* calculate worldspace projector normal (for best projector test) */
00256         projectors[i].normal[0] = 0;
00257         projectors[i].normal[1] = 0;
00258         projectors[i].normal[2] = 1;
00259         mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
00260     }
00261 
00262     numFaces = dm->getNumFaces(dm);
00263 
00264     /* make sure we are not modifying the original UV map */
00265     tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
00266             CD_MTFACE, uvname, numFaces);
00267 
00268     numVerts = dm->getNumVerts(dm);
00269 
00270     coords = MEM_callocN(sizeof(*coords) * numVerts,
00271                  "uvprojectModifier_do coords");
00272     dm->getVertCos(dm, coords);
00273 
00274     /* convert coords to world space */
00275     for(i = 0, co = coords; i < numVerts; ++i, ++co)
00276         mul_m4_v3(ob->obmat, *co);
00277     
00278     /* if only one projector, project coords to UVs */
00279     if(num_projectors == 1 && projectors[0].uci==NULL)
00280         for(i = 0, co = coords; i < numVerts; ++i, ++co)
00281             mul_project_m4_v3(projectors[0].projmat, *co);
00282 
00283     mface = dm->getFaceArray(dm);
00284 
00285     /* apply coords as UVs, and apply image if tfaces are new */
00286     for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
00287         if(override_image || !image || tface->tpage == image) {
00288             if(num_projectors == 1) {
00289                 if(projectors[0].uci) {
00290                     unsigned int fidx= mf->v4 ? 3:2;
00291                     do {
00292                         unsigned int vidx= *(&mf->v1 + fidx);
00293                         project_from_camera(tface->uv[fidx], coords[vidx], projectors[0].uci);
00294                     } while (fidx--);
00295                 }
00296                 else {
00297                     /* apply transformed coords as UVs */
00298                     unsigned int fidx= mf->v4 ? 3:2;
00299                     do {
00300                         unsigned int vidx= *(&mf->v1 + fidx);
00301                         copy_v2_v2(tface->uv[fidx], coords[vidx]);
00302                     } while (fidx--);
00303                 }
00304             } else {
00305                 /* multiple projectors, select the closest to face normal
00306                 * direction
00307                 */
00308                 float face_no[3];
00309                 int j;
00310                 Projector *best_projector;
00311                 float best_dot;
00312 
00313                 /* get the untransformed face normal */
00314                 if(mf->v4) {
00315                     normal_quad_v3(face_no, coords[mf->v1], coords[mf->v2], coords[mf->v3], coords[mf->v4]);
00316                 } else { 
00317                     normal_tri_v3(face_no, coords[mf->v1], coords[mf->v2], coords[mf->v3]);
00318                 }
00319 
00320                 /* find the projector which the face points at most directly
00321                 * (projector normal with largest dot product is best)
00322                 */
00323                 best_dot = dot_v3v3(projectors[0].normal, face_no);
00324                 best_projector = &projectors[0];
00325 
00326                 for(j = 1; j < num_projectors; ++j) {
00327                     float tmp_dot = dot_v3v3(projectors[j].normal,
00328                             face_no);
00329                     if(tmp_dot > best_dot) {
00330                         best_dot = tmp_dot;
00331                         best_projector = &projectors[j];
00332                     }
00333                 }
00334 
00335                 if(best_projector->uci) {
00336                     unsigned int fidx= mf->v4 ? 3:2;
00337                     do {
00338                         unsigned int vidx= *(&mf->v1 + fidx);
00339                         project_from_camera(tface->uv[fidx], coords[vidx], best_projector->uci);
00340                     } while (fidx--);
00341                 }
00342                 else {
00343                     unsigned int fidx= mf->v4 ? 3:2;
00344                     do {
00345                         unsigned int vidx= *(&mf->v1 + fidx);
00346                         float tco[3];
00347 
00348                         copy_v3_v3(tco, coords[vidx]);
00349                         mul_project_m4_v3(best_projector->projmat, tco);
00350                         copy_v2_v2(tface->uv[fidx], tco);
00351 
00352                     } while (fidx--);
00353                 }
00354             }
00355         }
00356 
00357         if(override_image) {
00358             tface->tpage = image;
00359         }
00360     }
00361 
00362     MEM_freeN(coords);
00363     
00364     if(free_uci) {
00365         int j;
00366         for(j = 0; j < num_projectors; ++j) {
00367             if(projectors[j].uci) {
00368                 MEM_freeN(projectors[j].uci);
00369             }
00370         }
00371     }
00372     return dm;
00373 }
00374 
00375 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
00376                         DerivedMesh *derivedData,
00377                         int UNUSED(useRenderParams),
00378                         int UNUSED(isFinalCalc))
00379 {
00380     DerivedMesh *result;
00381     UVProjectModifierData *umd = (UVProjectModifierData*) md;
00382 
00383     result = uvprojectModifier_do(umd, ob, derivedData);
00384 
00385     return result;
00386 }
00387 
00388 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
00389                         struct EditMesh *UNUSED(editData),
00390                         DerivedMesh *derivedData)
00391 {
00392     return applyModifier(md, ob, derivedData, 0, 1);
00393 }
00394 
00395 
00396 ModifierTypeInfo modifierType_UVProject = {
00397     /* name */              "UVProject",
00398     /* structName */        "UVProjectModifierData",
00399     /* structSize */        sizeof(UVProjectModifierData),
00400     /* type */              eModifierTypeType_NonGeometrical,
00401     /* flags */             eModifierTypeFlag_AcceptsMesh
00402                             | eModifierTypeFlag_SupportsMapping
00403                             | eModifierTypeFlag_SupportsEditmode
00404                             | eModifierTypeFlag_EnableInEditmode,
00405 
00406     /* copyData */          copyData,
00407     /* deformVerts */       NULL,
00408     /* deformMatrices */    NULL,
00409     /* deformVertsEM */     NULL,
00410     /* deformMatricesEM */  NULL,
00411     /* applyModifier */     applyModifier,
00412     /* applyModifierEM */   applyModifierEM,
00413     /* initData */          initData,
00414     /* requiredDataMask */  requiredDataMask,
00415     /* freeData */          NULL,
00416     /* isDisabled */        NULL,
00417     /* updateDepgraph */    updateDepgraph,
00418     /* dependsOnTime */     NULL,
00419     /* dependsOnNormals */  NULL,
00420     /* foreachObjectLink */ foreachObjectLink,
00421     /* foreachIDLink */     foreachIDLink,
00422     /* foreachTexLink */    NULL,
00423 };