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

Posted

技术标签:

【中文标题】我有一个 OpenGL 镶嵌球体,我想在其中切一个圆柱形孔【英文标题】:I have an OpenGL Tessellated Sphere and I want to cut a cylindrical hole in it 【发布时间】:2010-10-18 22:33:26 【问题描述】:

我正在开发一个软件,它生成一个多边形网格来表示一个球体,我想在球体上切一个洞。这个多边形网格只是球体表面的覆盖。我很清楚如何确定哪些多边形将与我的洞相交,我可以将它们从我的收藏中删除,但在那之后我有点困惑。我想知道是否有人可以帮助我了解高级概念?

基本上,我设想了三种情况:

1.) The cylindrical hole does not intersect my sphere.
2.) The cylindrical hole partially goes through my sphere.
3.) The cylindrical hole goes all the way through my sphere. 

对于#1,我可以对此进行测试(不删除多边形)并采取相应措施(什么也不做)。对于#2 和#3,我不确定如何重新镶嵌我的球体以解决这个洞。对于#3,我有一个想法,基本上是这样的:

a.) Find your entry point (a circle)
b.) Find your exit point (a circle) 
c.) Remove the necessary polygons
d.) Make new polygons along the 4* 'sides' of the hole to keep my 
    sphere a manifold. 

这个极其简化的算法有一些我想填补的“洞”。例如,我实际上不希望我的洞有 4 个边 - 它应该是一个圆柱体,或者至少是一个镶嵌的表示圆筒。我也不确定如何制作这些新的多边形以使我的球体在镶嵌表面上留有一个洞。

我不知道如何处理场景 #2。

【问题讨论】:

您是否真的需要存储网格几何图形,或者可视化是唯一重要的方面? 可视化是唯一重要的方面。我们正在使用我们对象的其他(更精确的数学)定义作为模拟的输入——这仅用于可视化。我们目前正在将半透明圆柱体放入我们的可视化中来表示孔,这看起来不太好。 实际上,我们确实需要处理用户输入 STL(立体光刻,CAD)文件的情况,因此解决方案需要能够处理这些情况。 【参考方案1】:

听起来你想要constructive solid geometry。

Carve 可能会做你想做的事。如果您只想运行时渲染,OpenCSG 可以工作。

【讨论】:

感谢您的建议。如果 OpenCSG 允许我指定这些类型的图元(球体 - 圆柱体),而无需重新编写我的整个基于 OpenGL 的几何包,这将非常好。 Carve 听起来也很有趣,我将继续阅读这些内容。【参考方案2】:

今年早些时候,我使用标量字段实现了 CSG 操作。如果性能不重要,它会很好地工作。也就是说,计算不是实时的。问题是导数并没有在任何地方定义,所以你可以忘记以这种方式计算廉价的顶点法线。它必须作为一个后步骤来完成。 请参阅此处查看我使用的论文(在第一个答案中),以及我制作的一些屏幕截图:

CSG operations on implicit surfaces with marching cubes

此外,这种方式的 CSG 需要使用隐式曲面来表示初始网格。虽然任何几何网格都可以分割成平面,但它不会给出好的结果。所以球体必须用半径和原点来表示,圆柱体必须用半径、原点和底高来表示。

【讨论】:

感谢您的回答。我们不必实时执行此操作 - 在用户添加孔(减去?)之后,可以进行几秒钟的后期处理和重新渲染。我想我开始理解需要对我的形状进行更精确的数学定义,以便执行这些任意的加法和减法。似乎完全在顶点中工作不会让我到达我想去的地方。 此外,由于您不需要计算实际的顶点,因此您可以使用我的文章中应用于 raymarching 的文章中的 CSG 方程。这是使用 DirectX 或 OpenGL 着色器的可行解决方案。【参考方案3】:

好吧,如果您只想渲染(可视化),那么您可能根本不需要更改生成的网格。而是使用模板缓冲区来渲染带有孔的球体。例如,我正在渲染圆盘(薄圆柱体),其外边缘附近有圆形孔(作为机械的基板),周围有固体和透明物体的组合,所以我需要这些孔是真正的孔。由于我懒得对运行时生成的形状进行三角测量,因此我为此选择了模板。

    使用 Stencil 缓冲区创建 OpenGL 上下文

    我使用 8 位的模板,但这种技术只使用一位。

    使用0 清除模板并关闭深度和颜色蒙版

    这必须在使用模板渲染网格之前完成。因此,如果您有更多以这种方式呈现的对象,则需要在每个对象之前执行此操作。

    使用1 为实体网格设置模板

    使用0 清除孔网的模板

    打开深度和颜色蒙版并在模板为1的地方渲染实体网格

在代码中是这样的:

// [stencil]
glEnable(GL_STENCIL_TEST);
// whole stencil=0
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
// turn off color,depth
glStencilMask(0xFF);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
// stencil=1 for solid mesh
glStencilFunc(GL_ALWAYS,1,0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glCylinderxz(0.0,y,0.0,r,qh);
// stencil=0 for hole meshes
glStencilFunc(GL_ALWAYS,0,0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
for(b=0.0,j=0;j<12;j++,b+=db)
    
    x=dev_R*cos(b);
    z=dev_R*sin(b);
    glCylinderxz(x,y-0.1,z,dev_r,qh+0.2);
    
// turn on color,depth
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// render solid mesh the holes will be created by the stencil test
glStencilFunc(GL_NOTEQUAL,0,0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColor3f(0.1,0.3,0.4);
glCylinderxz(0.0,y,0.0,r,qh);
glDisable(GL_STENCIL_TEST);

其中glCylinderxz(x,y,z,r,h) 只是在(x,y,z) 处渲染圆柱体的函数,半径为ry-axis 作为其旋转轴。 db 是角度步长(2*Pi/12)。半径为r-big,dev_r-孔半径,dev_R-孔中心,而qh是板的厚度。

结果看起来像这样(2个板块中的每一个都用这个渲染):

这种方法更适合薄物体。如果您的切割导致的边足够厚,那么您需要添加切割边渲染,否则这些部分的照明可能会出错。

【讨论】:

以上是关于我有一个 OpenGL 镶嵌球体,我想在其中切一个圆柱形孔的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL 中导航超球体的表面

使用 opengl 在球体上渲染图像

如何在 OpenGL 中创建 3D 太阳系中的星空背景?

用 Opengl 画一个球体

OpenGL:球体减慢帧速率

在 OpenGL 中将纹理映射到球体时出现接缝问题