Notifications
Clear all

[Closed] help finding an object's height??

Hi everyone, I need to find the height of an object (like a cylinder, box or pyramid’s height) that doesn’t have a height property.
The height must be along the z axis.
I thought that will come out easily, using just the z component of the bounding box of the object. I wrote these few lines: (just make a cylinder, select it and run the script)

a = point()  --marker at zero height
      b = point() --marker at full height
      ob = selection[1] --you need to select something!
      a.transform = ob.transform --aligns a to ob
      b.transform = ob.transform --aligns b to ob
      objHeight = ob.max[3]-ob.min[3] --measures the height
      in coordsys local(move b [0,0,objHeight]) --moves b the height along its z axis  
          
      and got this problem:
      [img] http://www.morphostudios.com/fotos/cgtalk/height.jpg [/img]
      
      It seems that max is calculating the bounding box in world space coords,
      do you know if there is a way to do it locally, or something else that could help me getting the objects height?

note: I’m using a cylinder just for illustration prupouses, the final objects will not have the height property, and always will have their pivots aligned to their bases along the z axis

 Thanks in advance!
10 Replies
1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

Here is a 3rd method (it is about as fast as the first way HalfVector posted), but instead of moving the object around, it uses a temp. bend modifier:

fn getLocalHeight theObj =
 (
 addModifier theObj (theBend = Bend()) --add a bend to the object
 classof theObj								 --this is a hack causing a fast reevaluation of the stack!
 min = getModContextBBoxMin theObj theBend --get the min. of the modifier's BBox
 max = getModContextBBoxMax theObj theBend --get the max. of the modifier's BBox
 deleteModifier theObj theBend					 --delete the modifier
 max.z-min.z											 --return the result
 )

Note: If your object has any bindings to Space Warps, both HV’s first and my function will not cut it as my modifier would be added below the WSMs, and his function would change the effect of WSMs by changing the TM. Only the SnapshotAsMesh method would take Space Warps into account!

Cheers,
Bobo

Hi.

Right now I can think of two ways to calculate the local height of an object.

First method:

fn getHeight node = (

	oldTransform = node.transform
	node.transform *= (inverse node.transform)
	bbMin = node.min
	bbMax = node.max
	node.transform = oldTransform

	return (bbMax.z - bbMin.z)
)

This method is faster and consumes less memory but it modifies the actual node’s transform matrix so when you execute the function, you’ll see how your object change its position/rotation/scale and very quickly returns to its original situation.

The second method doesn’t have this problem because we are working with a mesh version of the original object. What we do is loop through all its vertices and transform them back to object space (multiplying the vertex by the inverse of the node’s transform). This way we are able to extract the real height of the object.

fn getHeight node = (

	local msh = snapshotAsMesh node

	local height = ((getVert msh 1) * (inverse node.transform)).z
	
	for i in 2 to msh.numVerts do (
		local vert = (getVert msh i) * (inverse node.transform)
		if vert.z > height do
			height = vert.z
	)

	delete msh
	
	return height
)

I think the two methods work fine but are not tested too much. I have created them in a couple minutes.

HTH.

Thanks HalfVector, that worked pretty well. Personally I prefer the first method, I think the second one can get a little heavy with high vertex counts. Thanks again, it helped me a lot!

You’re Welcome!

Hi.

I want to revise something about the second method I proposed to point out an obvious optimization. You can precalculate the inverse of the transform matrix so the script won’t recalculate it each iteration.

fn getHeight node = (

	local msh = snapshotAsMesh node

	local invTransform = inverse node.transform

	local height = ((getVert msh 1) * invTransform).z
	
	for i in 2 to msh.numVerts do (
		local vert = (getVert msh i) * invTransform
		if vert.z > height do
			height = vert.z
	)

	delete msh
	
	return height
)

Best regards.

I don’t think that this code is correct.
It somehow assumes that the height of the object is the .Z of the vertex with the largest distance from the local origin (pivot point), but this is only true in special cases like Box, Teapot and Cylinder, while with a sphere, the function would return the Radius and not the Diameter. This is even more important with arbitrary meshes.
You would have to look for both the Min and the Max and return the difference in Z…

1 Reply
(@halfvector)
Joined: 11 months ago

Posts: 0

You are right, the code will only return the correct height of objects whose pivot points are on their base. So I’ve modified the function:

fn getLocalHeight node = (

	local msh = snapshotAsMesh node

	local invTransform = inverse node.transform

	local pt = (getVert msh 1) * invTransform

	local minHeight = pt.z
	local maxHeight = pt.z
	
	for i in 2 to msh.numVerts do (
		local vert = (getVert msh i) * invTransform
		if vert.z > maxHeight do
			maxHeight = vert.z
		if vert.z < minHeight do
			minHeight = vert.z
	)

	delete msh
	
	return (maxHeight - minHeight)
)

Hope it’s OK now…

Hi!
Thanks for the help! I just have a question:

Originally posted by Bobo

 fn getLocalHeight theObj =
       (
       addModifier theObj (theBend = Bend()) --add a bend to the object
 classof theObj								 --this is a hack causing a fast reevaluation of the stack!
       min = getModContextBBoxMin theObj theBend --get the min. of the modifier's BBox
       max = getModContextBBoxMax theObj theBend --get the max. of the modifier's BBox
 deleteModifier theObj theBend					 --delete the modifier
 max.z-min.z											 --return the result
       ) 

what is the reason to put this line?:
classof theObj –this is a hack causing a fast reevaluation of the stack!

Thanks!

As the remark says, it is a quick way to force a fast internal stack reevaluation.

Here is what happens:

Say you are in Create mode and the stack is not visible in the Command panel.
You add a Bend modifier to the stack.
Then you ask for the min. and max. of its bounding box.
Problem is, the modifier is on the stack but the stack is not visible and has not been reevaluated yet, so the bounding box does not “know” the size of the object at this point. So the resulting height would be very close to zero.

One way to fix this would be to force the command panel into Modify mode (max modify mode), but this means redrawing the command panel and it is slower.
Calling “classof theObj” requests the class of the object as seen on top of the stack. MAXScript notices that the modifier stack requires reevaluation because of a new unevaluated modifier and does it “behind the scenes” without the need to display the modifier in the command panel.
As a result, the code evaluates much faster! – on my machine, using classof returns the height in between 0 and 16 ms, replacing the classof with “max modify mode” causes the result to be returned in between 40 and 60 ms. A HUGE difference, if you are going to call the function on many objects!

Cheers,
Bobo

Thanks for the info Bobo!:applause: