ScriptSpot

Forum topic · General Scripting

apply a state for every camera in the scene!

By artrender.info · 2013-05-14

Description

I have a house in 3d and a background in it! I want to create scene states for every camera, so when I switch to any of them, I would see automatically the changes according to it's state! Any ideas?

Comments (32)

magicseed · 2016-09-20

Hi,

Where to download this script please?

Regards,
neil

but still the same

artrender.info · 2013-05-17

May be smth else?


try(destroyDialog ::bgaRoll)catch()

rollout bgaRoll "• • •"
(
	local d
	fn collectStates = (for s in 1 to sceneStateMgr.GetCount() collect sceneStateMgr.GetSceneState s)
	fn collectCameras ddl lb = if (cams = for c in cameras where not isKindof c TargetObject collect c).count != 0 do
	(
		local states = collectStates(), stCamList = #(), avCamList = #()
		for c in cams do
		(
			userProp = getUserPropBuffer c
			if userProp == "" then append avCamList c.name else
			(
				if findItem states userProp != 0 then append stCamList c.name else
				(
					setUserPropBuffer c "" ; append avCamList c.name
				)
			)
		)
		ddl.items = avCamList ; lb.items = stCamList
	)
	dropDownList ddl1 "Scene States:" width:190 pos:[5,5]
	dropDownList ddl2 "Available Cameras:" width:190 pos:[5,45]
	button btn1 "Set State To Camera" width:110 height:20 pos:[5,86]
	button btn2 "Refresh All" width:78 height:20 pos:[117,86]
	listbox lbox "State Cameras:" width:190 height:15 pos:[5,110]
	fn init = 
	(
		bgaRoll.ddl1.items = collectStates() 
		collectCameras bgaRoll.ddl2 bgaRoll.lbox
	)
	on bgaRoll open do init()

on btn2 pressed do 
(
	objTMData = attributes objData
    (
		local objTMS = for o in objects collect DataPair o o.transform 
		fn setObjTM arr = 
		(
			for i in 1 to arr.count where isValidNode arr[i].v1 do arr[i].v1.transform = arr[i].v2
		)
    )
    local d = FreeCamera()
	custAttributes.add d objTMData
 
)
on btn2 rightclick do
(
    ca = custAttributes.get d objTMData
    ca.setObjTM ca.objTMS
)	
	
	
	
	
	on btn1 pressed do 
	(
		if bgaRoll.ddl1.items.count != 0 and bgaRoll.ddl2.items.count != 0 do
		(
			if (cam = getNodeByName bgaRoll.ddl2.selected) != undefined do
			(			
				setUserPropBuffer cam bgaRoll.ddl1.selected
				bgaRoll.lbox.items = append bgaRoll.lbox.items bgaRoll.ddl2.selected
				bgaRoll.ddl2.items = deleteitem bgaRoll.ddl2.items bgaRoll.ddl2.selection
			)
		)
	)
	on lbox selected itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then select c else init()
	)
	on lbox doubleClicked itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then 
		(
			if sceneStateMgr.FindSceneState (st = getUserPropBuffer c) != 0 do
			(
				sceneStateMgr.RestoreAllParts st
				viewport.setCamera c
			)
		) else init()
	)
)
createDialog bgaRoll 200 330 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

in line

