How to bend a cylinder in three.js?

2019-06-06 14:36发布

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

    parameters

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?

1条回答
Melony?
2楼-- · 2019-06-06 14:43

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:

  1. straight form coordinate system

    Create position P0 and 3 basis vectors X0,Y0,Z0 representing coordinates of the mesh in straight form. Let assume the Z0 is the axis you want to bend.

    P0X0Y0Z0

  2. convert each vertex into P0,X0,Y0,Z0 local coordinates

    so any point P is transformed into:

    P.x' = dot( P-P0 , X0 )
    P.y' = dot( P-P0 , Y0 )
    P.z' = dot( P-P0 , Z0 )
    
  3. 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 rotate X0,Y0,Z0 into X1,Y1,Z1 if the bending is around X then X1 = X0 and you need to rotate just the other two vectors.

    P1X1Y1Z1

  4. convert P' into bended form P''

    simply do this:

    P'' = P1 + P.x'*X1 + P.y'*Y1
    

    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 the P.z ... as its encoded in the P1 position already. So also no real need to compute the Z1 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 if Y0=(0,1,0) its even simpler just point on circle Y1=(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:

preview

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 chose P0,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:

//---------------------------------------------------------------------------
//--- tube with sinus screw -------------------------------------------------
//---------------------------------------------------------------------------
const int ca=20;
const int cb=50;
const float r0=0.3;
const float r1=0.35;
const float l1=2.0;
const float nz=5.0;
vec3 pnt0[ca][cb];  // straight mesh
vec3 nor0[ca][cb];
vec2 txr0[ca][cb];
//---------------------------------------------------------------------------
vec3 pnt1[ca][cb];  // bended mesh
vec3 nor1[ca][cb];
vec2 txr1[ca][cb];
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void obj0_init()    // sin screw
    {
    int     i,j,i0,j0;
    float   a,b,l,da,db,dl,r,s,c,tx,ty;
    float   dtx=1.0/float(ca-1),dty=1.0/float(cb-1);
    vec3    u,v;
    // pnt,txr
    da=2.0*M_PI/float(ca-1);
    db=nz*2.0*M_PI/float(cb);
    dl=l1/float(cb);
    for (a=0.0,tx=0.0,i=0;i<ca;i++,a+=da,tx+=dtx)
        {
        s=sin(a);
        c=cos(a);
        for (l=-0.5*l1,b=0,ty=0.0,j=0;j<cb;j++,b+=db,l+=dl,ty+=dty)
            {
            r=r0+((r1-r0)*cos(a+b));
            pnt0[i][j].x=r*c;
            pnt0[i][j].y=r*s;
            pnt0[i][j].z=l;
            txr0[i][j].x=tx;
            txr0[i][j].y=ty;
            }
        }
    // nor
    for (i0=ca-2,i=0;i<ca;i0=i,i++)
     for (j0=cb-1,j=0;j<cb;j0=j,j++)
        {
        u=pnt0[i][j]-pnt0[i0][j];
        v=pnt0[i][j]-pnt0[i][j0];
        nor0[i][j]=normalize(cross(v,u));
        }
    }
//---------------------------------------------------------------------------
void obj1_bend(vec3 center) // bend obj0 -> obj1 ... pc center, P0,X0,Y0,Z0 = unit matrix
    {
    int i,j,i0,j0;
    float a,r;
    vec3 p,p1,x1,y1,u,v;
    // bend pnt, copy txr
    r=length(center);
    for (i=0;i<ca;i++)
     for (j=0;j<cb;j++)
        {
        p=pnt0[i][j];               // p' = p

        a=p.z/r;                    // arc length -> angle [rad]
        p1=center;                  // p1 point on circleYZ (bending around X)
        p1.y-=r*cos(a);
        p1.z-=r*sin(a);
        x1=vec3(1.0,0.0,0.0);       // basis vectors
        y1=vec3(0.0,cos(a),sin(a));

        p=p1+(p.x*x1)+(p.y*y1);     // p''

        pnt1[i][j]=p;
        txr1[i][j]=txr0[i][j];
        }
    // nor
    for (i0=ca-2,i=0;i<ca;i0=i,i++)
     for (j0=cb-1,j=0;j<cb;j0=j,j++)
        {
        u=pnt1[i][j]-pnt1[i0][j];
        v=pnt1[i][j]-pnt1[i][j0];
        nor1[i][j]=normalize(cross(v,u));
        }
    }
//---------------------------------------------------------------------------
void obj0_draw()
    {
    int i,j;
    glColor3f(1.0,1.0,1.0);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    for (i=0;i<ca-1;i++)
        {
        glBegin(GL_QUAD_STRIP);
        for (j=0;j<cb;j++)
            {
            glTexCoord2fv(txr0[i+1][j].dat);
            glNormal3fv  (nor0[i+1][j].dat);
            glVertex3fv  (pnt0[i+1][j].dat);
            glTexCoord2fv(txr0[i  ][j].dat);
            glNormal3fv  (nor0[i  ][j].dat);
            glVertex3fv  (pnt0[i  ][j].dat);
            }
        glEnd();
        }
    }
//---------------------------------------------------------------------------
void obj1_draw()
    {
    int i,j;
    glColor3f(1.0,1.0,1.0);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    for (i=0;i<ca-1;i++)
        {
        glBegin(GL_QUAD_STRIP);
        for (j=0;j<cb;j++)
            {
            glTexCoord2fv(txr1[i+1][j].dat);
            glNormal3fv  (nor1[i+1][j].dat);
            glVertex3fv  (pnt1[i+1][j].dat);
            glTexCoord2fv(txr1[i  ][j].dat);
            glNormal3fv  (nor1[i  ][j].dat);
            glVertex3fv  (pnt1[i  ][j].dat);
            }
        glEnd();
        }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

And the main VCL app code (ignore the VCL stuff just port/use what you need):

//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
double divide(double a,double b){ if (fabs(b)<1e-10) return 0.0; return a/b; }
#include "GLSL_math.h"
#include "zavit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
vec3 center=vec3(0.0,1.7,0.0);
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    float aspect=float(xs)/float(ys);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0/aspect,aspect,0.1,100.0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0,0.0,-5.5);
    glRotatef(80.0,1.0,0.0,0.0);        // Z+ up slightly forw
    static float ang=0.0; ang+=5.0;
    glRotatef(45.0+ang,0.0,0.0,1.0);    // X+ right forw, Y+ left forw, + animation rotation around up

    glEnable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    // original mesh
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glTranslatef(-0.7,0.0,0.0);
    glColor3f(1.0,1.0,1.0);
    obj0_draw();
    glPopMatrix();

    // bended mesh
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glTranslatef(+0.7,0.0,0.0);
    glColor3f(1.0,1.0,1.0);
    obj1_draw();


    glDisable(GL_LIGHTING);
    glColor3f(1.0,0.0,0.0);
    glPointSize(10.0);
    glBegin(GL_POINTS);
    glVertex3fv(center.dat);    // bending center
    glVertex3f(0.0,0.0,0.0);    // P0
    glEnd();
    glPointSize(1.0);
    glBegin(GL_LINES);
    glVertex3fv(center.dat);
    glVertex3f(0.0,0.0,0.0);
    glEnd();

/*
    glBegin(GL_LINES);
    glColor3f(1.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(1.0,0.0,0.0);
    glColor3f(0.0,1.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,1.0,0.0);
    glColor3f(0.0,0.0,1.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.0,1.0);
    glEnd();
*/
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    gl_init(Handle);
    obj0_init();
    obj1_bend(center);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    gl_exit();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    gl_resize(ClientWidth,ClientHeight);
    gl_draw();
    }
