Maxscript to help with Corona LIghts viewport display performance bug

Dear all,
i recently came by with very disturbing issue with corona lights: once we increased the numbers of lights over 100, the viewport performance would collapse.
So i reached out to the forums only to be told to upgrade and maybe it would fix the problem. for me the update timeline is very long so mmmmm maybe thinking corona not worth it… good old vray to the rescue
so given the enlighten i received from the moderators, i thought i would give something back: I wrote this little tool that basically stores on your hard drive a text file with the light names and sizes. this way I can reduce the light size to 0 and regain the viewport performance until render time.
read the code and see for your selfs. also edit the code to create the proper text file in your location.
if you don’t know how to do this than this is not for you.
Enjoy

------SCRIPT STARTS HERE

---- funciton to find item in 2d Array

fn findItemIn2DArray array2D valueForSearch =
(
    for i = 1 to array2D.count do
    (
        local index = findItem array2D[i] valueForSearch
        if index != 0 then return #(i, index) -- Return row and column indices
    )
    return undefined -- Return undefined if the value is not found
)

---- function create array with exisitng lights and their size.2d ARRAY [z`name, width, height]

fn lightArraySizes arr = (
	for l in lights where (classof l != Targetobject) do (
		if (classof l == CoronaLight) then (
		 append arr #(l.name, l.width, l.height)
		)
	) 

)
---- function to update array by removing deleted lights. 
fn updatelightsArray arr = (


)

fn selectobjectbyname nameobj = (
	objNode = execute ("select $'" + nameobj + "'*")
	return objNode
)

---- function to restore lights size

---- function to set light size to 0

---- actual script



try (destroyDialog lightShrinker) catch()
rollout lightShrinker "FACK LIGHTER"
(
	button btn1 "SAVE THEM LIGHTS!!!" width:170  height:50 align:#center 	 
	button btn2 "SHRINK THEM LIGHTS" width:170  height:50 align:#center 
	button btn3 "RISE MY CHILDS!!RISE!!" width:170  height:50 align:#center  

	local currFile = ""
	local out_lightsfile = ""
	on btn1 pressed do
	(	
		if maxfilename != "" then (		
		out_lightsfile = "D:\\WORK\\_DAILY SAVES\\" + (getFilenameFile maxfilename) + "_" + (timestamp() as string) + ".txt" ----please remember to change this
		currFile = out_lightsfile
		print out_lightsfile
			) else (Print "please save file first")



		out_file = createfile out_lightsfile
		for l in lights where (classof l != Targetobject) do (
			if (classof l == CoronaLight) then (
				format "%,%,%\n" l.name l.width l.height to:out_file					
			)

		)
		close out_file
		print "Done!!"
	)
	on btn2 pressed do
	(
	 for l in lights where (classof l != Targetobject) do (
				if (classof l == CoronaLight) then (
					l.width = 0				

				)
		)
	)
	on btn3 pressed do
	(
		print currFile
		in_file = openFile currFile
		lightsArrayFromFile = #()
		 if in_file != undefined then
		   (
			   while not eof in_file do 
				(

					lrn = readline in_file
					---print ("hell:" + lrn ) 
					newString = filterString lrn ","
					append lightsArrayFromFile newString 
					----append lightsArrayFromFile lrn

				)
				----print lightsArrayFromFile
 				for e =1 to lightsArrayFromFile.count do (
					restoredlight = getNodeByName lightsArrayFromFile[e][1]
 					restoredlight.width = lightsArrayFromFile[e][2] as float
 					restoredlight.height = lightsArrayFromFile[e][3] as float
 				)

		   )
		--$.width = random 20 150
		--$.height = random 20 150		   
		---print lightsArrayFromFile
	)

)
 CreateDialog lightShrinker 


-------SCRIPT ENDS HERE

moderators edit: wrapped script’s text into the code tags to improve message’s readability.

------new code

---- funciton to find item in 2d Array

fn findItemIn2DArray array2D valueForSearch =
(
    for i = 1 to array2D.count do
    (
        local index = findItem array2D[i] valueForSearch
        if index != 0 then return #(i, index) -- Return row and column indices
    )
    return undefined -- Return undefined if the value is not found
)

---- function create array with exisitng lights and their size.2d ARRAY [z`name, width, height]

