Weighted LookAt constraint effect, with rotation limits

I've been trying to something working but I think I've reached the LIMITS of my current abilities. Ha ha.

Basically:
At a weight of zero, the target has no effect on the object, and the object can be rotated freely within its constraints. At a weight of 100, the object cannot be rotated manually, and follows the target (again, within the limits that have been set).

Here's what I've put together so far. To make it simpler to test, I've stuck a custom attribute on the target object to adjust the weight of the lookAt effect.

It gets generally the effect I am trying to accomplish, but the objects in the scene can still end up rotating beyond the desired limits. (Also, I tend to get this guy while testing out the scene: http://i.gyazo.com/350ae6bdc912780dc0421eaa9b1a7613.png

I would be really happy if someone could make this work! At the moment I can't afford a bounty, but a donation at some point in the future would not be out of the question.

----

EDIT:

Okay, I don't know why I was trying to put the script controller after the Euler XYZ controller. It's much simpler to do it this way. I've also removed the custom attribute from the target object as the "weighted" part should be relatively easy once I get the other part working. So, the test case to look at:

delete objects
s = geoSphere name:"Target" radius:10
 
parentPoint = point pos:[50,50,0]
 
lookObjects = for i = 1 to 5 collect (
	rot = 15
	pyramid width:10 depth:10 pos:[random 0 100, random 0 100, random  0 100] rotation:(eulerAngles (random rot -rot) (random rot -rot) (random rot -rot))
)
 
(
	lookTarget = s
 
	for i = 1 to lookObjects.count do (
		o = lookObjects[i]
		o.objectOffsetRot = eulerAngles 90 0 90
		o.parent = parentPoint
 
		orc = o.rotation.controller = rotation_List()
		orc.setName 1 "Initial Rotation"
 
		p = point axisTripod:on box:on cross:off parent:o.parent transform:o.transform
 
		prc = p.rotation.controller = rotation_List()
		prc[2].controller	= lookAt_Constraint lookAt_Vector_Length:0 --upNode_World:false --relative:true 
		prc[2].controller.appendTarget lookTarget 100
		prc.setActive 2
		prc.weight = #(100, 50 + (i * 10))
 
		orc = lookObjects[i].rotation.controller
		orc[2].controller = orientation_Constraint()
		orc[2].controller.appendTarget p 50
 
		orc[3].controller = rotation_Script()
		orc[3].controller.addObject "lookRot" orc[2].controller
 
		ss = stringStream ""
		format "a = lookRot.value as eulerAngles\n" to:ss
		format "eulerAngles (amin (amax -15 a.x) 15) (amin (amax -30 a.y) 30) (amin (amax -45 a.z) 45)" to:ss
		orc[3].controller.script = ss
 
		orc[4].controller = euler_XYZ()
		orc.weight = #(0, 0, 100, 100)
 
		rotLimits = #(15, 30, 45)
		ax = #("x", "y", "z")
 
		for j = 1 to 3 do (
			o[3][2][4][j].controller = float_Limit()
			uls = o[3][2][4][j][2][1].controller = float_Script()
			uls.addObject "scriptRot" orc[3]
			uls.script = "degToRad (" + rotLimits[j] as string + " - (scriptRot.value as eulerAngles)." + ax[j] + ")"
 
			lls = o[3][2][4][j][2][2].controller = float_Script()
			lls.addObject "scriptRot" orc[3]
			lls.script = "degToRad (-" + rotLimits[j] as string + " - (scriptRot.value as eulerAngles)." + ax[j] + ")"
		)
 
		orc.setActive 4
	)
)

--------
OLD VERSION:

global lookControls = attributes lookControls attribID:#(0x58ae9e8e, 0x5b3c35a0) (
	parameters params rollout:RO_Look (
		maxObjectTab type:#maxObjectTab tabSizeVariable:on
		str type:#float ui:sld_Str default:50
	)
 
	fn adjustLookWeights = (
		c = this.maxObjectTab.count
 
		for i = 1 to c do (
			n = this.maxObjectTab[i].node
 
			if classof n == point then (
				val = (i as float / c) * this.RO_Look.sld_Str.value
				n.rotation.controller.weight[2] = val
			)
			else
				n.rotation.controller.weight[2] = 100 - this.RO_Look.sld_Str.value
		)
	)
 
	rollout RO_Look "Look Controls" (
		slider sld_Str "" pos:[18, 30]
		on sld_Str changed val do adjustLookWeights()
	)
)
 
