Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

HELP: How to sync a plugin parameter to a layer transform's position ?

Explorer ,
Jan 24, 2023 Jan 24, 2023

Hi everyone, 

 

I have written a plugin that checkouts a layer (PF_ADD_LAYER) and displays it on the layer the effect is applied to. I've also made it possible to control the position of the displayed layer through controls on the effect's UI (PF_ADD_POINT for the position for example, PF_ADD_ANGLE for the rotation etc).

 

My question is: how can I automatically sync these transform parameters (position, rotation, scale...) to the selected source layer's transform data, so the checkout layer is displayed at the same position as the original layer ? Yes it is possible to do it through the traditional After Effects' expressions. But I was looking for a way to do it automatically within the plugin.

 

screenshot.jpg

TOPICS
SDK
1.8K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jan 24, 2023 Jan 24, 2023

You probably simply need to query the default property streams, instanciate them and weave them into your matrices. 

 

Mylenium 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Jan 24, 2023 Jan 24, 2023

Are you wanting your plugin's transform params to be synced to your original layers transforms? The only way is by expressions since params can't be updated on the fly through c++ plugins. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 25, 2023 Jan 25, 2023

short answer: highly unrecommended.

 

long answer:

well... there no "link" method (besides expressions, as you have said). you can check the values on idle time and then copy them if changed, but that won't work during rendering. it would also be problematic with undo/redo as the user may be aditing the target layer...

 

my suggestion is to add a drop down with 2 options:

1. manual controls

2. follow original layer

if 1 is seleted, show the controls. if 2 is selected hide the controls and get the values from the original layer.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 27, 2023 Jan 27, 2023

Thanks a lot for your answer. I've managed to implement the first option, however I struggle to implement the second one:

I am able to get the selected source layer's transform data (position, rotation...) using the AEGP_SuiteHandler methods. However I am not sure how to watch for changes on this data. I tried creating another thread and check the values each second. But it doesn't work and I don't like this solution. Is there another cleaner method to do it?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 27, 2023 Jan 27, 2023

lookup GuidMixInPtr.

it's means of telling AE during SmartPreRender calls what external data (that is not directly referenced by the effect using traditional methods) this render relies on. AE calls pre-render whenever there's a change in the comp, to let effects report if they were relying on some external data that might have changed.

if the resulting GUID differs from the one AE has associated with the cached frame, AE invalidates the cahce and re-renders.

you can factor anything you like into the GuidMixInPtr function, including the transform data of some random layer.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 28, 2023 Jan 28, 2023

Thanks a lot for your great answer. I've managed to implement what you've said and the effect re-renders when, for example, the opacity of the source layer has changed. However it does not work properly when the source layer has the opacity animated with keyframes. When I push the play button, it just flickers a lot.

Here is my code to get the opacity. Is there something specific to do in order to get the value at the current time, even with keyframes ?

PF_Err get_layer_opacity(AEGP_SuiteHandler& suites, AEGP_LayerH* layer_handle, AEGP_StreamValue2* outValue) {
    PF_Err err = PF_Err_NONE;

    A_Time thisTime;
    AEGP_StreamRefH stream;

    ERR(suites.LayerSuite8()->AEGP_GetLayerCurrentTime(*layer_handle, AEGP_LTimeMode_LayerTime, &thisTime));
    ERR(suites.StreamSuite4()->AEGP_GetNewLayerStream(globalID, *layer_handle, AEGP_LayerStream_OPACITY, &stream));
    ERR(suites.StreamSuite4()->AEGP_GetNewStreamValue(globalID, stream, AEGP_LTimeMode_LayerTime, &thisTime, FALSE, outValue));

    return err;
}

And here is my code included in the PreRender function:

    if (extra->cb->GuidMixInPtr) {
        AEGP_SuiteHandler suites(in_data->pica_basicP);

        get_layer_handle(suites, in_data, &currentLayer);

        if (currentLayer) {
            get_layer_opacity(suites, &currentLayer, &opacityValue);
        }
            
        extra->cb->GuidMixInPtr(in_data->effect_ref, sizeof(opacityValue), reinterpret_cast<void*>(&opacityValue));
    }

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 28, 2023 Jan 28, 2023

about AEGP_GetLayerCurrentTime, it refers to the current time of the time marker in the comp's UI, not the currently rendered frame.

quoting from the sdk guide: "Get current time, in layer or composition timespace. This value is not updated during rendering."

 

you should convert time time from the in_data to comp time using AEGP_ConvertLayerToCompTime, and then get the layer time using the comp time flag. (or convert back to layer time using AEGP_ConvertCompToLayerTime)

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 29, 2023 Jan 29, 2023

