[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!
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!
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…
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