on btn2 rightclick do
(
ca = custAttributes.get d objTMData -- Unable to convert: undefined to type: MaxObject <<

ahhh

artrender.info · 2013-05-17

srry! My fault!

STILL THE SAME ERROR

artrender.info · 2013-05-17


try(destroyDialog ::bgaRoll)catch()


rollout bgaRoll "• • •"
(
	

	fn collectStates = (for s in 1 to sceneStateMgr.GetCount() collect sceneStateMgr.GetSceneState s)
	fn collectCameras ddl lb = if (cams = for c in cameras where not isKindof c TargetObject collect c).count != 0 do
	(
		local states = collectStates(), stCamList = #(), avCamList = #()
		for c in cams do
		(
			userProp = getUserPropBuffer c
			if userProp == "" then append avCamList c.name else
			(
				if findItem states userProp != 0 then append stCamList c.name else
				(
					setUserPropBuffer c "" ; append avCamList c.name
				)
			)
		)
		ddl.items = avCamList ; lb.items = stCamList
	)
	dropDownList ddl1 "Scene States:" width:190 pos:[5,5]
	dropDownList ddl2 "Available Cameras:" width:190 pos:[5,45]
	button btn1 "Set State To Camera" width:110 height:20 pos:[5,86]
	button btn2 "Refresh All" width:78 height:20 pos:[117,86]
	listbox lbox "State Cameras:" width:190 height:15 pos:[5,110]
	fn init = 
	(
		bgaRoll.ddl1.items = collectStates() 
		collectCameras bgaRoll.ddl2 bgaRoll.lbox
	)
	on bgaRoll open do init()
	
on btn2 pressed do 
(
	objTMData = attributes objData
    (
		local objTMS = for o in objects collect DataPair o o.transform 
		fn setObjTM arr = 
		(
			for i in 1 to arr.count where isValidNode arr[i].v1 do arr[i].v1.transform = arr[i].v2
		)
    )
    local d = FreeCamera()
	custAttributes.add d objTMData
 
)
on btn2 rightclick do
(
    ca = custAttributes.get d objTMData
    ca.setObjTM ca.objTMS
)	
	
	
	
	
	on btn1 pressed do 
	(
		if bgaRoll.ddl1.items.count != 0 and bgaRoll.ddl2.items.count != 0 do
		(
			if (cam = getNodeByName bgaRoll.ddl2.selected) != undefined do
			(			
				setUserPropBuffer cam bgaRoll.ddl1.selected
				bgaRoll.lbox.items = append bgaRoll.lbox.items bgaRoll.ddl2.selected
				bgaRoll.ddl2.items = deleteitem bgaRoll.ddl2.items bgaRoll.ddl2.selection
			)
		)
	)
	on lbox selected itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then select c else init()
	)
	on lbox doubleClicked itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then 
		(
			if sceneStateMgr.FindSceneState (st = getUserPropBuffer c) != 0 do
			(
				sceneStateMgr.RestoreAllParts st
				viewport.setCamera c
			)
		) else init()
	)
)
createDialog bgaRoll 200 330 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

in line

on btn2 rightclick do
(
ca = custAttributes.get d objTMData -- Unable to convert: undefined to type: MaxObject <<

barigazy · 2013-05-17

I already told you. You need to put local variable "d" outside function.

rollout bgaRoll "• • •"
(
local d
...
)

... but

barigazy · 2013-05-17

you not need this free camera (it'sonly for example). What you need is to add this CA to all cameras in List View. You can add also more infos not only scene objects transform informations.

:)

barigazy · 2013-05-17

Try to write something and then we talk.

I look at this code, and I can't understand!

artrender.info · 2013-05-17

if

ca = custAttributes.get d objTMData 

doesn't work for camera d, then it will not work for other cameras as well ?!!!?

barigazy · 2013-05-17

The problem is not CA. You need to define better scenario for this tool, because there is more limitations that you need to consider.
The main problems are:
- Transform, animated and linked objects
- Different count of objects in different states
and who knows what more.
That's why Autodesk recreate whole State Scene in max2013+ ei. max2012(SAP)
I never play with this. Maybe someone can help you with that.

now I can rest in piece!

artrender.info · 2013-05-16

Barigazy, look! I've added to your code some lines from previous hints


try(destroyDialog ::bgaRoll)catch()


	objTMData = attributes objData
	(
		local objTMS = for o in objects collect DataPair o o.transform 
		fn setObjTM arr = 
			for i in 1 to arr.count where isValidNode arr[i].v1 do 
				arr[i].v1.transform = arr[i].v2
	)
rollout bgaRoll "• • •"
(
	

	fn collectStates = (for s in 1 to sceneStateMgr.GetCount() collect sceneStateMgr.GetSceneState s)
	fn collectCameras ddl lb = if (cams = for c in cameras where not isKindof c TargetObject collect c).count != 0 do
	(
		local states = collectStates(), stCamList = #(), avCamList = #()
		for c in cams do
		(
			userProp = getUserPropBuffer c
			if userProp == "" then append avCamList c.name else
			(
				if findItem states userProp != 0 then append stCamList c.name else
				(
					setUserPropBuffer c "" ; append avCamList c.name
				)
			)
		)
		ddl.items = avCamList ; lb.items = stCamList
	)
	dropDownList ddl1 "Scene States:" width:190 pos:[5,5]
	dropDownList ddl2 "Available Cameras:" width:190 pos:[5,45]
	button btn1 "Set State To Camera" width:110 height:20 pos:[5,86]
	button btn2 "Refresh All" width:78 height:20 pos:[117,86]
	listbox lbox "State Cameras:" width:190 height:15 pos:[5,110]
	fn init = 
	(
		local d = FreeCamera()
		custAttributes.add d objTMData
		bgaRoll.ddl1.items = collectStates() 
		collectCameras bgaRoll.ddl2 bgaRoll.lbox
	)
	on bgaRoll open do init()
	on btn2 pressed do 
	(
		--init()
		ca = custAttributes.get d objTMData
		ca.setObjTM ca.objTMS
	)
	on btn1 pressed do 
	(
		if bgaRoll.ddl1.items.count != 0 and bgaRoll.ddl2.items.count != 0 do
		(
			if (cam = getNodeByName bgaRoll.ddl2.selected) != undefined do
			(			
				setUserPropBuffer cam bgaRoll.ddl1.selected
				bgaRoll.lbox.items = append bgaRoll.lbox.items bgaRoll.ddl2.selected
				bgaRoll.ddl2.items = deleteitem bgaRoll.ddl2.items bgaRoll.ddl2.selection
			)
		)
	)
	on lbox selected itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then select c else init()
	)
	on lbox doubleClicked itm do 
	(
		if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then 
		(
			if sceneStateMgr.FindSceneState (st = getUserPropBuffer c) != 0 do
			(
				sceneStateMgr.RestoreAllParts st
				viewport.setCamera c
			)
		) else init()
	)
)
createDialog bgaRoll 200 330 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

