Xna StencilBuffers - PullRequest
       5

Xna StencilBuffers

0 голосов
/ 17 октября 2011

Я работал не покладая рук, пытаясь заставить работать трафаретные буферы, но безуспешно в xna 4.0

 private void DrawReflectionMask()
    {
        if (AlphaEffect == null)
        {
            AlphaEffect = new AlphaTestEffect(GraphicsDevice);
            AlphaEffect.VertexColorEnabled = true;
            AlphaEffect.DiffuseColor = Color.White.ToVector3();
            AlphaEffect.AlphaFunction = CompareFunction.Equal;
            AlphaEffect.ReferenceAlpha = 0;
            AlphaEffect.World = Matrix.Identity;
            AlphaEffect.View = Matrix.Identity;

        }
        if(mReflection == null)
        {
            mReflection = Content.Load<Texture2D>("reflection");
            mMask = Content.Load<Texture2D>("ice-mask");
        }
        mSpriteBatch.End();

        RenderTarget2D lMaskRenderTarget = new RenderTarget2D(mGraphicsDevice, mPixelViewport.Width, mPixelViewport.Height,false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0 ,RenderTargetUsage.DiscardContents);


        GraphicsDevice.SetRenderTarget(lMaskRenderTarget);
        BlendState lOldState = GraphicsDevice.BlendState;
        GraphicsDevice.BlendState = ABlendState;
        GraphicsDevice.Clear(ClearOptions.Stencil | ClearOptions.Target, new Color(0,0,0,1), 0, 0);
        SpriteBatch.Begin(SpriteSortMode.Immediate,null,null, AlwaysStencilState,null);
        for (int x = mViewPort.Viewport.Left; x < mViewPort.Viewport.Right; x++)
        {
            for (int y = mViewPort.Viewport.Top; y < mViewPort.Viewport.Bottom; y++)
            {
                int lTileIndex = mMap[x, y].TileID;
                Rectangle lSourceRectangle = new Rectangle((lTileIndex % 8) * 32, (lTileIndex / 8) * 32, 32, 32);
                mSpriteBatch.Draw(mMask,
                                  new Vector2((x - mViewPort.Viewport.X) * 32, (y - mViewPort.Viewport.Y) * 32),
                                  lSourceRectangle,
                                  Color.White);
            }
        }
        SpriteBatch.End();

        GraphicsDevice.BlendState = lOldState;
        SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, EqualStencilState, null);
        for (int x = 0; x < 4; x++)
        {
            for (int y = 0; y < 3; y++)
            {
                SpriteBatch.Draw(mReflection, new Vector2(x * 256, y * 256), Color.White);
            }
        }
        SpriteBatch.End();

        GraphicsDevice.SetRenderTarget(null);
        //lMaskRenderTarget.SaveAsPng(new FileStream("Image.png", FileMode.Create), lMaskRenderTarget.Width, lMaskRenderTarget.Height);
        SpriteBatch.Begin();
        SpriteBatch.Draw(lMaskRenderTarget, Vector2.Zero, Color.White);
    }

Это моя функция, которую я использую, чтобы попытаться нарисовать маску трафарета ...

public static DepthStencilState AlwaysStencilState = new DepthStencilState()
    {

        StencilEnable = true,
        StencilFunction = CompareFunction.Always,
        StencilPass = StencilOperation.Replace,
        ReferenceStencil = 1,
        DepthBufferEnable = false,
    };
    public static DepthStencilState EqualStencilState = new DepthStencilState()
    {
        StencilEnable = true,
        StencilFunction = CompareFunction.Equal,
        StencilPass = StencilOperation.Keep,
        ReferenceStencil = 1,
        DepthBufferEnable = false,
    };

Это мои трафаретные состояния ...

Что я пытаюсь сделать, так это скрыть части текстуры на основе маски.

Вот мое отражение ...

http://www.badsheepgaming.com/Kevin/reflection.png

Вот моя маска

http://www.badsheepgaming.com/Kevin/ice-mask.png

Вот что я получаю с этим кодом

http://www.badsheepgaming.com/Kevin/outcome.png

и вот что я ожидаю

http://www.badsheepgaming.com/Kevin/cow.png

1 Ответ

0 голосов
/ 17 октября 2011

Уже поздно, и я не очень хорош в объяснении трафаретных буферов, но я уже с ними обходился.Кроме того, я понятия не имею, сработает ли это, но, похоже, никто не отвечает, поэтому я решил попробовать.

Без фактической компиляции вашего кода это выглядит как всенастроен на работу, как вы намерены.Рисуйте плитки, а затем рисуйте отражение только поверх плиток, верно?Я полагаю, что проблема здесь в том, что даже когда ваша плитка полностью прозрачна, эти пиксели все еще прорисовываются, и поэтому тест трафарета проходит, и заменяет существующий 0 на 1.

Шаг 1: Тестирование, чтобы увидеть, действительно ли это проблема.

Попробуйте нарисовать любую другую плитку ... if((x + y) % 2 == 0) { /* draw tile */ }.Если это создает шаблон шахматной доски для вашего отражения, то вы знаете, что прозрачные пиксели проходят тест трафарета.Перейдите ко второму шагу (в противном случае дайте мне знать, что это не сработало).

Шаг 2 : устранение проблемы прохода трафарета

Вам понадобится способ обрезатьэти прозрачные пиксели, прежде чем они смогут пройти тест трафарета.Вы можете сделать это с помощью цветового ключа или пиксельного шейдера.Чтобы использовать Цветовой ключ, выберите свой ресурс изображения для плиток и нажмите на вкладку / меню свойств.Под этим вы должны найти опции «Использовать цветовой ключ» и «Цветовой ключ».Вы должны быть в состоянии выбрать прозрачный цвет вашего изображения в качестве Цветового ключа, и это предотвратит рендеринг этой части изображения (оно будет обрезано) и не пройдет проверку трафарета.

Альтернатива # 1 :

Вы можете запрограммировать пиксельный шейдер, который рисует отражение при рисовании ваших плиток.Это позволит вам добавить правильное количество отражений к каждой части плитки, даже если у плитки есть «закрашенные» края (градиентная прозрачность).Вы не сможете получить плавный вид с помощью цветовой клавиши.

Alternative # 2 :

Предполагая, что вы рисуете плитки на полностью прозрачном фонеВы можете нарисовать Отражение с помощью специального режима наложения.

Source = DestAlpha
Dest = One

Это будет дополнительно рисовать отражение на непрозрачных частях изображения.Или вы могли бы объединить их друг с другом (я думаю, что это так?):

Source = Dest
Dest = Zero

В любом случае, я надеюсь, что это каким-то образом поможет или, по крайней мере, приведет вас в правильном направлении.Я желаю вам удачи в поиске хорошего ответа.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...