Imagem de desenho com mistura aditiva

a pergunta foi respondida. Para mais informações, confira O EDIT # 4 no final deste texto.

Estamos a trabalhar num motor de gamemaking que está a correr muito bem. Estou a trabalhar no Criador da animação e estava a pensar se seria possível desenhar uma imagem com mistura aditiva.

Deixa-me explicar.

Usamos o sistema.Biblioteca de desenho de C# e nós trabalhamos com formulários do Windows. Por agora, o Usuário é capaz de criar sua animação, importando Um framed imagem de animação (uma imagem contendo cada moldura da animação) e o Usuário é capaz de arrastar e largar essas molduras onde quiser.

O verdadeiro problema é que não conseguimos descobrir como desenhar um quadro com a mistura aditivo.

Eis uma amostra do que é a mistura aditiva, se não a compreenderes. Não te censuro, tenho dificuldade em escrever em inglês. Additive blending exemple

estamos a usar o seguinte método para desenhar num painel ou directamente no formulário. Por exemplo aqui está o código para desenhar um mapa em mosaico para o editor de mapas. Uma vez que o código AnimationManager é uma confusão, será mais claro com este exemplo.

        using (Graphics g = Graphics.FromImage(MapBuffer as Image))
        using (Brush brush = new SolidBrush(Color.White))
        using (Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0), 1))
        {
            g.FillRectangle(brush, new Rectangle(new Point(0, 0), new Size(CurrentMap.MapSize.Width * TileSize, CurrentMap.MapSize.Height * TileSize)));

            Tile tile = CurrentMap.Tiles[l, x, y];
            if (tile.Background != null) g.DrawImage(tile.Background, new Point(tile.X * TileSize, tile.Y * TileSize));

            g.DrawRectangle(pen, x * TileSize, y * TileSize, TileSize, TileSize);
        }
Há uma maneira possível de desenhar uma imagem com um desenho aditivo e, se assim for, ficaria eternamente grato se alguém me pudesse indicar como. Obrigado.

Editar #1 :

para desenhar imagens, estamos a usar uma matriz de cores para definir matiz e alph (opacidade) como esta:

ColorMatrix matrix = new ColorMatrix
(
    new Single[][]  
    { 
        new Single[] {r, 0, 0, 0, 0},
        new Single[] {0, g, 0, 0, 0},
        new Single[] {0, 0, b, 0, 0},
        new Single[] {0, 0, 0, a, 0},
        new Single[] {0, 0, 0, 0, 1}
    }
);

talvez a matriz de cores possa ser usada para mistura aditiva?

Editar #2 :

Encontrei este artigo de Mahesh Chand.

Depois de mais navegação, pode não ser possível com uma matriz de cores, mesmo que possa realizar muito em relação às transformações de cores. Responderei à minha pergunta se for encontrada uma solução.

Obrigado pela ajuda.

editar #3 :

XNA tem muita documentaçãoaqui sobre mistura. Encontrei a fórmula usada para realizar mistura aditiva em cada pixels de uma imagem.

PixelColor = (fonte * [1, 1, 1, 1]) + (destino * [1, 1, 1, 1])

Talvez haja uma maneira de usar esta fórmula no contexto actual? Vou começar uma recompensa de 50 na próxima edição, precisamos mesmo que isto funcione.

Obrigado novamente pelo seu tempo.

editar #4

Graças ao axon, agora o problema está resolvido. Usando o XNA e o seu Spritebatch, poderá conseguir uma mistura aditiva ao fazê - lo:

Primeiro de tudo o que cria é um GraphicsDevice e um SpriteBatch

// In the following example, we want to draw inside a Panel called PN_Canvas. 
// If you want to draw directly on the form, simply use "this" if you
// write the following code in your form class

PresentationParameters pp = new PresentationParameters();

// Replace PN_Canvas with the control to be drawn on
pp.BackBufferHeight = PN_Canvas.Height;
pp.BackBufferWidth = PN_Canvas.Width;
pp.DeviceWindowHandle = PN_Canvas.Handle;
pp.IsFullScreen = false;

device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, pp);
batch = new SpriteBatch(device);

então, quando for a altura de desenhar no controlo ou no formulário (com o evento OnPaint, por exemplo), poderá usar o seguinte bloco de código

// You should always clear the GraphicsDevice first
device.Clear(Microsoft.Xna.Framework.Color.Black);

// Note the last parameter of Begin method
batch.Begin(SpriteSortMode.BackToFront, BlendState.Additive);
batch.draw( /* Things you want to draw, positions and other infos */ );
batch.End();

// The Present method will draw buffer onto control or form
device.Present();
Author: Érik Desjardins, 2012-08-29

1 answers

