Skip to main content
Inspiring
February 25, 2024
Beantwortet

Writing a Plugin that scales the layer applied to

  • February 25, 2024
  • 2 Antworten
  • 2248 Ansichten

Hi, im new to writing ae plugins and wanted to try figure out how to write a simple plugin that can scale the footage,layer etc... of what its applied to. 

 

i understand in logic of how to do it:

 

find out layer w&h in pixels

CurrentscaleX = 100;

CurrentScaleY = 100;

 

scaleP.ScaleMultipler = params[EXAMPLE_SCALE]->u.fs_d.value / 100;     ie 101/100= 1.01 scale increase  

 

if (ScaleP ) {

 NewscaleX = CurrentScaleX * Scale Multiplier; 

 NewscaleY = CurrentScaleY * Scale Multiplier; 

 

CurrentScaleX = NewScaleX;

CurrentScaleY = NewScaleY;

}

 

but as to writing that logic into a format the sdk can understand i have no idea. would be great if i could get a bit of help.

Beste Antwort von Mallowed

oh gawd no! construct one matrix and do the transormation only once. both for performance sake and for not re-sampling the image 3 times which will blur your image in a nasty way.

 

you're putting the correct stuff in the correct places in the matrix, but these operations need to be multiplied as whole matrices for each of the transformation operations, and not multiplying the separate components in the matrix.

lookup matrix multiplication. you'll find a function in no time.

 

but here's some shortcuts before going on this adventure:

the default matirx which does nothing is rederred to as "identity mtrix". it's filled as follows:

1, 0, 0,

0, 1, 0,

0, 0, 1,

use that as the base for each of your separate transform, scale and rotate matrices, and then multiply them.

 

2. matrix operations happen relative to the top left corner of the image. if you want it relative to the center you need to first create an transpose matrix for half the width and height.

so what you'd actually want to do to construct a proper transformation matrix is:

1. create a transpose matrix for negative the anchor point value. that moves the image's pivot point to the matrix's 0,0 coordinate.

2. multiply that matrix by the scale matrix, which will now happen around the anchor point.

3. multiply the previous result by the rotation marix (again, will happen aroung the expected point)

4. multiply the previous result by another transform matrix with the x/y position values.

that's it. your matrix is ready to use.

when going more advanced, you'll want to factor in pixel aspext ration as well. it would just mean doing a scaling matrix on x and the begining and end steps.


I cannot thank you enough for all the help through this. i have the image scaling through the slider now without issue, i need to make it scale from the center of the layer but im sure i can figure out the rest myself, i cannot thank you enough through all of this. you are a legend,

 

Mal

2 Antworten

Community Expert
February 25, 2024

generally speaking, a plug-in receives an input buffer with pixels to mnipulate, and an output buffer to put the results into. *how* the output buffer is filled is entirely up to you. AE doesn't care.

so to scale your image you could use your won algorithm to shuffle pixels around, use 3rd party libraries, OR use some of the tools supplied by AE's API.

for example, you could use transform_world() from PF_WorldTransformSuite1 to transpose, scale to rotate an image.

here's a thread talking aobut it:
https://community.adobe.com/t5/after-effects-discussions/help-with-transform-world/m-p/1840909

search the forum for more info, this function has been talked about here on numerous occasions.

Inspiring
February 25, 2024

thank you for this, i saw in the sdk documentation about transform_world() but didnt know how to execute it. do just code it directly into the render section of the cpp file or do i use a err(suites.pf_worldtransfomsuite1 )-> and pass it through to a func8?

 

sorry if this seems like a silly question but still very new to this 

Community Expert
February 26, 2024

thank you that is very usefull information but what im struggling with is the data that world_transfrom() requires,

 

here is what i have so far but is returning a error at the ERR():

 

static PF_Err
Scale8(
void* refcon,
A_long xL,
A_long yL,
PF_Pixel8* inP,
PF_Pixel8* outP)
{
PF_Err err = PF_Err_NONE;
 
ScaleInfo *ScaleP = reinterpret_cast<ScaleInfo*>(refcon);
 
if (ScaleP) {
ScaleP->ScaleFactor;
ScaleP->Amplitude;
ScaleP->translateX;
ScaleP->translateY;
}
 
return err;
}
 
