Как я могу использовать Программу построения теней в XNA для окраски единственных пикселей?

У меня есть стандарт 800x600 окно в моем проекте XNA. Моя цель состоит в том, чтобы окрасить каждый отдельный пиксель на основе прямоугольного массива, который содержит булевы значения. В настоящее время я использую 1x1 Структура и тяну каждый спрайт в своем массиве.

Я очень плохо знаком с XNA и происхожу из среды GDI, таким образом, я делаю то, что я сделал бы в GDI, но это не масштабируется очень хорошо. Мне сказали в другом вопросе использовать Программу построения теней, но после большого исследования, я все еще не смог узнать, как выполнить эту цель.

Мои циклы приложения через координаты X и Y моей прямоугольной антенной решетки, делает вычисления на основе каждого значения и повторно присваивает/перемещает массив вокруг. В конце я должен обновить свой "Холст" с новыми значениями. Меньший образец моего массива был бы похож:

0,0,0,0,0,0,0
0,0,0,0,0,0,0
0,0,0,0,0,0,0
1,1,1,1,1,1,1
1,1,1,1,1,1,1

Как я могу использовать программу построения теней для окраски каждого пикселя?

Очень упрощенная версия вычислений была бы:

        for (int y = _horizon; y >= 0; y--)  // _horizon is my ending point
        {
            for (int x = _width; x >= 0; x--) // _width is obviously my x length.
            {
                if (grains[x, y] > 0)
                {
                    if (grains[x, y + 1] == 0)
                    {
                        grains[x, y + 1] = grains[x, y];
                        grains[x, y] = 0;
                    }
                }
            }
        }

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

Начальная буква:

0,0,0,1,0,0,0
0,0,0,0,0,0,0
0,0,0,0,0,0,0
1,1,1,0,1,1,1
1,1,1,1,1,1,1

Во-первых:

0,0,0,0,0,0,0
0,0,0,1,0,0,0
0,0,0,0,0,0,0
1,1,1,0,1,1,1
1,1,1,1,1,1,1

Во-вторых:

0,0,0,0,0,0,0
0,0,0,0,0,0,0
0,0,0,1,0,0,0
1,1,1,0,1,1,1
1,1,1,1,1,1,1

Финал:

0,0,0,0,0,0,0
0,0,0,0,0,0,0
0,0,0,0,0,0,0
1,1,1,1,1,1,1
1,1,1,1,1,1,1

Обновление:

После применения кода Render2DTarget и размещения моих пикселей, я заканчиваю с нежелательной границей на моих пикселях, всегда налево. Как я могу удалить это?

сопроводительный текст http://www.refuctored.com/borders.png

сопроводительный текст http://www.refuctored.com/fallingdirt.png

Часть кода для применения структур:

    RenderTarget2D target;
    Texture2D texture;
    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        texture = Content.Load("grain");
        _width = this.Window.ClientBounds.Width - 1;
        _height = this.Window.ClientBounds.Height - 1;
        target = new RenderTarget2D(this.GraphicsDevice,_width, _height, 1, SurfaceFormat.Color,RenderTargetUsage.PreserveContents);
     }

 protected override void Draw(GameTime gameTime)
    {
        this.GraphicsDevice.SetRenderTarget(0, target);
        this.GraphicsDevice.SetRenderTarget(0, null);
        this.GraphicsDevice.Clear(Color.SkyBlue);
        this.spriteBatch.Begin(SpriteBlendMode.None,SpriteSortMode.Deferred,SaveStateMode.None);
        SetPixels(texture);
        this.spriteBatch.End();
    }

 private void SetPixels(Texture2D texture)
    {
        for (int y = _grains.Height -1; y > 0; y--)
        {
            for (int x = _grains.Width-1; x > 0; x--)
            {
                if (_grains.GetGrain(x, y) >0)
                {
                    this.spriteBatch.Draw(texture, new Vector2(x,y),null, _grains.GetGrainColor(x, y));
                }
            }
        }
    }

11
задан Danny Varod 11 April 2010 в 23:40
поделиться

4 ответа

Этот метод не использует пиксельные шейдеры, но если вы хотите использовать метод SetData Texture2D вместо вызова SpriteBatch.Draw () для каждый пиксель, вы можете найти это полезным. Я использовал массив uint вместо bool для представления ваших цветов. Если вы можете обойтись 8-битной цветной текстурой, вы можете ускорить это, изменив формат текстуры.

