IMPORTANT UPDATE! May 12 13, 2026



Tomorrow Today Last Wednesday, on the 13th of May, the manual Patrons group (the one that gives you your green username AND access to dedicated Patrons spaces on WSL) will be has been DELETED.

This means that your access to those spaces will be has been revoked until you connect your Patreon account to WSL using the link below, which will give you access to the NEW, future-proof Patrons+++ group.

With the imminent release of ZEPPO BETA 2 - tentatively planned for released Friday today yesterday (!!) - I wouldn't dawdle... with Beta 2 (i.e. all my late nights in the past month), Zeppo has become something truly special, battle-tested and multi-user hardened in an actual production.

Yes, there will be a Reactor release eventually, and no, it won't have all the bells and whistles - those are for Patrons, because they are the ones keeping WSL afloat, which is still only barely these days...

I'd better get back to prepping that done did release then!

Thank you,

Pieter


[DEV] Corner Pinner

Where the future is being made, today.

Welcome to the WSL development corner!

In this forum, please post your development projects. You get kudos and feedback here.
Topics ideally have preset prefixes, and this is what they (might) mean:

  • [DEV] - very much work in progress, don't build a business on this, could go anywhere
  • [BETA] - should kinda do what it's supposed to do, please test, give feedback
  • [RC] - this may end up in Reactor soon, polishing up, now's the time for last minute thoughts
  • [ABD] - died a premature death, sadness, will not see the light of day ever (unless someone picks up the scraps)

Once a development project has been released (hurray), topics can be marked as - you guessed it - [RELEASED] :cheer:

Development topics only, please. For generic questions, how-to's, questions and inquiries about existing tools etc, please go to the appropriate other forums.
User avatar
danell
Fusionista
Posts: 588
Joined: 9 years ago
Reactions score: 17
Location: Norrköping
Real name: Jacob Danell
Has thanked: 7 times
Been thanked: 48 times

[DEV] Corner Pinner

#1

Unread post by danell »

I have for a while wanted some more control when working with corner pin (positioners) in Fusion.
We have had the old OpenCL fuse BetterCornerPin but that one doesn't work for later Fusion versions.
Sooo I took opon myself and made a new corner pin fuse!

It takes insperation (and some matrix code) from BetterCornerPin but also adds a lot of nice extra features!


Current features:

  • DCTL driven, so very fast!

  • Set source and destination positions directly in the same node

  • Bi-Linear and Perspective mapping

  • Perspective croppig

  • Show a grid overlay! It uses the grid overlay from the planar tracker so it only shows perspective mapping.

  • Edge sampling

  • Custom clipping

  • Invert the transformation

  • Same overlays as in Corner Positioner

  • Offset sliders!

    • Horizontal

    • Vertical

    • Left

    • Bottom

    • Right

    • Top

  • Copy Src to Dst or Dst to Src.


I also have some features I wish to implement:

Todo features:

  • Figure out a way to genereate/refesh dropdown lists for better tracker-connection


There is bugs dotted around but wanted to get it out already for maybe some ideas :)

Known bugs

  • If DoD exceeds 10.000 or -10.000 and matrix is set to invert the DoD overflows and flips


Changelog:
v0.10 2025-04-14:

  • Updated perspective crop calculation
  • Fixed position preview control if source positions have bin moved
  • You can now connect tracker nodes to source positions
  • Perspective crop now have DoD
  • Fixed show/hide controls correctly when comp is re-opened

v0.9 2025-04-13:

  • Replaced Mapping Type buttons with slider for extra flexibility
  • Fixed Bi-Linear interpolation
  • Added Fill clipping mode

v0.8 2025-04-13:

  • Added quick-connect to tracker node.
  • Fixed bug with DoD not correctly calculated when points are outside the window size.

v0.7 2025-04-01:

  • Cleaned up MapQuad and mat calculations
  • The preview controls now follows the image's corners when any corner is disabled or with offsets

v0.6 2025-03-26:

  • All enable-combinations now works
  • Fixed offsets not offsetting correctly
  • Fixed missed mat inverse in CheckRequest
  • Split up BuildMatrix code to reduce duplicated code
  • Shuffle s/d 3 and 4 to match the controls

v0.5 2025-03-25:

  • Reworked DoD calculations
  • Added clipping mode (None and Frame)
  • Code cleanup of unneeded calculations

