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

Tin*_*Zea 5 javascript geometry trigonometry three.js

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

我想指定这些参数:

  • 弯曲开始- 弯曲开始于圆柱体高度的百分之多少
  • 弯曲结束- 弯曲结束于圆柱体高度的百分之多少
  • 角度- 弯曲的强度

    参数

我将用滑块控制它们。我的圆柱体形状是通过用户绘制的贝塞尔曲线的挤压创建的( Three.js 中几何类的扩展)。

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

我不是最擅长数学,所以这就是为什么我要求可以在 Three.js 中完成此操作的提示或公式。我想也许我可以在中心轴上放一条线,然后用贝塞尔曲线弯曲它。从那里我可以使用线位置来影响圆柱体的顶点。这听起来是个好主意吗?

Spe*_*tre 5

您需要做的是将网格切成片,并以与我在此处处理圆圈相同的方式转换每个片:

这样做是这样的:

  1. 直形坐标系

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

    P0X0Y0Z0

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

    所以任意点P都会转化为:

    P.x' = dot( P-P0 , X0 )
    P.y' = dot( P-P0 , Y0 )
    P.z' = dot( P-P0 , Z0 )
    
    Run Code Online (Sandbox Code Playgroud)
  3. 创建折弯形状坐标系P1,X1,Y1,Z1

    因此,只需根据P.z'用作参数(弯曲形状上的弧长)计算弯曲弧的角度并旋转X0,Y0,Z0到,X1,Y1,Z1如果弯曲在X那时X1 = X0,您只需要旋转其他两个向量。

    P1X1Y1Z1

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

    只需这样做:

    P'' = P1 + P.x'*X1 + P.y'*Y1
    
    Run Code Online (Sandbox Code Playgroud)

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

[笔记]

请注意,如果弯曲太大,太大的弯曲可能会破坏您的网格拓扑,然后您可以使切片彼此相交。

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

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

[编辑1] C++/GL 示例

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

预览

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

网格和弯曲zavit.h

P.x' = dot( P-P0 , X0 )
P.y' = dot( P-P0 , Y0 )
P.z' = dot( P-P0 , Z0 )
Run Code Online (Sandbox Code Playgroud)

以及主要的VCL应用程序代码(忽略VCL内容,只需移植/使用您需要的内容):

P'' = P1 + P.x'*X1 + P.y'*Y1
Run Code Online (Sandbox Code Playgroud)

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

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

[Edit2] 一些更多的简化和可重复性

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

新的方法

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

双弯

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

这里是新的 C++ 代码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();
        }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

VCL窗口代码:

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