Notifications
Clear all

[Closed] Math for a bend

 PEN

Any one know any good reference for how the math for the bend modifier works?

13 Replies

I think you should look into rotation transformation which is a kind of a linear transformation
http://www.kwon3d.com/theory/transform/rot.html
http://mathworld.wolfram.com/RotationMatrix.html

 PEN

Thanks Matan, I have been trying this already but what I get it s spiral. If you consider the pivot of an object at the end of it and you bend the the object the last vert will end up back at the pivot. If you just rotate it, it circles the pivot. I’ll keep playing with it how ever when I get a chance.

Thanks for the suggestions.

now there’s a couple of pages of pain

 PEN

It is actually easy in Max script as you can just use rotateX matrix and it will take care of all of it for you.

the bend modifier’s source code seems to be part of the SDK – might be able to glean it from there

I don’t have a reference, but basically you’d have to do something like this:

-First sort the vertices along the bend-axis. (so you can travel along later)
-For each vertex in mesh, find closest point on bend-axis. This point is the vertex’s pivot.
-Then travel along the bend-axis and rotate all remaining vertices and pivots by bend-angle/vertex-count around the current pivot.

Does that make sense?

 PEN

yes it does make sense but not sure how to go about that. I’ll play around, nothing major I’m doing, just want to know how. Richard I will have a look in the SDK.

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

Here is a SIMPLE implementation (from top of my head without looking at the SDK)

plugin simpleMod MyBend
   name:"MyBend"
   classID:#(0x33635bb3, 0x5db238c1)
   version:1
   ( 
   parameters main rollout:params
   (
   amount type:#float ui:spn_amount default:0
   )
   
   rollout params "MyBend Parameters"
   (
   spinner spn_amount "Amount: " range:[-100000,100000,0] scale:1
   )
   
   on map i p do
   (
   if amount != 0 then
   (
   	theRadius = 180/amount*extent.z/Pi 
   	TM = rotateYMatrix (amount*p.z/extent.z)
   	TM.row4 = [theRadius,0,0]
   	[p.x-theRadius,p.y,0] * TM
   )
   else p
   )
   
   )

Here is the logic.
p is the position of the vertex in object space.
Let’s say you have a cylinder. If you apply a Bend with 360 degrees, the TOP vertex (with Z equal to the height of the modifier context bounding box) will do a full rotation about a center outside of the cylinder and end up at the vertex with the same X and Y, but at the BOTTOM of the bounding box. The question is – WHERE is this center of rotation outside of the object that you have to rotate about?

The answer is surprisingly easy – if you have a line with a length L and you want to bend it to 360 degrees as described above, we have L = 2PiR. We need to know what R is, and it is L/2/Pi. In other words, for 180 degrees, the Radius is L/Pi, for 90 degrees it will be 2*L/Pi and so on, growing as the angle gets smaller.

The amount parameter defines the actual angle we want to rotate at. So we divide 180 by the amount and multiply by the L (which is the Z component of the modifier bounding box’s extent) divided by Pi. The result is the actual Radius we want to rotate with, which gives us the center of rotation that we need for all vertices. In other words, we used the top point of the modifier context to figure out the center of rotation, now we can apply a different rotation to each vertex based on its normalized position within the Z of the bounding box. A vertex at the base will not rotate at all, a vertex at the top will do the full rotation, a vertex at half the height will do half of the rotation.

So we create a Rotation matrix to rotate about the Y axis and use the normalized height of the vertex (p.z/extent.z) to multiply the amount in degrees. Once again, this gives us 0 degrees for a vertex with Z = 0 and ‘amount’ degrees for a vertex with p.z = Extents.z

Then we shift the transformation matrix’ row4 to the center of rotation.
We take the projection of the vertex P in the XY plane and shift it along X by the radius so that the vector we will be rotating is defined by the new rotation center and the vertex’s projection on the XY plane. The Y remains the same and the Z is 0. We multiply this ground plane projection of the vertex by the rotation angle and the vertex ends up on an arc with center the point we calculated in the beginning.

This modifier does not implement the Direction yet, it just rotates about the Y axis, but it shows the basic idea…

Since we have a division of 180 by the amount, we have to make sure we never perform this when the angle is 0. Thus the IF statement which returns the undeformed position if 0.

Hi Paul,
I found special interest in your problem since it requires me to implement
my current study subject which is linear transformations and matrices.

So I took some extra time looking into this problem and I think the key here
is to find the pivot of rotation.

The data you would probably need is:

  • alpha = The angle of bend

  • vertPos = the position of the vertex in local space

  • center = The center of the bend modifier in local space

  • maxDist = The distance along the axis that you would like to bend between the center of the bend modifier and the max point of the bounding box

  • vertDist = The distance of the vertex from the center along the bend axis

Now you need to calculate a couple of things:

The rotation angle for the current vertex
beta = alpha * vertDist / maxDist

The radius of the rotation circle
rad = vertDist / beta in radians

The pivot of rotation (assuming we are trying to bend the z axis on the x,z plane)
piv = center + [beta / abs(beta) * rad,0,0]

The rotation matrix (assuming we are trying to bend the z axis on the x,z plane)
rotMatrix = matrix3 [cos(beta), 0, -sin(beta)] [0, 1, 0] [sin(beta), 0, cos(beta)] piv

The new position of the current vertex
newPos = vertPos * rotMatrix

I didn’t try to implement this so I might have some mistakes along the way but this should be the way

Matan.

Edit: Here is the correct Direction version:

plugin simpleMod MyBend
name:"MyBend"
classID:#(0x33635bb3, 0x5db238c1)
version:1
( 
parameters main rollout:params
(
amount type:#float ui:spn_amount default:0
direction type:#float ui:spn_direction default:0	
)

rollout params "MyBend Parameters"
(
spinner spn_amount "Amount: " range:[-100000,100000,0] scale:1
spinner spn_direction "Direction: " range:[-100000,100000,0] scale:1
	
)

on map i p do
(
if amount != 0 then
(
	theDirMatrix = rotateZMatrix -direction
	theRadius = 180/amount*extent.z/Pi
	theRadiusOffset = [theRadius,0,0] * theDirMatrix 
	TM = rotateYMatrix (amount*p.z/extent.z) * theDirMatrix
	TM.row4 = theRadiusOffset
	(([p.x,p.y,0]-theRadiusOffset)*inverse theDirMatrix) * TM 
)
else p
)

)

The main difference is that instead of using the positive X axis as is to project where the center of rotation will be, we take that X axis and rotate about the Z. Then we transform the previous (bend) rotation matrix by this new (direction) matrix, use the offset radius as the row4 and also use the transformed vector to offset the vertex position, then transform out of the direction matrix and bend using the bend matrix. In short, we generalize the previous X-only center by placing it around at the angle specified by the Direction parameter.

Page 1 / 2