General-purpase bending code

Friendly Greetings!

I need to devise a function bends a mesh of points into a curve, depending on the angle entered. So an angle of 90 will turn a cylinder along the y-axis into a ring bending towards the x-axis. The function should not add new vertices, polygons or in anyway change the mesh structure to which it is applied. It should simply loop through the vertices and adjust their positions.

Any help? I’m really stuck.

try this:

p1 = rot( p0, a * len( 0, p0 ))

where:
p0     input vertex
p1     output vertex
rot    rotation around some axis
a      amount of bending (0=none)
len    distance of two points (0=origin)

in practice, this approach says:
please rotate this point around an axis, but as it gets farther from the origin (in the original mesh), rotate it more.

this means that an origin has to be specified, and that points at the origin won’t be affected.

in you exaple, you need a specific rotation function, one wich rotates around the z axis:

s = sin( a )
c = cos( a )

|X|   |c -s|   |x|
| | = |    | * | |
|Y|   |s  c|   |y|

Could you post some example code?

I understand the theory, but not the implementation :frowning:

Ideally, when the origin distance is set to zero, and the mesh is at the origin, the shape should be tapered to a point so at all x-axis values are 0.

Simply setting the rotation to 0 in this case will not achieve this - the mesh must be scaled too.

if you’re in need of a bender like the tool in 3DSmax, then you do not want the sort of tapering you talk about…
because if you have your cylinder for example, when you bend it, it won’t resemble a torus as it should.

btw, mine is intended as just a quick specialized hack to give something to work on, and this can be the code:

struct v3 { float x,y,z; }

v3	base_mesh[ ... ];
v3	bent_mesh[ ... ];

void	rot( v3* out, v3 in, float angle ) {
	float	s = sin( angle );
	float	c = cos( angle );
	
	out->x = c*in.x - s*in.y;
	out->y = s*in.x + c*in.y;
}

float	len( v3 a, v3 b ) {
	a.x -= b.x;
	a.y -= b.y;
	a.z -= b.z;
	return sqrt( a.x*a.x + a.y*a.y + a.z*a.z );
}

void bend( v3* out, v3* in, int verts, v3 origin, float amount ) {
	for( i=0; i<verts; i++ ) {
		 rot( &out[i], in[i], amount * len( origin, in[i] ));
	}
}

Thanks, that’s pretty much the code I had (except I used the dot product between origin and p0, which was wrong).

I have a cylinder mesh centered at 0,0,0 extending from -1 to +1 on each axis. What values should I use to bend it into a torus, as you suggest? I can produce all manor of strange shapes, but the cylinder will NOT bend-in-on-itself as you would expect.

What values should I use for origin and amount? You say the origin is the center of the mesh (0,0,0), but that value results in no bend, and it seems that only y-axis values for origin result in a bend around x.

(I can also scale the mesh first to make it thinner, if that makes any difference).

the equation i suggested cannot in fact bend a cylinder to a torus: i’ve discovered it just yesterday.
to do it, a different equation and method is needed.

since it is an interesting topic, i’m going to find a good equation soon: once i have it, i’ll let you know.

Cheers that would be ace!

I would imagine it would work something like this (for bending a Y-Axis-alingned cylinder around Z):

  1. Translate point by R along X, where r is the circle radius.
  2. Rotate point by angle A, computed from R and point’s Y position. The further the point is along Y, the greater the bend.

The trouble is, you need to careful with the sign of these components. The computed Angle, A, must always be positive, although this can be accomplished with a sqrt.

But the origin in this case is the center of the imaginary circle around which the shape is being bent. In my example it’s 0,0,0. The radius r, would determine the severity of the bend. The length of the cylinder must determine by how much it is bent. A long cylinder could be turned into a torus (with the right setting for r), but a short cylinder would look more like a wedge.

Is this making any sense? :confused:

I don’t have the answer but your problem looks like the inverse of this:
http://www.mathpages.com/home/kmath504.htm

maybe it can help…

here’s my algorithm, it works as the one in 3DSmax:

V3		rot( V3 in, float angle ) {
	float	s = sin( angle );
	float	c = cos( angle );
	return V3(
		c*in.x - s*in.y,
		s*in.x + c*in.y,
		in.z
	);
}

void	bend( V3* out, V3* in, int count, float angle ) {

	if( angle == 0 ) {	//	because it would mead a circle with infinite radius
		memcpy( out, in, count*sizeof(out[0]));
		return;
	}

	int		i;

	//	find the mesh extension

	float	max = in[0].y;
	for( i=0; i<count; i++ ) if( max < in[i].y ) max = in[i].y;

	float	cx = max / angle;	//	find center of rotation

	for( i=0; i<count; i++ ) {

		float	a = in[i].y * angle / max;	//	amount of rotation depends on vertex position
		
		V3		v = in[i];

		v.y = 0;
		v.x += cx;
		v = rot( v, a );
		v.x -= cx;

		out[i] = v;
	}
}

it works by first thinking of a vertical cylinder, starting from level 0 up to level max:
it takes one ring of vertices (same level), lower them to level 0, and rotates around the circle center by an amount linearly dependent on the level of the ring in the base mesh.

the code instead thinks in term of a y axis, instead of z.

this method extends to any shape, but the code it’s a prototype, it lacks some robustness…
the mesh axis (y in this case) is bent around a circle wich center has y and z coordinate fixed and set to 0.
the mesh extension calculation is not very much satisfying to me.
also, some benefit can be obtained from a more rigorous formulation, such as matrices… code tidyness at least.

to make a torus out of a cylinder, you can set the angle to M_2PI

hope it is what you need.

That’s EXACTLY what I need and it works great - just the way I wanted. Really thanks!

You’ve made my day :smiley: :smiley: :smiley:

good to hear :slight_smile:
btw, what are you going to use it for, maybe some modeling app… ?

Yup Im making a making a modelling app. The above image is of a tube, offsetted from the origin and bent by 180 degrees using that code.