v0.4 2025-03-23:

  • Fixed error for dst output transformation.
  • Fixed math for offsets to work when src doesn't have default values
  • Fixed data- and valid window for perspective crop
  • Hide unusable controls for perspective crop

v0.3 2025-03-23:

  • Added perspective crop
  • Added anti-aliasing and super sampling options

v0.2 2025-03-17:

  • Added undo to button presses

v0.1, 2025-03-14:

  • Init release

Latest Version:

CornerPinner.fuse

Old Version:

CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
CornerPinner.fuse
You do not have the required permissions to view the files attached to this post.
Last edited by danell 1 year ago, edited 14 times in total.

User avatar
JustCropIt
Fusionator
Posts: 1254
Joined: 2 years ago
Reactions score: 296
Has thanked: 265 times
Been thanked: 286 times

Re: [DEV] Corner Pinner

#2

Unread post by JustCropIt »

Heja!

Nice! There's some stuff in the video that reminds me of my macros over here (not sure they still work though).

Looking forward to giving it a spin (and a twist and a stretch)!


User avatar
JustCropIt
Fusionator
Posts: 1254
Joined: 2 years ago
Reactions score: 296
Has thanked: 265 times
Been thanked: 286 times

Re: [DEV] Corner Pinner

#3

Unread post by JustCropIt »

Probably out of scope for it but I've gotta ask... would it be possible to have an option to have the image/footage tile? Like outside the original image... uh... if you know what I mean. Was kinda hoping that the Edges setting was going to do that. Not sure what it does now?

Anyways, snappy stuff. Sweet!


User avatar
danell
Fusionista
Posts: 588
Joined: 9 years ago
Reactions score: 17
Location: Norrköping
Real name: Jacob Danell
Has thanked: 7 times
Been thanked: 48 times

Re: [DEV] Corner Pinner

#4

Unread post by danell »

Seeing your macro moving horizontally was actually what got me to start working on this fuse :D

About the tiling, that's exactly what Edge does. You just have to reload the fuse for it to reload the edge sampling (Fusion bug).

I also need to add the DoD code so you can fill the window instead of it making the DoD as small as possible, cutting off the edges


User avatar
JustCropIt
Fusionator
Posts: 1254
Joined: 2 years ago
Reactions score: 296
Has thanked: 265 times
Been thanked: 286 times

Re: [DEV] Corner Pinner

#5

Unread post by JustCropIt »

danell wrote: 1 year ago

Seeing your macro moving horizontally was actually what got me to start working on this fuse :D

Hah! That makes my day:) I remember it being apjobbigt to work with the "grid" and custom viewer controls in the macro. Never again. It's all yours now!

danell wrote: 1 year ago

About the tiling, that's exactly what Edge does. You just have to reload the fuse for it to reload the edge sampling (Fusion bug).

Well, look at that.... be still my beating heart! Sooo... uh... would it then be possible to (maybe with an option) have it only render to the "horizon"?

Here's some UI (in the Inspector) feedback ripped of the top of my head.

  • Add a Spacer between the Vertical/Horizontal Offsets and the side offsets. To group them up a bit more.
  • Probably remove the word Offset from all those offsets in that section. The word Offset is already in the nest header. Removes some clutter which is always nice.
  • I like pushing the UI a bit just to try things out. One thing I've done in... hrm... brb... my gradient map macro was to add checkboxes to enable/disable nests... in the nest header. Kinda. Really liked that. First thing I thought about when scrolling through settings in your fuse. Anything that saves some vertical space is worth a thought when you start having to scroll (IMO). It's a bit on the experimental side but having used it I think it's a great, intuitive and practical thing.
  • There's one Separator too much at the bottom:)

User avatar
mseredkin
One Hundred
Posts: 314
Joined: 11 years ago
Reactions score: 38
Location: Moscow, Russia
Has thanked: 150 times
Been thanked: 31 times

Re: [DEV] Corner Pinner

#6

Unread post by mseredkin »

What a wonderful tool, I especially like the horizontal and vertical offset functions.
He doesn't seem to like margins on the edges of the source image.

image.webp

It works better with a full frame

image.webp
You do not have the required permissions to view the files attached to this post.

User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#7

Unread post by ShadowMaker SdR »

danell wrote: 1 year ago

Add perspective crop functionality like from @ShadowMaker SdR's macro ([DEV] New Macro: SdR_PerspectiveCrop)