delete objects
s = geoSphere name:"Target" radius:10
 
parentPoint = point pos:[50,50,0]
 
lookObjects = for i = 1 to 5 collect (
	rot = 15
	pyramid width:10 depth:10 pos:[random 0 100, random 0 100, random  0 100] rotation:(eulerAngles (random rot -rot) (random rot -rot) (random rot -rot))
)
 
(
	lookTarget = s
	custAttributes.add lookTarget lookControls
 
	for i = 1 to lookObjects.count do (
		o = lookObjects[i]
		o.objectOffsetRot = eulerAngles 90 0 90
		o.parent = parentPoint
 
		orc = o.rotation.controller = rotation_List()
		orc[2].controller = euler_XYZ()
 
		for j = 1 to 3 do (
		o[3][2][2][j].controller	= float_Limit()
			o[3][2][2][j][2][1].value = degToRad 30
			o[3][2][2][j][2][2].value = degToRad -30
		)
 
		orc.setName 1 "Initial Rotation"
		orc.setActive 2
 
		p = point parent:o.parent transform:o.transform axisTripod:true
 
		prc = p.rotation.controller = rotation_List()
		prc[2].controller	= lookAt_Constraint lookAt_Vector_Length:0 --upNode_World:false --relative:true 
		prc[2].controller.appendTarget lookTarget 50
		prc.setActive 2
		prc.weight = #(100, 50 + (i * 10))
 
		orc = lookObjects[i].rotation.controller
		orc[3].controller = orientation_Constraint()
		orc[3].controller.appendTarget p 50
		orc[4].controller = rotation_Script()
 
		orc[4].controller.addObject "parent" o.parent
		orc[4].controller.addObject "initRot" orc[1].controller
		orc[4].controller.addObject "eulerRot" orc[2].controller
		orc[4].controller.addObject "lookRot" orc[3].controller
		orc[4].controller.addConstant "weights" orc[6]
 
		ss = stringStream ""
		format "a = (lookRot.value * inverse parent.transform.rotation) as eulerAngles\n" to:ss
		format "w2 = weights[2].value / 100\n" to:ss
		format "xL = radToDeg eulerRot[1].lower_Limit - (eulerRot[1].value * w2)\n" to:ss
		format "xU = radToDeg eulerRot[1].upper_Limit - (eulerRot[1].value * w2)\n" to:ss
		format "yL = radToDeg eulerRot[2].lower_Limit - (eulerRot[2].value * w2)\n" to:ss
		format "yU = radToDeg eulerRot[2].upper_Limit - (eulerRot[2].value * w2)\n" to:ss
		format "zL = radToDeg eulerRot[3].lower_Limit - (eulerRot[3].value * w2)\n" to:ss
		format "zU = radToDeg eulerRot[3].upper_Limit - (eulerRot[3].value * w2)\n" to:ss
		format "eulerAngles ((amin (amax xL a.x) xU) - initRot[1].value) ((amin (amax yL a.y) yU) - initRot[1].value) ((amin (amax zL a.z) zU) - initRot[1].value)" to:ss
		ss = ss as string
 
		orc[4].controller.script = ss
		orc.weight = #(100, 50, 0, 100)
 
		append lookTarget.maxObjectTab (nodeTransformMonitor node:o forwardTransformChangeMsgs:false)
		append lookTarget.maxObjectTab (nodeTransformMonitor node:p forwardTransformChangeMsgs:false)
	)
)

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Malkalypse's picture

I modified the code a bit,

I modified the code a bit, getting rid of anything that's not pertinent, and hopefully making it a bit easier to work with.

----
EDIT:
In case anyone is not seeing where the trouble is coming in: when you manually rotate the pyramids, they can end up with rotation values outside the specified range.

barigazy's picture

...

I saw your thread on CGTalk. Your task I quite complex. DenisT will probably help you after all because this is his area.
I can only suggest this tutorial maybe can help you somehow

http://joleanes.com/tutorials/flippingless/flippingless_01.php

bga

Malkalypse's picture

Denis won't be able to help

Denis won't be able to help me because his solution is part of a proprietary script, so that leaves me looking elsewhere ><;

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.