-2

How can I create the following model:

img

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?

genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 3
    Few weeks? ago I saw this exact image and question asking almost the same in here it was you? If not try to find it (I can not find it now possibly ... deleted). Anyway yes this can be done in C++/OpenGL ... you can create the mesh as a set of curved cones ... so create few randomly curved paths (use any CUBIC curve... like BEZIER...) and then just superimpose the cone to the curve (use its points as a centers for the cone circles) ...see [Smoothly connecting circle centers](https://stackoverflow.com/a/25182327/2521214) on how to do the curved cones ... – Spektre Nov 30 '18 at 19:25
  • @Spektre: Yup, I remember the same one. – genpfault Nov 30 '18 at 19:54
  • 2
    @Spektre: Ah [there we go](https://stackoverflow.com/questions/53204972/question-about-modelling-a-specific-3d-model). – genpfault Nov 30 '18 at 19:55
  • @genpfault Yep that is the one ...How did you find the question so quickly? btw I do not think this is too broad as you can see even few lines of the C++ code and I got the major skeleton done already.... – Spektre Nov 30 '18 at 20:00
  • 1
    @Spektre: The profile -> votes -> closure list (along with 'deletion') is one of the few places I've been able to find that lists deleted posts. I just scanned backward looking at likely deleted questions. I really wish the other activity feeds (all actions -> comments in particular) had the same property :( – genpfault Nov 30 '18 at 20:25

1 Answers1

2

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:

curves

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

cones

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

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • I usually just outsource my linear algebra to [GLM](https://glm.g-truc.net) and call it a day :) – genpfault Nov 30 '18 at 21:17
  • hi, I would like to ask you how can I use the Random(ize) functions because the compiler cannot recognize them? Should I include additional library? And secondly the ide says that num is not part of List? I would like to ask why is that ? Thanks in advance! – Peter Petrov Dec 01 '18 at 18:38
  • @PeterPetrov `Randomize()` and `Random()` are VCL specific but you can use what ever capability you have at disposal like `random()` IIRC it is in `conio.h` or `stdio.h` ... any pseudo random generator on interval `0-1` would do ... The `Randomize()` is just an init of the generator and `Random()` returns pseudo-random value on `<0,1>` interval – Spektre Dec 01 '18 at 20:14
  • @PeterPetrov the List is mine own class for dynamic array (described in the answer) you can use static array instead or a std::vector or whatever container you got at your disposal ... – Spektre Dec 01 '18 at 20:21