static PF_Err 
Render (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
AEGP_SuiteHandler suites(in_data->pica_basicP);
 
/* SCALEFUNCT. */
 
ScaleInfo ScaleP;
AEFX_CLR_STRUCT(ScaleP); // clears the struct
 
A_long scaleX = 1;
A_long scaleY = 1;
A_long skewX = 0;
A_long skewY = 0;
A_long posX = 0;
A_long posY = 0;
A_long rotationAngle = ScaleP.Amplitude * (M_PI / 180);
 
PF_CompositeMode mode;
 
mode.opacity = 255;
 
mode.opacitySu = 32768;
 
mode.rgb_only = false;
 
mode.xfer = PF_Xfer_IN_FRONT;
 
Matrix2D transformationmatrix;
 
transformationmatrix.a = scaleX * ScaleP.ScaleFactor * cos(rotationAngle);
transformationmatrix.b = skewY * sin(rotationAngle);
transformationmatrix.c = skewX * cos(rotationAngle);
transformationmatrix.d = scaleY * ScaleP.ScaleFactor * sin(rotationAngle);
transformationmatrix.tx = posX + ScaleP.translateX;
transformationmatrix.ty = posY + ScaleP.translateY;
 
PF_Rect dest;
dest.bottom = in_data->height;
dest.left = 0;
dest.right = in_data->width;
dest.top = 0;
 
int quality = PF_Quality_HI;
ScaleP.ScaleFactor = params[MSHAKE_SCALE]->u.fs_d.value;
 
ERR(suites.WorldTransformSuite1()->transform_world( in_data,
quality, // scaling quality? LO/HI = blinear/detail presevering upscale??
0, // probably set to 0?? (ik this is flags and its fine to set to 0 but still dont understand what it does)
PF_Field_FRAME, // field (still not sure what this does)
&params[MSHAKE_INPUT]->u.ld, // src_world (still not sure what this does)
&mode, // comp_mode (not sure what this does)
NULL, // null (no mask data so this takes the whole frame)
&transformationMatrix, // define m - 1 is &m 2 is (&m1, &m2)
1, // matrices amount 1 is transfrom 2 is motion blur and transfrom
true, //src2dts_matrix (still not sure what this does)
&dest, //dest_rect - calc the whole screen
Scale8)); // output (do i pass to my func here?)
 
 
return err;
}

ooohhh... that's a bit of a mess.

first off, the docs are wrong about putting in_data on the first arg. the best way to figure out how to use a callback (if you don't find it in the SDK sample projects) is to go to the function definition in the code. here's what it looks like there:

 

PF_Err (*transform_world)(
PF_ProgPtr effect_ref,
PF_Quality quality,
PF_ModeFlags m_flags,
PF_Field field,
const PF_EffectWorld *src_world,
const PF_CompositeMode *comp_mode,
const PF_MaskWorld *mask_world0,
const PF_FloatMatrix *matrices,
A_long num_matrices,
PF_Boolean src2dst_matrix,
const PF_Rect *dest_rect,
PF_EffectWorld *dst_world);

 

 

so now we can see the first arg is actually the effect_ref (in_data->effect_ref) that should go there, but i put a NULL instead. (otherwise it checks for interrupts)

 

in the last arg, you need to put a PF_EffectWorld, not a function. the output buffer would do. transform_world does the calculations of what pixel goes where according to the passed matrix.

 

for a matrix you need to fill a PF_FloatMatrix. read up on transformation matrices. just note that AE's matrices are column based instead of row based as is usually demostrated, so you might need to change the pocation of the elements from x,y to y,x. (it's called transposing a matrix)

 

about PF_Field_FRAME. frames in videos might be interlaced (where even rows come from one moment in time and odd rows from another). in the in_data, ae tells you is the input is interlaced or not, and you should act accordingly throught your process. if all you do is change pixel colors, then it doesn't matter. if you're doing scaling it matter a lot, because pixels originating from odd lines must end up on odd lines or they will appear on screen at the wrong time. read up on interlacing.

 

src2dst_matrix tells AE that the passed matrix transfroms points from source coordinates to destination coordinates. if set to false, the transformation will be reversed. 

 

PF_CompositeMode tells AE how to treat the incoming pixels in regards to pixels already inside the dst buffer. so it doesn't only transform but only composites the transformed image on top of the existing buffer. hence, the opacity and transfer mode options.

Mylenium
Legend
February 25, 2024