//---------------------------------------------------------------------------

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:

new approach

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):

double bend

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:

//---------------------------------------------------------------------------
//--- tube with sinus screw -------------------------------------------------
//---------------------------------------------------------------------------
// https://stackoverflow.com/a/54050883/2521214
//---------------------------------------------------------------------------
const int   ca= 20;     // points per slice
const int   cb=100;     // slices
const float r0=  0.3;   // minor screw radius
const float r1=  0.35;  // major screw radius
const float l1=  4.0;   // tube length
const float nz= 10.0;   // screws
//---------------------------------------------------------------------------
vec3 bend_pc; int bend_j0,bend_j1;  // just for debug draw
//---------------------------------------------------------------------------
// straight mesh
vec3 pnt0[ca][cb];  // vertex
vec3 nor0[ca][cb];  // normal
vec2 txr0[ca][cb];  // texcoord
vec3 mid0[cb];      // slice center
vec3 dir0[cb];      // slice central axis (normalized)
float len0[cb];     // slice arclength position
//---------------------------------------------------------------------------
// bended mesh
vec3 pnt1[ca][cb];  // vertex
vec3 nor1[ca][cb];  // normal
vec2 txr1[ca][cb];  // texcoord
vec3 mid1[cb];      // slice center
vec3 dir1[cb];      // slice central axis (normalized)
float len1[cb];     // slice arclength position
//---------------------------------------------------------------------------
void obj0_init()    // sin screw
    {
    int     i,j,i0,j0;
    float   a,b,l,da,db,dl,r,s,c,tx,ty;
    float   dtx=1.0/float(ca-1),dty=1.0/float(cb-1);
    vec3    u,v;
    // pnt,txr
    da=2.0*M_PI/float(ca-1);
    db=nz*2.0*M_PI/float(cb);
    dl=l1/float(cb);
    for (a=0.0,tx=0.0,i=0;i<ca;i++,a+=da,tx+=dtx)
        {
        s=sin(a);
        c=cos(a);
        for (l=-0.5*l1,b=0,ty=0.0,j=0;j<cb;j++,b+=db,l+=dl,ty+=dty)
            {
            r=r0+((r1-r0)*cos(a+b));
            pnt0[i][j].x=r*c;
            pnt0[i][j].y=r*s;
            pnt0[i][j].z=l;
            txr0[i][j].x=tx;
            txr0[i][j].y=ty;
            }
        }
    // mid,dir
    for (l=0.0,j=0;j<cb;j++,l+=dl)
        {
        mid0[j]=vec3(0.0,0.0, l-(0.5*l1));
        dir0[j]=vec3(0.0,0.0,dl);
        len0[j]=l;
        }
    // nor
    for (i0=ca-2,i=0;i<ca;i0=i,i++)
     for (j0=cb-1,j=0;j<cb;j0=j,j++)
        {
        u=pnt0[i][j]-pnt0[i0][j];
        v=pnt0[i][j]-pnt0[i][j0];
        nor0[i][j]=normalize(cross(u,v));
        }
    }
//---------------------------------------------------------------------------
void obj1_copy()    // obj1 = obj0
    {
    int i,j;
    for (i=0;i<ca;i++)
     for (j=0;j<cb;j++)
        {
        pnt1[i][j]=pnt0[i][j];
        txr1[i][j]=txr0[i][j];
        nor1[i][j]=nor0[i][j];
        }
    for (j=0;j<cb;j++)
        {
        mid1[j]=mid0[j];
        dir1[j]=dir0[j];
        len1[j]=len0[j];
        }
    }
//---------------------------------------------------------------------------
vec3 rotatex(vec3 p,vec3 p0,float a)
    {
    vec3 q; p-=p0;
    q.z=+(p.z*cos(a))+(p.y*sin(a));
    q.y=-(p.z*sin(a))+(p.y*cos(a));
    q.x=p.x;
    return q+p0;
    }
//---------------------------------------------------------------------------
vec3 rotatey(vec3 p,vec3 p0,float a)
    {
    vec3 q; p-=p0;
    q.x=+(p.x*cos(a))+(p.z*sin(a));
    q.z=-(p.x*sin(a))+(p.z*cos(a));
    q.y=p.y;
    return q+p0;
    }
//---------------------------------------------------------------------------
vec3 rotatez(vec3 p,vec3 p0,float a)
    {
    vec3 q; p-=p0;
    q.x=+(p.x*cos(a))+(p.y*sin(a));
    q.y=-(p.x*sin(a))+(p.y*cos(a));
    q.z=p.z;
    return q+p0;
    }
//---------------------------------------------------------------------------
void obj1_bendx(float l0,float l1,float ang)    // [units],[units],[rad] bend obj1 around x axis
    {
    int i,j,i0,j0,j1;
    float a,r,l;
    vec3 PC,p,u,v;
    vec3 P0,X0,Y0,Z0;
    // find start and end of bend
    for (j0= 0;(j0<cb)&&(len1[j0]<l0);j0++);
    for (j1=j0;(j1<cb)&&(len1[j1]<l1);j1++);
    if (j0>cb) return;          // no bend
    // coordinate system0
    P0=mid1[j0];
    Z0=normalize(dir1[j0]);
    X0=vec3(1.0,0.0,0.0);
    Y0=cross(Z0,X0);
    X0=cross(Y0,Z0);
    // bend center
    r=(l1-l0)/ang;
    PC=P0-(Y0*r);
    r=fabs(r);
    // just for debug draw
    bend_pc=PC;
    bend_j0=j0;
    bend_j1=j1;
    // bend <l0,l1)
    for (j=j0;j<cb;j++)
        {
        // arc length -> angle [rad] and length correction
        if (j<j1)
            {
            a=ang*(len1[j]-l0)/(l1-l0);
            p=Z0*(len1[j]-l0);
            }
        else{
            a=ang;
            p=Z0*(l1-l0);
            }
        // transform system0 -> system1
        mid1[j]=rotatex(mid1[j]-p,PC,a);
        dir1[j]=rotatex(dir1[j],vec3(0.0,0.0,0.0),a);
        for (i=0;i<ca;i++) pnt1[i][j]=rotatex(pnt1[i][j]-p,PC,a);
        }
    // nor
    for (i0=ca-2,i=0;i<ca;i0=i,i++)
     for (j0=cb-1,j=0;j<cb;j0=j,j++)
        {
        u=pnt1[i][j]-pnt1[i0][j];
        v=pnt1[i][j]-pnt1[i][j0];
        nor1[i][j]=normalize(cross(u,v));
        }
    }
//---------------------------------------------------------------------------
void obj0_draw()
    {
    int i,j;
    glColor3f(1.0,1.0,1.0);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CW);
    for (i=0;i<ca-1;i++)
        {
        glBegin(GL_QUAD_STRIP);
        for (j=0;j<cb;j++)
            {
            glTexCoord2fv(txr0[i+1][j].dat);
            glNormal3fv  (nor0[i+1][j].dat);
            glVertex3fv  (pnt0[i+1][j].dat);
            glTexCoord2fv(txr0[i  ][j].dat);
            glNormal3fv  (nor0[i  ][j].dat);
            glVertex3fv  (pnt0[i  ][j].dat);
            }
        glEnd();
        }
    }
//---------------------------------------------------------------------------
void obj1_draw()
    {
    int i,j;
    glColor3f(1.0,1.0,1.0);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CW);
    for (i=0;i<ca-1;i++)
        {
        glBegin(GL_QUAD_STRIP);
        for (j=0;j<cb;j++)
            {
            glTexCoord2fv(txr1[i+1][j].dat);
            glNormal3fv  (nor1[i+1][j].dat);
            glVertex3fv  (pnt1[i+1][j].dat);
            glTexCoord2fv(txr1[i  ][j].dat);
            glNormal3fv  (nor1[i  ][j].dat);
            glVertex3fv  (pnt1[i  ][j].dat);
            }
        glEnd();
        }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

And the VCL window code:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
double divide(double a,double b){ if (fabs(b)<1e-10) return 0.0; return a/b; }
#include "GLSL_math.h"
#include "zavit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    float aspect=float(xs)/float(ys);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0/aspect,aspect,0.1,100.0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0,0.0,-5.5);
    glRotatef(-80.0,1.0,0.0,0.0);       // Z+ up slightly forw
    static float ang=0.0; ang+=5.0;
    glRotatef(45.0+ang,0.0,0.0,1.0);    // X+ right forw, Y+ left forw, + animation rotation around up

    glEnable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    // [original mesh]
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glTranslatef(-0.7,0.0,0.0);
    glColor3f(1.0,1.0,1.0);
    obj0_draw();
    glPopMatrix();

    // [bended mesh]
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glTranslatef(+0.7,0.0,0.0);
    glColor3f(1.0,1.0,1.0);
    obj1_draw();

    // debug draws
    int j;
    glDisable(GL_LIGHTING);
    glDisable(GL_DEPTH_TEST);

    // global coordinates
    glBegin(GL_LINES);
    glColor3f(1.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(1.0,0.0,0.0);
    glColor3f(0.0,1.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,1.0,0.0);
    glColor3f(0.0,0.0,1.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.0,1.0);
    glEnd();

    // mesh axis
    glLineWidth(2.0); glColor3f(0.9,0.6,0.1); glBegin(GL_LINE_STRIP);
    for (j=0;j<bend_j0;j++) glVertex3fv(mid1[j].dat); if (j<cb){ glVertex3fv(mid1[j].dat); glVertex3fv(bend_pc.dat); }
    for (   ;j<bend_j1;j++) glVertex3fv(mid1[j].dat); if (j<cb){ glVertex3fv(mid1[j].dat); glVertex3fv(bend_pc.dat); }
    for (   ;j<cb     ;j++) glVertex3fv(mid1[j].dat);
    glEnd(); glLineWidth(1.0);
    // bending center
    glColor3f(1.0,0.0,0.0);
    glPointSize(10.0);
    glBegin(GL_POINTS);
    glVertex3fv(bend_pc.dat);
    glEnd();
    glPointSize(1.0);

    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    gl_init(Handle);
    obj0_init();
    obj1_copy();
    obj1_bendx(1.0,1.5,+45.0*M_PI/180.0);
    obj1_bendx(2.5,3.0,-45.0*M_PI/180.0);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    gl_exit();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    gl_resize(ClientWidth,ClientHeight);
    gl_draw();
    }
//---------------------------------------------------------------------------

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 and bendz 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:

  1. you use fixed P0X0Y0Z0 which prevents you from applying bend more than once.
  2. at line 155

    var PC = new THREE.Vector3().copy(P0).sub(PC_X);
    

    it does not correspond to mine

    PC=P0-(Y0*r);
    

    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.

  3. at line 173

    var p = new THREE.Vector3().copy(X0);
    p.multiplyScalar(slice_arc_length[j]-l0);
    

    I got:

    p=Z0*(len1[j]-l0);
    

    so clearly different axis again. You should use the height of cylinder axis... The same is also in the else at line 180.

  4. So if I see it right this is axis correspondence

    mine    yours   meaning
    X0      Z0      bending rotation axis
    Y0      X0
    Z0      Y0      cylinder height
    
  5. line 182

    you got:

    center_points[j] = rotatey(p,PC,a);
    center_vector[j] = rotatey(center_vector[j], new THREE.Vector3(0,0,0),a);
    for (var i=0; i<20; i++){ slices[i][j]= rotatey(slices[i][j].sub(p),PC,a); }
    

    I got:

    mid1[j]=rotatex(mid1[j]-p,PC,a);
    dir1[j]=rotatex(dir1[j],vec3(0.0,0.0,0.0),a);
    for (i=0;i<ca;i++) pnt1[i][j]=rotatex(pnt1[i][j]-p,PC,a);
    

    in case you mid[] is zero then still you need to use -p. Also you are rotating around y but from axis correspondence you are using in previous code you should rotate around z !!!

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

  1. line 105

    var Z_Copy = new THREE.Vector3().copy(Z0);
    Z_Copy.multiplyScalar(r);
    var PC = new THREE.Vector3().copy(P0).sub(Z_Copy);
    

    should be:

    var X_Copy = new THREE.Vector3().copy(X0);
    X_Copy.multiplyScalar(r);
    var PC = new THREE.Vector3().copy(P0).sub(X_Copy);
    

    as you are rotating around Z so the center PC must be shifted in other axis... so X 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 and dir 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 the P0X0Y0Z0 computation from the mid,dir so you can apply the bend repetitively ...

If I swap to your axises it would be:

P0=mid1[j0];
Y0=normalize(dir1[j0]);
Z0=vec3(0.0,0.0,1.0);
X0=cross(Y0,Z0);
Y0=cross(Z0,X0);

[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:

  1. At line 186:

    var point_temp = new THREE.Vector3().copy(slices[j][i]);
    

    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.

  2. your rotatez

    is wrong as you got:

    p.x=+(p.x*Math.cos(a))+(p.y*Math.sin(a));
    p.y=+(p.x*Math.sin(a))+(p.y*Math.cos(a));
    p.z=p.z;
    

    and I got

    p.x=+(p.x*Math.cos(a))+(p.y*Math.sin(a));
    p.y=-(p.x*Math.sin(a))+(p.y*Math.cos(a));
    p.z=p.z;
    

    but anyway it also could be:

    p.x=+(p.x*Math.cos(a))-(p.y*Math.sin(a));
    p.y=+(p.x*Math.sin(a))+(p.y*Math.cos(a));
    p.z=p.z;
    

    try which one works I have my equations for rotatex tested not for rotatez ... the two versions just rotate in opposite directions so both are correct but the code can work correctly only with one.

  3. 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 your cos and sin functions need [deg] or [rad] ? Currently all angles computed are in [rad].

查看更多
登录 后发表回答