[Closed] How can I make this update between frames on render?
I’m working on something to improve working with lights in Max. The sample below is a simplified version of a small part of what I’m doing, but it illustrates the issue I’m having. Basically, this script should allow a light’s shadow type to be animated. It works while scrubbing the slider, but not while rendering multiple frames at a time. What is it I’m doing wrong?
-- Function to set a light's shadow type
fn setShadowType lit t = (
local sg = &lit.shadowGenerator
case t of (
1: if classOf (*sg) != Adv__Ray_Traced do (*sg) = Adv__Ray_Traced()
2: if classOf (*sg) != mental_ray_Shadow_Map do (*sg) = mental_ray_Shadow_Map()
3: if classOf (*sg) != Area_Shadows do (*sg) = Area_Shadows()
4: if classOf (*sg) != ShadowMap do (*sg) = ShadowMap()
5: if classOf (*sg) != RayTraceShadow do (*sg) = RayTraceShadow()
default: ()
)
)
-- Function called by ddl_ShadowType handler
fn h_ddl_ShadowType ctrl = (
local h = ctrl.modifiers[#holder]
setShadowType h.lit h.shadowType
)
-- Custom attributes for control object
ca_ShadowControl = attributes "shadowControl" (
parameters params rollout:RO (
lit type:#maxObject
shadowType type:#integer ui:ddl_ShadowType animatable:true default:1
)
rollout RO "Shadow Control" (
local ctrl
dropDownList ddl_ShadowType "Shadow Type" \
items:#("Adv. Ray Traced", "mental ray Shadow Map", "Area Shadows", "Shadow Map", "Ray Traced Shadows")
on RO open do (
animButtonState = true
ctrl = (refs.dependentNodes (custAttributes.getOwner this))[1]
)
on ddl_ShadowType selected s do h_ddl_ShadowType ctrl
)
)
-- Set up callbacks
-------------------
unregisterTimeCallback updateShadows
callbacks.removeScripts id:#shadowControl
fn updateShadows = (
format "fn updateShadows
"
format " currentTime: %
" currentTime
local ctrl
for o in objects where (o.modifiers[#holder] != undefined) do ctrl = o
local h = ctrl.modifiers[#holder]
local lit = refs.dependentNodes h.lit firstOnly:true
local sg = &lit.shadowGenerator
case h.shadowType of (
1: if classOf (*sg) != Adv__Ray_Traced do (*sg) = Adv__Ray_Traced()
2: if classOf (*sg) != mental_ray_Shadow_Map do (*sg) = mental_ray_Shadow_Map()
3: if classOf (*sg) != Area_Shadows do (*sg) = Area_Shadows()
4: if classOf (*sg) != ShadowMap do (*sg) = ShadowMap()
5: if classOf (*sg) != RayTraceShadow do (*sg) = RayTraceShadow()
)
format " classOf lit.shadowGenerator: %
" (classOf lit.shadowGenerator)
)
registerTimeCallback updateShadows
callbacks.addScript #preRenderEval "updateShadows()" id:#shadowControl
-- Set up test scene
(
delete objects
p = plane pos:[0,0,0] length:200 width:200
s = sphere pos:[37.5,25,50]
lit = freeSpot pos:[0,0,200] castShadows:on
ctrl = point pos:[0,0,0] size:100 box:on cross:off
holder = emptyModifier name:"holder"
custAttributes.add holder ca_ShadowControl #unique
addModifier ctrl holder
holder.lit = lit
with animate on for k = 0 to 4 do at time k ( -- General Parameters: (Shadow Types)
ctrl.modifiers[#holder].shadowType = k + 1
h_ddl_ShadowType ctrl
)
)
The #preRenderFrame notification is “sent out after the renderer has taken a snapshot of the scene geometry”.
Have you tryed with the #preRenderEval?
Yes, I tried #prerendereval, but there was no difference in the result
I’ve edited the script to output every time the setShadowType function runs, along with the current time and the resulting shadow generator of the light.
As it renders, it displays the following in the listener:
fn updateShadows
currentTime: 0f
classOf lit.shadowGenerator: Adv__Ray_Traced
fn updateShadows
currentTime: 1f
classOf lit.shadowGenerator: mental_ray_Shadow_Map
fn updateShadows
currentTime: 2f
classOf lit.shadowGenerator: Area_Shadows
fn updateShadows
currentTime: 3f
classOf lit.shadowGenerator: shadowMap
fn updateShadows
currentTime: 4f
classOf lit.shadowGenerator: raytraceShadow
So the function is clearly being called, but for whatever reason the resulting changes are being ignored by the renderer. Hopefully this can help someone figure out what the problem is?
So after some further testing I have come to the realization that these callbacks don’t work the way I thought they did. Either there is some way to make them do what I want, or I will have to find a different approach…
Another scripter (PolyTools3D) helped me out on a previous project, and I thought I might be able to apply what I learned from there to this script.
My idea is that maybe I can create an array of temporary lights, each with its own shadow generator, just prior to rendering, and delete them afterward. When I run the following it works as expected, but it requires the associated function to be run by the user manually. My attempts to incorporate calling the functions directly through the callbacks result in the created script controller executing improperly.
Can anyone take a look at this and see if there is a way to fix that?
fn createShadowLightArray ctrl src = (
L1 = copy src; L1.name = "L1"; L1.shadowGenerator = (Adv__Ray_Traced())
L2 = copy src; L2.name = "L2"; L2.shadowGenerator = (mental_ray_Shadow_Map())
L3 = copy src; L3.name = "L3"; L3.shadowGenerator = (Area_Shadows())
L4 = copy src; L4.name = "L4"; L4.shadowGenerator = (shadowMap())
L5 = copy src; L5.name = "L5"; L5.shadowGenerator = (raytraceShadow())
global lightArray = #(L1, L2, L3, L4, L5)
scr = ctrl.visibility.controller
for lit in lightArray do scr.AddNode lit.name lit
expr = "lightArray = #(L1, L2, L3, L4, L5)
"
expr += "for lit = 1 to lightArray.count do try (lightArray[lit].enabled = (ctrl.lit == lit); lightArray[lit].ishidden = (ctrl.lit != lit)) catch()
"
expr += "1"
scr.setExpression expr
return lightArray
)
fn destroyShadowLightArray ctrl lightArray = (
scr = ctrl.visibility.controller
for lit in lightArray do (
scr.deleteVariable lit.name
delete lit
)
scr.setExpression "1"
)
(
delete objects
box()
global testLight = omniLight pos:[0,0,50] castShadows:on
global ctrl = plane length:50 width:150 lengthSegs:1 widthSegs:1 wireColor:white --isSelected:true
ctrl.visibility = float_script()
scr = float_script()
ctrl.visibility.controller = scr
scr.AddNode "ctrl" ctrl
scr.setExpression "1"
ca = attributes ca attribID:#(0, 0) (
parameters params rollout:params (
lit type:#integer default:1 animatable:on ui:lightID
)
rollout params "Shadow Lights Control" (
radiobuttons lightID "Light ID" labels:#("1", "2", "3", "4", "5")
)
)
custAttributes.add ctrl ca #unique
callbacks.removeScripts id:#test
callbacks.addScript #preRender "testLight.enabled = false; for lit in lightArray do lit.enabled = true" id:#test
callbacks.addScript #postRender "testLight.enabled = true; destroyShadowLightArray ctrl lightArray" id:#test
seed 0
with animate on (
for j = 50 to 0 by (random -1 -5) do at time j ctrl.lit = random 1 5
)
completeRedraw()
/*
-- RUN PRIOR TO RENDERING
global lightArray = createShadowLightArray ctrl testLight
*/
)
I’m starting to think I am going to have to look to the SDK for a solution…