如何在 OpenTK 中裁剪圆形区域(迷你地图!) [英] How to clip circular region in OpenTK (mini-map!)

查看:123
本文介绍了如何在 OpenTK 中裁剪圆形区域(迷你地图!)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的游戏是在 C# 中使用 OpenTK 编写的,它是 OpenGL 的包装器.我正在渲染我的小地图,如下所示.问题是对象的边缘没有被剪裁,所以它们会溢出.我可以渲染一个更粗的边框来隐藏它,但这并不理想,它不适用于较大的对象.可能有轨迹线和其他东西也超出了界限.我只是使用基本原语渲染这些.

My game is in C# using OpenTK, which is a wrapper around OpenGL. I'm rendering my mini-map as shown below. The problem is that objects aren't clipped at the edge, so they bleed over. I could render a thicker border to hide it, but that's not ideal and it won't work for larger objects. There could be trajectory lines and other things which also bleed beyond the bounds. I'm just rendering these using basic primitives.

我该如何剪裁这个区域?有没有办法将它渲染到隐藏的画布上,然后只复制圆形区域?

How can I go about clipping this region? Is there any way to render this to a hidden canvas then copy just the circular region over?

解决方案

@BDL 回答了这个问题,但我必须再调整一些东西才能让它工作,所以这里是完整的解决方案,以防有人觉得它有用:

@BDL answered the question, but I had to tweak a few more things to get it to work, so here is the full solution in case anyone finds it useful:

在 GameWindow 构造函数 GraphicsMode 参数中启用模板缓冲区.

Enable the stencil buffer in the GameWindow constructor GraphicsMode param.

    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 )
    {

然后使用这个块来绘制模板,在我的例子中是一个圆圈:

Then use this block to draw the stencil, which is a circle in my case:

        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);

然后在该区域内绘制您想要的所有其他内容,在我的情况下是小地图上的项目.

Then draw everything else you want within that region, which are the items on the minimap in my case.

然后,当您完成模板的使用时,只需清除它,以便其他一切都可以正常呈现.就我而言,这是在 RenderMinimap 方法的末尾.

Then when you're done with the stencil usage, just clear it so everything else will render okay. In my case, this is at the end of the RenderMinimap method.

        // disable stencil
        GL.Clear(ClearBufferMask.StencilBufferBit);
        GL.Disable(EnableCap.StencilTest);

这是在圆圈边缘正确裁剪项目的结果小地图.看起来很棒.(飞船在游戏空间,不在小地图上)

Here's the resulting minimap properly clipping items at the edge of the circle. Looks great. (the ship is in game space, not on the minimap)

推荐答案

使用模板缓冲区可以在任意区域进行裁剪:

Clipping in arbitrary regions is possible by using the stencil buffer:

首先用 0 (glClear) 清除模板缓冲区.

First clear the stencil buffer with 0 (glClear).

接下来,在启用以下模板操作的情况下渲染背景圆(剪切区域):

Next, render the background circle (the clipping region) with the following stencil operations enabled:

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

这会将圆形覆盖的所有像素的模板缓冲区设置为 1.

This will set the stencil buffer to 1 for all pixels covered by the circle.

当您现在渲染应在圆圈内显示的内容时,请使用以下设置:

When you now render the content that should be displayed inside the circle use the following settings:

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

这里,只有在模板缓冲区中已经存储了 1 时,模板测试才会成功(这仅适用于剪切区域内的像素).在其他任何地方,模板测试都将失败,并且不会渲染任何内容.

Here, the stencil test only succeeds if there is already a 1 stored in the stencil buffer at that locations (which is only true for pixels inside the clipping region). Everywhere else the stencil test will fail and nothing will be rendered.

不要忘记确保您的帧缓冲区具有可用的模板缓冲区.

Don't forget to make sure that your framebuffer has a stencil buffer available.

这篇关于如何在 OpenTK 中裁剪圆形区域(迷你地图!)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