What a remarkable coincidence. I was just DM'ing with @tida about the only part that's still missing from my macro: correct estimation of the aspect ratio of the section of the image I'm cropping. There's so much math involved and matrices and I don't understand any of it. And all the info must be in Fusion's native tool, it's just not exposed. Maybe you have all the info available to you @danell. So if it can be added to your fuse it will always be more efficient than my macro attempts. Maybe the three of us should talk this over to make it happen in some way?


User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#8

Unread post by ShadowMaker SdR »

@danell I've been looking at this page, because it seemed to cover the aspect ratio aspect of what I was after, but maybe (at least a part) of your equations already takes care of this, I dunno?

https://andrewkay.name/blog/post/aspect ... rspective/


User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#9

Unread post by ShadowMaker SdR »

If you take a look at the section on page 6 and 7 or so of this pdf, they talk about all the stuff you need to find the aspect ratio as well.
But like I said, my math skills aren't good enough tot even see if these two equations are talking about the same stuff.
It appears to be similar and it goes through 20 steps or so to set everything up, but since we set a couple of these parameters up ourselves (the projected resulting corner points of the rectangle) it should be relatively doable to extract the aspect ratio of the image I want to crop.

Does that make sense to you?

Digital-Signal-Processing.pdf
You do not have the required permissions to view the files attached to this post.

User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#10

Unread post by ShadowMaker SdR »

And I do see a lot of mention of uv in your Fuse code, I'm just not sure if it's the same uv that they're referring to in the two examples I mentioned above.


User avatar
danell
Fusionista
Posts: 588
Joined: 9 years ago
Reactions score: 17
Location: Norrköping
Real name: Jacob Danell
Has thanked: 7 times
Been thanked: 48 times

Re: [DEV] Corner Pinner

#11

Unread post by danell »

Update time!
v0.3 2025-03-23:

  • Added perspective crop (@ShadowMaker SdR)
  • Added anti-aliasing and super sampling options

v0.2 2025-03-17:

  • Added undo to button presses

The math behind the perspective crop was very complicated to understand but with the help of some Claude 3.7 I got it working nicely :D


User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#12

Unread post by ShadowMaker SdR »

