Homebrew transform jack

Attached is a viewport component (068). It has two modes:
When the mouse is over the panel, press and hold “t” key
use geo viewport like mouse navigation to tumble and to home the view Press t + h

Select either of the two control points (blue crosses)

a transform handle is displayed

And here’s the problem I can’t find a solution for:
Currently the transform is just controlled via “u” panel variable, so whatever axis you pick the xform is increased if you move to the right and decreased if you move left. What I can’t figure out is how can I set this up so that it works like the interaction with the transform jack in the geo viewer? I mean how to translate my 2D u+v variables so that they are “aligned” to the axis I’m adjusting (in relation to the current view that is).

Hope that made sense and thanks in advance
editor.toe (11.2 KB)

New version, same problem (and a bug)

How can I control the picked transform handle with the 2D panel variables in respect to the current viewpoint and handle rotations?
Any help/ideas highly appreciated

Differences to the old file:
Transformations are now “cumulative?”, so you can rotate and then translate and rotate/translate again and it will always adjust the appropriate values.
Tumble mode is now activated via “z” key
You can switch between translate and rotate jack via “t” + “r” keys.

PS: If you want to manually enter values for the transformations, adjust either “/level1/local/set_variables” or “/level1/_/level2/local/set_variables”

jack.toe (14.3 KB)

There’s also a little bug with the replace CHOP in this file. Try translating the x axis, then press “r” to enter rotate mode and rotate an axis, then back to translate … At some point the replace CHOP’s replaces the wrong channel, i.e. input two is “ry” and the channel which changes is tx. Hope you can reproduce.

Hey Achim,

While trying to solve this issue, I realized that the transform order for the Object CHOP and Transform CHOPs (and a few others) was totally wrong in code. The selected transform order wasn’t what got used internally. This is why you needed to change your transform and object CHOPs to translate, rotate, scale instead of leaving them at scale, rotate, translate. So that being fixed should make things easier to work with.

You’ll need a new version of Touch to use this file, but here’s the idea.

Using the Object CHOPs located in /, you’ll notice I’m calculating the transform from object space to world space (using the /level1/HANDLE/pos transform), and then from world space to camera space (using the camera’s transform). This transform you now have is a way to take the points of your axis and put them into camera space.

If you look at /level1/HANDLES/pos/select1, you’ll see I’ve picked out the start and end points of one of the axii (in camera space). If you now tumble around the camera, no matter what your orientation is, tx will always decrease/increase when you pan left/right, ty will always decrease/increase when you pan down/up and similarly for tz.

Similarly using this transform you can take the (u,v) s, create a point/vector out of them, and transform them into camera space. Or you can take vector from camera space and transform them into object space ( using /cameraToObject that I created for you).

Now what you do with this really depends on how you are going to use u,v, but hopefully these are the tools you need to get this working.

I can reproduce the replace CHOP bug, looking into it.

Remember this file won’t work correctly until the next build of Touch (I’ve already fixed the Object/Transform CHOP transform order parameters for you).

Is that the info you were looking for?
jack.33.toe (14.4 KB)

The Replace CHOP bug is now fixed.

thank you malcolm, sounds like it’s the info I was looking for. I’ll respond once a new build is released.

Hey Malcolm,
thanks a lot for the file. I have three little questions regarding your setup:

The /identity op is just a Null serving as the origin, right?

You’re referencing /objectToWorld in /object2, and /objectToWorld is also located at 0,0,0.
So is /objectToWorld just another origin and can be replaced with /identity?

Are /object3 and /cameraToObject just used for visualization? I can’t find any reference to these anywhere.

Thank you

Right, /identity is just serving as the origin.

Sorry, I must have forgotten to fix an export when renaming these nodes. The export prefix for object1 should be /objectToWorld.
That way we are transforming in a chain Object Space -> World Space -> Camera Space.

object3 is used to create the correct transform for cameraToObject. I made this node for you so you had a way to transform from camera space to object space (its just the inverse of objectToCamera). No they aren’t currently used.

Hey Malcolm,

after trying for the last hours, I’m afraid I can’t really follow your ideas. I don’t see/understand how I can to use the “camera space axis” or the "panel uv > vector > camera space " data to control my transform jack. If you find some time I would highly appreciate another example/description.

Thank’s again

Let me first make sure I understand the behavior you want. When you pick a transform jack (say one that is pointing up) you want it to move when you move the mouse up/down. Regardless of what jack (+X, -X, +Z etc.) it actually is, right?

Yes. I want to move the jack along the picked axis. So selecting the red axis of the transform jack and then moving the mouse in the direction of/along the selected axis should move the jack and the associated geo object along that axis. Basically I’d like to exactly mimic touch’s geo viewport/transform jack.

Sorry, what do you mean by “jack (+X, -X, +Z etc.)”

What I mean by +X -X etc. is the 6 different transform jacks that can be chosen from. +X is one end of the red axis while -X is the other end.+Y is one end of the green axis while -Y is the other end. Now in your sample I guess you only have 3 jacks, X Y and Z, and clicking on either end of the jack does the same thing.