fn lightArraySizes arr = (
	for l in lights where (classof l != Targetobject) do (
		if (classof l == CoronaLight) then (
		 append arr #(l.name, l.width, l.height)
		)
	) 

)

fn selectobjectbyname nameobj = (
	objNode = execute ("select $'" + nameobj + "'*")
	return objNode
)

---- function to restore lights size

---- function to set light size to 0

---- actual script



try (destroyDialog lightShrinker) catch()
rollout lightShrinker "FACK LIGHTER"
(
	button btn1 "SAVE THE LIGHTS!!!" width:170  height:50 align:#center 	 
	button btn2 "SHRINK THE FUCKERS" width:170  height:50 align:#center 
	button btn3 "RISE MY CHILDS!!RISE!!" width:170  height:50 align:#center  

	local currFile = ""
	local out_lightsfile = ""
	local arrayLightsinfo = #()

	on btn1 pressed do
	(	
		if maxfilename != "" then (		
		out_lightsfile = "D:\\WORK\\_DAILY SAVES\\" + (getFilenameFile maxfilename) + "_" + (timestamp() as string) + ".txt"
		---currFile = out_lightsfile
		print ("Save a copy in " + out_lightsfile)
			) else (Print "please save file first")



		---out_file = createfile out_lightsfile
		for l in lights where (classof l != Targetobject) do (
			if (classof l == CoronaLight) then (
				append arrayLightsinfo #(l.name as string,l.width,l.height)
				---format "%,%,%\n" l.name l.width l.height to:out_file					
			)

		)
		---close out_file
		--print arrayLightsinfo
		print ("Done!! Saved " + (arrayLightsinfo.count  as string)+ " lights to memory!!!") ----- elephant memory
	)
	on btn2 pressed do
	(
	 for l in lights where (classof l != Targetobject) do (
				if (classof l == CoronaLight) then (
					l.width = 0				

				)
		)
		print ("Done!! Shrinked " + (arrayLightsinfo.count  as string)+ " lights!!!")
	)
	on btn3 pressed do
	(
		---print currFile
		---in_file = openFile currFile
		lightsArrayFromFile = #()

			for e =1 to arrayLightsinfo.count do (
 					restoredlight = getNodeByName arrayLightsinfo[e][1]
  					restoredlight.width = arrayLightsinfo[e][2] as float
  					restoredlight.height = arrayLightsinfo[e][3] as float
  				)
		print ("Done!! REstored " + (arrayLightsinfo.count  as string)+ " lights from memory!!!")


-- 		 if in_file != undefined then
-- 		   (
-- 			   while not eof in_file do 
-- 				(
-- 					 
-- 					lrn = readline in_file
-- 					---print ("hell:" + lrn ) 
-- 					newString = filterString lrn ","
-- 					append lightsArrayFromFile newString 
-- 					----append lightsArrayFromFile lrn
-- 					
-- 				)
-- 				----print lightsArrayFromFile
--  				for e =1 to lightsArrayFromFile.count do (
-- 					restoredlight = getNodeByName lightsArrayFromFile[e][1]
--  					restoredlight.width = lightsArrayFromFile[e][2] as float
--  					restoredlight.height = lightsArrayFromFile[e][3] as float
--  				)

-- 		   )
		--$.width = random 20 150
		--$.height = random 20 150		   
		---print lightsArrayFromFile
	)

)
 CreateDialog lightShrinker 

I have logged this internally to see if the performance can be further improved.

(Report ID=CMAX-2096)

Dear Avi
thank you.
I have also updated this script only to work in the scene that is opened.
Ps Having fun here.

MAXSCRIPT:

---- funciton to find item in 2d Array

fn findItemIn2DArray array2D valueForSearch =
(
    for i = 1 to array2D.count do
    (
        local index = findItem array2D[i] valueForSearch
        if index != 0 then return #(i, index) -- Return row and column indices
    )
    return undefined -- Return undefined if the value is not found
)

