Announcement

Collapse
No announcement yet.

Maxscript callback help

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Maxscript callback help

    I'm looking for a little guidance in getting a callback to work for what I need. I can usually limp by in maxscript using the online help but for callbacks it seems kind of cryptic. There seems to be a thousand options with little help beyond the one example (I don't want to delete the teapot I just made!). Simply put, I'm trying to have a my script do something (i.e., a function) whenever a physical camera deleted in the scene. I can add the #selectedNodesPreDelete callback to watch for node deletions and get the list of nodes deleted through callbacks.notificationParam() and then check if one of them is a physical cameras but if I then run the function the nodes aren't actually deleted yet so nothing is really changed, right? If I use the #selectedNodesPostDelete I have no idea if it was a camera that was deleted because notificationParam is undefined.

    Am I going about this right? Seems like I'm missing some important element or concept about callbacks. Is there a better way?

    Any help is greatly appreciated. Anyone know a good tutorial for callbacks?
    Last edited by dlparisi; 01-02-2016, 10:46 AM.
    www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

  • #2
    What do you want to do with the cameras? I can help, but I'm not exactly sure what you want to do.

    Yes, if that callback fires, your node won't actually be deleted yet. Do you want it so the vray camera isn't deleted?

    Code:
    (
        global OnCameraDelete
    
    
        -- Remove previous callbacks we setup
        callbacks.removeScripts id:#testOnCameraDelete
    
    
        -- Add the callback for the function OnCameraDelete()
        callbacks.addScript #selectedNodesPreDelete "OnCameraDelete()" id:#testOnCameraDelete
        
        -- Here's the function that gets called when the callback fires
        function OnCameraDelete = (
            local SelectedObjects = callbacks.notificationParam()
            
            -- The SelectedObjects array contains all of the objects we had selected for deletion
            for o in SelectedObjects do (
                if (classof o == VRayPhysicalCamera) then 
                (
                    print ("V-Ray camera selected for deletion: " + o.name)
                )
            )        
        )
    )
    Last edited by MoonDoggie; 01-02-2016, 11:22 AM.
    Colin Senner

    Comment


    • #3
      Thanks a lot Colin. I have a camera lister script/dialog that allows me to quickly adjust the cameras in the scene. It's started from Track's camera lister (can't find the link now) but I've heavily modified to it my needs, added some functionality and added support for physical cameras. It works great but I'm just trying to push it so that if a scene camera is deleted it automatically refreshes the dialog UI which then has the new list of cameras (without the deleted one). It basically just rebuilds the camera list from scratch each time it's refreshed so the camera should no longer be in the scene. I know I could easily set it up to catch any errors if I try to adjust a deleted camera, I'm just trying to be fancy. I may try to have it remove the matching, to be deleted camera, from the array of scene cameras it collects (code portion below). This might get complicated if I delete multiple cameras though.
      Code:
      physCamArr=for p in cameras where (classof  p == Physical and p.isHidden != true ) collect p
      So in short, I need know that a camera has been deleted, then after deletion, rebuild the UI. Honestly, don't spend a lot of time on this, but thanks for your help.
      www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

      Comment


      • #4
        Here's what I think you're asking for:

        The PostDelete callback doesn't work obviously, as you've pointed out the object no longer exists.

        Here's one way to save any vray camera from being deleted.

        Code:
        (
            global OnCameraPreDelete
            global OnCameraPostDelete
            
            global ArrayOfObjectsToNotDelete
            
            -- Here's the function that gets called when the callback fires
            --function OnCameraPostDelete = (
                -- Doesn't work, object is deleted
            --)
            
            -- Here's the function that gets called when the callback fires
            function OnCameraPreDelete = (
                -- Store a global variable of objects to not delete
                ArrayOfObjectsToNotDelete = #()
                
                local SelectedObjects = (callbacks.notificationParam())
                
                local newCamera = #()
                local originalName = ""
                    
                -- The SelectedObjects array contains all of the objects we had selected for deletion
                for o in SelectedObjects do (
                    if (classof o == VRayPhysicalCamera) then 
                    (
                        print ("Cloning the V-Ray camera selected for deletion: " + o.name)
                        
                        -- Save the original camera's name
                        originalName = o.name
                        
                        maxOps.CloneNodes &o cloneType:#instance newNodes:&newCamera
                        
                        -- Rename the cloned camera to the original name
                        newCamera[1].name = originalName
                    )
                )        
            )    
            
            -- Remove previous callbacks we setup
            callbacks.removeScripts id:#OnCameraPreDelete
            --callbacks.removeScripts id:#OnCameraPostDelete
        
        
            -- Add the callback for the function OnCameraDelete()
            callbacks.addScript #selectedNodesPreDelete "OnCameraPreDelete()" id:#OnCameraPreDelete
            
            -- Add the callback for the function OnCameraDelete()
            --callbacks.addScript #selectedNodesPostDelete "OnCameraPostDelete()" id:#OnCameraPostDelete
        
        
            callbacks.show #selectedNodesPreDelete
            --callbacks.show #selectedNodesPostDelete
                
            true
        )
        Colin Senner

        Comment


        • #5
          Originally posted by dlparisi View Post
          Thanks a lot Colin. I have a camera lister script/dialog that allows me to quickly adjust the cameras in the scene. It's started from Track's camera lister (can't find the link now) but I've heavily modified to it my needs, added some functionality and added support for physical cameras. It works great but I'm just trying to push it so that if a scene camera is deleted it automatically refreshes the dialog UI which then has the new list of cameras (without the deleted one). It basically just rebuilds the camera list from scratch each time it's refreshed so the camera should no longer be in the scene. I know I could easily set it up to catch any errors if I try to adjust a deleted camera, I'm just trying to be fancy. I may try to have it remove the matching, to be deleted camera, from the array of scene cameras it collects (code portion below). This might get complicated if I delete multiple cameras though.
          Code:
          physCamArr=for p in cameras where (classof  p == Physical and p.isHidden != true ) collect p
          So in short, I need know that a camera has been deleted, then after deletion, rebuild the UI. Honestly, don't spend a lot of time on this, but thanks for your help.
          Gotcha, here is a proof of concept:

          Notes: There are lots of other callbacks we would need to use to detect any possibility of a new camera.

          Code:
          (
          	-- Global declarations 
          	global rlt_test
          	global OnCameraPossibleChangeEvent	-- Callback for post delete
          
          
          	callbacks.removeScripts id:#OnCameraPossibleChangeEvent
          	
          	-- Add the callback for the functions
          	callbacks.addScript #selectedNodesPostDelete "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent	-- Node deleted
          	callbacks.addScript #postNodesCloned "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node cloned
          	callbacks.addScript #sceneNodeAdded "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node added
          	callbacks.addScript #nodeHide "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node hidden
          	callbacks.addScript #nodeUnhide "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node unhidden
          	
          	--callbacks.show id:#OnCameraPossibleChangeEvent
          	
          	-- Here's the function that gets called when the callback fires
          	function OnCameraPossibleChangeEvent = (	
          		if (rlt_test != undefined) then
          		(
          			rlt_test.updateUI()	-- Call the update ui in the script
          		)
          	)
          	
          	-- Destroy previous versions of the script if already running
          	try (destroyDialog rlt_test) catch()
          	
          	rollout rlt_test "Up-to-date Cameras"
          	(
          		multiListBox lst_cameras "Cameras:" height:20
          			
          		-- Update the listbox in the rollout
          		fn updateUI = 
          		(
          			-- Get the visible cameras in the scene
          			local visiblePhysicalCameras = for c in cameras where ((classof c == VRayPhysicalCamera) AND (c.isHidden == false)) collect c.name
          			lst_cameras.items = visiblePhysicalCameras
          		)
          		
          		on rlt_test open do 
          		(
          			updateUI()
          		)
          		
          		on rlt_test close do 
          		(
          			callbacks.removeScripts id:#OnCameraPossibleChangeEvent
          		)
          	)
          	createDialog rlt_test 250 350
          )
          Colin Senner

          Comment


          • #6
            Thanks for all of your feedback. Really, really appreciated. If I understand it correctly though this is updating the dialog UI whenever ANY object is deleted, added or cloned in the scene, right? For a simple dialog like your example that's fine, but in mine it's pulling in many of the camera settings with spinners and dropdowns so it's much slower....

            Click image for larger version

Name:	DIALOG.jpg
Views:	1
Size:	46.2 KB
ID:	859679

            Is there no way to filter the callbacks to just Cameras?
            www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

            Comment


            • #7
              Correct, there is no way that I know of to filter just to cameras.

              Here's a solution that will help minimize your calls

              Code:
              (
              	-- Global declarations 
              	global rlt_test
              	global AddCallbacks
              	global RemoveCallbacks
              	global OnCameraPossibleChangeEvent	-- Callback for post delete
              
              
              	function AddCallbacks = (
              		-- Add the callback for the functions
              		callbacks.addScript #selectedNodesPostDelete "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent	-- Node deleted
              		callbacks.addScript #postNodesCloned "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node cloned
              		callbacks.addScript #sceneNodeAdded "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node added
              		callbacks.addScript #nodeHide "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node hidden
              		callbacks.addScript #nodeUnhide "OnCameraPossibleChangeEvent()" id:#OnCameraPossibleChangeEvent		-- Node unhidden
              	)
              	
              	function RemoveCallbacks = (
              		callbacks.removeScripts id:#OnCameraPossibleChangeEvent
              	)
              	
              	-- Here's the function that gets called when the callback fires
              	function OnCameraPossibleChangeEvent = (	
              		local objectsAffected = (callbacks.notificationParam())
              		local cameraAffected = false
              			
              		print "*"
              		
              		if (objectsAffected == undefined) then
              		(
              			-- PostDelete Callback won't leave us notification parameters because the nodes have been deleted, we need to tell our ui to update anyway
              			cameraAffected = true
              		)
              			
              		if (objectsAffected != undefined) then
              		(
              			-- This callback fired and notification parameter with objects, check to see if a physical camera was affected
              			for o in objectsAffected where (classof o == VRayPhysicalCamera) do 
              			(
              				-- At least one VRayPhysicalCamera was affected by this call back
              				cameraAffected = true
              				break
              			)
              		)
              		
              		if (cameraAffected == false) then
              		(
              			print "No Vray Camera affected, don't update the UI"
              			return false
              		)
              		
              		if ((rlt_test != undefined) AND (cameraAffected == true)) then
              		(
              			print "Updating entire UI"
              			rlt_test.updateUI()	-- Call the update ui in the script
              		)	
              	)
              	
              	-- Destroy previous versions of the script if already running
              	try (destroyDialog rlt_test) catch()
              	
              	rollout rlt_test "Up-to-date Cameras"
              	(
              		ListBox lst_cameras "Cameras:" height:20 width:150
              		label lbl_camera_fov "FoV: "
              			
              		-- Here depending on your control types you can register an event to fire when the lst_cameras changes at all, possible with dotNet controls, but if the listbox is changed, you can easily create a new function to update all the values too
              		fn updateCameraValuesUI idx = 
              		(
              			-- Currently only display the last of the camera's value, but easily changable to show them all as you have in your ui
              			local cam = GetNodeByName lst_cameras.items[idx]
              			lbl_camera_fov.text = ("FoV: " + cam.fov as string)
              		)
              		
              		-- Update the listbox in the rollout
              		fn updateUI = 
              		(
              			-- Get the visible cameras in the scene
              			local visiblePhysicalCameras = for c in cameras where ((classof c == VRayPhysicalCamera) AND (c.isHidden == false)) collect c.name
              			lst_cameras.items = visiblePhysicalCameras
              		)
              		
              		on lst_cameras selected val do 
              		(
              			-- Call the values ui updater
              			updateCameraValuesUI val
              		)
              
              
              		
              		on rlt_test open do 
              		(
              			AddCallbacks()
              			updateUI()
              		)
              		
              		on rlt_test close do 
              		(
              			RemoveCallbacks()
              		)
              	)
              	createDialog rlt_test 250 350
              )
              Colin Senner

              Comment


              • #8
                Basically, you'll only call your update properties ui when there is a camera change, which will help minimizing calls.

                Since some callbacks won't give you notification parameters (like nodePostDelete) you'll just need to redraw your ui anyway, but best case is register a different function for that one callback and decide exactly what you want to do at that point (for instance, global variable like "VRayCameraWillBeDeleted = false", register a #selectedNodesPreDelete, check for a camera affected, set global var to true, register a #selectedNodesPostDelete and if that variable is true set it to false and update the ui.

                The above seems like over programming though, simpler is always better in the programming world.

                You'll just have to see if the code is performant, if it isn't you can refactor down and start timing function executions so you can figure out your bottleneck.

                Honestly, I just give the user a "refresh" button always.

                You could create a timer object in your rollout that updates the ui every 15s automatically regardless though if you wanted to go that route.
                Last edited by MoonDoggie; 01-02-2016, 01:59 PM.
                Colin Senner

                Comment


                • #9
                  Run that code and check the listener window for how often it prints that it's updating the ui, that'll give you a decent feel.
                  Colin Senner

                  Comment


                  • #10
                    Originally posted by MoonDoggie View Post
                    Honestly, I just give the user a "refresh" button always.
                    Damn man. Thanks for everything. I'll sift through the script and hopefully it'll work for me. I've already got a refresh button in there, just trying to be fancy with it. Thanks again.
                    www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

                    Comment


                    • #11
                      And "wow" you type fast.
                      www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

                      Comment


                      • #12
                        Originally posted by dlparisi View Post
                        And "wow" you type fast.
                        Heh. If you have any questions don't be afraid to post them. Slow-ish morning so it was no problem at all. Keep me updated.
                        Colin Senner

                        Comment


                        • #13
                          Since some callbacks won't give you notification parameters (like nodePostDelete) you'll just need to redraw your ui anyway, but best case is register a different function for that one callback and decide exactly what you want to do at that point (for instance, global variable like "VRayCameraWillBeDeleted = false", register a #selectedNodesPreDelete, check for a camera affected, set global var to true, register a #selectedNodesPostDelete and if that variable is true set it to false and update the ui.
                          I like this option actually. It seems pretty easy to implement and does what I need it to do (i.e., update the UI only when a camera has been deleted) and it doesn't seem to be acheivable any other way (your code simply updates the UI whenever any deletion occurs which is what I'm trying to avoid). It doesn't seem overly complicated or over programmed, especially in comparison to the rest of the code in my script which is pretty redundant and messy in spots . I put together this sample which I'll need to incorporate, along with your hiding, cloning, & added callbacks into my current script. Thanks again for all your help, super helpful.

                          Code:
                          global isCameraBeingDeleted=false
                          
                          
                          fn predeleted = (
                              if callbacks.notificationParam()!=undefined then (
                                  local deletedobjects = callbacks.notificationParam()
                                  for i in deletedobjects do --if i!=undefined then
                                  (
                                      if classof i == Physical or classof i == VRayPhysicalCamera then 
                                      (
                                          print "Is a camera"
                                          isCameraBeingDeleted=true
                                          callbacks.addscript #selectedNodesPostDelete "postdeleted()" id:#camModifed
                                          exit
                                      )
                                      else
                                      (
                                          print  "Not a camera"
                                      )
                                  )
                              )    
                          )
                          
                          fn postdeleted = (
                              if isCameraBeingDeleted==true then 
                              (
                                  print "refreshUI()"
                              )
                              isCameraBeingDeleted=false    
                              callbacks.removeScripts #selectedNodesPostDelete id:#camModifed
                          )
                          
                          --unregister any preDelete callbacks
                          callbacks.removeScripts #selectedNodesPreDelete id:#camModifed
                          
                          --register the function as general callback
                          callbacks.addscript #selectedNodesPreDelete "predeleted()" id:#camModifed
                          Last edited by dlparisi; 02-02-2016, 09:12 AM.
                          www.dpict3d.com - "That's a very nice rendering, Dave. I think you've improved a great deal." - HAL9000... At least I have one fan.

                          Comment


                          • #14
                            Glad I could help.
                            Colin Senner

                            Comment

                            Working...
                            X