So here’s another sample (I killed your script that turns on/off the keyboard CHOP in this, just FYI).

When you open the file you’ll see a CHOP in /level1/HANDLES/pos called directionOfPositiveY. This is a vector that describes the direction that the +Y jack is pointing in the camera view (Currently up and to the left). You can tell this from the numbers since the X is negative but Y is positive. So if the user grabs the Y jack you can tell that visually its pointing up and to the left. So the user would expect mouse movements up and to the left would move this jack up and to the left. This means if you get -U and +V values for the change in panel values, the user is moving the mouse in that direction. How tightly you want to tie the mouse movement to this vector is up to you. To start you could just negate the value in /viewport/pickEditorView/subtract if the mouse is moving in the opposite direction than the way the axis is pointing (+U and -V in our default example).

So depending one which jack is chosen, in /level1/HANDLES/pos/pickTheSelectedAxisHere, you’d choose the *0, *2 or *4 values, depending on if tx ty or tz jack is chosen.

Make sense?

Note: due to the projection there is a little discrepancy between what you see and the the vector directionOfPositiveY has (when the green axis is pointing directly up/down you may not get tx = 0 and ty = 1. This is due to the projection. If you change your projection to orthographic it’ll match up correctly, but its probably not necessary.
jack.toe (15 KB)

Thank you Malcolm. It makes sense, at least a little (seems like I need to go to math school).

I transformed your setup into mine, so everything is now in “/viewport/pickEditorView”
After you selected the geo cross in the viewer, the handle/jack is displayed (if not you need to temp. enter into “/viewport/pickEditorView/handle”)

Now you can select each axis and get that axis’s “directionOfPositive” data (in the red colored CHOP). Below that CHOP I created a a CHOP called “in_which_Quadrant”, so if the axis points up/right == 1, down/right == 2, down/left ==3 and up/left ==4. Below that is the same for the mouse movement. (No sure if these are actually useful).

That’s all I got. Not much.
So I still don’t get how to use panel u/v to move the jack correctly along the selected axis and having the jack “stick to/follow” the mouse position.

Would it be too much to ask for an example where you integrate this? Maybe for the x and y axis. :blush:

Thanks again
Achim (feeling stupid)
jack.toe (15 KB)

Do I need to transform my u,v values from screen space to camera/object space in order to have the handle follow the mouse position?
If so, could you please let me know how to do this conversion?

Ya sorry, I haven’t had a chance to work on the .toe file yet.

You don’t need to work in screen space actually. Camera space will get you close enough to what you want. Camera space is defined as a space where the camera is located at (0,0,0), right is always +X, left is -X, up is +Y and down -Y. This is always true regardless of how your camera is orientated (rotate it, move it, twist it, the numbers will always be relative to how the camera sees everything).

I’m not entirely clear of the movement you want. Lets say you click on an axis thats pointing left/right in the viewer and you move your mouse up, what do you want to happen? Would you expect your object to move up?
The way I see these jacks working is that they are always locked onto their ‘paths’, (they can only move in two directions, forwards or backwards along their current paths). But maybe you are trying to do something else?

Anyway, to do the conversion here’s how.
A vector can be defined as a point subtracted from another point. In this case you’ll want to use two points, the point where the user first clicked his mouse, and where the mouse position is now.
Lets say the user clicked and you got a UV or (100,100), and now he’s dragged his mouse up and to the right to (125,115).
So the vector is (125,115) - (100, 100), which gives you (25, 15). Now since right is +X and up is +Y , you can map this (U,V) vector to (X,Y,Z) easily, it’s simply (25, 15, 0).
Next you’ll probably want to normalize this vector. To normalize a vector you do (X,Y,Z) / length(X,Y,Z). I do this using CHOPs in the .toe file already, look at the Math CHOPs named ‘calcLength’ and ‘invert’. Those give us 1.0 / length(X,Y,Z). Which I multiply by the vector to normalize it.

So now you have a normalized vector in Camera Space. Now transform it back into object space so you can compare it to the original axii (which are the untransformed original axii). Doing this is a little clunky, but here’s how. Create an Add SOP and put your (X,Y,Z) values into a point. Then use the SOP To CHOP, and use /cameraToObject as the Transform Object parameter. You can see me doing this with /level1/HANDLES/pos/add1 and ‘sopto2’ (although I’m just transforming (0,0,0) in this case).
(/cameraToObject is relative to /level1/HANDLES/pos only btw).

The values you get you can now compare to the original axii and you now know the users movement relative to the axii. If you want to just forget about any axis-based motion, and instead just drag the object around the screen, you can just add this vector to the transform for the object and it’ll move around in a visually correct way (you can use the vector length you calculated earlier to know how far to move it).

Let me know if I’m still not explaining it well enough.

No. Moving straight up wouldn’t move the object at all, moving up and to the right would move the object to the right…Like you said, it’s locked to the ‘path’

So now I got it almost. In the file, please click in the viewer pane at u = 0.5 and v=0.1.
Now move the mouse straight to the right

The “null1” object (black cross in the viewer) jumps 1 unit to the right

If you do a more “circular” movement,i.e. down > right > up,

The “null1” object (black cross in the viewer) “smoothly” moves to the right

So what I would like to achieve is, when I click and move right, the black cross now sticks to the mouse u position, so I guess I need to “transform” the distance in uv movement to a distance in object space. That’s where I though I might need that screen space conversion.
jack.89.toe (17.2 KB)

To illustrate the “handle follows mouse” problem, here’s another file. (It doesn’t normalize the u,v vector, so the red colored ops are not used)

Everything works fine. You can pick any axis and move the object, tumble the cam and then adjust the handle again…

But the problem is, if you select the x axis and move to the right, the handle moves much slower than the mouse, i.e. it does not stick to the mouse position. Couldn’t find a way to use the normalized u,v vector to achieve this.

And I can’t figure out how to map the same approach to a rotation jack?
jack.97.toe (17.5 KB)

Ah ok, ya you’re right you would use screen space for this. Currently there is no way for you to get the projection matrix from a Camer OBJ. Maybe I’ll add an unproject expression that allows you to take screen space coordinates and unproject them into Camera Space.

In the meantime you could use an orthogonal camera to get the results you want (it just won’t look quite as nice).

When using an orthogonal projection, camera space coordinates are mapped to screen space using (-OrthoWidth/2, OrthoWidth/2). I.E if you have an ortho width of 10, an X of -5 will be at the left edge of the screen and and X of +5 will be at the right edge of the screen. This is true regardless of how far or close the object is to the camera.

So using that information, lets say the mouse has moved 0.1 units in U. If you have an ortho width of 10, that means you want to move the object 1 unit in object space (just add 1 to the X transform and it’ll stick to the mouse).

For the rotations is more tricky, but again just requires some more vector math.

I would think the tangent to the circle at the point the user clicked the mouse is the value you’d want use to control the movement (I havn’t tried though so I’m not sure if it’ll feel right).
To get this it’s pretty easy, but not obvious.

Since the 3 circles for the rotate jacks are centered around (0,0,0), they have the nice property that the point position of any point on the circle can also be used as the normal. (Take a Sphere SOP and notice how all of its normals are the same value as it’s P attribute).
We want the tangent though, which is perpendicular to the normal.
Since these 3 circles lay on the XY, XZ and YZ planes, we can drop the unused component in each case and work in the 2D world.
So lets say someone clicked on the Green circle, this is the Y rotation jack, and it lays on the XZ plane. Lets say the point the user clicked on is (-0.86, 0, 0.48) (I just clicked on a random point on the circle to get these values from the RenderPick CHOP).
We can drop the Y value, which gives us (-0.86, 0.48). Now, a trick for 2D vectors is that (x,y) is perpendicular to(y,-x). So the perpendicular vector to (-0.86, 0.48) is (0.48, 0.86). Now throw the Y back in there (0.48, 0, 0.86).
So using that you can compare your transformed into object space u,v vector and decide how much to rotate the object.
You use the RenderPick CHOP with Fetch Position set to ‘In SOP Space’ (SOP Space is the same thing as Object Space) to get the position on the circle the user picked which all this is derived from.

Let me know how it goes (I’m mostly just theorizing here on if this will ‘feel’ right).

That’s always the point where I can’t follow. How to I “compare” these two vectors and as a result get the single value I need to apply for rotation?

So I did as suggested, and in the attached file I now (hopefully) have
a u,v vector transformed to object space ("/viewport/pickEditorView/substract1" ::op colored red)
a tangent to the point where I clicked on the rotation circle ("/viewport/pickEditorView/invert" ::op colored red)

If you select the object in the viewer to display the handle, and then click somewhere on the red x-axis rotation handle, two lines are drawn, one to the point clicked and one which should represent the tangent to that point. (You can switch between rotate and translate handles with ‘r’ and ‘t’ keys)

So how do I compare these vectors in a way that I get an rx value which can be put into “/viewport/pickEditorView/transform1/rx” op colored red ?

jack.312.toe (18 KB)

Ah, sorry. I’m sure there are quite a few ways to do this but a simple way is to take the dot-product of the two vectors (after normalizing them). This value will be a value between -1 and 1, which says how close the two vectors are to pointing in the same direction. 1 means they are pointing in exactly the same direction. 0 means they are perpendicular, and -1 means they are pointing in the opposite direction from each other.
So in the attached file I normalize and take the dot-product and you end up with a single value in the node “moveFactor”. If this values is 1 is means the user is moving his mouse in the exact correct direction that the jack ‘wants’ to move.
How much to add to rx is a guessing game now, add some value to rx as the user moves the mouse and see how it feels and scale up/down the change to rx until you get a feel you like. Multiply this change by the moveFactor, and you should get a good feel I think.

Beyond this you could use some other vector math like projecting vectors onto planes to try different ways to use these vectors (There is no ‘right’ answer, I’m still just thinking out loud here without actually trying the process).
jack.320.toe (18.7 KB)

I just realized you need to turn off the ‘display’ flag for those ‘normalizer’ COMPs cause they are making it not possible to click in the bottom left hand quadrant of your panel.