问题描述
如何创建以下模型:
从第一张图开始.它可以完全在 OpenGL 中编程还是应该使用其他软件,如 3d Studio Max 或 Unity?是否应该使用一些特定的算法?
是的,这可以在 C++/OpenGL
中完成创建从中心发射的随机曲线
简单的 3D 二次多项式曲线将符合要求.
将曲线转换为圆锥
简单地沿每条曲线插入点并将其用作锥形切片的中心.方向由沿曲线的上一个或下一个点设置.插入锥形切片并将它们的点添加到某个点列表中.见:
[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
create random curves emitting from center
simple 3D quadratic polynomial curve will fit the bill.
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:
create faces
simply connect the computed points to form the cones using any primitive ... I would suggest
GL_QUAD
s...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 coefficientsa1[],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 producta = b x c
a = vector_mul(b[3],c[3])
is dot producta = (b.c)
vector_one(a[3],b[3])
is unit vectora = b/|b|
vector_copy(a[3],b[3])
is just copya = b
vector_add(a[3],b[3],c[3])
is addinga = b + c
vector_sub(a[3],b[3],c[3])
is substractinga = b - c
vector_neg(a[3],b[3])
is negationa = -b
vector_ld(a[3],x,y,z)
is just loadinga = (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 asdouble xxx[];
xxx.add(5);
adds5
to end of the listxxx[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 arrayxxx.reset()
clears the array and setxxx.num=0
xxx.allocate(100)
preallocate space for100
items这篇关于在 OpenGL 中编程特定的 3d(星形)模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!