[Closed] zoom extends selected to fit object's width and height-capture viewport
Hi all,
I have a project need to capture viewport,the question is not how to capture the viewport,the question is how can I let the object in viewport to fit itself width and length,the output aspect size has already adjusted to object ‘s width and height in viewport manually,but how can I do that via maxscript?like below(In safe Frames mode):
The default zoom extends selected is to much empty area that what I don’t want,any help would be appreciate,thanks!
Yes,finally,it seemed I found a solution here:
using a camera to handle this.
After tested,it’s not work for orthographic views(my project need to capture orthographic views),I still need to find a solution…
:shrug:
Not perfect and barely tested with default settings. The ‘border’ parameter was supposed to be in pixels, but I can’t make it fit perfectly.
If objects are too far away, you may need to do a “max zoomext sel” to get better results before running it.
Hopefully it should do well for what you need.
(
fn FitNodesToViewport border:0 useSafeFrame:false passes:1 =
(
if viewport.gettype() != #view_iso_user do return ()
nodes = for j in selection where iskindof j geometryclass collect j
if nodes.count == 0 do return ()
for k = 1 to passes do
(
minx = miny = 1E9
maxx = maxy = -1E9
gw.settransform (matrix3 1)
hTransPoint = gw.htranspoint
for node in nodes do
(
mesh = snapshotasmesh node
for j = 1 to mesh.numverts do
(
pos = hTransPoint (getvert mesh j)
minx = amin minx pos.x
maxx = amax maxx pos.x
miny = amin miny pos.y
maxy = amax maxy pos.y
)
free mesh
)
brWidth = amax 1 (maxx-minx)
brHeight = amax 1 (maxy-miny)
viewSize = getviewsize()
viewWidth = viewSize[1] as float
viewHeight = viewSize[2] as float
if useSafeFrame do viewWidth = viewHeight*renderwidth/renderheight
deltax = viewWidth / brWidth
deltay = viewHeight / brHeight
fov = viewport.getfov()
if deltay < deltax then factor = ((brHeight+(border*2)) * fov / viewHeight) / fov
else factor = ((brWidth+(border*2)) * fov / viewWidth) / fov
pt1 = gw.getpointoncp [minx+brWidth/2.0, viewSize.y-(maxy-brHeight/2.0)]
pt2 = gw.getpointoncp (viewSize/2.0)
tm = getviewtm()
pretranslate tm (pt2-pt1)
viewport.settm tm
if abs (1-factor) > 0.005 do viewport.zoom factor
)
completeredraw()
)
FitNodesToViewport border:10 passes:3
)
Hi!
The script FitNodesToViewport by @PolyTools3D is great and works almost as I want it. But in the front view, the script doesn’t work, the model has zoomed out far away. This is the case for all views where the angle is almost tangent to the grid. In the top view, it works perfectly, so I started to wonder if the reason for the behavior in the front view is because gw.getPointOnCP. So I added at the beginning of the script a grid helper which is facing the view in the viewport. I make this grid active and this solves the problem. I now thought that the problem was solved but now it acts very strange from other angles. Any suggestion why this happens?
Thanks!
Sebastian
Hello Sebastian,
The reason the script doesn’t work on orthographic views is that it is meant to work only in isometric views.
I’ve modified it to work on both views now. Please note that while the algorithm works (at least as far as I could test), the implementation is sub-optimal as it snapshots the objects in each loop and parse all the vertices positions.
Ideally you would do this only once, outside the loop, and then just update the values. For many objects with many vertices the increment in performance should be very noticeable. Also, the code needs to be cleaned up.
Tested on Max 2016 only.
(
fn FitNodesToViewport border:0 passes:2 =
(
case viewport.gettype() of
(
#view_top: ()
#view_bottom: ()
#view_right: ()
#view_left: ()
#view_front: ()
#view_back: ()
#view_iso_user: ()
#view_shape: ()
#view_persp_user: return false -- doesn't work
#view_camera: return false -- doesn't work
#view_spot: return false -- doesn't work
#view_grid: return false -- doesn't work
)
nodes = for j in selection where canconvertto j editable_mesh collect j
if nodes.count == 0 do return false
viewSize = getviewsize()
hTransPoint = gw.htranspoint
FOV = viewport.getfov()
viewport.zoom 1E-9
max zoomext sel
gw.settransform (matrix3 1)
done = false
for k = 1 to passes while not done do
(
minx = miny = 1E9
maxx = maxy = -1E9
for node in nodes do
(
mesh = snapshotasmesh node
for j = 1 to mesh.numverts do
(
pos = hTransPoint (getvert mesh j)
minx = amin minx pos.x
maxx = amax maxx pos.x
miny = amin miny pos.y
maxy = amax maxy pos.y
)
free mesh
)
viewWidth = viewSize[1] as float
viewHeight = viewSize[2] as float
brWidth = amax 1 (maxx-minx)
brHeight = amax 1 (maxy-miny)
offset_x = minx + ((brWidth - viewWidth ) * 0.5)
offset_y = miny + ((brHeight - viewHeight) * 0.5)
if displaySafeFrames do
(
viewAspect = viewWidth / viewHeight
renderAspect = getrendimageaspect()
if viewAspect > renderAspect then viewWidth = viewHeight*renderwidth/renderheight
else viewHeight = viewWidth*renderheight/renderwidth
)
deltax = viewWidth / brWidth
deltay = viewHeight / brHeight
if deltay < deltax then factor = ((brHeight+(border*2)) * FOV / viewHeight) / FOV
else factor = ((brWidth+(border*2)) * FOV / viewWidth) / FOV
viewport.pan -offset_x offset_y
viewport.zoom factor
if abs (1-factor) < 0.01 do done = true
)
completeredraw()
return true
)
FitNodesToViewport border:20 passes:10
)
Thank you so much! It works perfectly. I will use it in the perspective view so I replaced “return false” with (). The script will be used for batch rendering a lot of products where they all have the same camera angles. The products are in different shapes and sizes, and we want them all to have the same amount of border space. 3ds Max zoom extents aren’t precise, but your script works as it should.
Again, thank you for your help!