Panorama camera support for UV project modifier
authorCampbell Barton <ideasman42@gmail.com>
Tue, 23 Mar 2010 20:04:05 +0000 (20:04 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 23 Mar 2010 20:04:05 +0000 (20:04 +0000)
source/blender/blenkernel/intern/modifier.c
source/blender/blenlib/BLI_uvproject.h
source/blender/blenlib/intern/uvproject.c

index b10456c..8739a9c 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "BLI_kdtree.h"
 #include "BLI_rand.h"
+#include "BLI_uvproject.h"
 
 #include "MEM_guardedalloc.h"
 
@@ -3673,6 +3674,7 @@ typedef struct Projector {
        Object *ob;                             /* object this projector is derived from */
        float projmat[4][4];    /* projection matrix */ 
        float normal[3];                /* projector normal in world space */
+       void *uci;                              /* optional uv-project info (panorama projection) */
 } Projector;
 
 static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
@@ -3688,9 +3690,11 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        int num_projectors = 0;
        float aspect;
        char uvname[32];
+       float aspx= umd->aspectx ? 1.0f : umd->aspectx;
+       float aspy= umd->aspecty ? 1.0f : umd->aspecty;
+       int free_uci= 0;
        
-       if(umd->aspecty != 0) aspect = umd->aspectx / umd->aspecty;
-       else aspect = 1.0f;
+       aspect = aspx / aspy;
 
        for(i = 0; i < umd->num_projectors; ++i)
                if(umd->projectors[i])
@@ -3705,20 +3709,6 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        /* make sure we're using an existing layer */
        validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname);
 
