在 OpenGL 中编程特定的 3d(星形)模型? [关闭]

Posted

技术标签:

【中文标题】在 OpenGL 中编程特定的 3d(星形)模型? [关闭]【英文标题】:Programming a specific 3d (star-like) model in OpenGL? [closed] 【发布时间】:2018-11-30 18:06:40 【问题描述】:

如何创建以下模型:

从第一张图纸开始。它可以完全在 OpenGL 中编程,还是应该使用 3d Studio Max 或 Unity 等其他软件?是否有一些特定的算法应该使用?

【问题讨论】:

几周?以前我看到这个确切的图像和问题在这里问几乎相同的是你吗?如果不尝试找到它(我现在可能找不到它......已删除)。无论如何,是的,这可以在 C++/OpenGL 中完成......您可以将网格创建为一组弯曲的圆锥......所以创建一些随机弯曲的路径(使用任何 CUBIC 曲线......像 BEZIER......)然后只是将圆锥叠加到曲线上(使用其点作为圆锥圆的中心)...请参阅Smoothly connecting circle centers 了解如何制作弯曲圆锥... @Spektre:是的,我记得同一个。 @Spektre: 啊there we go. @genpfault 是的,就是这样......你是怎么这么快找到问题的?顺便说一句,我认为这并不太宽泛,因为您甚至可以看到几行 C++ 代码,而且我已经完成了主要的骨架...... @Spektre:个人资料 -> 投票 -> 关闭列表(连同“删除”)是我能够找到列出已删除帖子的少数几个地方之一。我只是回顾了一下可能被删除的问题。我真的希望其他活动提要(尤其是所有操作-> cmets)具有相同的属性:( 【参考方案1】:

是的,这可以在 C++/OpenGL

中完成

    创建从中心发射的随机曲线

    简单的 3D 二次多项式曲线可以满足要求。

    将曲线转换为圆锥

    只需沿每条曲线插入点并将其用作圆锥切片的中心。方向由曲线上的上一个或下一个点设置。插入圆锥切片并将它们的点添加到某个点列表中。见:

    Smoothly connecting circle centers

    创建面孔

    只需使用任何原语连接计算点以形成锥体...我建议GL_QUADs...

    核心

    如果您还想添加核心(核?),可以将其做成一个球体,在其表面添加一些噪声,并可能进行一些过滤以使其平滑一点...

这里是简单的曲线生成C++例子:

List<double> pnt;
void spicule_init()
    
    double t,tt,x,y,z;
    double a0[3],a1[3],a2[3];
    int ix0,ix,i,j;
    Randomize();
    for (i=0;i<20;i++)                      // cones
        
        // random quadratic 3D curve coeff
        for (j=0;j<3;j++)
            
            a0[j]=0.0;                      // center (0,0,0)
            a1[j]=2.0*(Random()-0.5);       // main direction
            a2[j]=1.0*(Random()-0.5);       // curvature
            
        // curve interpolation
        ix0=pnt.num;
        for (t=0.0;t<=1.0;t+=0.04)
         for (tt=t*t,j=0;j<3;j++)
          pnt.add(a0[j]+(a1[j]*t)+(a2[j]*tt));
        
    

生成点预览:

[Edit1] 添加圆锥体、法线和面后,它看起来像这样:

它远非完美,但我认为这是一个很好的起点。只需调整半径r 和曲线系数a1[],a2[] 即可获得所需的形状......并且可能会添加核心或检查自相交,我懒得这样做......

这里是更新的 C++/GL 代码:

//---------------------------------------------------------------------------
List<double> pnt,nor;   // points, normals
List<int> fac;          // QUAD faces
//---------------------------------------------------------------------------
void Circle3D(List<double> &pnt,List<double> &nor,double *p0,double *n0,double r,int N)
    
    int i;
    double a,da=divide(pi2,N),p[3],dp[3],x[3],y[3];
    vector_ld(x,1.0,0.0,0.0); if (fabs(vector_mul(x,n0)>0.7)) vector_ld(x,0.0,1.0,0.0);
    vector_mul(x,x,n0); vector_one(x,x);
    vector_mul(y,x,n0); vector_one(y,y);
    for (a=0.0,i=0;i<N;i++,a+=da)
        
        vector_mul( p,x,cos(a));
        vector_mul(dp,y,sin(a));
        vector_add(p,p,dp); nor.add(p[0]); nor.add(p[1]); nor.add(p[2]);
        vector_mul(p,p,r);
        vector_add(p,p,p0); pnt.add(p[0]); pnt.add(p[1]); pnt.add(p[2]);
        
    
//---------------------------------------------------------------------------
void spicule_init() // generate random spicule mesh
    
    const int N=36;                         // points/circle
    const int N3=3*N;
    double t,tt,x,y,z,r;
    double a0[3],a1[3],a2[3];
    double p[3],n[3];
    int e,i,j,i00,i01,i10,i11;
    Randomize();
    pnt.num=0; nor.num=0; fac.num=0;
    for (i=0;i<20;i++)                      // cones
        
        // random quadratic 3D curve coeff
        for (j=0;j<3;j++)
            
            a0[j]=0.0;                      // center (0,0,0)
            a1[j]=2.0*(Random()-0.5);       // main direction and size
            a2[j]=1.0*(Random()-0.5);       // curvature
            
        // curve interpolation
        vector_ld(n,0.0,0.0,0.0);
        for (e=0,t=0.05;t<=1.0;t+=0.05)
            
            // points,normals
            for (tt=t*t,j=0;j<3;j++) p[j]=a0[j]+(a1[j]*t)+(a2[j]*tt);
            r=0.15*(1.0-pow(t,0.1));        // radius is shrinking with t
            vector_sub(n,p,n);              // normal is p(t)-p(t-dt)
            Circle3D(pnt,nor,p,n,r,N);      // add circle to pnt (N points)
            vector_copy(n,p);               // remember last point
            // faces
            if (!e) e=1; continue;        // ignore first slice of cone
            i00=pnt.num- 3; i10=i00-N3;
            i01=pnt.num-N3; i11=i01-N3;
            for (j=0;j<N;j++)
                
                fac.add(i00);
                fac.add(i01);
                fac.add(i11);
                fac.add(i10);
                i00=i01; i01+=3;
                i10=i11; i11+=3;
                
            
        
    
//---------------------------------------------------------------------------
void spicule_draw() // render generated spicule
    
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    int i,j;
    glColor3f(1.0,1.0,1.0);
    glBegin(GL_QUADS);
    for (i=0;i<fac.num;i++)
        
        j=fac.dat[i];
        glNormal3dv(nor.dat+j);
        glVertex3dv(pnt.dat+j);
        
    glEnd();
    
//---------------------------------------------------------------------------

如果您不知道如何计算交叉/点积或绝对值等向量运算,请参阅:

// cross product: W = U x V
W.x=(U.y*V.z)-(U.z*V.y)
W.y=(U.z*V.x)-(U.x*V.z)
W.z=(U.x*V.y)-(U.y*V.x)
// dot product: a = (U.V)
a=U.x*V.x+U.y*V.y+U.z*V.z
// abs of vector a = |U|
a=sqrt((U.x*U.x)+(U.y*U.y)+(U.z*U.z))

vector_mul(a[3],b[3],c[3]) 是叉积 a = b x c a = vector_mul(b[3],c[3]) 是点积 a = (b.c) vector_one(a[3],b[3]) 是单位向量 a = b/|b| vector_copy(a[3],b[3]) 只是复制a = b vector_add(a[3],b[3],c[3]) 正在添加a = b + c vector_sub(a[3],b[3],c[3]) 正在减去 a = b - c vector_neg(a[3],b[3]) 是否定的a = -b vector_ld(a[3],x,y,z) 正在加载 a = (x,y,z)

还可以在这里找到一些(如果不是全部)使用的向量数学:

Understanding 4x4 homogenous transform matrices

我也使用我的动态列表模板,所以:

List&lt;double&gt; xxx;double xxx[]; 相同 xxx.add(5);5 添加到列表末尾 xxx[7]访问数组元素(安全) xxx.dat[7]访问数组元素(不安全但快速直接访问) xxx.num是数组实际使用的大小 xxx.reset() 清除数组并设置xxx.num=0 xxx.allocate(100)100 项目预分配空间

【讨论】:

我通常只是将我的线性代数外包给GLM,然后收工:) 你好,我想问你如何使用 Random(ize) 函数,因为编译器无法识别它们?我应该包括其他库吗?其次,ide 说 num 不是 List 的一部分?我想问这是为什么?提前致谢! @PeterPetrov Randomize()Random() 是特定于 VCL 的,但您可以使用您拥有的任何功能,例如 random() IIRC 它位于 conio.hstdio.h ... 任何间隔0-1 上的伪随机生成器会做... Randomize() 只是生成器的一个初始化,Random()&lt;0,1&gt; 间隔上返回伪随机值 @PeterPetrov List 是我自己的动态数组类(在答案中描述)您可以使用静态数组或 std::vector 或您可以使用的任何容器...跨度>

以上是关于在 OpenGL 中编程特定的 3d(星形)模型? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

通过OpenGL理解前端渲染原理

如何在opengl中计算给定3D点及其2D屏幕位置的投影/模型视图矩阵

OpenGL ES之3D模型加载和渲染

通过OpenGL理解前端渲染原理

在 android 中使用 opengl 在 glsurfaceview 中显示 3D 模型的问题

我的OpenGL学习进阶之旅Assimp库支持哪些3D模型格式?