Notifications
Clear all

[Closed] Calculate Object Render Region

I want to calculate the Render Region for a group of object, and it needs to be done without using ViewportTM as this is a pre-render script.

I always get confused when working in camera space. Needs to return a box2 value as with regionrender values.

Will attempt to solve it but if anyone has the code to hand or feels like a challenge, feel free to contribute.

8 Replies
 lo1

Sorry, are you saying you want to know the coordinates of the object in the viewport’s coordinate space without knowing the viewport’s coordinate space?

I might be wrong but I don’t think this will work the way you want it to for two reasons:

  1. I don’t think you can change render settings with a pre-render script because Max takes a snapshot of the render settings before the script is run.
  2. As lo said, region render uses viewport coordinate space.

However, I tried to do something like this a while back but didn’t use it for anything in the end. Sorry it’s a bit messy but you’re welcome to use any of this if it helps:

try (destroyDialog BBautoRegion) catch ()

rollout BBautoRegion "AutoRegion"
(
	fn bb2rect =
	(
		if $ != undefined then
		(
			renderSceneDialog.close()
			vpSize = getViewSize()
			gw.setTransform(Matrix3 1)
			sel = getCurrentselection() as array
			BBmask = sel[1]
			gwMin = gw.wTransPoint BBmask.center
			gwMax =  gw.wTransPoint BBmask.center
			
			for BBmask in sel do
			(
				objBB = nodeGetBoundingBox BBmask (Matrix3 1) --get selection BB in worldspace co-ordsys
				for zi = 1 to 2 do
				(
					for yi = 1 to 2 do
					(
						for xi = 1 to 2 do
						(
							gw.setTransform(Matrix3 1)
							wsPt = point3 obJBB[xi][1] objBB[yi][2] objBB[zi][3]
							gwPnt = gw.wTransPoint wsPt
							
							if (gwPnt.x < gwMin.x) then
							(
								if (gwPnt.x > 0) then (gwMin.x = gwPnt.x) else (gwMin.x = 0) --set gwMin.x
							)
							if (gwPnt.y < gwMin.y) then
							(
								if (gwPnt.y > 0) then (gwMin.y = gwPnt.y) else (gwMin.y = 0) --set gwMin.y
							)
							if (gwPnt.x > gwMax.x) then
							(
								if (gwPnt.x < vpSize.x) then (gwMax.x = gwPnt.x) else (gwMax.x = vpSize.x) --set gwMax.x
							)
							if (gwPnt.y > gwMax.y) then
							(
								if (gwPnt.y < vpSize.y) then (gwMax.y = gwPnt.y) else (gwMax.y = vpSize.y) --set gwMax.x
							)
						) --end x loop
					) --end y loop
				)--end z loop
			)--end o loop
			
			if getRendImageAspect() < (vpSize.x/vpSize.y) then
			(
				roScale = (renderHeight/vpSize.y)
				roPad = ((vpSize.x*roScale)-(renderWidth))/2
				roRegion = box2 (point2 ((gwMin.x*roScale)-roPad) (gwMin.y*roScale)) (point2 ((gwMax.x*roScale)-roPad) (gwMax.y*roScale))
			)
			else
			(
				roScale = (renderWidth/vpSize.x)
				roPad = ((vpSize.y*roScale)-(renderHeight))/2
				roRegion = box2 (point2 (gwMin.x*roScale) ((gwMin.y*roScale)-roPad)) (point2 (gwMax.x*roScale) ((gwMax.y*roScale)-roPad))
			)
			
			EditRenderRegion.IsEditable = true
			if viewport.activeViewport != 0 then viewport.setRegionRect viewport.activeViewport roRegion
			EditRenderRegion.UpdateRegion()
			setRenderType #region
			renderSceneDialog.open() --need test for previous state
			displaySafeFrames  = true --need test for previous state
		)
	)--end fn bb2rect
	
	fn autobb2rect ev nd =
	(
		registerRedrawViewsCallback bb2rect
		redrawViews()
		unregisterRedrawViewsCallback bb2rect
		redrawViews()
	)
	
	local sfState
	
	on BBautoRegion open do
	(
		sfState = displaySafeFrames
		displaySafeFrames = true
		unregisterRedrawViewsCallback bb2rect
	)
	
	on BBautoRegion close do
	(
		displaySafeFrames = BBautoRegion.sfState
		unregisterRedrawViewsCallback bb2rect
	)

	button setRegion "Set Region" pos:[5,10]
	checkButton autoRegion "Auto Region" pos:[80,10]

		on setRegion pressed do
		(
			if selection.count == 1 then
			(
				autobb2rect 1 1
			)
		)
		
		on autoRegion changed state do
		(
			if state == true then
			(
				autobb2rect 1 1
				selChanged = NodeEventCallback mouseUp:true selectionChanged:autobb2rect all:autobb2rect
			)
			else
			(
				selChanged = undefined
				gc light:true
			)
		)
	)--end rollout