A runt it, then I move an object from the scene and then,
When I press refresh, I get error

-- Unable to convert: undefined to type: MaxObject
error for -> ca = custAttributes.get d objTMData

barigazy · 2013-05-16

You can't acess local variable d. You need to put local d outside event ei. function. Or even better why not add all inside "on btn2" event

on btn2 pressed do
(
objTMData = attributes objData
(
local objTMS = for o in objects collect DataPair o o.transform
fn setObjTM arr =
(
for i in 1 to arr.count where isValidNode arr[i].v1 do arr[i].v1.transform = arr[i].v2
)
)
local d = FreeCamera()
custAttributes.add d objTMData

)
on btn2 rightclick do
(
ca = custAttributes.get d objTMData
ca.setObjTM ca.objTMS
)

thx

artrender.info · 2013-05-16

I wonder, are you just one person - barigazy, or a big team of experts! You answer 24h/24h to our question! Do you sleep, do you eat? Or you have made a script for all this things that take too much time! Share with me if you have such scripts? A script - not to go to the shop, not to cook and so on!

:)

barigazy · 2013-05-16

Yup. I'm human :) No team just me.

Barigazy, tell me please

artrender.info · 2013-05-16

How to check if an object is parent?

barigazy · 2013-05-16

Check

$.children.count
--if more the zero then this is the parent

some useful fn's

barigazy · 2013-05-16


fn getGrandParentName obj =
(
local pn = obj.name
-- repeat while there are more parents
while obj.parent != undefined do
(
-- follow link out to next parent & pretend its name
obj = obj.parent ; pn = obj.name
) ; pn
)
grandParentname = getGrandParentName $
--------------------------------------------
--to check if obj transform is animated
$[3].isAnimated
--------------------------------------------
fn getAllChildren obj =
(
local o = obj,childArr = #()
while o.children[1] != undefined do
(
append childArr o.children[1]
o = childArr[childArr.count]
)
childArr
)

thx

artrender.info · 2013-05-16

I think, I will have for every camera from the listbox, rightclick/ in a popup window- button pick object you want to transform => pick the object => check if it is animated and then if it is parent-=>if not allow user to move/scale/rotate that object! a button-save transform, dropdown lsit with objects that are linked to that camera and with the option to remove any of objects from the list! This way, the script will do it's job!

I need of course much more time to do that, but I will try to make it later! I appreciate very much your time, Barigazy!!!!!!!!!!!

great

artrender.info · 2013-05-15

but may be we have to give possibility to select from non animated objects and nonparent only, because we change coordinates of them for given cameras!

Thank you Barigazy! It's a blessing to have you here! You help us a lot! May be, that's why 3d max does not contain scene states for object transforms - because of animation of the object!

barigazy · 2013-05-16

this is the recursive code from mxs help

animated_props = #()
fn getAnimatedProps theObject =
(
if try(theObject.isAnimated)catch(false) do append animated_props theObject
for i = 1 to theObject.numSubs do getAnimatedProps theObject[i]
)
getAnimatedProps $
if animated_props.count == 0 then "non animated object" else "animated object"

barigazy · 2013-05-15


-- test with this:
-- create first some random objects in the scenes

-- define custAttributes and assigne to some object in this case free camera
objTMData = attributes objData
(
local objTMS = for o in objects collect DataPair o o.transform
fn setObjTM arr = for i in 1 to arr.count where isValidNode arr[i].v1 do arr[i].v1.transform = arr[i].v2
)
d = FreeCamera()
--assigne to camera
custAttributes.add d objTMData
-- now you can test by changing position and rotation of scene objects
-- and finaly run next two lines
ca = custAttributes.get d objTMData
ca.setObjTM ca.objTMS

-- this is not good way if some objects are parented or animated

a simple thing

artrender.info · 2013-05-15

a takes so much time to think, rethink and so on!

barigazy · 2013-05-15

wait a minute

