Help please: Want to get name from self reference


#1

I have a script (shown below)
the first line assigns a specific object name to an attribute.
This will always be self-referencing.
How do I make this automatic so that it’s easy to drop the script on multiple objects?
Currenty:
obj = $Ball
want something like:
obj = thisObj.name

Can’t seem to find the correct syntax. Apologies for the newbie question.

Full script:
obj = $Ball
timeres = 1f
fn getrot t =
(
if t<=0f then return quat 0 0 0 1 – t=0 => no rotation
t0 = t-timeres – previous frame time
t1 = t – current time
rot0 = getrot(t0) – previous rotation:
p0 = at time t0 obj.position-- previous position
p1 = at time t1 obj.position-- current position
if(p0==p1) then return rot0 – no distance is traveled
dif = p1-p0 – difference in positions
len = Length(dif) – distance that’s traveled
vec = dif / len – normalized movement vector.
r0 = at time t0 obj.radius – previous radius
r1 = at time t1 obj.radius – current radius
rotax = cross vec [0, 0, 1] – rotation axis
angle = 360*len/((r0+r1)*pi)-- rotation amount (in degs)
rotdif = quat angle rotax – rotation from t0 to t1
rot1 = rot0 + rotdif – total rotation
)
getrot(currentTime)


#2

If you want to use your script for multiple objects:

(
	timeres = 1f
	fn getrot t =
	(
		selObjsArr = selection as array
		for obj in selObjsArr do
		(
			if t<=0f then return quat 0 0 0 1 – t=0 -- no rotation
			t0 = t-timeres --previous frame time
			t1 = t – current time
			rot0 = getrot(t0) -- previous rotation:
			p0 = at time t0 obj.position-- previous position
			p1 = at time t1 obj.position-- current position
			if(p0==p1) then return rot0 -- no distance is traveled
			dif = p1-p0 -- difference in positions
			len = Length(dif) -- distance that’s traveled
			vec = dif / len -- normalized movement vector.
			r0 = at time t0 obj.radius -- previous radius
			r1 = at time t1 obj.radius --current radius
			rotax = cross vec [0, 0, 1] -- rotation axis
			angle = 360*len/((r0+r1)*pi)-- rotation amount (in degs)
			rotdif = quat angle rotax --rotation from t0 to t1
			rot1 = rot0 + rotdif -- total rotation
		)
	)
	getrot(currentTime)
)

#3

Hi,
Thanks for the reply. Seems to be an error though.
call needs function or class, got: 73f

I did neglect to mention previously that this script is used as a rotation script controller for the object in question (in example above “Ball”).

Any ideas?

Thanks in advance.


#4

no… this is wrong.

the best solution is to pass object to the getrot function


#5

whole function is wrong …

