[Closed] Lookat Angle Snap Question
I’m trying to set up an object so that it rotates to look at a camera, but only on the z axis. I also want it to rotate by increments of 45 degrees. What I have done so far is to have a dummy with a lookat constraint set to the camera, and then my object is inheriting it’s z rotation from the dummy. This works fine, but now I need to set something up so that if the rotation of my dummy is less than 45 degrees, then the rotation of the object should be 0. If the dummy’s rotation is between 45 and 90 degrees, the object’s rotation should be 45 and so on. I figure I need to set this up in the wire parameters of the object, but I can’t get it to work. If anyone has any advice on how to do this or if there is a more simple way to do this, I would appreciate it.
Thanks in advance.
first all i hope we are talking about an object camera (meaning it’s a real node, not viewport view) … where is a difference? the renderability… the viewport solution can’t be renderable in general case. so it’s not interesting for me.
second… you have to understand that an object can’t look at camera if camera doesn’t look at the object. otherwise we have to not only rotate the object but also move it.
well… to make a facing all the time to a camera is easy. it’s just smartly inversed the camera’s rotation. but the snapping needs a script…
an expression controller could be better than a script… but the max doesn’t have a rotation expression controller. so the only solution is a script controller. which one to pick? does the camera all the time looks at the object?
Personally, I’ve never been a fan of wire parameters. Likely cause I tried to use them a bit when they were added and I had all sorts of problems with them randomly disconnecting from time to time. Where possible, I just use expression controllers for their speed and if expression can’t get me there, or I’m too lazy to nut out the expression version of a script controller, or speed isn’t an issue, I use script controllers. I find the more complex expressions harder to write and definitely harder to read than script controllers.
Whenever I need something to “lookat” but only on one axis, I use the upnode to lookat.
For example, if I want something to pivot only on it’s Z, I will make a helper that is directly above the object that I’m assigning the Z lookat to and make that the lookat target. I then switch the upnode mode to lookat and make another point that that is the upnode in the controller, but is actually going to be your one-axis lookat object.
All said, I just had a bit of fun making what you need. Here’s a script that will create a setup like you need.
The object upnodePoint_MoveMe is what you move around and the red object is the one that has the incremental Zrotation based on the rotation of lookerPoint. lookatPoint is the lookat target to keep the lookerPoint looking up and only rotating on the Z axis. There’s likely a more elegant solution with less point helpers and more code, but this seems to work.
(
clearlistener()
delete objects
lookerPoint = point box:on cross:on
lookerPoint.name = "lookerPoint"
lookerPoint.pos = [0,0,0]
lookatPoint = point box:on cross:on
lookatPoint.name = "lookatPoint"
lookatPoint.pos = [0,0,100]
upnodePoint = point box:on cross:on
upnodePoint.name = "upnodePoint_MoveMe"
upnodePoint.pos = [0,-100,0]
for points in helpers do points.wirecolor = yellow
expTrans = ExposeTm box:off cross:off axistripod:on
expTrans.name = "expTrans"
expTrans.pos = [0,0,50]
expTrans.wirecolor = red
expTrans.exposeNode = lookerPoint
zRotScript = float_script()
zRotScript.addtarget "driver" expTrans.worldEulerZ.controller
zRotScript.script = "degToRad((((driver+22.5)as integer)/45)*45)
"
expTrans.rotation.controller.Z_rotation.controller = zRotScript
la = lookat_constraint()
la.target_axis = 2
la.upnode_ctrl = 0
la.StoUP_axis = 1
la.StoUP_axisFlip = on
la.upnode_world = false
la.appendTarget lookatPoint 100
la.pickUpNode = upnodePoint
lookerPoint.rotation.controller = la
)
Actually, I just double checked it after I’d posted and it’s not quite working properly… I’ll see if I can sort it out and post another version.
Seems that the top one only works if the driver value is above 0. Fixing it now.
Cg.
OK, this one seems to work. I’ve added an option to change the increment value.
(
clearlistener()
delete objects
increment = 45
lookerPoint = point box:on cross:on
lookerPoint.name = "lookerPoint"
lookerPoint.pos = [0,0,0]
lookatPoint = point box:on cross:on
lookatPoint.name = "lookatPoint"
lookatPoint.pos = [0,0,100]
upnodePoint = point box:on cross:on
upnodePoint.name = "upnodePoint_MoveMe"
upnodePoint.pos = [0,-100,0]
for points in helpers do points.wirecolor = yellow
expTrans = ExposeTm box:off cross:off axistripod:on
expTrans.name = "expTrans"
expTrans.pos = [0,0,50]
expTrans.wirecolor = red
expTrans.exposeNode = lookerPoint
zRotScript = float_script()
zRotScript.addtarget "driver" expTrans.worldEulerZ.controller
theScript = "inc = " + (increment as string)+ "
"
theScript += "if driver >= 0 then degToRad ((((driver+(inc/2.0))/inc)as integer)*inc)
"
theScript += "else degToRad ((((driver-(inc/2.0))/inc)as integer)*inc)
"
zRotScript.script = theScript
expTrans.rotation.controller.Z_rotation.controller = zRotScript
la = lookat_constraint()
la.target_axis = 2
la.upnode_ctrl = 0
la.StoUP_axis = 1
la.StoUP_axisFlip = on
la.upnode_world = false
la.appendTarget lookatPoint 100
la.pickUpNode = upnodePoint
lookerPoint.rotation.controller = la
)
Dennis, since we only need to rotate on one axis, it’s fine to use a float expression (or script as I did) on only the needed axis. I’m going to take a guess and say that they might be trying to set up something like sprite cards for trees or people in arch vis. But who knows?
Cg.
it will be hard to do if the object is a child. it doesn’t matter which and how many axis has to be constraint. in general case we have to calculate whole rotation (quaternion). so unlikely we can use an expression controller.
Dennis, I’m usually very reluctant to say you are wrong, ’cause it seems you are rarely wrong. But I think in this instance, you possibly are. Or maybe I’m not understanding you properly.
check the thing… you have to constraint the node rotation to some other. only one axis. whatever.
but you have to do it the world space of coordinates. if you want to use an expression float controller as component of Euler_XYZ controller you have to use a matrix algebra. the expression script doesn’t provide these methods. you can do by using a pure math… sure. but… (after here you can continue yourself)
i’ve did it. it’s the pain. trust me
forget about a snap. forget about a specified axis. just try to make an expression controller works as look-at constraint.
when you do it i will be wrong about said above
Hi Chris,
Thank you so much for taking the time to work through this issue. Sorry it took me so long to get back to you. I didn’t have a lot of free time to work on this, and I wanted to give it a solid try before I came back begging for help. I did end up getting stuck, though.
I’m trying to recreate what you did, but I’m still fairly new to scripting, so forgive me if I messed something up. Right now I have a scene with 4 objects: 2 boxes and 2 points. The first box is the one I want to have turn, so it’s called rotator. Above it is a point called lookerPoint. The second box is the object that will move around, and I named it upnodePoint_MoveMe. I don’t know if that’s right, but I was trying to stick to the formula. Above the second box is a point called lookatPoint. lookerPoint has a lookat constraint on it aimed at lookatPoint. I then went to parameters of my rotator box in the hierarchy tab and assigned a float expression controller to the z rotation. This opens up the script window, which is where I tried to plug in the script you provided, and this is where I got stuck. At this point besides the lookat constraint I haven’t linked anything.
If you could let me know where I went awry, I would greatly appreciate it. I put the file I am working on in Max 2012 here:
https://drive.google.com/file/d/0B3-PI_GT3mUXUjB1aFN2ZjNrSmM/edit?usp=sharing
Thanks again,
Sean
Ah Denis, you are likely absolutely right about expression controller and lookat. But that’s not what I was talking about. I see that with your “pure maths” approach you cannot do it with an expression. But I do think that you sometimes get caught up in the perfection of it rather than just trying to solve the problem while utilising all the things we have in max rather than just awesome code. I was meaning that for these purposes, you can use a lookat controller (as you’ve said in the past that they’re good) And then using the lookat rotation on the single axis by making the lookat just look directly up to a non moving object and use the lookat-type upnode to do the single axis spinning. So you can get an object to only spin on one axis while looking. Then you can take that rotation value and turn it into a stepped value via an exposeTransform helper. I’ve not had a chance to get back and make the expression version. Yet. I’d like to be able to do it whenI have the time. Even if it’s just for myself. The script version is listed above. I do think that when you mentioned something about world-local space, I thought that using the local space would be better than world incase you link all the things to a rootnode and move and rotate it around in the scene.