C ++ OpenGL:如何在圆柱上做第二个圆?

时间:2018-11-17 18:37:51

标签: c++ opengl graphics 3d glm-math

所以基本上我有一个带有底座的圆柱体(圆柱体下面有一个圆),但是上面没有圆。我想把它做成一个封闭的圆柱体。

这是我的bool CMyApp :: Init()函数的重要部分:

Vertex vert[(N+1)*(M+1) + N+2];   //NxM rectangle for our parametric equation
for (int i=0; i<=N; ++i)
    for (int j=0; j<=M; ++j)
    {
        float u = i/(float)N;
        float v = j/(float)M;

        vert[i + j*(N+1)].p = GetUV(u, v);
        vert[i + j*(N+1)].c = glm::normalize( vert[i + j*(N+1)].p );
    }

vert[(N + 1)*(M + 1)].p = glm::vec3(0, 0, 0); //center point for cone base
vert[(N + 1)*(M + 1)].c = glm::vec3(0, 0, 0);
for (int i = 0; i <= N; i++) {
    vert[(N + 1)*(M + 1) + 1 + i].p = vert[(N)-i].p; //cone base
    vert[(N + 1)*(M + 1) + 1 + i].c = vert[(N)-i].c;
}

渲染功能:

glDrawElements( GL_TRIANGLES,       
                3*2*(N)*(M),         
                GL_UNSIGNED_SHORT,  
                0);                 

glDrawArrays(GL_TRIANGLE_FAN, (N + 1)*(M + 1) + 1, (N + 2)); //draw cone base

之所以有“圆锥底”,是因为我是从“绘制圆锥体”项目开始的。

我如何在圆柱体上方第二个圆?

编辑: M,N:常量编号(20和10)

我的参数方程式(这是一个名为GetUV()的函数):

u *= 2*3.1415f;
float cu = cosf(u), su = sinf(u), cv = cosf(v), sv = sinf(v);
float M = 2.f;
float r = 0.5;
float m = v*M;

return glm::vec3(r*sinf(u), m, r*cosf(u));

我如何创建索引(在Init()函数内部):

 GLushort indices[3*2*(N)*(M)];
for (int i=0; i<N; ++i)
    for (int j=0; j<M; ++j)
    {
        indices[6*i + j*3*2*(N) + 0] = (i)      + (j)*  (N+1);
        indices[6*i + j*3*2*(N) + 1] = (i+1)    + (j)*  (N+1);
        indices[6*i + j*3*2*(N) + 2] = (i)      + (j+1)*(N+1);
        indices[6*i + j*3*2*(N) + 3] = (i+1)    + (j)*  (N+1);
        indices[6*i + j*3*2*(N) + 4] = (i+1)    + (j+1)*(N+1);
        indices[6*i + j*3*2*(N) + 5] = (i)      + (j+1)*(N+1);
    }

2 个答案:

答案 0 :(得分:0)

绘制另一个圆形帽的最简单方法是仅更改圆形的模型矩阵,然后再次进行绘制调用。因此,如果您在致电glDrawArrays()之前正在做这样的事情:

glm::mat4 modelViewMatrix = calculateModelViewMatrix();
glUniformMatrix4fv(modelViewLocation, 1, FALSE, modelViewMatrix);

执行相同的操作,但平移modelViewMatrix使其位于圆柱体的另一端。

答案 1 :(得分:0)

所以N是圆圆周上的点数,M是单位高度上的点数...

在您的GetUV中,LOL正在计算cu,su,cv,sv,但没有使用它们,而是您再次使用相同的sincos调用。如果我看对了,u=<0,1>映射圆/圆柱体的圆周(XZ平面圆),v=<0,1>映射高度(Y)。但是看来,该函数本身应以适当的方式运行(比可能的速度缓慢),因为这种错误的M_PI使用可能会导致伪像。

第一个问题我看到的是

vert[i + j*(N+1)].c = glm::normalize( vert[i + j*(N+1)].p );

我会摆脱那条线,因为它将创建圆锥体……您不再想要了(顺便说一句,很奇怪又缓慢的圆锥体创建方法)

i + j*(N+1)也很丑,我会这样做:

for (int ix=0,j=0; j<=M; j++)
 for (int i=0; i<=N; i++,ix++)
  {
  float u = i/(float)N;
  float v = j/(float)M;
  vert[ix].p = GetUV(u, v);
  }

