Upgrades to the UVProject modifier:
authorBen Batt <benbatt@gmail.com>
Wed, 22 Nov 2006 15:09:41 +0000 (15:09 +0000)
committerBen Batt <benbatt@gmail.com>
Wed, 22 Nov 2006 15:09:41 +0000 (15:09 +0000)
 - New perspective projection capability. If a camera is used as the
   projection object, the modifier detects whether to do perspective or
   orthographic projection based on the camera type. If any other object
   type is used as the projection object, orthographic projection is used.
 - Orthographic projection actually works properly now.
 - The projected UVs are scaled and offset so that the image is centred in
   the projecting camera's view.
 - AspX and AspY inputs have been added to control the aspect ratio of the
   projected UVs.

Also:
 - I have added the Mat4MulVec3Project() function to BLI_arithb.h; this
   function converts a 3-dimensional vector to homogeneous coordinates
   (4-dimensional, with the 4th dimension set to 1), multiplies it with the
   given matrix, then projects it back to 3 dimensions by dividing through
   with the 4th dimension. This is useful when using projection matrices.

source/blender/blenkernel/intern/modifier.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/src/buttons_editing.c

index d87d8b528d9701c7c4e3a70ca55ee93686f3741c..92a4df5ca277ad3242dee7f2be3da3e76dee82d2 100644 (file)
@@ -2477,6 +2477,7 @@ static void uvprojectModifier_initData(ModifierData *md)
        umd->image = NULL;
        umd->flags = MOD_UVPROJECT_ADDUVS;
        umd->num_projectors = 1;
+       umd->aspectx = umd->aspecty = 1.0f;
 }
 
 static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target)
@@ -2490,6 +2491,8 @@ static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target)
        tumd->image = umd->image;
        tumd->flags = umd->flags;
        tumd->num_projectors = umd->num_projectors;
+       tumd->aspectx = umd->aspectx;
+       tumd->aspecty = umd->aspecty;
 }
 
 static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob,
