Notifications
Clear all

[Closed] Changing a node's position at render time

Is there a way to simply intercept a node’s rendering and change the basis that it passes to the renderer? I just want something to look like it’s in a different position when a button is pressed but not actually save the altered position in the max file

11 Replies
1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

In a pre-render callback, it is possible to modify any aspects of the scene and then restore them after the rendering finishes. This cannot be done per frame, it has to happen once before the scene is evaluated by the renderer.

See the Tutorial “How To … Change Objects At Render Time” in the MAXScript Help.

Thanks! That sounds like exactly what I needed

It looks like this only affects when I do a complete render of the scene, is it possible to change how the viewports render the objects?

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

You asked for “render time”, I gave you render time.

I don’t see why you couldn’t change the objects you want inside the script that enables/disables the state. No callbacks needed, just use the handle of the button you have created, or have a flag variable and change it between true and false using a MacroScript.

If you have no idea what I just said, let me know

Yeah, I apologize for not being more clear. What I’m trying to do is modify the position of 2 background layers at different speeds as I move the camera around they parallax correctly according to some settings. I was seeing if there was a way I could intercept the viewport rendering so only the way it looks changes but not the actual max stored positions.

If that is not possible I could just move the physical positions of the layers as the camera node gets moved around. I was a bit hesitant to do that because I don’t want the altered positions to be saved. The next person would then open the max file without being in “parallax mode” and all the positions will be off.

I suppose I could intercept the saving callback and make sure I move the positions back before saves occur, but then max crashes would be a problem still because the recovery file would be wrong as well.

You can register a redraw views callback (check out “Viewport Redraw Callback Mechanism” in the Help), but you have to keep in mind that any changes you make ARE actually applied to the objects.

The idea with a pre-save callback to restore the original positions might be a good one.

You could store the original transforms in the user properties or as AppData to be able to restore later.

Alternatively, you could apply layered or List controllers to the objects in question and change the active layer to switch between default and interactive transforms.

Hi,

Maybe you could acheive what you want usng the reaction manager. No scripting required. Simply changed the state of your objects depending on the position of the camera.

Josh.

Great suggestion, I think that will work well.

The Reaction Manager works great, but judging from my search results there is no way to automate position reaction creations through the SDK is there?

just my try at it, this is not fully tested and it’s obviously slower since it need to stop rendering every frame but I just wanted to see if it was possible to do it this way


/* 
	MarTroYx 04//27//2010 
*/ 
 
global g__CurrentFrame	= undefined 
global g__Finished			= undefined 
global g__NeedClosing		= undefined 
--//-- 
fn UpdateSceneOnFrameChange = ( 
	--//-- just something to do on frame change to see if it actualy work :-P 
	seed( currenttime as integer) 
	for f in objects do f.wirecolor = random blue white 
	) 
--//-- 
fn RemoveRenderCallbackAndReset = ( 
	g__CurrentFrame=g__Finished=g__NeedClosing=undefined 
	callbacks.removeScripts id:#mx_preRenderEval 
	callbacks.removeScripts id:#mx_postRender 
	callbacks.removeScripts id:#mx_preRenderFrame 
	callbacks.removeScripts id:#mx_postRenderFrame 
	ok 
	) 
--//-- 
fn AddRenderCallback = ( 
	RemoveRenderCallbackAndReset() 
	--//-- 
	callbacks.addScript #preRenderEval " 
	if g__CurrentFrame == undefined then ( 
		g__Finished			= false 
		g__NeedClosing		= false 
		rendStart 			= animationrange.Start 
		rendEnd 				= animationrange.End+1f 
		g__CurrentFrame	= rendStart 
		slidertime			= g__CurrentFrame 
		) 
	else if slidertime < rendEnd-1f then ( 
		animationrange = interval currenttime rendEnd 
		) 
	--//-- 
	if currenttime == rendEnd do ( 
		animationrange = interval g__CurrentFrame (rendEnd-1f) 
		slidertime = g__CurrentFrame 
		g__CurrentFrame=g__Finished=g__NeedClosing=undefined 
		) 
	" id:#mx_preRenderEval 
	--//-- 
	callbacks.addScript #postRender " 
	if (slidertime <= rendEnd) and g__Finished == false do ( 
		g__NeedClosing 	= false 
		ReclusionBypass=dotnetobject \"system.windows.forms.timer\" 
		ReclusionBypass.interval=1 
		dotnet.addEventHandler ReclusionBypass \"tick\" (fn doit s e = (; 
			try ( 
					local Xdialog=windows.getChildrenHWND 0 parent:#max 
					--//-- 
					for f in Xdialog do ( 
						if matchpattern f[5] pattern:\"*, frame*\" ignoreCase:false do ( 
							local targetBT = windows.getChildHWND f[1] \"Render\" 
							--//-- 
							if targetBT != undefined then ( 
								UpdateSceneOnFrameChange() -->ask for scene change here 
								UIAccessor.PressButton targetBT[1] -->then continue on with next frame 
								) 
							else (format \"Error #1
\" to:listener) 
							--//-- 
							exit 
							) 
						) 
					--//-- 
					s.stop() 
					s.dispose() 
					gc light:true 
					) 
			catch 
					( 
					format \"Error #2
\" to:listener 
					s.stop() 
					s.dispose() 
					) 
				) 
			) 
		ReclusionBypass.start() 
		) 
	" id:#mx_postRender 
	--//-- 
	callbacks.addScript #preRenderFrame " 
	if (g__NeedClosing == true and (slidertime < rendEnd)) or g__NeedClosing == undefined do ( 
		local Xdialog=windows.getChildrenHWND 0 parent:#max 
		--//-- 
		for f in Xdialog do ( 
			if matchpattern f[5] pattern:\"*Rendering*\" ignoreCase:false do ( 
				UIAccessor.SendMessageID f[1] #IDCANCEL 
				exit 
				) 
			) 
		--//-- 
		gc light:true 
		)  
	" id:#mx_preRenderFrame 
	--//-- 
	callbacks.addScript #postRenderFrame " 
	if (slidertime <= rendEnd) do ( 
		g__NeedClosing	= true 
		) 
	" id:#mx_postRenderFrame 
	--//-- 
	) 
--//-- 
--//--note that this only work in active range. 
--//--this also assume that render frame windows is activated  
--//--& that you're using quickrender  
--//--& that render option dialog is closed :-) 
--//-- 
AddRenderCallback() 
clearlistener() 
ok 
--//--

Best regard,
Martin

…just a quick fix to make it work with mentalray