[Closed] Changing a node's position at render time
Is there a way to simply intercept a nodes rendering and change the basis that it passes to the renderer? I just want something to look like its in a different position when a button is pressed but not actually save the altered position in the max file
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.
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?
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.
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