XNA Sprite Flash Effect

8

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

Я использовал очень простой пользовательский шейдер, чтобы сделать это в XNA 3.1, но WP7 не поддерживает их, и найти альтернативу оказалось сложно.

Буду признателен за любую помощь или предложения. Я бы предпочел не создавать вручную сплошную белую копию каждого спрайта в моей игре.

Райан Макд
источник
1
Хорошо, я нашел способ, но это не красиво. Дай мне немного почистить, и я обновлю свой ответ.
Дэвид Гувея

Ответы:

9

Способ 1

Вам не нужно создавать сплошную белую версию каждого спрайта в вашей игре вручную - вы также можете автоматизировать процесс во время загрузки. Другими словами, вы можете использовать Texture2D.GetData()для доступа к пикселям вашей текстуры (и извлекать их как простые Color[]), перебирать их, заменяя непрозрачный пиксель сплошным белым, а затем сохранять его в новой текстуре, используя и Texture2D.SetData().

Способ 2

Я пытался поиграться, BlendStateно не смог найти способ сделать все это белым, по крайней мере, в рамках ограничений профиля Reach. Но если кто-то знает способ, дайте мне знать. Однако я нашел способ сделать это, используя буфер трафарета и встроенный AlphaTestEffectкласс. Идея заключается в следующем:

  1. Создайте буфер с буфером трафарета.
  2. Очистите буфер трафарета до нуля.
  3. Нарисуйте спрайты, которые вы хотите подкрасить белым, и всякий раз, когда они проходят альфа-тестирование, установите буфер трафарета в этом месте на 1.
  4. Нарисуйте белый квадрат, покрывающий весь экран, но только там, где значение буфера трафарета равно 1.

Вот код, который я использовал:

(Шаг 1) Сначала убедитесь, что создается резервный буфер с местом для буфера трафарета:

graphics = new GraphicsDeviceManager(this) { PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 };

(Шаг 2) Создайте белую текстуру 1x1, которая будет масштабироваться, чтобы заполнить весь экран:

private Texture2D pixel;
pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new[] { Color.White });

(Шаг 3) А теперь самое сложное - рендеринг. Ну, не очень сложно, но требует двух DepthStencilStateобъектов и одного AlphaTestEffectобъекта. Вы должны создать их только один раз.

// Clear stencil buffer
GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0f, 0);

// Prepare the alpha test effect object (create it only once on initilization)
AlphaTestEffect alphaTestEffect = new AlphaTestEffect(GraphicsDevice)
{
    DiffuseColor = Color.White.ToVector3(), 
    AlphaFunction = CompareFunction.Greater, 
    ReferenceAlpha = 0, World = Matrix.Identity, 
    View = Matrix.Identity, 
    Projection = Matrix.CreateTranslation(-0.5f, -0.5f, 0) * 
    Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1)
};

// Prepare the first DepthStencilState (create only once, or put it in a static class)
DepthStencilState beforeDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Always,
    StencilPass = StencilOperation.Replace, 
    ReferenceStencil = 1
};

// Draw your sprites using the structures above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, beforeDepthStencilState, null, alphaTestEffect);
spriteBatch.Draw(sprite, new Vector2(300, 150), Color.White);
spriteBatch.End();

// Prepare the second DepthStencilState (create only once, or put it in a static class)
DepthStencilState afterDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Equal, 
    ReferenceStencil = 1
};

// Draw a full screen white quad with the structure above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, afterDepthStencilState, null);
spriteBatch.Draw(pixel, GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();

И результат:

введите описание изображения здесь

Дэвид Гувея
источник
Удивительно! Большое спасибо за то, что приложили столько усилий, Дэвид. Жаль, что нет более простого решения, но это должно хорошо сработать.
Райан МакД