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
是做什么的?为什么是glDrawElements
和glDrawArrays
?元素列表在哪里?
抱歉,我编辑了帖子。
【参考方案1】:
绘制另一个圆形帽最简单的方法是更改圆形的模型矩阵并再次进行绘制调用。所以如果你在打电话给glDrawArrays()
之前做这样的事情:
glm::mat4 modelViewMatrix = calculateModelViewMatrix();
glUniformMatrix4fv(modelViewLocation, 1, FALSE, modelViewMatrix);
做同样的事情,但翻译modelViewMatrix
,使其位于圆柱体的另一端。
【讨论】:
我的目标是用第一个圆绘制的相同方式制作另一个圆,使用顶点向量。 您可以通过复制几何图形并在 CPU 上进行转换然后再次将其上传到 GPU 来手动执行相同的操作,但效率会低得多。在这种情况下,这可能没什么大不了的,但您应该改掉多次上传相同几何图形的习惯,因为在编写高性能 3D 代码时这是一种反模式。【参考方案2】:所以N
是圆周上的点数,M
是每个高度的点数...
LOL 在您的GetUV
中,您正在计算cu,su,cv,sv
但不使用它们,而是再次使用相同的sin
和cos
调用。如果我没看错,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
和 GL_TRIANGLES
。这几乎是正确的,但您应该这样做:
2x GL_TRIANGLE_FAN
每个基地一个
1x GL_TRIANGLES
或 GL_QUADS 其余的
由于您想使用索引,因此将所有索引用作三角形并正确输入索引缓冲区基本上更简单/更快,因此您只需进行一次绘制调用。遗憾的是,我们没有看到您正在计算索引的代码部分...
为什么N+1
和M+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:如何在圆柱体上制作第二个圆圈?的主要内容,如果未能解决你的问题,请参考以下文章