本文介绍了在 OpenGL 中编程特定的 3d(星形)模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建以下模型:


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

解决方案

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

中完成

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

    简单的 3D 二次多项式曲线将符合要求.

  2. 将曲线转换为圆锥

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

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

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

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

      //---------------------------------------------------------------------列表<double>pnt,也没有;//点,法线列表事实;//四面体//---------------------------------------------------------------------------void Circle3D(List &pnt,List &nor,double *p0,double *n0,double r,int N){国际我;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);对于 (a=0.0,i=0;i

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

      //叉积:W = U x VW.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)//点积:a = (U.V)a=U.x*V.x+U.y*V.y+U.z*V.z//向量的绝对值 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)

      还可以在此处找到一些(如果不是全部)使用的矢量数学:

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


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

      How can I create the following model:


      by starting from the first drawing. Could it be programmed in OpenGL entirely or should I use other software like 3d Studio Max or Unity? Are there some specific algorithms that should be used?

      解决方案

      Yes this can be done in C++/OpenGL

      1. create random curves emitting from center

        simple 3D quadratic polynomial curve will fit the bill.

      2. convert the curves to cones

        simply interpolate points along each curve and use it as a center for the cone slice. The direction is set by the previous or next point along the curve. Interpolate the cone slices and add their points to some point list. See:

      3. create faces

        simply connect the computed points to form the cones using any primitive ... I would suggest GL_QUADs...

      4. core

        if you want to add also the core (nuclei?) it can be done a s a sphere with some noise added to its surface and probably some filtering to smooth it a bit...

      Here simple curve generation C++ example:

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

      Preview of the generated points:

      [Edit1] When added the cones,normals and faces it looks like this:

      Its far from perfect but I think is a good start point. Just tweak the radius r and the curve coefficients a1[],a2[] to achieve desired shape ... and may be add the core and or check for self intersections too, I am too lazy to do that...

      Here the updated C++/GL code:

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

      If you do not know how to compute vector operations like cross/dot products or absolute value see:

      // 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]) is cross product a = b x c
      a = vector_mul(b[3],c[3]) is dot product a = (b.c)
      vector_one(a[3],b[3]) is unit vector a = b/|b|
      vector_copy(a[3],b[3]) is just copy a = b
      vector_add(a[3],b[3],c[3]) is adding a = b + c
      vector_sub(a[3],b[3],c[3]) is substracting a = b - c
      vector_neg(a[3],b[3]) is negation a = -b
      vector_ld(a[3],x,y,z) is just loading a = (x,y,z)

      Also some (if not all the) Vector math used can be found here:

      I also use mine dynamic list template so:


      List<double> xxx; is the same as double xxx[];
      xxx.add(5); adds 5 to end of the list
      xxx[7] access array element (safe)
      xxx.dat[7] access array element (unsafe but fast direct access)
      xxx.num is the actual used size of the array
      xxx.reset() clears the array and set xxx.num=0
      xxx.allocate(100) preallocate space for 100 items

      这篇关于在 OpenGL 中编程特定的 3d(星形)模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 16:25