fn getrot t =
(
    if t<=0f then return quat 0 0 0 1 – t=0 => no rotation
    t0 = t-timeres – previous frame time
    t1 = t – current time
    rot0 = getrot(t0) – previous rotation: ...

the function recursively goes to zero time … which doesn’t make sense

here is how the function template might look:

fn getRot obj t offset:1f = 
(
	rot = quat 1

	if t > 0f do
	(
		...

		rot = ...
	)

	rot
)

#6

This is wrong in this particular case, or in general?


#7

the function must return some kind of “rotation” value. in your implementation the function used for the node’s array … so at least it should return an array … which doesn’t make sense for recursive using

I doubt at all that this function, as shown, can do anything reasonable


#8

My goal was to show him how to apply the code he have to multiple objects. I didn’t read the rest of the code. :slight_smile:


#9

Thanks for the replies. There was an error in the code I pasted. The corrected version is below. It definitely works and is functioning as I require. But I have to change the object name each time I apply it to a new object. I want to mod the code so it knows which object it is in.

I apply the script to the rotation controller script. If you animate a sphere objects motion, this applies proper roll rotations without nasty gimbal lock.

With this corrected code… anyone have suggestions?
Thanks for all the inputs so far.

obj = $Ball
timeres = 1f
fn getrot t =
(
if t<=0f then return quat 0 0 0 1 – t=0 => no rotation
t0 = t-timeres – previous frame time
t1 = t – current time
rot0 = getrot(t0) – previous rotation:
p0 = at time t0 obj.position-- previous position
p1 = at time t1 obj.position-- current position
if(p0==p1) then return rot0 – no distance is traveled
dif = p1-p0 – difference in positions
len = Length(dif) – distance that’s traveled
vec = dif / len – normalized movement vector.
r0 = at time t0 obj.radius – previous radius
r1 = at time t1 obj.radius – current radius
rotax = cross vec [0, 0, 1] – rotation axis
angle = 360*len/((r0+r1)*pi)-- rotation amount (in degs)
rotdif = quat angle rotax – rotation from t0 to t1
rot1 = rot0 + rotdif – total rotation
)
getrot(currentTime)


#10

Hmmm… some reason when I post the script here in the message body it changes something (perhaps minus’ into dashes, dunno) when I paste it back it buggers up. :confused:


#11

post it inbetween [code] ... [/code] tags


#12

Thanks.

So the working code is:

obj = $Ball
timeres = 1f
fn getrot t =
(
 if t<=0f then return quat 0 0 0 1 -- t=0 => no rotation
 t0 = t-timeres -- previous frame time
 t1 = t -- current time
 rot0 = getrot(t0) -- previous rotation:
 p0 = at time t0 obj.position-- previous position
 p1 = at time t1 obj.position-- current position
 if(p0==p1) then return rot0 -- no distance is traveled
 dif = p1-p0 -- difference in positions
 len = Length(dif) -- distance that's traveled
 vec = dif / len -- normalized movement vector.
 r0 = at time t0 obj.radius -- previous radius
 r1 = at time t1 obj.radius -- current radius
 rotax = cross vec [0, 0, 1] -- rotation axis
 angle = 360*len/((r0+r1)*pi)-- rotation amount (in degs)
 rotdif = quat angle rotax -- rotation from t0 to t1
 rot1 = rot0 + rotdif -- total rotation
)
getrot(currentTime)

#13

fn getWheelRotation obj t offset:1f =
(
	rot = quat 1
	if t > 0f do 
	(
		t0 = t - offset -- previous frame time
		t1 = t
		rot = getWheelRotation obj t0 offset:offset -- previous rotation:
		p0 = at time t0 obj.position-- previous position
		p1 = at time t1 obj.position-- current position
		if (p0 != p1) do 
		(
			r0 = at time t0 obj.radius -- previous radius
			r1 = at time t1 obj.radius -- current radius
			vec = normalize (p1 - p0) -- difference in positions
			len = length (p1 - p0) -- difference in positions
			axis = cross vec z_axis -- rotation axis
			angle = radtodeg (len * 2 /(r0 + r1)) -- rotation amount (in degs)
			turn = quat angle axis -- rotation from t0 to t1
			rot += turn -- total rotation
		)
	)
	rot
)

fn doWheelSetup obj = 
(
	obj.objectoffsetrot = eulerangles 90 90 0
	
	c = obj.rotation.controller = rotation_script() 
	c.addnode "obj" obj
	c.addconstant "offset" 1f
	c.setexpression "getWheelRotation obj F offset:offset"	
)


delete objects

w0 = cylinder radius:20 height:4 sides:64 slice:on slicefrom:350 pos:[0,0,20] wirecolor:green
doWheelSetup w0	
w1 = cylinder radius:20 height:4 sides:64 slice:on slicefrom:350 pos:[0,0,-30] wirecolor:orange
doWheelSetup w1

animate on at time 50 
(
	w0.pos = [200,0,40] 
	w0.radius = 40 

	w1.pos = [300,0,-40] 
	w1.radius = 10 
)

#14

this is better (at least it is faster):

delete objects
gc()

w = cylinder radius:20 height:4 sides:64 slice:on slicefrom:350 pos:[0,0,20] wirecolor:green

fn setupWheelControl obj = 
(
	obj.objectoffsetrot = eulerangles 90 90 0
	w.radius.controller = bezier_float()

	cc = obj.rotation.controller = rotation_list()
	c = cc.available.controller = rotation_script()

	c.addconstant "step" 1f
	c.addobject "radius" obj.baseobject[#radius]
	c.addobject "pos" obj.controller[#position]

	ss = @"
	(
		rot = quat 1
		at time 0f
		(
			p0 = pos.value
			r0 = radius.value
		)
		for t = 1f to F by step do at time t
		(
			p1 = pos.value
			r1 = radius.value
			vec = normalize (p1 - p0)
			len = length (p1 - p0)
			axis = cross vec z_axis 
			angle = radtodeg (len * 2 /(r0 + r1))
			turn = quat angle axis
			rot += turn

			p0 = p1
			r0 = r1
		)
		rot
	)
	"

	c.setexpression ss
	c
)

setupWheelControl w

animate on at time 100 
(
	w.pos = [400,0,40] 
	w.radius = 40 
)


#15

Hi, thanks for your input and help, but these scripts create a rolling cylinder… I’m working with a sphere that rolls in all directions on a plane.

Just looking for a way to run my existing script (which does exactly what I need) but I want to be able to drop it into the rotation controller for multiple balls and it work without me having to edit and retype the object name. Gonna be working with hundreds of balls.


#16

my script does exactly what you need. just try to understand how it works

fn setupBallControl obj = 
(
	obj.radius.controller = bezier_float()

	cc = obj.rotation.controller = rotation_list()
	c = cc.available.controller = rotation_script()

	c.addconstant "step" 1f
	c.addobject "radius" obj.baseobject[#radius]
	c.addobject "pos" obj.controller[#position]

	ss = @"
	(
		rot = quat 1
		at time 0f
		(
			p0 = pos.value
			r0 = radius.value
		)
		for t = 1f to F by step do at time t
		(
			p1 = pos.value
			r1 = radius.value
			vec = normalize (p1 - p0)
			len = length (p1 - p0)
			axis = cross vec z_axis 
			angle = radtodeg (len * 2 /(r0 + r1))
			turn = quat angle axis
			rot += turn

			p0 = p1
			r0 = r1
		)
		rot
	)
	"

	c.setexpression ss
	c
)


delete objects

redraw off
(
	plane name:#ground width:400 length:400 wirecolor:green 
	ch = Checker()
	ch.coords.U_Tiling = 2
		
	mat = Standard diffusemap:ch showinviewport:on 

	for k=5 to 20 do 
	(
		at time 0 b = geosphere radius:k pos:(random [-190,-190,k] [190,190,k]) 
		animate on at time (random 25 75) b.pos = random [-190,-190,k] [190,190,k] 
		animate on at time 100 b.pos = random [-190,-190,k] [190,190,k] 
			
		b.mat = mat
		setupBallControl b		
	)
)

#17

Thanks again, but still not working :frowning:
Using Max 2021 if that makes any difference.

If I put it in the script controller for rotation then I get:

Type error: Call needs function or class, got: undefined.

If I put it in in the rotation scripts of an xform in the stack (useful for later using a point cache), it states illegal self reference and actually hangs max.

Kinda out of ideas now, except the brute force rename in scripts many times.

Any last ditch ideas or suggestions?

Thanks though for all who tried.