Thank you for putting in all the hard work. I am a bit afraid that there are still some issues.
Does this comp give you the results you're after? It's an artificial test case with a 2:1 aspect rectangle, but perspective crop makes it an 2.5 :1 result.
Also I don't think everything maps to where it should. If I don't change anything to the default destination, the area I cover with the controls should feel the complete image, shouldn't it? Because on my system it doesn't.

  1. {
  2.         Tools = ordered() {
  3.                 Shape3D1 = Shape3D {
  4.                         Inputs = {
  5.                                 ["Transform3DOp.Rotate.X"] = Input { Value = 90, },
  6.                                 ["MtlStdInputs.Diffuse.Color.Red"] = Input { Value = 0.016, },
  7.                                 ["MtlStdInputs.Diffuse.Color.Green"] = Input { Value = 0.488, },
  8.                                 ["MtlStdInputs.MaterialID"] = Input { Value = 1, },
  9.                                 ["SurfacePlaneInputs.SizeLock"] = Input { Value = 0, },
  10.                                 ["SurfacePlaneInputs.Width"] = Input { Value = 2, },
  11.                                 ["SurfacePlaneInputs.ObjectID.ObjectID"] = Input { Value = 1, }
  12.                         },
  13.                         ViewInfo = OperatorInfo { Pos = { 275, 181.5 } },
  14.                 },
  15.                 Camera3D1 = Camera3D {
  16.                         NameSet = true,
  17.                         CustomData = {
  18.                                 Settings = {
  19.                                         [1] = {
  20.                                                 Tools = ordered() {
  21.                                                         Camera3D1 = Camera3D {
  22.                                                                 Inputs = {
  23.                                                                         ApertureW = Input { Value = 0.831496062992126 },
  24.                                                                         AoV = Input { Value = 19.2642683071402 },
  25.                                                                         ["Stereo.Mode"] = Input { Value = FuID { "OffAxis" } },
  26.                                                                         ["MtlStdInputs.MaterialID"] = Input { Value = 1 },
  27.                                                                         ApertureH = Input { Value = 0.467716535433071 },
  28.                                                                         FilmGate = Input { Value = FuID { "BMD_URSA_4K_16x9" } },
  29.                                                                         ["SurfacePlaneInputs.ObjectID.ObjectID"] = Input { Value = 1 }
  30.                                                                 },
  31.                                                                 Name = "Camera3D1",
  32.                                                                 CtrlWZoom = false,
  33.                                                                 NameSet = true,
  34.                                                                 ViewInfo = OperatorInfo { Pos = { 550, 214.5 } },
  35.                                                                 CustomData = {
  36.                                                                 }
  37.                                                         }
  38.                                                 }
  39.                                         },
  40.                                         [6] = {
  41.                                                 Tools = ordered() {
  42.                                                         Camera3D1 = Camera3D {
  43.                                                                 Inputs = {
  44.                                                                         FLength = Input { Value = 49.0568334445481 },
  45.                                                                         ["Transform3DOp.Translate.Z"] = Input { Expression = "self.ImageInput.Metadata.Translate.Z" },
  46.                                                                         ImagePlaneEnabled = Input { Value = 0 },
  47.                                                                         AoV = Input {
  48.                                                                                 Value = 19.2642683071402,
  49.                                                                                 Expression = "self.ImageInput.Metadata.RSCameraFOV or self.ImageInput.Metadata['rs/camera/fov']"
  50.                                                                         },
  51.                                                                         AovType = Input { Value = 1 },
  52.                                                                         ["Transform3DOp.Rotate.Y"] = Input { Expression = "self.ImageInput.Metadata.Rotate.Y" },
  53.                                                                         ApertureH = Input { Value = 0.9 },
  54.                                                                         FilmGate = Input { Value = FuID { "HD" } },
  55.                                                                         ["Transform3DOp.Rotate.X"] = Input { Expression = "self.ImageInput.Metadata.Rotate.X" },
  56.                                                                         ["Transform3DOp.Translate.X"] = Input { Expression = "self.ImageInput.Metadata.Translate.X" },
  57.                                                                         PlaneOfFocus = Input { Expression = "self.ImageInput.Metadata.RSCameraDOFFocusDistance or self.ImageInput.Metadata['rs/camera/DOFFocusDistance']" },
  58.                                                                         FilmBack = Input { Value = 1 },
  59.                                                                         ["Transform3DOp.Rotate.RotOrder"] = Input { Value = FuID { "ZXY" } },
  60.                                                                         ["Transform3DOp.Rotate.Z"] = Input { Expression = "self.ImageInput.Metadata.Rotate.Z" },
  61.                                                                         ["Stereo.Mode"] = Input { Value = FuID { "OffAxis" } },
  62.                                                                         ApertureW = Input { Value = 1.6 },
  63.                                                                         ["Transform3DOp.Translate.Y"] = Input { Expression = "self.ImageInput.Metadata.Translate.Y" },
  64.                                                                         ["SurfacePlaneInputs.ObjectID.ObjectID"] = Input { Value = 1 },
  65.                                                                         ["MtlStdInputs.MaterialID"] = Input { Value = 1 }
  66.                                                                 },
  67.                                                                 CtrlWZoom = false,
  68.                                                                 NameSet = true,
  69.                                                                 ViewInfo = OperatorInfo { Pos = { 387, 145 } },
  70.                                                                 CustomData = {
  71.                                                                 }
  72.                                                         }
  73.                                                 }
  74.                                         }
  75.                                 },
  76.                         },
  77.                         Inputs = {
  78.                                 ["Transform3DOp.Translate.X"] = Input { Value = -1.46298219890137, },
  79.                                 ["Transform3DOp.Translate.Y"] = Input { Value = 1.59090669689661, },
  80.                                 ["Transform3DOp.Translate.Z"] = Input { Value = 2.20513688644509, },
  81.                                 ["Transform3DOp.Rotate.X"] = Input { Value = -37.7999992370605, },
  82.                                 ["Transform3DOp.Rotate.Y"] = Input { Value = -33.2000007629395, },
  83.                                 FLength = Input { Value = 18.2123442718302, },
  84.                                 ["Stereo.Mode"] = Input { Value = FuID { "OffAxis" }, },
  85.                                 FilmGate = Input { Value = FuID { "BMD_URSA_4K_16x9" }, },
  86.                                 ["SurfacePlaneInputs.ObjectID.ObjectID"] = Input { Value = 1, },
  87.                                 ["MtlStdInputs.MaterialID"] = Input { Value = 1, }
  88.                         },
  89.                         ViewInfo = OperatorInfo { Pos = { 275, 214.5 } },
  90.                 },
  91.                 Merge3D1 = Merge3D {
  92.                         Inputs = {
  93.                                 SceneInput1 = Input {
  94.                                         SourceOp = "Shape3D1",
  95.                                         Source = "Output",
  96.                                 },
  97.                                 SceneInput2 = Input {
  98.                                         SourceOp = "Camera3D1",
  99.                                         Source = "Output",
  100.                                 }
  101.                         },
  102.                         ViewInfo = OperatorInfo { Pos = { 440, 214.5 } },
  103.                 },
  104.                 Renderer3D1 = Renderer3D {
  105.                         CustomData = {
  106.                                 ToolVersion = 2,
  107.                         },
  108.                         Inputs = {
  109.                                 Width = Input { Value = 1920, },
  110.                                 Height = Input { Value = 1920, },
  111.                                 ["Gamut.SLogVersion"] = Input { Value = FuID { "SLog2" }, },
  112.                                 SceneInput = Input {
  113.                                         SourceOp = "Merge3D1",
  114.                                         Source = "Output",
  115.                                 },
  116.                                 RendererType = Input { Disabled = true, },
  117.                                 OutputType = Input { Disabled = true, }
  118.                         },
  119.                         ViewInfo = OperatorInfo { Pos = { 605, 214.5 } },
  120.                 },
  121.                 CornerPinner1 = Fuse.CornerPinner {
  122.                         CtrlWZoom = false,
  123.                         Inputs = {
  124.                                 MappingType = Input { Value = 0, },
  125.                                 HorizontalOffset = Input { Value = 0.239, },
  126.                                 TopLeftDst = Input { Value = { -0.00147710487444609, 1.00295420974889 }, },
  127.                                 TopLeftSrc = Input { Value = { 0.0550570962479609, 0.615823817292007 }, },
  128.                                 TopRightSrc = Input { Value = { 0.682784461663948, 0.801947389885807 }, },
  129.                                 BottomLeftDst = Input { Value = { -0.00738552437223043, -0.00443131462333826 }, },
  130.                                 BottomLeftSrc = Input { Value = { 0.213703099510604, 0.380505709624796 }, },
  131.                                 BottomRightSrc = Input { Value = { 0.931076672104405, 0.669249592169657 }, },
  132.                                 Input = Input {
  133.                                         SourceOp = "Renderer3D1",
  134.                                         Source = "Output",
  135.                                 }
  136.                         },
  137.                         ViewInfo = OperatorInfo { Pos = { 770, 214.5 } },
  138.                 }
  139.         }
  140. }

