ScriptSpot

Forum topic · Scripts Wanted

Weighted LookAt constraint effect, with rotation limits

By Malkalypse · 2014-08-06

Description

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 (3)

Malkalypse · 2014-08-07

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.

Malkalypse · 2014-08-06

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