---- function create array with exisitng lights and their size.2d ARRAY [z`name, width, height]

fn lightArraySizes arr = (
	for l in lights where (classof l != Targetobject) do (
		if (classof l == CoronaLight) then (
		 append arr #(l.name, l.width, l.height)
		)
	) 

)

fn selectobjectbyname nameobj = (
	objNode = execute ("select $'" + nameobj + "'*")
	return objNode
)

fn lightshr arraynameh indexh = (
	lighttoshrink = getNodeByName arraynameh[indexh][1]
	lighttoshrink.width = 0.0
	lighttoshrink.height = 0.0

)

fn restorelight arrayname index= (	 
	restoredlight = getNodeByName arrayname[index][1]
	restoredlight.width = arrayname[index][2] as float
	restoredlight.height = arrayname[index][3] as float
)

---- function to restore lights size

---- function to set light size to 0

---- actual script



try (destroyDialog lightShrinker) catch()
rollout lightShrinker "FACK LIGHTER"
(
	button btn1 "SAVE THE LIGHTS!!!" width:170  height:50 align:#center 	 
	button btn2 "SHRINK THE FUCKERS" width:170  height:50 align:#center 
	button btn3 "RISE MY CHILDS!!RISE!!" width:170  height:50 align:#center  

	local currFile = ""
	local out_lightsfile = ""
	local arrayLightsinfo = #()
	local clights = #()

	on btn1 pressed do
	(	
		with redraw off(
		if maxfilename != "" then (		
		out_lightsfile = "D:\\WORK\\_DAILY SAVES\\" + (getFilenameFile maxfilename) + "_" + (timestamp() as string) + ".txt"
		---currFile = out_lightsfile
		print ("Save a copy in " + out_lightsfile)
			) else (Print "please save file first")



		---out_file = createfile out_lightsfile
		clights = for l in lights where ((classof l != Targetobject) and (classof l == CoronaLight)) collect #(l.name as string,l.width,l.height) 

			)
			-- 		for l in lights where (classof l != Targetobject) do (
-- 			if (classof l == CoronaLight) then (
-- 				append arrayLightsinfo #(l.name as string,l.width,l.height)
-- 				---format "%,%,%\n" l.name l.width l.height to:out_file					
-- 			)
-- 			
-- 		)
		---close out_file
		--print arrayLightsinfo
		print ("Done!! Saved " + (clights.count  as string)+ " lights to memory!!!") ----- elephant memory
	)

	on btn2 pressed do
	(		
		with redraw off(
		for l=1 to clights.count do (
			lightshr clights l				
		)
		)
		print ("Done!! Shrinked " + (clights.count  as string)+ " lights!!!")
	)

	on btn3 pressed do
	(
		with redraw off(
		---print currFile
		---in_file = openFile currFile
		---lightsArrayFromFile = #()		
		for e =1 to clights.count do (
				restorelight clights e
			)
		print ("Done!! REstored " + (clights.count  as string)+ " lights from memory!!!")
		)

-- 		 if in_file != undefined then
-- 		   (
-- 			   while not eof in_file do 
-- 				(
-- 					 
-- 					lrn = readline in_file
-- 					---print ("hell:" + lrn ) 
-- 					newString = filterString lrn ","
-- 					append lightsArrayFromFile newString 
-- 					----append lightsArrayFromFile lrn
-- 					
-- 				)
-- 				----print lightsArrayFromFile
--  				for e =1 to lightsArrayFromFile.count do (
-- 					restoredlight = getNodeByName lightsArrayFromFile[e][1]
--  					restoredlight.width = lightsArrayFromFile[e][2] as float
--  					restoredlight.height = lightsArrayFromFile[e][3] as float
--  				)

-- 		   )
		--$.width = random 20 150
		--$.height = random 20 150		   
		---print lightsArrayFromFile
	)

)
 CreateDialog lightShrinker 

I hope the devs will look seriously at that issue next year. I personally rarely work with scenes that have more than dozen lights in them and i wasn’t even aware of this issue, but recently i downloaded free scene from Evermotion and it has a Christmas tree with thousands Corona lights on it and the viewport performance in that scene is ridiculously bad. Worst of all that it doesn’t matter if lights are being displayed in the viewport or hidden, performance never improves. Luckily there was easy solution in that case - replace Corona lights with spheres with Corona light material, which fixes viewport FPS instantly, but i think it shouldn’t be that way, one should be able to use Corona lights freely without having to pay massive performance cost.

or you can use my script for temp fix while working on other things in your scene. when you need to render just rebuild the lights and off you go.
I am testing it with over 5k lights and it takes about 15859 ms to run

---- SCRIPT

fn findItemIn2DArray array2D valueForSearch =
(
    for i = 1 to array2D.count do
    (
        local index = findItem array2D[i] valueForSearch
        if index != 0 then return #(i, index) -- Return row and column indices
    )
    return undefined -- Return undefined if the value is not found
)

---- function create array with exisitng lights and their size.2d ARRAY [z`name, width, height]

