forked from bartvdbraak/blender
Upgrades to the UVProject modifier:
- 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.
This commit is contained in:
parent
03f4a36d73
commit
bb7ad80269
@ -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];
|
||||
/* calculate a projection matrix and normal for each projector */
|
||||
for(i = 0; i < num_projectors; ++i) {
|
||||
float tmpmat[4][4];
|
||||
float offsetmat[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 projection matrix */
|
||||
Mat4Invert(projectors[i].projmat, projectors[i].ob->obmat);
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
|
||||
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];
|
||||
|
@ -400,6 +400,11 @@ Mat3Clr(
|
||||
void
|
||||
Mat3One(
|
||||
float m[][3]
|
||||
);
|
||||
void
|
||||
Mat4MulVec3Project(
|
||||
float mat[][4],
|
||||
float *vec
|
||||
);
|
||||
void
|
||||
Mat4MulVec(
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user