How would you arc or bend a cylinder type geometry (that has distortion) in three.js?
Id like to specify these parameters:
- Bend Start - at what percent of the cylinder's height the bend starts
- Bend End - at what percent of the cylinder's height the bend ends
Angle - how strong the bend is
I'll be controlling them with sliders. My cylinder shape is created from an extrusion of a bezier curve that the user draws (extension of geometry class in three.js).
I'd also like to be able to layer several bend effects on top of each other. So a bend could affect the first part, then a second bend could bend the cylinder back.
I'm not the best at math, so that's why i'm asking for tips or formulas that could do this in three.js. I'm thinking maybe i could put a line at the center axis then bend that with a bezier curve. From there i could use the lines position to influence the vertices of the cylinder. Does this sound like a good idea?
What you need to do is cut your mesh into slices and convert each slice in the same manner as I do the circles in here:
That is done like this:
straight form coordinate system
Create position
P0
and 3 basis vectorsX0,Y0,Z0
representing coordinates of the mesh in straight form. Let assume theZ0
is the axis you want to bend.convert each vertex into
P0,X0,Y0,Z0
local coordinatesso any point
P
is transformed into:create bend form coordinate system
P1,X1,Y1,Z1
so simply based on the
P.z'
used as a parameter (arclength on the bended shape) compute the angle of the bended arc and rotateX0,Y0,Z0
intoX1,Y1,Z1
if the bending is aroundX
thenX1 = X0
and you need to rotate just the other two vectors.convert P' into bended form P''
simply do this:
now
P''
is the final vertex of your shape. So you can render you mesh after converting all of its points. As you can see we do not need theP.z
... as its encoded in theP1
position already. So also no real need to compute theZ1
basis vector too.[Notes]
Beware that too big bends can corrupt your mesh topology if you bend too much then you can self intersect the slices between each other.
Also all the corresponding basis vectors should have the same size Ideally unit.
The rotation of
Y0 -> Y1
is simple 2D problem and ifY0=(0,1,0)
its even simpler just point on circleY1=(cos(a),sin(a),0)
... so you do not even need the 2D rotation formula.[Edit1] C++/GL example
I was curious so I take a generated tube with sinus screw and bend it... This is the result:
I rendered both straight and bended meshes for visual comparison. The red point is the bend center and the line connects it to
P0
. I choseP0,X0,Y0,Z0
to match unit matrix. The example is transformed so it matches the images in this question (in un-animated state). Here the C++/GL code I done this with:The mesh and bending zavit.h:
And the main VCL app code (ignore the VCL stuff just port/use what you need):
For OpenGL I am using GLEW and mine gl_simple.h which can be found here:
the GLSL_math.h is mine vector math mimicking GLSL math but you can use any vector math... You just need
+,-,dot,cross,normalize,length
which are all basic operations and you can code it on your own too or use GLM or whatever...[Edit2] some more simplification and repeatability
Well according to your sketch and late comments It will not work with heights. Instead use arc-lengths (height in straight form mesh) as parameters. After some more taught I ended up with this:
To simplify things I added for each slice a center point, main axis direction and slice length. That enables much simpler computations ... Here preview of applied 45 deg bend twice (+45 and -45):
The RGB lines are global coordinate system for the bended mesh render, yellowish is the mesh center axis + bending range of last bend for debug and red is the last bend center.
here new C++ code
zavit.h
:And the VCL window code:
Architecture is the same just the usage changed a bit now bend is applied directly on the mesh1 so it does not use the mesh0 anymore. So you need to copy mesh0 to mesh1 before use.
Also I exploited the fact that my mesh is sorted by arclength (
pnt1[angle][arclength]
) so I can process slices instead of raw points.You can analogically write
bendy
andbendz
functions just change the math a bit to match swapped axises ... If you do not need the original mesh then you can remove it now ...[Edit3] visual comparison with yours code
Its foreign language to me but similar to C/C++ so from a quick view:
P0X0Y0Z0
which prevents you from applying bend more than once.at line 155
it does not correspond to mine
you have different axis and no radius scale !!! in case your axises have different meaning then mine then you just swap the
X,Y,Z
accordingly but you still need to use the radius. This one is the position if the center of bending so if wrongly computed the bend is wrong too ... The axis used must be not the one around which the rotation is done and not height of the cylinder.at line 173
I got:
so clearly different axis again. You should use the height of cylinder axis... The same is also in the else at line 180.
So if I see it right this is axis correspondence
line 182
you got:
I got:
in case you
mid[]
is zero then still you need to use-p
. Also you are rotating aroundy
but from axis correspondence you are using in previous code you should rotate aroundz
!!!So you are wrongly setting the center of rotation, rotate around a wrong axis. Also check if you choose correctly the axises (they need to have the same meaning in your mesh).
[Edit4] another comparison
line 105
should be:
as you are rotating around
Z
so the centerPC
must be shifted in other axis... soX
that is why your bend is just shifted instead of rotated.Looks like the rest of code should be OK but to be sure I would also render the
mid
anddir
arrays to see if they are really where they should be in respect to the mesh (the yellow center line of mesh in my preview). Once the bend is working you should also port theP0X0Y0Z0
computation from themid,dir
so you can apply the bend repetitively ...If I swap to your axises it would be:
[edit5] another comparison
You are doing the same mistakes again and again ... incorrectly re-writing equations so no brainner its not working right. This time:
At line 186:
you forgot to add the
point_temp.sub(p);
that is the reason for distortion of shape and most likely also for the different rotation.your
rotatez
is wrong as you got:
and I got
but anyway it also could be:
try which one works I have my equations for
rotatex
tested not forrotatez
... the two versions just rotate in opposite directions so both are correct but the code can work correctly only with one.angular units
the bend of mid line (that one you got "right" in code) does not resemble rotation around
PC
it might be caused by #2 but it also can be caused by wrong angle units. Do yourcos
andsin
functions need[deg]
or[rad]
? Currently all angles computed are in[rad]
.