fn lightArraySizes arr = (
	for l in lights where (classof l != Targetobject) do (
		if (classof l == CoronaLight) then (
		 append arr #(l, l.width, l.height)
		)
	) 

)


fn lightshr arraynameh indexh = (
	ls = arraynameh[indexh][1]
	ls.width = 0.0
	ls.height = 0.0

)

fn restorelight arrayname index= (	 
	rl = arrayname[index][1]
	rl.width = arrayname[index][2] as float
	rl.height = arrayname[index][3] as float
)


try (destroyDialog lightShrinker) catch()
rollout lightShrinker "FACK LIGHTER"
(
	button btn1 "SAVE THE LIGHTS!!!" width:170  height:50 align:#center 	 
	button btn2 "SHRINK THE FUCKERS" width:170  height:50 align:#center 
	button btn3 "RISE MY CHILDS!!RISE!!" width:170  height:50 align:#center  

	local currFile = ""
	local out_lightsfile = ""
	local arrayLightsinfo = #()
	local clights = #()

	on btn1 pressed do
	(					
		clights = for l in lights where ((classof l != Targetobject) and (classof l == CoronaLight)) collect #(l,l.width,l.height) 
		print ("Done!! Saved " + (clights.count  as string) + " lights to memory!!!") ----- elephant memory
	)

	on btn2 pressed do
	(	
		startTime = timestamp()
		undo off (
			max create mode
			with redraw off(
				for l=1 to clights.count do (
					lightshr clights l

				)
			)
		print ("Done!! Shrinked " + (clights.count  as string)+ " lights!!!")	
		endTime = timestamp()
		format "Elapsed time to shrink your lights: % ms\n" (endTime - startTime)
		)
	)

	on btn3 pressed do
	(
		startTime = timestamp()
		undo off (
			max create mode
			with redraw off( 		
				for e=1 to clights.count do (
					restorelight clights e
				)			
			)
		print ("Done!! REstored " + (clights.count  as string)+ " lights from memory!!!")
		endTime = timestamp()
		format "Elapsed time to restore your light thingies: % ms\n" (endTime - startTime)

		)
	)

)
 CreateDialog lightShrinker 

Dear Corona team
can you please let me know if this BUG is still happening in version 14? As I mentioned on other posts our upgrade path here is too slow. So I need to know if we upgrade our studio to version 14 this problem/BUG will not happen.

Hi,

No changes in regards to this in Corona 14.

Thank you Aram,
This is now becoming an Issue for us here in the office as our projects often have over 1k corona lights for some areas. the performance degradation makes it impossible to work sometimes. I have no Idea why this does not happen in VRAY also a CHAOS product.

Dear Corona TEAM
any idea on how and when and if this issue with the corona lights will be fixed?
Any reply is much appreciated.

Hi,

Please be sure that I have bumped this yet again for future prioritization.
What is technically possible is already done for optimizing spherical light performance.

For future improvement we may need to change it from geometrical represetantion to spline-like, just like VRay has it.

Dear Corona team finally upgraded to the 14 version and max 2026.
Good work, but still the same viewport performance issue.
Please bump this higher next time. as viewport performance shouldn’t be an issue caused by the render engine.

Thanks again.

Just updating here that this was bumped internally and our devs are looking into it

I always find interesting how users solve most of the issues that corona team cant even notice.
May I ask how does this script works? what does each button does?