diff --git a/img/swingpolar.gif b/img/swingpolar.gif new file mode 100644 index 0000000..034e6de Binary files /dev/null and b/img/swingpolar.gif differ diff --git a/src/config.json b/src/config.json index 9304025..36e2ef0 100644 --- a/src/config.json +++ b/src/config.json @@ -154,6 +154,12 @@ "script": "skeleton", "tooltip": "Links each selected puppet pin's position to a new null object's position. Helpful for stacking position animations. Select any number of puppet pins on a single layer." }, + { + "type": "button", + "text": "PP Polar", + "script": "bonePolar", + "tooltip": "Pair Pin Polar. Pairs a puppet pin (child) to another puppet pin (parent) so the child pin moves with the parent, but uses polar coordinates centered around the anchor point instead of cartesian. Select two puppet pins on the same layer." + }, { "type": "button", "text": "Stitch", diff --git a/src/script/bone.js b/src/script/bone.js index 9bf9b88..c27efb5 100644 --- a/src/script/bone.js +++ b/src/script/bone.js @@ -5,7 +5,7 @@ export default function bone() { boneFn(false); } -function boneFn(isPolar) { +export function boneFn(isPolar) { const comp = compUtils.getActiveComp(); const selectedLayers = compUtils.getSelectedLayers(comp); if (selectedLayers.length != 1) { @@ -42,15 +42,20 @@ function boneFn(isPolar) { let parentPos = parentPoint.property("Position").value; if (isPolar) { - childPos = [Math.sqrt(childPos[0] * childPos[0] + childPos[1] * childPos[1]), Math.atan2(childPos[1], childPos[0])]; - parentPos = [Math.sqrt(parentPos[0] * parentPos[0] + parentPos[1] * parentPos[1]), Math.atan2(parentPos[1], parentPos[0])]; - childPoint.property("Position").expression = `parentPos = effect("Puppet").arap.mesh("Mesh 1").deform("${parentPoint.name}").position - transform.position;\r\n` + - `childPos = [length(parentPos) * ${(childPos[0] / parentPos[0])}, Math.atan2(parentPos[1], parentPos[0])${mathUtils.formatNumber(childPos[1] - parentPos[1])}];\r\n` + - '[childPos[0] * Math.cos(childPos[1]), childPos[0] * Math.sin(childPos[1])] + transform.position'; + const layerPos = selectedLayers[0].property("Position").value; + childPos = [childPos[0] - layerPos[0], childPos[1] - layerPos[1]]; + parentPos = [parentPos[0] - layerPos[0], parentPos[1] - layerPos[1]]; + const childRPos = [Math.sqrt(childPos[0] * childPos[0] + childPos[1] * childPos[1]), Math.atan2(childPos[1], childPos[0])]; + const parentRPos = [Math.sqrt(parentPos[0] * parentPos[0] + parentPos[1] * parentPos[1]), Math.atan2(parentPos[1], parentPos[0])]; + childPoint.property("Position").expression = `parentPos = effect("Puppet").arap.mesh("Mesh 1").deform("${parentPoint.name}").position - [${layerPos[0]}, ${layerPos[1]}];\r\n` + + `childCPos = (effect("Puppet").arap.mesh("Mesh 1").deform("${childPoint.name}").position.numKeys > 0 ? loopOut() : ` + + `effect("Puppet").arap.mesh("Mesh 1").deform("${childPoint.name}").position)\r\n` + + `childPos = [length(parentPos) * ${(childRPos[0] / parentRPos[0])}, Math.atan2(parentPos[1], parentPos[0])${mathUtils.formatNumber(childRPos[1] - parentRPos[1])}];\r\n` + + `[childPos[0] * Math.cos(childPos[1]), childPos[0] * Math.sin(childPos[1])] + childCPos - [${childPos[0]}, ${childPos[1]}]`; } else { childPoint.property("Position").expression = `p = effect("Puppet").arap.mesh("Mesh 1").deform("${parentPoint.name}").position;\r\n` + `p2 = (effect("Puppet").arap.mesh("Mesh 1").deform("${childPoint.name}").position.numKeys > 0 ? loopOut() : ` + `effect("Puppet").arap.mesh("Mesh 1").deform("${childPoint.name}").position)\r\n` + - `p + p2 - [${parentPos[0]},${parentPos[1]}]`; + `p + p2 - [${parentPos[0]}, ${parentPos[1]}]`; } } diff --git a/src/script/bonePolar.js b/src/script/bonePolar.js new file mode 100644 index 0000000..fb3541f --- /dev/null +++ b/src/script/bonePolar.js @@ -0,0 +1,5 @@ +import { boneFn } from './bone' + +export default function bonePolar() { + boneFn(true); +} \ No newline at end of file diff --git a/user_docs.md b/user_docs.md index 423e7d9..a59cc5c 100644 --- a/user_docs.md +++ b/user_docs.md @@ -33,6 +33,7 @@ - [Parallax](#parallax) - [Chain](#chain) - [Create Ref](#create-ref) + - [Pair Pin Polar](#pair-pin-polar) - [Stitch](#stitch) - [Round](#round) - [Graph Spd](#graph-spd) @@ -80,6 +81,8 @@ Tips: ![Pop up](img/popup.png) - Some buttons will read a value from the Settings tab which will affect functionality, such as the loop length. Check each script's documentation for which settings are read. +- All plugin functionality is achieved using vanilla AE. You can uninstall the plugin at any time without breaking existing projects. +- This also means you can tweak any generated result if it's not to your liking. ## Errors @@ -464,6 +467,22 @@ The null's animation will be added to the puppet pin's animation. This lets you You can also just precomp, but that might break rigging. +## Pair Pin Polar + +*Pair Pin Polar: Pairs a puppet pin (child) to another puppet pin (parent) so the child pin moves with the parent, but uses polar coordinates centered around the anchor point instead of cartesian. Select two puppet pins on the same layer.* + +This is similar to [Pair Pin](#pair-pin), except it uses relative polar coordinates instead of cartesian. It took an hour to get the math right and I used it like thrice so maybe just skip this and use [Pair Pin](#pair-pin). + +In essence, assuming the parent is at (x, y), Pair Pin sets the child at (x + Δx, y + Δy), where (Δx, Δy) is the distance between the child and the parent when the button is clicked. + +Pair pin polar uses polar coordinates, so if the parent is at (r, θ), Pair Pin Polar sets the child at (r + Δr, θ + Δθ), where (Δr, Δθ) is as above. The anchor point is used as the origin. + +The effect becomes a lot more obvious when rotating around an anchor point: + +![Swing Polar](img/swingpolar.gif) + +Don't worry too much about it, but the idea is that it works better than Pair Pin for orbiting movement since it maintains the relative angle and distance from the anchor point. + ## Stitch *Stitches two layers together so each child layer's puppet pins are linked (same as Link button) to a puppet pin on the parent layer if they are close enough. Place puppet pins in the same locations on two layers, and select the two layers.*