createDialog BBautoRegion

Select a perspective or camera viewport and run the script and press the ‘auto region’ button. Select one or more objects and the region render box will automatically fit to anything your selection.

Dan

Thanks Dan, I’m going to pass these point2 value to Deadline so it’s not really a pre-render script, as it’ll be set before submission, but needs to be automatic.

I’ll test it in a bit and see how I get on… Cheers…

Dave

It works, but a) is really really slow and b) if the object goes off the edge of the Frame the region is rendering into negative space, which causes issues when rendering.

I’ll have a look at it and see what I can do, cheers for the base though

Yes it is slow. Like I said, it was never really finished or used for anything. I thought it did clip the region to the viewport if the object went off the frame though.

fn bb2rect =
	(
		if $ != undefined then
		(
			renderSceneDialog.close()
			vpSize = getViewSize()
			gw.setTransform(Matrix3 1)
			sel = getCurrentselection() as array
			BBmask = sel[1]
			gwMin = gw.wTransPoint BBmask.center
			gwMax =  gw.wTransPoint BBmask.center
			
			for BBmask in sel do
			(
				objBB = nodeGetBoundingBox BBmask (Matrix3 1) --get selection BB in worldspace co-ordsys
				for zi = 1 to 2 do
				(
					for yi = 1 to 2 do
					(
						for xi = 1 to 2 do
						(
							gw.setTransform(Matrix3 1)
							wsPt = point3 obJBB[xi][1] objBB[yi][2] objBB[zi][3]
							gwPnt = gw.wTransPoint wsPt
							
							if (gwPnt.x < gwMin.x) then
							(
								if (gwPnt.x > 0) then (gwMin.x = gwPnt.x) else (gwMin.x = 0) --set gwMin.x
							)
							if (gwPnt.y < gwMin.y) then
							(
								if (gwPnt.y > 0) then (gwMin.y = gwPnt.y) else (gwMin.y = 0) --set gwMin.y
							)
							if (gwPnt.x > gwMax.x) then
							(
								if (gwPnt.x < vpSize.x) then (gwMax.x = gwPnt.x) else (gwMax.x = vpSize.x) --set gwMax.x
							)
							if (gwPnt.y > gwMax.y) then
							(
								if (gwPnt.y < vpSize.y) then (gwMax.y = gwPnt.y) else (gwMax.y = vpSize.y) --set gwMax.x
							)
						) --end x loop
					) --end y loop
				)--end z loop
			)--end o loop
			global roRegion
			if getRendImageAspect() < (vpSize.x/vpSize.y) then
			(
				roScale = (renderHeight/vpSize.y)
				roPad = ((vpSize.x*roScale)-(renderWidth))/2
				roRegion = box2 (point2 ((gwMin.x*roScale)-roPad) (gwMin.y*roScale)) (point2 ((gwMax.x*roScale)-roPad) (gwMax.y*roScale))
			)
			else
			(
				roScale = (renderWidth/vpSize.x)
				roPad = ((vpSize.y*roScale)-(renderHeight))/2
				roRegion = box2 (point2 (gwMin.x*roScale) ((gwMin.y*roScale)-roPad)) (point2 (gwMax.x*roScale) ((gwMax.y*roScale)-roPad))
			)
			
			if roRegion.x < 0 then (roRegion.w += roRegion.x; roRegion.x = 0)
			if roRegion.y < 0 then (roRegion.h += roRegion.y; roRegion.y = 0)
			if roRegion.w + roRegion.x > Renderwidth then roRegion.w = Renderwidth - roRegion.x
			if roRegion.h + roRegion.y > RenderHeight then roRegion.h = RenderHeight - roRegion.y
			
			EditRenderRegion.IsEditable = true
			if viewport.activeViewport != 0 then viewport.setRegionRect viewport.activeViewport roRegion
			EditRenderRegion.UpdateRegion()
			setRenderType #region
			renderSceneDialog.open() --need test for previous state
			displaySafeFrames  = true --need test for previous state
		)
	)--end fn bb2rect

Updated it to fix the values if they’re outside of the range.

I’ve got to have a re-think for how this is going to work… I thought I could pass the values to Deadline, but as the scene builds itself on the render slave I won’t know what the area will before I kick it off… hhmmmm…

You could always send the script to deadline as a postLoad script. That way it will set the region for the chosen objects before it starts rendering.

Postload scripts allow layers and objects to be hidden and unhidden, materials to be changed and a few other things. Prerender is very restrictive and won’t allow any of the previous things mentioned to be changed.

Hmmm…I wonder where you got that idea from Tim!