绘制相交圆的轮廓
我有一组点,每个点都有一个“影响”区域或基本上是一个半径。我希望能够将所有点的每个影响圈绘制为一条简单的圆形线。
它们会重叠,但我希望绘制所形成形状的外部。我知道这可能需要我找出它们相交的位置,并以某种方式形成一个完整的形状来绘制。问题是有些点甚至可能不会触及其他点!所以我也需要能够解决这个问题。
我试图简单地说明我的意思:
请注意,我希望简单地绘制黑线,不充满。这是因为我希望背景图像和其他几何图形能够显示出来。
我会在 openGL 中执行此操作,因此圆可能会使用 GL_LINES 或类似的方法来制作,其中各种顶点形成曲线,但我真的不知道如何计算出这个周长。
如果有人有任何建议或可以指出我如何解决这个问题,我将不胜感激!
这可能更像是一个数学问题,我不是在寻找代码,而是实际上如何计算出这些形状。我就是想不出该怎么做!
*****编辑:用我想出的解决方案,希望可以帮助其他人!
因此,我使用了建议的想法,并基本上决定最好的方法是使用模板缓冲区进行绘制。现在这意味着我循环遍历我的点 3 次,但我需要对它们进行一些仔细的排序以仅找到可见的点。
因此,就代码而言,我现在有了这个:
private void stencilCircleAroundStars()
{
//Lets try and draw something here using stencil
glColorMask(false, false, false, false); //Disable colour mask
glEnable(GL_STENCIL_TEST); // Enable Stencil Buffer For "marking" the outer circle
glDisable(GL_DEPTH_TEST);// Disable Depth Testing
for (Object value : stars.values())
{
Star star = (Star)value;
glStencilFunc(GL_ALWAYS, 1, 1); // Always Passes, 1 Bit Plane, 1 As Mask
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 1 Where We Draw Any Polygon
//Draw the large circle
starOb.location.copy(star.location);
starOb.setScale(2000);
starOb.draw();
}
for (Object value : stars.values())
{
Star star = (Star)value;
//Now we change the functions and remove a slightly smaller circle from buffer.
glStencilFunc(GL_ALWAYS, 0, 0); // Always passes, 0 bit plane, 0 as mask;
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 0 Where We Draw Any Polygon
starOb.location.copy(star.location);
starOb.setScale(1900);
starOb.draw();
}
//Now we enable the colour
glColorMask(true, true, true, true);
glStencilFunc(GL_EQUAL, 1, 1); // We Draw Only Where The Stencil Is 1
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Don't Change The Stencil Buffer
glColor4f(0.5f, 1.0f, 0.5f, 0.5f);
for (Object value : stars.values())
{
Star star = (Star)value;
starOb.location.copy(star.location);
starOb.setScale(2000);
starOb.draw();
}
//Now we are done .. disable
glDisable(GL_STENCIL_TEST);
}
我的点本质上是出于程序目的而称为“星星”的实体,而 StarOb 是我从文件中加载的四边形的集合,这些四边形形成了一个漂亮的平滑圆圈。
我禁用颜色遮罩并循环一次,将最大的圆绘制到模板缓冲区中并将值设置为 1。然后我再次循环将较小的缩放圆绘制到模板缓冲区中,但这次将值设置为 0。这应该在任何不接触其他恒星的恒星周围留下一个边界,并且将有效地消除它们重叠的地方。
我最终重新启用颜色蒙版并实际绘制彩色圆圈。模板缓冲区阻止内部渲染,我得到了我想要的!然后我禁用模板缓冲区。
如果您确实想观看它,这里有一个生成多个不断增加的点的视频:它的视频运行
这是一个低质量版本的结果(测试时未绘制背景):
I have a set of points and each one has an area of "influence" or essentially a radius. I would like to be able to draw each one of these influence circles for all the points as a simple circular line.
They will overlap however I wish to draw the outside of the shape formed. I know this would probably require me working out where they intersect and somehow forming a total shape to draw. The problem is that some points might not even touch others! So I need to be able to work that out too.
I have attempted to illustrate what I mean simply:
Note that I wish to draw simply the black line, no fill. This is because I wish background images and other geometry to show through.
I would be doing this in openGL so the circle would be probably made using GL_LINES or some such with various vertices forming the curves but I really just don't have any idea about how I would work out this perimeter.
If anyone has any advice or could point me at how I might go about working this out it would be greatly appreciated!
This might be more of a maths question, I am not looking for bits of code but actually how to go about working out these shapes. I just can't think about how to do it!
*****Edit: with the solution I came up with, hopefully might help someone else!
So I used the suggested ideas and basically decided the best way would be to draw using the stencil buffer. This now means that I loop through my points 3 times but I need to do some careful sorting of them to find only visible ones anyway.
So code wise I now have this:
private void stencilCircleAroundStars()
{
//Lets try and draw something here using stencil
glColorMask(false, false, false, false); //Disable colour mask
glEnable(GL_STENCIL_TEST); // Enable Stencil Buffer For "marking" the outer circle
glDisable(GL_DEPTH_TEST);// Disable Depth Testing
for (Object value : stars.values())
{
Star star = (Star)value;
glStencilFunc(GL_ALWAYS, 1, 1); // Always Passes, 1 Bit Plane, 1 As Mask
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 1 Where We Draw Any Polygon
//Draw the large circle
starOb.location.copy(star.location);
starOb.setScale(2000);
starOb.draw();
}
for (Object value : stars.values())
{
Star star = (Star)value;
//Now we change the functions and remove a slightly smaller circle from buffer.
glStencilFunc(GL_ALWAYS, 0, 0); // Always passes, 0 bit plane, 0 as mask;
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 0 Where We Draw Any Polygon
starOb.location.copy(star.location);
starOb.setScale(1900);
starOb.draw();
}
//Now we enable the colour
glColorMask(true, true, true, true);
glStencilFunc(GL_EQUAL, 1, 1); // We Draw Only Where The Stencil Is 1
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Don't Change The Stencil Buffer
glColor4f(0.5f, 1.0f, 0.5f, 0.5f);
for (Object value : stars.values())
{
Star star = (Star)value;
starOb.location.copy(star.location);
starOb.setScale(2000);
starOb.draw();
}
//Now we are done .. disable
glDisable(GL_STENCIL_TEST);
}
My points are in essence entities called "stars" for the purpose of my program and StarOb is a collection of quads I have loaded from a file which form a nice smooth circle.
I disable colour mask and I loop through once, drawing the largest circle I can into the stencil buffer and setting a value of 1. I then loop around again drawing the smaller scaled circle into the stencil buffer but this time setting a value of 0. This should leave a border around any star that is not touching other stars and will effectively remove where they overlap.
I finally re-enable the colour mask and actually draw the coloured circles. the stencil buffer stops the insides from being rendered and I get what I wanted! I then disable the stencil buffer.
If you really wanted to see it, here's a video of generating several increasing amounts of points: Video of it running
Here is a low quality version of how it came out (background was not drawn while testing):
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,想象背景不存在。我很确定您知道该怎么做,绘制每个圆圈,然后绘制其内部(如实心圆圈)以删除内部的弧线。
现在要对图像执行相同的操作,您可以执行以下任一操作。您可以做的一件事是禁用颜色缓冲区上的写入,执行该过程并更改模板缓冲区。然后启用在颜色缓冲区上的写入并绘制整个屏幕矩形,从而填充您在模板缓冲区中标记的像素。
然而,由于多种原因,您可能无法使用模板缓冲区,例如您将其用于其他用途。在这种情况下,另一种方法是执行相同的操作,但不是在模板缓冲区中渲染,而是在纹理中渲染。然后绑定该纹理并在屏幕上绘制一个矩形。
我很确定你也可以通过累积缓冲区来实现这一点,但我从未使用过它,所以我不能真正告诉你(如果有人知道这一点,请编辑我的答案并告诉我们如何做)
First, imagine the background was not there. I'm pretty sure you'd know how to do it, draw each circle then draw their insides (as in a filled circle) to remove the arcs that are inside.
Now to do the same over an image, you could do either of these things. One thing you can do is to disable writing on the color buffer, do that procedure and change the stencil buffer. Then enable writing on the color buffer and draw a whole screen rectangle which consequently fills the pixels you have marked in the stencil buffer.
The stencil buffer may not be usable to you however for a couple of reasons, such as you are using it for something else. In this case, an alternative would be to do the same thing, but instead of rendering in the stencil buffer, you render in a texture. Then bind that texture and draw a rectangle on the screen.
I'm quite certain you could achieve this with the accumulation buffer too, but I have never used it so I can't really tell (if anyone knows about that, please edit my answer and tell us how)
两次通过:
GL_LINES
或GL_LINE_LOOP
绘制所有圆形轮廓。确保将glLineWidth()
设置为3
或更大。GL_TRIANGLE_STRIP
可能很有用)。步骤 2 中的实心圆将覆盖步骤 1 中的所有轮廓像素,但仅覆盖它们重叠的地方。这样你就可以得到完整的、不重叠的轮廓。
如果您想要更广泛的轮廓宽度(即大于大多数 OpenGL 实现允许的 ~10
glLineWidth()
),您应该在步骤 1 中重用步骤 2 中的实心圆渲染器,除非使用较大的半径。Two passes:
GL_LINES
orGL_LINE_LOOP
. Make sure you set yourglLineWidth()
to3
or greater.GL_TRIANGLE_STRIP
can be useful) with your "background" color and the same radius as the circles from step 1.The filled circles in step 2 will overwrite all the outline pixels from step 1 but only where they overlap. That leaves you with non-overlapping outlines intact.
If you want a wider range of outline widths (i.e., greater than the ~10 that most OpenGL implementations allow
glLineWidth()
) you should reuse the filled-circle renderer from step 2 in step 1 except with a larger radius.