Hi James Whitman here for PlugInEverything.com
And today we're going to look at how to create an art effects plugin
First thing you want to do is type in After Effects SDK into Google and you'll get this page
Then click get the SDKs and that will give you a download. That looks something like this got the
Manual and then some examples in here
We want under template skeleton and I'd recommend open visual studio in
Administrator mode because otherwise you probably won't be able to build the plugin and if you're on Mac
You won't have Visual Studio. You'll have Xcode. So in Windows we want to open the skeleton dot solution
And then once that's loaded, let's go to skeleton dot CPP and we're interested firstly in the render function
This is a skeleton template project. It actually does something. It's not very exciting
It just fills the screen with a solid color. So we're gonna delete all this stuff here
And we're also gonna delete the help of functions my simple gain func
Course analysis clean if we ran this the plug-in wouldn't do anything at all
It would just be playing what we want to do is draw a straight line and for that we're going to use an algorithm called
bresson Hamm's
line algorithm just typed in bresenhem's line algorithm and
Found this website the crazy programmer. He's pretty crazy. He's got an algorithm here that I'm gonna pinch
this is the function that draws a line and
we're gonna place it outside the render function and
You'll see it has a reference to a function called put pixel
which essentially it takes an x and
Y-coordinate and then draws that pixel a certain color
the way we're going to color pixels is first we need access to those pixels have a look in the
Sdk, and we open up the sdk guide on page 140
There is a function that does that for us
So i'm just going to copy that we want the sample integral 32
not the 64 because the 32 bit 1 that's going to allow us to
Work with 8 bits per channel. So it's 32 because there's a red green blue and 4 times 8 is 32
What this function does?
Is it returns a pixel?
it's actually a pointer to a pixel what we need to supply it is an effect world and an X and y coordinate an
Effect world is kind of like a frame buffer or a texture. It's it's the image that we want
Or the canvas rather that we want to draw to
Instead of saying put pixel x and y we're going to say we want to have a pixel
PF pixel and
We're going to call it my pixel and then we want to say that this pixel is equal to sample
Integral 32, then we will provide it with a frame buffer
We'll call it the output and then an X and y coordinate so we'll just supply the X and y coordinate now
We currently don't have access to the output
so what we'll do is just
Put that in here add in a PF effect world and we're going to make it a pointer and we're gonna call this the output
And this should actually be a pointer not an actual pixel and then we should supply that as a pointer as well
Now that we have a pointer to the pixel that we use wanted to sample. We can color blue Mario my pixels red equals
255 which is the brightest value that an eight bits per channel
Pixel can have and we might also want that to be on the Alpha. So I'll say my pixel
red equals my
pixel alpha
Which equals to 255 that will feel the pixel with red if we fill it with red
But the Alpha was zero, then the pixel would be blank because it would be it would be red a red pixel
But it would be transparent so we don't want that and then we're just gonna copy this function to here as well
Now we have our draw line function. We actually need to call it. So let's call it in here draw a line
and then we need to supply an X and y coordinate and x and y corn a
Gentile let's just supply it X Y x1. Y1
And output now we don't have those coordinates yet. So we'll create those
XY
X1 y1 and a long if you just go into it is just the aftereffects way to refer to an integer
now we might want to initialize these so X can be 0
Y can also be 0 and then so these are the start coordinates and then x1 and y1 can be the end coordinates
so I'm gonna make that the
Width of the entire canvas that x and y are going to be on the bottom left
so the bottom right of the output
if I start x and y are up at the top left of the screen and our
x1 and y1 a the bottom right of the screen
It's going to draw a line from the top left of the screen to the bottom right of the screen
And now we're ready to test out our plug-in we want to be in
Debug mode and then we want to select skeleton hit alt enter and we want to make sure that our output
directory is building it to where we want it to be but I've got a macro that points to
artifacts cc 2018 and then under debugging we want the
command to be
after-effects so if we hit edit
We can
actually use After Effects, so I'm gonna use a
ECC 2018 which is a macro that I have that points to after-effects and
hit apply on that now, let's
press local windows debugger that's gonna build and
run
After-effects we want to do in after-effects
it's just pretty much build a blank solid and then
Our plugins gonna be called skeleton and it looks good if we chose to 16 bits per channel
It's not really gonna work because we're only working at 8 bits per channel, but in 8 bits per channel
it does work nicely if we wanted it to work at other bit depths we'd have to do some more work and I don't really
Want to do that but this is a pretty boring line because it's always locked to the top left in the bottom, right?
Let's build a user interface so that we can actually control where this line is. Go back into visual studio and stop that
Let's go under skeleton to
Set up and here we currently have two parameters. I'm going to get rid of the first one
Now we want to find the macro PF add
point because we want to add a
Start and end point for our line and this is a macro here and it takes the arguments name x-default
Why default restrict bounds and an ID the name is a string will call this start and then we want an extra fault
Which is percentage based so we want the left to be at the top right then we're going to for restrict balance
That's a boolean
We're gonna save false and then the idea is gonna be start ID, which we haven't actually declared yet
so don't worry about that yet and
Then you want to after declaring each parameter clear the struct to make sure you're starting again with a clean
parameter and
Let's work on the second one. It's gonna be an end and we'll call this and
ID and
Then we want to set the X&Y default to
100 and 100 actually
let's go 75 75 and start at 25 25 and then we have a color and
We can use that to choose the color of our line. Now. We need to declare these IDs here. I can do that under headers
Skeleton not age. So these are the IDS that it's referring to so we had a start
ID and that this first one should be equal to once it's an enumeration and then we have the end ID
Which will be equal to 2 then we deleted this parameter the game disk
And I'm just gonna simplify this to color ID because we're gonna keep that we also have another enumeration up here
We want to make the same changes in this enumeration
The input is the very first one at 0 and then we have the start and you're just prefixed with the name of the plug-in
So I'm going to call it skeleton start
Skeleton and and then we've got skeleton color and at the moment this enumeration
Actually lines up with the second enumeration. You might be wondering why do we have two enumerations?
That's because this one is allowed the order of it is allowed to change but this one it's not allowed to change
Eventually, they might not match up when we declare parameters. We use the ideas here for going to params set up
I just need to change this one to
Color ID because I changed it and then we want to in the render function
access the parameters
we will refer to it by the skeleton prefix and we access these through the params array X is going to be params and
That's an array so then we identify which
element we want and that would be skeleton start and then we point that to you and then which kind of parameter this is a
Point def which is what we have is referred to as TD. I don't know why
And then we want the x value of that and I think for legacy reasons
This value is actually a fixed value. We need to convert that to an integer so we can use the macro
fix to
Float, which will just I believe divided by
65,000 or something. We can check what that does. Yeah
65536 and that will give us the value that we want even though this is going to return a float value
We are sampling whole values. So that's why we referring to it as an integer
That's X Y will refer to the same but the Y value then x1
will refer to the skeleton and
X value Y will be similar but refer to
The Y value and let's just neaten this up a bit
Got the start and the end values X and YX and y let's also pass this a color. We want to P a
Pixel and we'll call this color and then let's access it from the params
Skeleton color and then we want your CD which is color def which kind of makes more sense
got value and then we can pass that to our
draw line function pass it in after the
Output and this will be a PF
Pixel called color and then what we want to do is say instead of defining
This hard-coded red value here. We can say my pixal equals color, but this is a pointer
So we want to say what?
Point is pointing to should be equal to the value of the color that we pass in now we just want to make sure
that the color that we got has an alpha value because the color picker I don't think
Has an alpha value so we're going to just set that to 255 here
before we pass it in and then that way we don't have to worry about the Alpha because we know it's going to be
255 now let's just make sure that we copy the same
I like to rebuild if I change the parameters at all just so that it can refresh any of the resources that it has
Otherwise you might have trouble and we got a warning which was treated as an error. So let's just turn off
Warnings treated as errors under C C++ that by default is set to yes
But I don't care about warnings. Let's go build rebuild and then let's launch the debugger
create another solid and add skeleton and there we have it we have our
start and
Our end and the reason that that is here and there is because it starts at 25%
In and ends at 75% in what we set in our parameter defaults
You could move this around and even keyframe those and we also have a color which we can change which is nice
Let's just play with our algorithm. We can see there's a problem some cases. It doesn't really work
I guess the algorithm isn't very robust that might need to be improved
We just got an exception
We tried to access a pixel that actually doesn't exists fix that by checking that we don't sample any pixels
Outside of the buffer. Let's write a function
that takes in the x and
y-coordinate and the output buffer and will tell us whether the coordinates that we passed it or actually in or out will
Return a boolean value and we'll call this is inside
X coordinate the y coordinate and then the output buffer or the buffer whichever buffer we passed to it
And we're going to refer to it as the output and then we'll have a boolean value
is
Inside and we're gonna say it's not inside by default. It's just to be safe and we need spells correctly and
Then if a certain condition is met then is inside
its going to evaluate to true and
Then we will return
Is inside
The condition will have to be that X has to be greater than zero because if we pass it a coordinate that was say negative
Then it would be out of the bounds. So X has to be greater than zero
Y has to be greater than zero
X has to be less than the buffers width
and
Y has to be less than the buffers height
Because if for the x-coordinate was greater than the width it would obviously be out-of-bounds same with the height
But all these conditions are met then the coordinates that have passed
Are inside the bounds and therefore we will return true. Otherwise, we will return false now we can do is say if
Is inside which is going to run that function and we need to pass it the coordinates X
Y
output
Only if that's true
Will we color the pixel? Let's copy that again make sure it's the same here and
Let's run it again
And now let's draw it out of bounds and we can see that the plug-in does not crash
Thankfully although it still plays up you might have also noticed that this line is quite ugly and that would be a very keen
Observation that's because this line does not have any
anti-aliasing if you wanted an algorithm that would create a nice smooth line I recommend
Shaolin Wu's I'm not sure if that's how you pronounce it. Here's algorithm which draws a anti aliased line
Another solution might be to use a third-party library like Cairo which can draw anti aliased lines
It can draw Bezier lines or even OpenGL, but that might be a little bit overkill
This one is a little bit more code
but the result is much better than our very stair-step line because you'll notice that we're only ever
Drawing full pixels. We're not drawing transparent pixels the algorithm detects if it's either on or off
It's a boolean state and that's why it doesn't look so crash hot
But other algorithms can draw transparent pixels to create the illusion of a straight line
Thank you for watching and make sure you check out plugging everything
Com where we have lots of cool After Effects plugins, and we even have some free ones