-       /* make sure we are not modifying the original UV layer */
-       tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
-                       CD_MTFACE, uvname);
-
-       numVerts = dm->getNumVerts(dm);
-
-       coords = MEM_callocN(sizeof(*coords) * numVerts,
-                                "uvprojectModifier_do coords");
-       dm->getVertCos(dm, coords);
-
-       /* convert coords to world space */
-       for(i = 0, co = coords; i < numVerts; ++i, ++co)
-               mul_m4_v3(ob->obmat, *co);
-
        /* calculate a projection matrix and normal for each projector */
        for(i = 0; i < num_projectors; ++i) {
                float tmpmat[4][4];
@@ -3729,7 +3719,13 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
 
                if(projectors[i].ob->type == OB_CAMERA) {
                        cam = (Camera *)projectors[i].ob->data;
-                       if(cam->type == CAM_PERSP) {
+                       projectors[i].uci= NULL;
+
+                       if(cam->flag & CAM_PANORAMA) {
+                               projectors[i].uci= project_camera_info(projectors[i].ob, NULL, aspx, aspy);
+                               free_uci= 1;
+                       }
+                       else if(cam->type == CAM_PERSP) {
                                float perspmat[4][4];
                                float xmax; 
                                float xmin;
@@ -3778,15 +3774,15 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
                
                if (cam) {
-                       if (umd->aspectx == umd->aspecty) { 
+                       if (aspx == aspy) { 
                                offsetmat[3][0] -= cam->shiftx;
                                offsetmat[3][1] -= cam->shifty;
-                       } else if (umd->aspectx < umd->aspecty)  {
-                               offsetmat[3][0] -=(cam->shiftx * umd->aspecty/umd->aspectx);
+                       } else if (aspx < aspy)  {
+                               offsetmat[3][0] -=(cam->shiftx * aspy/aspx);
                                offsetmat[3][1] -= cam->shifty;
                        } else {
                                offsetmat[3][0] -= cam->shiftx;
-                               offsetmat[3][1] -=(cam->shifty * umd->aspectx/umd->aspecty);
+                               offsetmat[3][1] -=(cam->shifty * aspx/aspy);
                        }
                }
                
@@ -3799,8 +3795,23 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
        }
 
+       /* make sure we are not modifying the original UV layer */
+       tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
+                       CD_MTFACE, uvname);
+
+       
+       numVerts = dm->getNumVerts(dm);
+
+       coords = MEM_callocN(sizeof(*coords) * numVerts,
+                                "uvprojectModifier_do coords");
+       dm->getVertCos(dm, coords);
+
+       /* convert coords to world space */
+       for(i = 0, co = coords; i < numVerts; ++i, ++co)
+               mul_m4_v3(ob->obmat, *co);
+       
        /* if only one projector, project coords to UVs */
-       if(num_projectors == 1)
+       if(num_projectors == 1 && projectors[0].uci==NULL)
                for(i = 0, co = coords; i < numVerts; ++i, ++co)
                        mul_project_m4_v4(projectors[0].projmat, *co);
 
@@ -3810,17 +3821,26 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        /* apply coords as UVs, and apply image if tfaces are new */
        for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
                if(override_image || !image || tface->tpage == image) {
-                       if(num_projectors == 1) {
-                               /* apply transformed coords as UVs */
-                               tface->uv[0][0] = coords[mf->v1][0];
-                               tface->uv[0][1] = coords[mf->v1][1];
-                               tface->uv[1][0] = coords[mf->v2][0];
-                               tface->uv[1][1] = coords[mf->v2][1];
-                               tface->uv[2][0] = coords[mf->v3][0];
-                               tface->uv[2][1] = coords[mf->v3][1];
-                               if(mf->v4) {
-                                       tface->uv[3][0] = coords[mf->v4][0];
-                                       tface->uv[3][1] = coords[mf->v4][1];
+                               if(num_projectors == 1) {
+                                       if(projectors[0].uci) {
+                                               project_from_camera(tface->uv[0], coords[mf->v1], projectors[0].uci);
+                                               project_from_camera(tface->uv[1], coords[mf->v2], projectors[0].uci);
+                                               project_from_camera(tface->uv[2], coords[mf->v3], projectors[0].uci);
+                                               if(mf->v3)
+                                                       project_from_camera(tface->uv[3], coords[mf->v4], projectors[0].uci);
+                                       }
+                                       else {
+                                               /* apply transformed coords as UVs */
+                                               tface->uv[0][0] = coords[mf->v1][0];
+                                               tface->uv[0][1] = coords[mf->v1][1];
+                                               tface->uv[1][0] = coords[mf->v2][0];
+                                               tface->uv[1][1] = coords[mf->v2][1];
+                                               tface->uv[2][0] = coords[mf->v3][0];
+                                               tface->uv[2][1] = coords[mf->v3][1];
+                                               if(mf->v4) {
+                                                       tface->uv[3][0] = coords[mf->v4][0];
+                                                       tface->uv[3][1] = coords[mf->v4][1];
+                                               }
                                }
                        } else {
                                /* multiple projectors, select the closest to face normal
@@ -3858,23 +3878,32 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                                                best_projector = &projectors[j];
                                        }
                                }
-
-                               mul_project_m4_v4(best_projector->projmat, co1);
-                               mul_project_m4_v4(best_projector->projmat, co2);
-                               mul_project_m4_v4(best_projector->projmat, co3);
-                               if(mf->v4)
-                                       mul_project_m4_v4(best_projector->projmat, co4);
-
-                               /* apply transformed coords as UVs */
-                               tface->uv[0][0] = co1[0];
-                               tface->uv[0][1] = co1[1];
-                               tface->uv[1][0] = co2[0];
-                               tface->uv[1][1] = co2[1];
-                               tface->uv[2][0] = co3[0];
-                               tface->uv[2][1] = co3[1];
-                               if(mf->v4) {
-                                       tface->uv[3][0] = co4[0];
-                                       tface->uv[3][1] = co4[1];
+                               
+                               if(best_projector->uci) {
+                                       project_from_camera(tface->uv[0], coords[mf->v1], best_projector->uci);
+                                       project_from_camera(tface->uv[1], coords[mf->v2], best_projector->uci);
+                                       project_from_camera(tface->uv[2], coords[mf->v3], best_projector->uci);
+                                       if(mf->v3)
+                                               project_from_camera(tface->uv[3], coords[mf->v4], best_projector->uci);
+                               }
+                               else {
+                                       mul_project_m4_v4(best_projector->projmat, co1);
+                                       mul_project_m4_v4(best_projector->projmat, co2);
+                                       mul_project_m4_v4(best_projector->projmat, co3);
+                                       if(mf->v4)
+                                               mul_project_m4_v4(best_projector->projmat, co4);
+
+                                       /* apply transformed coords as UVs */
+                                       tface->uv[0][0] = co1[0];
+                                       tface->uv[0][1] = co1[1];
+                                       tface->uv[1][0] = co2[0];
+                                       tface->uv[1][1] = co2[1];
+                                       tface->uv[2][0] = co3[0];
+                                       tface->uv[2][1] = co3[1];
+                                       if(mf->v4) {
+                                               tface->uv[3][0] = co4[0];
+                                               tface->uv[3][1] = co4[1];
+                                       }
                                }
                        }
                }
@@ -3886,7 +3915,15 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        }
 
        MEM_freeN(coords);
-
+       
+       if(free_uci) {
+               int j;
+               for(j = 0; j < num_projectors; ++j) {
+                       if(projectors[j].uci) {
+                               MEM_freeN(projectors[j].uci);
+                       }
+               }
+       }
        return dm;
 }
 
index 8e9a851..a77ca60 100644 (file)
@@ -23,6 +23,7 @@
 #define BKE_UVPROJECT_H
 
 struct UvCameraInfo;
+struct Object;
 
 /* create uv info from the camera, needs to be freed */
 struct UvCameraInfo *project_camera_info(struct Object *ob, float rotmat[4][4], float winx, float winy);
index d6ba2d7..273cb01 100644 (file)
@@ -36,7 +36,7 @@ typedef struct UvCameraInfo {
        float shiftx, shifty;
        float rotmat[4][4];
        float caminv[4][4];
-       short do_persp, do_pano;
+       short do_persp, do_pano, do_rotmat;
 } UvCameraInfo;
 
 void project_from_camera(float target[2], float source[3], UvCameraInfo *uci)
@@ -47,7 +47,8 @@ void project_from_camera(float target[2], float source[3], UvCameraInfo *uci)
        pv4[3]= 1.0;
 
        /* rotmat is the object matrix in this case */
-       mul_m4_v4(uci->rotmat, pv4);
+       if(uci->do_rotmat)
+               mul_m4_v4(uci->rotmat, pv4);
 
        /* caminv is the inverse camera matrix */
        mul_m4_v4(uci->caminv, pv4);
@@ -87,7 +88,7 @@ void project_from_view(float target[2], float source[3], float persmat[4][4], fl
 {
        float pv[3], pv4[4], x= 0.0, y= 0.0;
 
-       mul_m4_v3(rotmat, pv);
+       mul_v3_m4v3(pv, rotmat, source);
 
        copy_v3_v3(pv4, source);
        pv4[3]= 1.0;
@@ -123,7 +124,7 @@ void project_from_view(float target[2], float source[3], float persmat[4][4], fl
 
 /* 'rotmat' can be obedit->obmat when uv project is used.
  * 'winx' and 'winy' can be from scene->r.xsch/ysch */ 
-UvCameraInfo *project_camera_info(Object *ob, float rotmat[4][4], float winx, float winy)
+UvCameraInfo *project_camera_info(Object *ob, float (*rotmat)[4], float winx, float winy)
 {
        UvCameraInfo uci;
        Camera *camera= ob->data;
@@ -138,7 +139,13 @@ UvCameraInfo *project_camera_info(Object *ob, float rotmat[4][4], float winx, fl
                UvCameraInfo *uci_pt;
 
                /* normal projection */
-               copy_m4_m4(uci.rotmat, rotmat);
+               if(rotmat) {
+                       copy_m4_m4(uci.rotmat, rotmat);
+                       uci.do_rotmat= 1;
+               }
+               else {
+                       uci.do_rotmat= 0;
+               }
 
                /* also make aspect ratio adjustment factors */
                if (winx > winy) {
@@ -166,7 +173,7 @@ void project_from_view_ortho(float target[2], float source[3], float rotmat[4][4
 {
        float pv[3];
 
-       mul_m4_v3(rotmat, pv);
+       mul_v3_m4v3(pv, rotmat, source);
 
        /* ortho projection */
        target[0] = -pv[0];