@@ -2531,7 +2534,7 @@ static void uvprojectModifier_updateDepgraph(ModifierData *md,
 
 typedef struct Projector {
        Object *ob;                             /* object this projector is derived from */
-       float imat[4][4];               /* world space -> projector space matrix */ 
+       float projmat[4][4];    /* projection matrix */ 
        float normal[3];                /* projector normal in world space */
 } Projector;
 
@@ -2546,6 +2549,10 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        int new_tfaces = 0;
        Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
        int num_projectors = 0;
+       float aspect;
+       
+       if(umd->aspecty != 0) aspect = umd->aspectx / umd->aspecty;
+       else aspect = 1.0f;
 
        for(i = 0; i < umd->num_projectors; ++i)
                if(umd->projectors[i])
@@ -2573,38 +2580,79 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
        for(i = 0, co = coords; i < numVerts; ++i, ++co)
                Mat4MulVecfl(ob->obmat, *co);
 
-       if(num_projectors == 1) {
-               float imat[4][4];
-
-               /* get projector space matrix */
-               Mat4Invert(imat, projectors[0].ob->obmat);
-               if(projectors[0].ob->type == OB_CAMERA) {
-                       Camera *cam = (Camera *)projectors[0].ob->data;
-                       if(cam->type == CAM_ORTHO)
-                               Mat4MulFloat3(imat[0], 1 / cam->ortho_scale);
-               }
+       /* calculate a projection matrix and normal for each projector */
+       for(i = 0; i < num_projectors; ++i) {
+               float tmpmat[4][4];
+               float offsetmat[4][4];
+
+               /* calculate projection matrix */
+               Mat4Invert(projectors[i].projmat, projectors[i].ob->obmat);
+
+               if(projectors[i].ob->type == OB_CAMERA) {
+                       Camera *cam = (Camera *)projectors[i].ob->data;
+                       if(cam->type == CAM_PERSP) {
+                               float perspmat[4][4];
+                               float xmax; 
+                               float xmin;
+                               float ymax;
+                               float ymin;
+                               float pixsize = cam->clipsta * 32.0 / cam->lens;
+
+                               if(aspect > 1.0f) {
+                                       xmax = 0.5f * pixsize; 
+                                       ymax = xmax / aspect;
+                               } else {
+                                       ymax = 0.5f * pixsize;
+                                       xmax = ymax * aspect; 
+                               }
+                               xmin = -xmax;
+                               ymin = -ymax;
+
+                               i_window(xmin, xmax, ymin, ymax,
+                                        cam->clipsta, cam->clipend, perspmat);
+                               Mat4MulMat4(tmpmat, projectors[i].projmat, perspmat);
+                       } else if(cam->type == CAM_ORTHO) {
+                               float orthomat[4][4];
+                               float xmax; 
+                               float xmin;
+                               float ymax;
+                               float ymin;
+
+                               if(aspect > 1.0f) {
+                                       xmax = 0.5f * cam->ortho_scale; 
+                                       ymax = xmax / aspect;
+                               } else {
+                                       ymax = 0.5f * cam->ortho_scale;
+                                       xmax = ymax * aspect; 
+                               }
+                               xmin = -xmax;
+                               ymin = -ymax;
 
-               /* convert coords to projector space */
-               for(i = 0, co = coords; i < numVerts; ++i, ++co)
-                       Mat4MulVecfl(imat, *co);
-       } else {
-               /* calculate a world space -> projector space matrix and normal 
-                * for each projector
-                */
-               for(i = 0; i < num_projectors; ++i) {
-                       Mat4Invert(projectors[i].imat, projectors[i].ob->obmat);
-                       if(projectors[i].ob->type == OB_CAMERA) {
-                               Camera *cam = (Camera *)projectors[i].ob->data;
-                               if(cam->type == CAM_ORTHO)
-                                       Mat4MulFloat3(*projectors[i].imat, 1 / cam->ortho_scale);
+                               i_ortho(xmin, xmax, ymin, ymax,
+                                       cam->clipsta, cam->clipend, orthomat);
+                               Mat4MulMat4(tmpmat, projectors[i].projmat, orthomat);
                        }
-                       projectors[i].normal[0] = 0;
-                       projectors[i].normal[1] = 0;
-                       projectors[i].normal[2] = 1;
-                       Mat4Mul3Vecfl(projectors[i].ob->obmat, projectors[i].normal);
+               } else {
+                       Mat4CpyMat4(tmpmat, projectors[i].projmat);
                }
+
+               Mat4One(offsetmat);
+               Mat4MulFloat3(offsetmat[0], 0.5);
+               offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
+               Mat4MulMat4(projectors[i].projmat, tmpmat, offsetmat);
+
+               /* calculate worldspace projector normal (for best projector test) */
+               projectors[i].normal[0] = 0;
+               projectors[i].normal[1] = 0;
+               projectors[i].normal[2] = 1;
+               Mat4Mul3Vecfl(projectors[i].ob->obmat, projectors[i].normal);
        }
 
+       /* if only one projector, project coords to UVs */
+       if(num_projectors == 1)
+               for(i = 0, co = coords; i < numVerts; ++i, ++co)
+                       Mat4MulVec3Project(projectors[0].projmat, *co);
+
        mface = dm->getFaceArray(dm);
        numFaces = dm->getNumFaces(dm);
 
@@ -2660,11 +2708,11 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                                        }
                                }
 
-                               Mat4MulVecfl(best_projector->imat, co1);
-                               Mat4MulVecfl(best_projector->imat, co2);
-                               Mat4MulVecfl(best_projector->imat, co3);
+                               Mat4MulVec3Project(best_projector->projmat, co1);
+                               Mat4MulVec3Project(best_projector->projmat, co2);
+                               Mat4MulVec3Project(best_projector->projmat, co3);
                                if(mf->v4)
-                                       Mat4MulVecfl(best_projector->imat, co4);
+                                       Mat4MulVec3Project(best_projector->projmat, co4);
 
                                /* apply transformed coords as UVs */
                                tface->uv[0][0] = co1[0];
index c478262d500fb8ccff2e0b0dee9c530d0aa00d63..fa7c05cce7c965b3be475bb66c3378cfec4096c8 100644 (file)
@@ -400,6 +400,11 @@ Mat3Clr(
        void 
 Mat3One(
        float m[][3]
+);
+       void
+Mat4MulVec3Project(
+       float mat[][4],
+       float *vec
 );
        void 
 Mat4MulVec(
index fd91a4231f67c456bbe1f8699196efa402244bff..de06fd3365d05aac96c99c16e24476e7540431f6 100644 (file)
@@ -838,6 +838,18 @@ void Mat4Mul3Vecfl( float mat[][4], float *vec)
        vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
 }
 
+void Mat4MulVec3Project(float mat[][4], float *vec)
+{
+       float w;
+
+       w = vec[0]*mat[0][3] + vec[1]*mat[1][3] + vec[2]*mat[2][3] + mat[3][3];
+       Mat4MulVecfl(mat, vec);
+
+       vec[0] /= w;
+       vec[1] /= w;
+       vec[2] /= w;
+}
+
 void Mat4MulVec4fl( float mat[][4], float *vec)
 {
        float x,y,z;
index 50cffb89872bff40d9dff28554d2f6255ea7ffbc..1665c0da98323aaf6a054bbddee928a5f059ca9e 100644 (file)
@@ -206,6 +206,7 @@ typedef struct UVProjectModifierData {
        struct Image *image;      /* the image to project */
        int flags;
        int num_projectors;
+       float aspectx, aspecty;
 } UVProjectModifierData;
 
 #define MOD_UVPROJECT_MAXPROJECTORS 10
index b5e7d2b539e08f32ed39aa69dd931519403c3c48..78771cac20c908e373fdba8e68d28865ca6bf2af 100644 (file)
@@ -1355,7 +1355,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                        height = 124;
                        if(dmd->texmapping == MOD_DISP_MAP_OBJECT) height += 19;
                } else if (md->type==eModifierType_UVProject) {
-                       height = 67 + ((UVProjectModifierData *)md)->num_projectors * 19;
+                       height = 86 + ((UVProjectModifierData *)md)->num_projectors * 19;
                } else if (md->type==eModifierType_Decimate) {
                        height = 48;
                } else if (md->type==eModifierType_Wave) {
@@ -1509,6 +1509,15 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                                     lx, (cy-=19), buttonWidth, 19,
                                     &umd->flags, 0, 0, 0, 0,
                                     "Add UV coordinates if missing");
+                       uiDefButF(block, NUM, B_MODIFIER_RECALC, "AspX:",
+                                 lx, (cy -= 19), buttonWidth / 2, 19, &umd->aspectx,
+                                 1, 1000, 100, 2,
+                                 "Horizontal Aspect Ratio");
+                       uiDefButF(block, NUM, B_MODIFIER_RECALC, "AspY:",
+                                 lx + (buttonWidth / 2) + 1, cy, buttonWidth / 2, 19,
+                                 &umd->aspecty,
+                                 1, 1000, 100, 2,
+                                 "Vertical Aspect Ratio");
                        uiDefButI(block, NUM, B_MODIFIER_RECALC, "Projectors:",
                                  lx, (cy -= 19), buttonWidth, 19, &umd->num_projectors,
                                  1, MOD_UVPROJECT_MAXPROJECTORS, 0, 0,