代码之家  ›  专栏  ›  技术社区  ›  Andrew Lundgren

如何在OpenTK(迷你地图!)

  •  4
  • Andrew Lundgren  · 技术社区  · 7 年前

    我的游戏是用C语言编写的,使用OpenTK,它是OpenGL的包装。我正在渲染我的迷你地图,如下所示。问题是,对象没有在边缘剪裁,因此它们会溢出。我可以渲染一个更厚的边界来隐藏它,但这并不理想,对于较大的对象也不起作用。可能有轨迹线和其他东西也会溢出边界。我只是用基本的原语渲染这些。

    我怎样才能裁剪这个区域?有没有办法将其渲染到一个隐藏的画布上,然后只复制圆形区域?

    enter image description here


    解决方案

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

    然后在这个区域内画出你想要的所有东西,在我的例子中就是小地图上的项目。

    然后,当您使用完模具后,只需清除它,其他所有内容都可以渲染。在我的例子中,这是renderminmap方法的末尾。

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

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

    enter image description here

    1 回复  |  直到 7 年前
        1
  •  2
  •   BDL Vyxzl    7 年前

    可以使用模具缓冲区在任意区域中剪切:

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

    不要忘记确保帧缓冲区中有可用的模具缓冲区。