User avatar
ShadowMaker SdR
Fusionator
Posts: 2085
Joined: 11 years ago
Reactions score: 98
Has thanked: 6 times
Been thanked: 65 times

Re: [DEV] Corner Pinner

#13

Unread post by ShadowMaker SdR »

image.webp
image.webp
You do not have the required permissions to view the files attached to this post.

User avatar
danell
Fusionista
Posts: 588
Joined: 9 years ago
Reactions score: 17
Location: Norrköping
Real name: Jacob Danell
Has thanked: 7 times
Been thanked: 48 times

Re: [DEV] Corner Pinner

#14

Unread post by danell »

Damn, I was cleaning up the code some but I guess I broke something :P


User avatar
danell
Fusionista
Posts: 588
Joined: 9 years ago
Reactions score: 17
Location: Norrköping
Real name: Jacob Danell
Has thanked: 7 times
Been thanked: 48 times

Re: [DEV] Corner Pinner

#15

Unread post by danell »

Update:
v0.4 2025-03-23:

  • Fixed error for dst output transformation.
  • Fixed math for offsets to work when src doesn't have default values
  • Fixed data- and valid window for perspective crop
  • Hide unusable controls for perspective crop

@ShadowMaker SdR The problem you see in your example comp have two problems. First it used Bi-Directional destination, it's currently very broken. Second there is a bug in 3Rn with its DoD and how DCTL code reads the data. You need to add a SetDoD node after the 3Rn to solve it.

The perspective cropping also doesn't give the correct image size. It's close but not correct, so I guess there is some finetuning left to do with its code.