how to inform max

artrender.info · 2013-05-15

which object it should understand like target objects that should move, why if there are more then one object that should have their own transformations?

however

artrender.info · 2013-05-15

not to copy, but to save!
and then, to be able to reload them again

Thank you, barigazy!!!

artrender.info · 2013-05-15

I've found some info about custom attributes here
http://www.paulneale.com/tutorials/custAttributes/customAttributes.htm

should I have smth like that?


ca=attributes object transform
(
	--Function for getting info about move, scale, roate
	fn move_scale_rotate object =
	(
             get move
             get rotate
             get scale
	)
)

Oh, yeeeeeeeeeeeeeees!!!

artrender.info · 2013-05-15

that's amazing! You have done all the script! That's really incredible! Thx Barigazy! Just my fault is that I didn't noticed that scene states do not support object transforms- I wanted to move/rotate the plane and save scene states for it! It is possible to copy and hide, but if I have heavy models to copy and hide then this would not be a good way! Why didn't they do object transform for scene states?!! 3dMax always needs a lot of improvements that had to be done 6 years ago! However,I don't imagine my life without it! hm...

barigazy · 2013-05-15

You can store transform in a struct or even better castom attribute and assigne to the camera

I want

artrender.info · 2013-05-14

to link somehow for every camera a scene state, so when switching to camera I would get this scene state switched on!

;)

barigazy · 2013-05-15

I wrote en example script for old (msx2012) scene state. For versions above 2012 you need to change state scene method. But concept that you ask is the same.
Cheers!

try(destroyDialog ::bgaRoll)catch()
rollout bgaRoll "• • •"
(
fn collectStates = (for s in 1 to sceneStateMgr.GetCount() collect sceneStateMgr.GetSceneState s)
fn collectCameras ddl lb = if (cams = for c in cameras where not isKindof c TargetObject collect c).count != 0 do
(
local states = collectStates(), stCamList = #(), avCamList = #()
for c in cams do
(
userProp = getUserPropBuffer c
if userProp == "" then append avCamList c.name else
(
if findItem states userProp != 0 then append stCamList c.name else
(
setUserPropBuffer c "" ; append avCamList c.name
)
)
)
ddl.items = avCamList ; lb.items = stCamList
)
dropDownList ddl1 "Scene States:" width:190 pos:[5,5]
dropDownList ddl2 "Available Cameras:" width:190 pos:[5,45]
button btn1 "Set State To Camera" width:110 height:20 pos:[5,86]
button btn2 "Refresh All" width:78 height:20 pos:[117,86]
listbox lbox "State Cameras:" width:190 height:15 pos:[5,110]
fn init = (bgaRoll.ddl1.items = collectStates() ; collectCameras bgaRoll.ddl2 bgaRoll.lbox)
on bgaRoll open do init()
on btn2 pressed do init()
on btn1 pressed do
(
if bgaRoll.ddl1.items.count != 0 and bgaRoll.ddl2.items.count != 0 do
(
if (cam = getNodeByName bgaRoll.ddl2.selected) != undefined do
(
setUserPropBuffer cam bgaRoll.ddl1.selected
bgaRoll.lbox.items = append bgaRoll.lbox.items bgaRoll.ddl2.selected
bgaRoll.ddl2.items = deleteitem bgaRoll.ddl2.items bgaRoll.ddl2.selection
)
)
)
on lbox selected itm do
(
if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then select c else init()
)
on lbox doubleClicked itm do
(
if isValidNode (c = (getNodeByName bgaRoll.lbox.selected)) then
(
if sceneStateMgr.FindSceneState (st = getUserPropBuffer c) != 0 do
(
sceneStateMgr.RestoreAllParts st
viewport.setCamera c
)
) else init()
)
)
createDialog bgaRoll 200 330 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

Thank you, barigazy!!!

artrender.info · 2013-05-14

in fact I have a multilistBox filled with cameras:


functionfn =
(
	camNamesList = #()
	camList = #()
	i=1
	while  i <= cameras.count do
	(
		if classof cameras[i] != Targetobject  then 
			append camNamesList cameras[i].name
		i = i+1
	)
)

rollout mycam "List Cameras"
(
	...
	functionfn()
	multilistBox mycameras "" items:camNamesList height:200 width: 200 pos:[0,0]
	...
)

But I don't understand what you meant "You can store scene state name in camera's user defined settings. Then when you select camera from dd list viewport will changed to this camera and you need also simple fn to restore scene state by name"

barigazy · 2013-05-14

Simply create dropdown list for all scene cameras. You can store scene state name in camera's user defined settings. Then when you select camera from dd list viewport will changed to this camera and you need also simple fn to restore scene state by name. Maybe is good to use camera name for scene state name.