Use 1) XNA (recomendado para velocidade), ou 2) use pixel-operations em C#. Pode haver outros métodos ,mas qualquer um destes trabalhos (estou usando cada um deles para efeitos 3D e aplicações de análise de imagem (respectivamente) que eu manter).

Operações de pixels em C#: Usando 3 bitmaps; bmpA, bmpB, bmpC, onde você deseja armazenar bmpA+bmpB em bmpC.

for (int y = 0; y < bmp.Height; y++)
{
    for (int x = 0; x < bmp.Width; x++)
    {
        Color cA = bmpA.GetPixel(x,y);
        Color cB = bmpB.GetPixel(x,y);
        Color cC = Color.FromArgb(cA.A, cA.R + cB.R, cA.G + cB.G, cA.B + cB.B);
        bmpC.SetPixel(x, y, cC);
    }
}

O código acima é muito lento. Uma solução mais rápida em C# poderia usar ponteiros como este:

    // Assumes all bitmaps are the same size and same pixel format
    BitmapData bmpDataA = bmpA.LockBits(new Rectangle(0, 0, bmpA.Width, bmpA.Height), ImageLockMode.ReadOnly, bmpA.PixelFormat);
    BitmapData bmpDataB = bmpB.LockBits(new Rectangle(0, 0, bmpA.Width, bmpA.Height), ImageLockMode.ReadOnly, bmpA.PixelFormat);
    BitmapData bmpDataC = bmpC.LockBits(new Rectangle(0, 0, bmpA.Width, bmpA.Height), ImageLockMode.WriteOnly, bmpA.PixelFormat);
    void* pBmpA = bmpDataA.Scan0.ToPointer();
    void* pBmpB = bmpDataB.Scan0.ToPointer();
    void* pBmpC = bmpDataC.Scan0.ToPointer();
    int bytesPerPix = bmpDataA.Stride / bmpA.Width;
    for (int y = 0; y < bmp.Height; y++)
    {
        for (int x = 0; x < bmp.Width; x++, pBmpA += bytesPerPix, pBmpB += bytesPerPix, pBmpC += bytesPerPix)
        {
            *(byte*)(pBmpC) = *(byte*)(pBmpA) + *(byte*)(pBmpB); // R
            *(byte*)(pBmpC + 1) = *(byte*)(pBmpA + 1) + *(byte*)(pBmpB + 1); // G
            *(byte*)(pBmpC + 2) = *(byte*)(pBmpA + 2) + *(byte*)(pBmpB + 2); // B
        }
    }
    bmpA.UnlockBits(bmpDataA);
    bmpB.UnlockBits(bmpDataB);
    bmpC.UnlockBits(bmpDataC);

O método acima descrito exige ponteiros e, portanto, deve ser compilado com a Directiva "insegura". Também assume 1 byte para cada um de R,G, E B. mude o código para se adequar ao seu formato de pixel.

O uso do XNA é muito mais rápido (desempenho), uma vez que é o hardware acelerado (pela GPU). Trata-se essencialmente do seguinte:: 1. Crie a geometria necessária para desenhar a imagem (um rectângulo, provavelmente um quad de ecrã completo). 2. Escreva um 'vertex-shader' e um 'pixel-shader'. O vértice-sombreado pode simplesmente passar-através do geometria não modificada. Ou pode aplicar uma projecção ortogonal (dependendo das coordenadas com que deseja trabalhar para o quad). O sombreador de pixels terá as seguintes linhas (HLSL):

float4 ps(vertexOutput IN) : COLOR 
{
    float3 a = tex2D(ColorSampler,IN.UV).rgb;
    float3 b = tex2D(ColorSampler2,IN.UV).rgb;
    return float4(a + b,1.0f);
}
Existem diferentes métodos disponíveis para aceder a texturas. O seguinte também irá funcionar (dependendo de como você quer que o código XNA se vincule aos parâmetros shader):
float4 ps(vertexOutput IN) : COLOR 
{
    float3 a = texA.Sample(samplerState, IN.UV).xyz;
    float3 b = texB.Sample(samplerState, IN.UV).xyz;
    return float4(a + b,1.0f);
}

Qual dos shaders acima que você usa irá depender se você quer usar o "sampler2D " ou" texture " HLSL interfaces para aceder às texturas.

Deve também ter o cuidado de utilizar um sistema de amostragem adequado para garantir que não é utilizada nenhuma amostragem (por exemplo, interpolação linear) ao procurar valores de cor, a menos que seja algo que queira (neste caso, utilize algo de qualidade superior/ordem superior).

O XNA também tem BlendStates incorporados que pode usar para especificar como as texturas sobrepostas serão combinadas. Ou seja, BlendState.Aditivo (ver publicação original actualizada).

 8
Author: axon, 2012-09-05 23:46:37