Как обрезать круговую область в OpenTK (мини-карта!) - PullRequest
0 голосов
/ 27 апреля 2018

Моя игра в C # использует OpenTK, который является оболочкой для OpenGL. Я рендерил свою мини-карту, как показано ниже. Проблема в том, что объекты не обрезаны по краям, поэтому они кровоточат. Я мог бы сделать более толстую границу, чтобы скрыть ее, но это не идеально, и это не будет работать для более крупных объектов. Там могут быть линии траектории и другие вещи, которые также выходят за пределы. Я просто отрисовываю их, используя базовые примитивы.

Как я могу обрезать этот регион? Есть ли способ сделать это на скрытом холсте, а затем скопировать только круговую область?

enter image description here


1012 * РЕШЕНИЕ *

@ BDL ответил на вопрос, но мне пришлось настроить еще несколько вещей, чтобы заставить его работать, поэтому вот полное решение на тот случай, если кто-нибудь найдет его полезным:

Включить буфер трафарета в параметре GraphicsMode конструктора GameWindow.

    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 голосов
/ 27 апреля 2018

Обрезка в произвольных областях возможна при использовании буфера трафарета:

Сначала очистите буфер трафарета с помощью 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, сохраненный в этих местах (что верно только для пикселей внутри области отсечения). В другом месте проверка трафарета не будет выполнена, и ничего не будет отображено.

Не забудьте убедиться, что в вашем фреймбуфере есть буфер трафарета.

...