如何在 OpenTK 中裁剪圆形区域(小地图!)
How to clip circular region in OpenTK (mini-map!)
我的游戏是在 C# 中使用 OpenTK 编写的,OpenTK 是 OpenGL 的包装器。我正在渲染我的迷你地图,如下所示。问题是对象没有在边缘被剪裁,所以它们会溢出。我可以渲染一个更粗的边框来隐藏它,但这并不理想,而且它不适用于较大的对象。可能有轨迹线和其他超出界限的东西。我只是使用基本原语渲染这些。
我该如何裁剪这个区域?有什么方法可以将其渲染为隐藏 canvas 然后只复制圆形区域吗?
解决方案
@BDL 回答了这个问题,但我必须再调整一些东西才能让它工作,所以这里是完整的解决方案,以防有人觉得它有用:
在 GameWindow 构造函数 GraphicsMode 参数中启用模板缓冲区。
private static OpenTK.Graphics.GraphicsMode GraphicsMode {
get {
var defaultMode = OpenTK.Graphics.GraphicsMode.Default;
var custom = new OpenTK.Graphics.GraphicsMode(
defaultMode.ColorFormat,
defaultMode.Depth,
1, // enable stencil buffer
defaultMode.Samples,
defaultMode.ColorFormat,
defaultMode.Buffers,
defaultMode.Stereo);
return custom;
}
}
public BaseHelioUI(int windowWidth, int windowHeight)
: base(
windowWidth,
windowHeight,
BaseHelioUI.GraphicsMode,
"",
GameWindowFlags.Default )
{
然后使用这个块来绘制模板,在我的例子中是一个圆圈:
GL.Enable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Always, 1, 0xFF);
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Replace );
GL.Clear(ClearBufferMask.StencilBufferBit);
// draw background & outline
this.Renderer.DrawCircle(
this.MinimapScreenCenter,
SENSOR_RANGE_IN_METERS * this.GameMetersToMinimapUnitsFactor,
Colors.ReduceAlpha( Colors.Black, MINIMAP_BACKGROUND_OPACITY )
//Colors.ReduceAlpha( Colors.DarkGrey, MINIMAP_BACKGROUND_OUTLINE_OPACITY),
//MINI_MAP_BORDER_WIDTH
);
GL.Enable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Equal, 1, 0xFF);
GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep);
然后在该区域内绘制您想要的所有其他内容,在我的例子中是小地图上的项目。
然后当您完成模板使用后,只需清除它,这样其他一切都会正常呈现。在我的例子中,这是在 RenderMinimap 方法的末尾。
// disable stencil
GL.Clear(ClearBufferMask.StencilBufferBit);
GL.Disable(EnableCap.StencilTest);
这是生成的小地图,正确地裁剪了圆圈边缘的项目。看起来很棒。 (船在游戏中 space,不在小地图上)
可以使用模板缓冲区在任意区域进行裁剪:
首先用 0 (glClear
) 清除模板缓冲区。
接下来,在启用以下模板操作的情况下渲染背景圆(剪裁区域):
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
这会将圆圈覆盖的所有像素的模板缓冲区设置为 1。
当您现在渲染应显示在圆圈内的内容时,请使用以下设置:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
这里,只有当模板缓冲区中的那些位置已经存储了 1 时,模板测试才会成功(这仅适用于裁剪区域内的像素)。在其他任何地方,模板测试都会失败,并且不会呈现任何内容。
不要忘记确保您的帧缓冲区有可用的模板缓冲区。
我的游戏是在 C# 中使用 OpenTK 编写的,OpenTK 是 OpenGL 的包装器。我正在渲染我的迷你地图,如下所示。问题是对象没有在边缘被剪裁,所以它们会溢出。我可以渲染一个更粗的边框来隐藏它,但这并不理想,而且它不适用于较大的对象。可能有轨迹线和其他超出界限的东西。我只是使用基本原语渲染这些。
我该如何裁剪这个区域?有什么方法可以将其渲染为隐藏 canvas 然后只复制圆形区域吗?
解决方案
@BDL 回答了这个问题,但我必须再调整一些东西才能让它工作,所以这里是完整的解决方案,以防有人觉得它有用:
在 GameWindow 构造函数 GraphicsMode 参数中启用模板缓冲区。
private static OpenTK.Graphics.GraphicsMode GraphicsMode {
get {
var defaultMode = OpenTK.Graphics.GraphicsMode.Default;
var custom = new OpenTK.Graphics.GraphicsMode(
defaultMode.ColorFormat,
defaultMode.Depth,
1, // enable stencil buffer
defaultMode.Samples,
defaultMode.ColorFormat,
defaultMode.Buffers,
defaultMode.Stereo);
return custom;
}
}
public BaseHelioUI(int windowWidth, int windowHeight)
: base(
windowWidth,
windowHeight,
BaseHelioUI.GraphicsMode,
"",
GameWindowFlags.Default )
{
然后使用这个块来绘制模板,在我的例子中是一个圆圈:
GL.Enable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Always, 1, 0xFF);
GL.StencilOp( StencilOp.Keep, StencilOp.Keep, StencilOp.Replace );
GL.Clear(ClearBufferMask.StencilBufferBit);
// draw background & outline
this.Renderer.DrawCircle(
this.MinimapScreenCenter,
SENSOR_RANGE_IN_METERS * this.GameMetersToMinimapUnitsFactor,
Colors.ReduceAlpha( Colors.Black, MINIMAP_BACKGROUND_OPACITY )
//Colors.ReduceAlpha( Colors.DarkGrey, MINIMAP_BACKGROUND_OUTLINE_OPACITY),
//MINI_MAP_BORDER_WIDTH
);
GL.Enable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Equal, 1, 0xFF);
GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep);
然后在该区域内绘制您想要的所有其他内容,在我的例子中是小地图上的项目。
然后当您完成模板使用后,只需清除它,这样其他一切都会正常呈现。在我的例子中,这是在 RenderMinimap 方法的末尾。
// disable stencil
GL.Clear(ClearBufferMask.StencilBufferBit);
GL.Disable(EnableCap.StencilTest);
这是生成的小地图,正确地裁剪了圆圈边缘的项目。看起来很棒。 (船在游戏中 space,不在小地图上)
可以使用模板缓冲区在任意区域进行裁剪:
首先用 0 (glClear
) 清除模板缓冲区。
接下来,在启用以下模板操作的情况下渲染背景圆(剪裁区域):
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
这会将圆圈覆盖的所有像素的模板缓冲区设置为 1。
当您现在渲染应显示在圆圈内的内容时,请使用以下设置:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
这里,只有当模板缓冲区中的那些位置已经存储了 1 时,模板测试才会成功(这仅适用于裁剪区域内的像素)。在其他任何地方,模板测试都会失败,并且不会呈现任何内容。
不要忘记确保您的帧缓冲区有可用的模板缓冲区。