下一个问题:您错误地使用了Draw方法...由于您想要一个点网格而不是2个圆,您将这些东西分为GL_TRIANGLE_FAN和{{1 }}。那几乎是正确的,但您应该:

2x GL_TRIANGLES每个基础一个 1x GL_TRIANGLE_FAN或GL_QUADS,其他

当您要使用索引时,将所有元素用作三角形并正确地将索引缓冲区正确地馈给基本上更简单/更快,因此您只需进行一次绘制调用。遗憾的是,我们看不到您正在计算索引的代码部分...

为什么GL_TRIANGLESN+1指向?您无需在M+1中复制第一点,而可以在索引中进行复制...

希望代码的 VBO 相关部分正确无误...

还要注意,另一个圆的面应具有相反的点,以便vert[]可以正确剔除面...

[Edit1] C ++示例

无论如何,如果您以后要使用法线,由于边缘上的法线不同,您也应该复制大写字母...如果按照我的编码风格将所有字母放在一起,我会得到:

GL_CULL_FACE

预览:

preview

您只需在整个//--------------------------------------------------------------------------- const int M=20; // points per circle circumference const int N=10; // point per cylinder height const int pnts=3*((M*(N+2))+2); // 3* number of points const int facs=3*M*(N+N+2); // 3* number of indices float pnt[pnts]; // (x,y,z) position per each point float nor[pnts]; // (x,y,z) normal per each point int fac[facs]; // (i0,i1,i2) indices per each TRIANGLE //--------------------------------------------------------------------------- void cylinder_init(float r,float h) { int i,j,ix,i0,i1,i2,i3; float x,y,z,a,da,dz; // compute position and normals ix=0; dz=h/double(N-1); da=2.0*M_PI/double(M); for (z=-0.5*h,j=0;j<N;j++,z+=dz) // circles for (a=0.0,i=0;i<M;i++,a+=da) { x=cos(a); y=sin(a); pnt[ix]=r*x; nor[ix]=x; ix++; pnt[ix]=r*y; nor[ix]=y; ix++; pnt[ix]=z; nor[ix]=0.0; ix++; } pnt[ix]= 0.0; nor[ix]= 0.0; ix++; // top cap pnt[ix]= 0.0; nor[ix]= 0.0; ix++; pnt[ix]=+0.5*h; nor[ix]=+1.0; ix++; for (j=ix-3*(M+1),i=0;i<M;i++) { pnt[ix]=pnt[j]; nor[ix]= 0.0; ix++; j++; pnt[ix]=pnt[j]; nor[ix]= 0.0; ix++; j++; pnt[ix]=pnt[j]; nor[ix]=+1.0; ix++; j++; } pnt[ix]= 0.0; nor[ix]= 0.0; ix++; // bottom cap pnt[ix]= 0.0; nor[ix]= 0.0; ix++; pnt[ix]=-0.5*h; nor[ix]=-1.0; ix++; for (j=0,i=0;i<M;i++) { pnt[ix]=pnt[j]; nor[ix]= 0.0; ix++; j++; pnt[ix]=pnt[j]; nor[ix]= 0.0; ix++; j++; pnt[ix]=pnt[j]; nor[ix]=-1.0; ix++; j++; } // compute triangle indices ix=0; i0=M-1; i1=0; i2=i0+M; i3=i1+M; // circles for (j=0;j<N-1;j++,i0+=M,i2+=M) for (i=0;i<M;i++,i0=i1,i1++,i2=i3,i3++) { fac[ix]=i0; ix++; fac[ix]=i1; ix++; fac[ix]=i2; ix++; fac[ix]=i2; ix++; fac[ix]=i1; ix++; fac[ix]=i3; ix++; } i2=M*N; i0=i2+M; i1=i2+1; // top cap for (i=0;i<M;i++,i0=i1,i1++) { fac[ix]=i0; ix++; fac[ix]=i1; ix++; fac[ix]=i2; ix++; } i2+=M+1; i0=i2+M; i1=i2+1; // bottom cap for (i=0;i<M;i++,i0=i1,i1++) { fac[ix]=i2; ix++; fac[ix]=i1; ix++; fac[ix]=i0; ix++; } } //--------------------------------------------------------------------------- 索引缓冲区上使用GL_TRIANGLES进行单次抽奖。