Notifications
Clear all

[Closed] Animating IsHidden

Anyway, I think the Display Filter solution is much cleaner and safer:

delete objects
sps = for k=1 to 100 collect
(
	s = geosphere segments:150 pos:(random -[200,200,200] [200,200,200])  
	
	animate on
	(
		t = random 0 100
		at time t s.visibility = on
		at time (random t 100) s.visibility = off
	)
	
	s
)

fn visibilityFilter node = (not node.visibility)
registerDisplayFilterCallback visibilityFilter "Visibility"
k = getNumberDisplayFilters()
setDisplayFilter k on

that’s what I ended up with in 2014

Btw shouldn’t this display filter somehow be applied/removed on scene load/reset? Plugin approach seems simpler in this regard

RegisterDisplayFilterCallback as I remember was added to 2016 first time

1 Reply
(@serejah)
Joined: 10 months ago

Posts: 0

It was already there in 2014 and I used it in my another script.
It was sphere creation that ate all the ram and hung the max. Your script actually works fine if I lower sphere segments count.

EmptyModifier changes class of object…

I have an “Illegal self-reference” in your controller script …

easy to reproduce:

fn visibilityFilter node = (not node.visibility)
registerDisplayFilterCallback visibilityFilter "Visibility"
k = getNumberDisplayFilters()
setDisplayFilter k on

There is no built-in mechanism to save custom display filters with the file. But you can do it with persistent general callbacks (e.g. #filePostOpen)

The Rendering radio buttons simply unhide all the objects when se to “Enable in Renderer”, so when you render an animation they will be all unhidden but still use their visibility property. You can avoid using it is you use the “Render Hidden Geometry” in the render tab.

Since the “hidden” property can’t be natively animated, if an object is hidden when the render starts, it won’t be rendered in the whole animation. Can’t even set its state in the preRender or preRenderFrame callbacks.

But be aware that using animating these properties are not completely safe. It may be better is you use the .boxMode property instead of the .isHidden, if you can afford to have a bunch of lines in the viewports.

Here is an updated version which solves some redrawing issues and with some options changed.

(

	VisibilityTrackDeff = attributes VisibilityTrack
	(
		parameters main rollout:params
		(
			renderMode type:#integer ui:rb_renderMode animatable:false default:1
			visible    type:#boolean ui:chk_visible   animatable:true  default:true
		)
		
		rollout params "Parameters"
		(
			groupbox     gb            "Render Mode" width:136 height:88
			radiobuttons rb_renderMode ""                     pos:[22,24] labels:#("Enable in Viewport", "Enable in Renderer")
			button       bt_updateAll  "Update All Instances" pos:[22,60] width:118 height:26
			checkbox     chk_visible   "Visible"              pos:[16,102] checked:true
			
			fn UpdateRenderMode obj: =
			(
				if obj == unsupplied do obj = (refs.dependentnodes (custattributes.getowner this) firstonly:off)[1]
				
				obj.visibility.controller.SetConstant "renderMode" rb_renderMode.state
				obj.visibility.controller.Update()
				
				nodeinvalrect obj
			)
			
			on rb_renderMode changed arg do
			(
				UpdateRenderMode()
				completeredraw()
			)
			
			on bt_updateAll pressed do
			(
				for j in (getclassinstances emptyModifier) where j.name == "Visibility" do
				(
					j.renderMode = rb_renderMode.state
					obj = (refs.dependentnodes j firstonly:off)[1]
					UpdateRenderMode obj:obj
				)
				completeredraw()
			)
			
			on chk_visible changed arg do UpdateRenderMode()
		)
		
		on create do
		(
			visible.controller = boolean_float()
		)
	)
	
	fn AddVisibilityModifier obj =
	(
		mdf = emptyModifier name:"Visibility"
		custattributes.add mdf VisibilityTrackDeff
		
		ctrl = float_script()
		ctrl.addnode     "obj" obj
		ctrl.addobject   "modifier" mdf
		ctrl.addobject   "visible"  mdf.visible.controller
		ctrl.addconstant "renderMode" 1
		
		scr  = "if (modifier.enabled == true) then"							+ "\n"
		scr += "("															+ "\n"
		scr += "	obj.isHidden = (renderMode==1 and visible.value==0)"	+ "\n"
		scr += "	obj.boxMode  = (renderMode==2 and visible.value==0)"	+ "\n"
		scr += "	if renderMode==2 then visible.value else 1"				+ "\n"
		scr += ")else("														+ "\n"
		scr += "	obj.boxMode  = false"									+ "\n"
		scr += "	obj.isHidden = false"									+ "\n"
		scr += "	1.0"													+ "\n"
		scr +=")"
		
		ctrl.setexpression scr
		
		obj.visibility = on
		obj.visibility.controller = ctrl
		
		addmodifier obj mdf
		
		return mdf
	)
	
	delete objects
	
	obj = teapot segs:64
	
	AddVisibilityModifier obj
	
	with animate on
	(
		for j = 0 to 100 by 20 do
		(
			at time j obj.modifiers[1].visible = not obj.modifiers[1].visible
		)
	)
	
)

And here is a version that uses the .boxMode property only (also evaluates the panel to avoid the circular dependency error).

(

	VisibilityTrackDeff = attributes VisibilityTrack
	(
		parameters main rollout:params
		(
			visible type:#boolean ui:chk_visible animatable:true default:true
		)
		
		rollout params "Parameters"
		(
			checkbox chk_visible "Visible" checked:true
		)
		
		on create do
		(
			visible.controller = boolean_float()
		)
	)
	
	fn AddVisibilityModifier obj =
	(
		mdf = emptyModifier name:"Visibility"
		custattributes.add mdf VisibilityTrackDeff
		
		ctrl = float_script()
		ctrl.addnode     "obj" obj
		ctrl.addobject   "modifier" mdf
		ctrl.addobject   "visible"  mdf.visible.controller
		
		scr  = "if (modifier.enabled == true) and getCommandPanelTaskMode() != #display then" + "\n"
		scr += "("									+ "\n"
		scr += "	obj.boxMode = visible.value==0"	+ "\n"
		scr += "	visible.value"					+ "\n"
		scr += ")else("								+ "\n"
		scr += "	obj.boxMode  = false"			+ "\n"
		scr += "	1.0"							+ "\n"
		scr +=")"
		
		ctrl.setexpression scr
		
		obj.visibility = on
		obj.visibility.controller = ctrl
		
		addmodifier obj mdf
		
		return mdf
	)
	
	delete objects
	
	obj = teapot segs:64
	
	AddVisibilityModifier obj
	
	with animate on
	(
		for j = 0 to 100 by 20 do
		(
			at time j obj.modifiers[1].visible = not obj.modifiers[1].visible
		)
	)
	
)

I think it is “safer” too, somehow. And you can code it with to work with a modifier, if preferred.

Well, if you code a paradox you end up with an infinite loop.

Your example is one case, but there are others. For instance, simply go to the display panel and attempt to evaluate the script.

The callback needs to validate objects.

fn visibilityFilter node = (not node.visibility)
registerDisplayFilterCallback visibilityFilter "Visibility"
k = getNumberDisplayFilters()
setDisplayFilter k on

delete objects
box()
max select all

Now try to move the box and you get:

>> MAXScript Display filter Callback Exception:
-- Unknown property: "visibility" in $<root> <<
Page 5 / 6