public class Game1 : Microsoft.Xna.Framework.Game
{
    // Set width, height
    const int WIDTH = 800;
    const int HEIGHT = 600;

    // Used to randomly fill in initial data, not necessary
    Random rand;

    // Graphics and spritebatch
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    // Texture you will regenerate each call to update
    Texture2D texture;

    // Data array you perform calculations on
    uint[] data;

    // Colors are represented in the texture as 0xAARRGGBB where:
    // AA = alpha
    // RR = red
    // GG = green
    // BB = blue

    // Set the first color to red
    const uint COLOR0 = 0xFFFF0000;

    // Set the second color to blue
    const uint COLOR1 = 0xFF0000FF;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";

        // Set width, height
        graphics.PreferredBackBufferWidth = WIDTH;
        graphics.PreferredBackBufferHeight = HEIGHT;
    }

    protected override void Initialize()
    {
        base.Initialize();

        // Seed random, initialize array with random picks of the 2 colors
        rand = new Random((int)DateTime.Now.Ticks);
        data = new uint[WIDTH * HEIGHT];
        loadInitialData();
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // Create a new texture
        texture = new Texture2D(GraphicsDevice, WIDTH, HEIGHT);
    }

    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // Run-time error without this
        // Complains you can't modify a texture that has been set on the device
        GraphicsDevice.Textures[0] = null;

        // Do the calculations
        updateData();

        // Update the texture for the next time it is drawn to the screen
        texture.SetData(data);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        // Draw the texture once
        spriteBatch.Begin();
        spriteBatch.Draw(texture, Vector2.Zero, Color.Purple);
        spriteBatch.End();

        base.Draw(gameTime);
    }

    private void loadInitialData()
    {
        // Don't know where the initial data comes from
        // Just populate the array with a random selection of the two colors
        for (int i = 0; i < WIDTH; i++)
            for (int j = 0; j < HEIGHT; j++)
                data[i * HEIGHT + j] = rand.Next(2) == 0 ? COLOR0 : COLOR1;

    }

    private void updateData()
    {
        // Rough approximation of calculations
        for(int y = HEIGHT - 1; y >= 0; y--)
            for (int x = WIDTH - 1; x >= 0; x--)
                if (data[x * HEIGHT + y] == COLOR1)
                    if (y + 1 < HEIGHT && data[x * HEIGHT + (y + 1)] == COLOR0)
                    {
                        data[x * HEIGHT + (y + 1)] = data[x * HEIGHT + y];
                        data[x * HEIGHT + y] = COLOR0;
                    }
    }
}
2
ответ дан 3 December 2019 в 12:17
поделиться

Как насчет этого ...

Создайте две текстуры (800x600)

Инициализируйте одну из них до начальных значений.

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

После рендеринга получившейся текстуры на экран вы меняете их местами, чтобы они были готовы к следующему кадру.

Изменить:

Вам понадобятся два экземпляра RenderTarget2D и создайте их с помощью RenderTargetUsage.PreserveContents. Вы можете начать с SurfaceFormat.Color и использовать черный для 0 и белый для 1. (Вы также можете найти 8-битный формат для экономии видеопамяти.)

new RenderTarget2D(_device, 800, 600, 1, SurfaceFormat.Color, RenderTargetUsage.PreserveContents);

Вы назначаете их тегу рендеринга следующим образом:

_device.SetRenderTarget(0, myRenderTarget);

Вы используете RenderTarget2D в качестве текстуры, например:

_device.Textures[0] = myRenderTarget.GetTexture();

Надеюсь, что это поможет ... Я могу извлечь больше из своего движка, так что просто спросите.

0
ответ дан 3 December 2019 в 12:17
поделиться

То, что вы пытаетесь сделать (рисовать пиксель за пикселем), - это то, что делает DirectX. XNA - это слой, созданный поверх DirectX, поэтому вам не нужно рисовать пиксель за пикселем. Если это действительно то, чем вы хотите заниматься, то вам, вероятно, следует изучать DirectX вместо XNA. Возможно, вам будет намного проще ...

0
ответ дан 3 December 2019 в 12:17
поделиться

Добавьте рекламный щит к вашей сцене (прямо перед камерой, чтобы он занимал до 800x600 пикселей).

Свяжите двоичный массив как текстуру.

В шейдере фрагмента (/ пикселя) вычисляют цвет фрагмента, используя 2D-положение фрагмента и текстуру.

0
ответ дан 3 December 2019 в 12:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: