如何在OpenTK中剪切圆形区域(迷你地图!)

时间:2018-04-27 05:37:17

标签: c# opengl opentk

我的游戏是在C#中使用OpenTK,它是OpenGL的包装器。我正在渲染我的迷你地图,如下所示。问题是物体没有被夹在边缘,所以它们会流血。我可以渲染一个较粗的边框来隐藏它,但这并不理想,它不适用于较大的物体。可能存在轨迹线和其他东西也超出界限。我只是使用基本原语渲染它们。

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

enter image description here

@BDL回答了这个问题,但我不得不调整更多的东西才能让它发挥作用,所以这里有完整的解决方案,万一有人发现它有用:

在GameWindow构造函数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 )
    {

然后使用此块绘制模板,在我的情况下是一个圆圈:

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

这里生成的迷你地图正确剪裁了圆圈边缘的项目。看起来很棒。 (船舶在游戏空间,而不是在小地图上)

enter image description here

1 个答案:

答案 0 :(得分:1)

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

首先用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个位置时才成功(对于剪切区域内的像素仅适用)。在其他地方,模板测试将失败,并且不会呈现任何内容。

请勿忘记确保您的帧缓冲区有可用的模板缓冲区。