Man you are amazing! That was it. It works well. I feel I am almost there!  The only thing is that when I push the memory usage to the max (99% of ram usage), I've got an exception thrown "error memory violation". However I've taken care to dispose all effects worlds and streams, as well as check for null pointers. Have you ever had this kind of error ? Also, I feel like  purging the memory in After Effects does not do anything to remove the memory allocated to my effect. The ram memory usage stays the same.
Thanks again for your time, it means a lot! 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 29, 2023 Jan 29, 2023

nope. never had that error. you'll need to do some elimination work by shutting down parts of your code until you see a change in ram consumption.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 01, 2023 Feb 01, 2023

Hi shachar,

I’ve made progress with my plug-in! And I’ve come up with the idea that it’s easier to set an expression on my plugin’s transform parameters (position, rotation, scale etc), so they get the exact same value as the checkout layer’s transform data. I need to do this in the plugin’s code, as it is easy to get the correct updated layer’s index with AEGP, even if the layer has moved in the comp.

However I’m having trouble setting an AE expression in c++: when setting the expression, AE throws a warning “A plug-in is attempting to do an invalid operation: modifying a locked project”.

Do you have an idea on how to fix this ?

Thanks in advance!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 01, 2023 Feb 01, 2023

that error message means you're trying to modify the "render" copy of the project. since CC2015 AE handles 2 copies of the project in parallel. the UI project is where the user operates, while the render project is a read only copy of the UI project that is intentionally locked so that the UI can remain resonsive while rendering.

AE syncs changes only from the UI copy to the render copy, and forbids plug-ins from making changes to the render copy. how do you know which copy you're operating on? during pre-render and smart-render calls, it's the render copy that's in use. so don't attempt any project changes from these calls.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 03, 2023 Feb 03, 2023

Okay thanks a lot Shachar!

Just in case, is there a way to checkout a layer with all its transform data already applied on it? Because the checkout parameter only displays the layer but we loose all the transform data. So I feel like I am reinventing the wheel here, by performing again all the transformations of the original layer...

The idea is just to clone a layer (with all its transform data) into another layer through a plugin. So if users make any changes on the original layer, it is reflected into the layer the effect is applied on. Is that possible?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 03, 2023 Feb 03, 2023

sadly no. but wait! it gets worse!

reading the parameters transform parameters doesn't take into account orientation or parenting. you can use AEGP_GetLayerToWorldXform to get the layer's transformation matrix post all parenting ect, and you can apply that directly into transform_world. so far so good.

and here's where it gets worse... the layer might be a 3D layer, in which case transform_world won't help. you can get the 4x4 transformation matrix for that layer, but you'll need to build your own 3D transformation rendering function, as AE doesn't supply one via the SDK.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 03, 2023 Feb 03, 2023

Oh... but it is possible to manage 3D transformations using usual matrix operations right ? What do you mean with "building my own rendering function", a renderer ???

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 03, 2023 Feb 03, 2023

for 3D transformations 4x4 matrices are used. the math is the same.

as for rendering, you only need to render texture transformation. not to handle polygon culling, shading, reflctions ect. just to get the gomtry right. having said that, yes, you can call it a renderer.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 04, 2023 Feb 04, 2023

Oh wow... why Adobe makes it so difficult to develop a simple plug-in ?

Maybe that's why there is no a built-in "Transfom 3D" effect...

Do you have any code that is public domain that I may use to start with 3D transformation rendering function ? I am not sure I have seen something like that in the SDK's examples.

Thanks a lot for your advices 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 04, 2023 Feb 04, 2023

i agree that this is something that is sorely missed in the SDK. i also do not know of a free library that does that. perhaps cairo would? to cairo doesn't do 32bpc to the best of my knowledge.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 06, 2023 Feb 06, 2023

Hi Shachar,

I think I understand much better what you meant by "building my own 3D transform function". I was playing with AEGP_GetLayerToWorldXform (which by the way is exactly what I was looking for earlier): we get a full 4x4 matrix with all the transformation of a layer (2D and 3D)

However the transform_world function used to transform an Effect_world only takes a matrix 3x3 as argument. And therefore only works for 2D transformations.

So I need to write a transform_world_3d function. But I am really not sure how to approach this. I surely do not want to create an Artisan, as I don't want to create a whole renderer just for this... 

Is there a way to retrieve the current matrix of a 3D effect world to do some operations on it, or a way to set the transform matrix of an effect world ?

I am a bit stuck here on how to start implementing this function.. what would be your approach for this kind of situation?


Thanks a lot for your time

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 06, 2023 Feb 06, 2023
LATEST

I don't think cairo can do 3d transforms unfortunately. The now deprecated GLator sample was handy for this, but it has been replaced by a compute pipeline. You can take the new procAmp sample and turn it into a render pipeline for 3d transforms but it's a fair amount of work. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines