如何在 three.js 中弯曲圆柱体?

How to bend a cylinder in three.js?

如何在 three.js 中弧形或弯曲圆柱形几何体(有变形)?

我想指定这些参数:

我将使用滑块控制它们。我的圆柱体形状是根据用户绘制的贝塞尔曲线的拉伸创建的(three.js 中的几何扩展 class)。

我还希望能够将多个弯曲效果叠加在一起。所以弯曲可能会影响第一部分,然后第二个弯曲可能会使圆柱体向后弯曲。

我不是最擅长数学的,所以我在 three.js 中寻求可以做到这一点的技巧或公式。我在想也许我可以在中心轴上放一条线然后用贝塞尔曲线弯曲它。从那里我可以使用线位置来影响圆柱体的顶点。这听起来是个好主意吗?

你需要做的是将你的网格切割成切片,并按照我在这里做圆圈的方式转换每个切片:

  • Smoothly connecting circle centers

这样做是这样的:

  1. 直式坐标系

    创建位置 P0 和 3 个基本向量 X0,Y0,Z0 以直线形式表示网格的坐标。假设 Z0 是您要弯曲的轴。

  2. 将每个顶点转换成P0,X0,Y0,Z0局部坐标

    所以任意一点P被转化为:

    P.x' = dot( P-P0 , X0 )
    P.y' = dot( P-P0 , Y0 )
    P.z' = dot( P-P0 , Z0 )
    
  3. 创建弯曲形式坐标系P1,X1,Y1,Z1

    所以简单地根据用作参数的P.z'(弯曲形状上的弧长)计算弯曲弧的角度,如果弯曲是旋转X0,Y0,Z0X1,Y1,Z1大约 X 然后 X1 = X0,你只需要旋转另外两个向量。

  4. 将P'转换为弯曲形式P''

    只需这样做:

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

    现在 P'' 是您形状的最终顶点。因此,您可以在转换所有点后渲染网格。如您所见,我们不需要 P.z ... 因为它已经编码在 P1 位置。所以也不需要计算 Z1 基向量。

[注释]

注意弯曲太大会破坏网格拓扑结构如果弯曲太多,则切片之间可能会自相交。

所有相应的基向量也应该具有相同的大小理想单位。

Y0 -> Y1 的旋转是简单的二维问题,如果 Y0=(0,1,0) 它更简单,只需指向圆 Y1=(cos(a),sin(a),0) ... 所以你甚至不需要二维旋转公式。

[Edit1] C++/GL 示例

我很好奇,所以我拿了一根带正弦螺钉的生成管并将其弯曲...这是结果:

我渲染了直线和弯曲的网格以进行视觉比较。红点是弯曲中心,直线连接到 P0。我选择了 P0,X0,Y0,Z0 来匹配单位矩阵。该示例已转换,因此它与此问题中的图像匹配(处于非动画状态)。这是我用 C++/GL 代码完成的:

网格和弯曲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();
        }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

和主要的 VCL 应用程序代码(忽略 VCL 东西只是 port/use 你需要的):

//---------------------------------------------------------------------------
#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();
    }
//---------------------------------------------------------------------------

对于 OpenGL 我正在使用 GLEW 和我的 gl_simple.h 可以可以在这里找到:

GLSL_math.h 是我的矢量数学模仿 GLSL 数学但你可以使用任何矢量数学......你只是需要 +,-,dot,cross,normalize,length 这些都是基本操作,您也可以自己编写代码或使用 GLM 或其他...

[Edit2] 更加简化和可重复

好吧,根据你的草图和后来的评论,它不适用于高度。而是使用弧长(直线网格中的高度)作为参数。经过更多的教导后,我得到了这个:

为了简化,我为每个切片添加了一个中心点、主轴方向和切片长度。这使得计算更简单......这里预览两次应用的 45 度弯曲(+45 和 -45):

RGB 线是弯曲网格渲染的全局坐标系,黄色是网格中心轴 + 最后弯曲的弯曲范围用于调试,红色是最后弯曲中心。

这里是新的 C++ 代码 zavit.h:

//---------------------------------------------------------------------------
//--- tube with sinus screw -------------------------------------------------
//---------------------------------------------------------------------------
// 
//---------------------------------------------------------------------------
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();
        }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

和VCL window代码:

//---------------------------------------------------------------------------
#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();
    }
//---------------------------------------------------------------------------

架构是相同的,只是用法有所改变,现在弯曲直接应用于 mesh1,因此它不再使用 mesh0。所以使用前需要将mesh0复制到mesh1。

我还利用了我的网格按弧长 (pnt1[angle][arclength]) 排序的事实,因此我可以处理切片而不是原始点。

您可以类比地编写 bendybendz 函数,只需稍微更改数学以匹配交换的轴...如果您不需要原始网格,那么您现在可以将其删除.. .

[Edit3] 与你的视觉对比 code

它对我来说是外语,但类似于 C/C++ 所以从速览来看:

  1. 您使用固定的 P0X0Y0Z0,这会阻止您多次应用弯曲。
  2. 第 155 行

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

    与我的不符

    PC=P0-(Y0*r);
    

    你有不同的轴并且没有半径刻度!!!如果您的轴与我的轴有不同的含义,那么您只需相应地交换 X,Y,Z 但您仍然需要使用半径。这是弯曲中心的位置,所以如果计算错误,弯曲也是错误的...使用的轴必须不是旋转所围绕的轴,也不是圆柱体的高度。

  3. 第 173 行

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

    我得到了:

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

    又明显不同轴了。你应该使用圆柱轴的高度......同样也在第180行的else中。

  4. 所以如果我没看错这就是轴对应

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

    你得到了:

    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); }
    

    我得到了:

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

    如果您的 mid[] 为零,那么您仍然需要使用 -p。你也在围绕 y 旋转,但是从你在之前的代码中使用的轴对应你应该围绕 z 旋转!!!

所以你错误地设置了旋转中心,绕着错误的轴旋转。还要检查你是否正确选择了轴(它们在你的网格中需要具有相同的含义)。

[Edit4] 另一个比较

  1. 第 105 行

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

    应该是:

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

    当您围绕 Z 旋转时,中心 PC 必须在其他轴上移动...所以 X 这就是为什么您的弯曲只是移动而不是旋转的原因。

看起来其余的代码应该没问题,但为了确保我也会渲染 middir 数组,看看它们是否真的在它们应该在网格方面的位置(我预览中的黄色网格中心线)。一旦弯曲开始工作,您还应该从 mid,dir 移植 P0X0Y0Z0 计算,以便您可以重复应用弯曲 ...

如果我换成你的坐标轴,它将是:

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

[edit5] 另一个比较

你一次又一次地犯同样的错误......不正确地重写方程式所以不用脑子它就不能正常工作。这次:

  1. 第 186 行:

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

    您忘记添加 point_temp.sub(p);,这是形状变形的原因,很可能也是不同旋转的原因。

  2. 你的rotatez

    你得到的是错误的:

    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;
    

    我得到了

    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;
    

    但无论如何也可能是:

    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;
    

    试试哪个有效 我有我的方程式 rotatex 测试没有 rotatez ...这两个版本只是在相反的方向旋转所以都是正确的但是代码只能正常工作一.

  3. angular 单位

    中线的弯曲(你在代码中 "right" 得到的那个)不像围绕 PC 的旋转,它可能是由 #2 引起的但它也可能是由错误的角度单位引起的。您的 cossin 函数需要 [deg][rad] 吗?当前计算的所有角度都在 [rad].