C ++ OpenGL:如何在圆柱体上制作第二个圆圈?

Posted

技术标签:

【中文标题】C ++ OpenGL:如何在圆柱体上制作第二个圆圈?【英文标题】:C++ OpenGL: How to make a second circle over the cylinder? 【发布时间】:2018-11-17 18:37:51 【问题描述】:

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

这是我的 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);
    

【问题讨论】:

M,N 是什么?你只需要 2 个圈子......但我什至没有看到任何 sin,cos 的圈子?通常是将 X,Y 计算为参数圆,Z 是常数(每个基数不同,它们的距离是圆柱体高度) ...GetUV 是做什么的?为什么是glDrawElementsglDrawArrays?元素列表在哪里? 抱歉,我编辑了帖子。 【参考方案1】:

绘制另一个圆形帽最简单的方法是更改​​圆形的模型矩阵并再次进行绘制调用。所以如果你在打电话给glDrawArrays()之前做这样的事情:

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

做同样的事情,但翻译modelViewMatrix,使其位于圆柱体的另一端。

【讨论】:

我的目标是用第一个圆绘制的相同方式制作另一个圆,使用顶点向量。 您可以通过复制几何图形并在 CPU 上进行转换然后再次将其上传到 GPU 来手动执行相同的操作,但效率会低得多。在这种情况下,这可能没什么大不了的,但您应该改掉多次上传相同几何图形的习惯,因为在编写高性能 3D 代码时这是一种反模式。【参考方案2】:

所以N 是圆周上的点数,M 是每个高度的点数...

LOL 在您的GetUV 中,您正在计算cu,su,cv,sv 但不使用它们,而是再次使用相同的sincos 调用。如果我没看错,u=&lt;0,1&gt; 映射圆/圆柱体的周长(XZ 平面圆),v=&lt;0,1&gt; 映射高度(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_FANGL_TRIANGLES。这几乎是正确的,但您应该这样做:

2x GL_TRIANGLE_FAN 每个基地一个 1x GL_TRIANGLES 或 GL_QUADS 其余的

由于您想使用索引,因此将所有索引用作三角形并正确输入索引缓冲区基本上更简单/更快,因此您只需进行一次绘制调用。遗憾的是,我们没有看到您正在计算索引的代码部分...

为什么N+1M+1 分?您不需要在vert[] 中复制第一个点,您可以在索引中执行此操作...

希望代码中VBO相关部分是正确的...

还要注意另一个圆的面应该有相反顺序的点,所以GL_CULL_FACE 会正确剔除面...

[Edit1] C++ 示例

无论如何,如果你想在后面使用法线,你还应该复制大写字母,因为边缘上的法线不同......如果我按照我的编码风格将所有内容放在一起,我会得到这个:

//---------------------------------------------------------------------------
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++;
        
    
//---------------------------------------------------------------------------

和预览:

您只需在整个 fac[facs] 索引缓冲区上使用带有 GL_TRIANGLES 的单次绘制。

【讨论】:

感谢您的回答,我编辑了帖子并添加了索引部分。 @JózsefHuszkó 你的问题解决了吗?

以上是关于C ++ OpenGL:如何在圆柱体上制作第二个圆圈?的主要内容,如果未能解决你的问题,请参考以下文章

如何在现代opengl中绘制圆柱体

在 OpenGL 4 中创建第二个 VAO 并绘制两个形状

我有一个 OpenGL 镶嵌球体,我想在其中切一个圆柱形孔

如何投影openGL控件的顶部和底部区域

如何提高自定义 OpenGL ES 2.0 深度纹理生成的性能?

如何在另一个屏幕上制作 MDDataTable?