绘制的图像与添加剂混合(Drawing image with additive blending)

2019-06-27 12:18发布

问题得到回答。 欲了解更多信息,请在本文的最后检查出编辑#4。

我们目前正在其上做得较好一gamemaking引擎。 我工作的动画创作者,想知道是否有可能与添加剂混合绘制图像。

让我解释。

我们使用C#System.Drawing中的库,我们使用Windows的工作形式。 现在,用户可以通过导入帧动画图像(含动画的每一帧图像)来创建自己的动画,并且用户能够拖拽这些帧的地方,他希望。

实际的问题是,我们无法弄清楚如何绘制与添加剂混合的框架。

这里有一个为例添加剂调合是什么,如果你不太明白这一点。 我不会怪你的,我也很难在英语写作。

我们使用下面的方法来绘制一个面板或直接在表格上。 对于为例这里是绘制的地图编辑器平铺图的代码。 由于AnimationManager代码是一个烂摊子,这将是与本例清晰。

        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);
        }

有没有用添加剂图纸绘制图像,如果是这样,我会永远感激,如果有人可以点我如何的一个可行的办法。 谢谢。

编辑#1:

为绘制图像,我们用的是彩色矩阵来设置色调和ALPH(不透明度)所示:

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}
    }
);

也许彩色矩阵可用于添加剂调合而成?

编辑#2:

刚刚发现这个文章马赫什昌。

进一步浏览后,可能无法用彩色矩阵虽然能够完成关于颜色变换了很多。 我会回答我的问题,如果解决方案中。

谢谢你的帮助。

编辑#3:

XNA有大量的文档资料在这里了解有关混合。 我发现用于完成对图像的每个像素的添加剂混合式。

PixelColor =(源* [1,1,1,1])+(目的地* [1,1,1,1])

也许有在当前的环境中使用这个公式的一种方式? 我将开始下一个编辑50赏金,我们真的需要这个工作。

再次感谢您的时间。

编辑#4

由于轴突,现在的问题就解决了。 使用XNA和Spritebatch,你可以做到添加剂调合这样做:

首先你创建的GraphicsDevice和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);

然后,当它的时间上的控制或窗体上绘制(与OnPaint事件为例),可以使用下面的代码块

// 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();

Answer 1:

既可以使用1)XNA(推荐速度),或2)在C#使用像素的操作。 可能还有其他的方法,但是这两种工作(我使用他们每个人对3D效果和图像分析应用(分别),我保持)。

像素操作在C#中:使用3位图; BMPA,bmpB,BMPC,要存储BMPA + bmpB在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);
    }
}

上面的代码是非常缓慢的。 在C#中更快的解决方案可以使用这样的指针:

    // 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);

上述方法需要指针,并因此必须与“不安全”的指令进行编译。 还假定对于每个R,G的1字节,以及B.更改以适应您像素格式的代码。

使用XNA是因为它快了很多(性能)硬件加速(由GPU)。 它主要包括以下内容:1.创建绘制图像(矩形,最有可能是全屏幕四)所需的几何形状。 2.写一个顶点着色器和像素着色器。 顶点着色器可以简单地直通几何不变。 或者,你可以申请一个正交投影(取决于你想用四上班什么坐标)。 像素着色器将具有以下线(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);
}

有可用于访问纹理不同的方法。 下面还将努力(这取决于你想如何XNA代码绑定到着色器参数):

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);
}

使用哪个取决于您是否要使用“sampler2D”或“纹理” HLSL接口来访问纹理上述着色器。

仰视时的颜色值,除非这就是你想要的东西,你也应该谨慎使用适当的采样设置,以确保没有采样(如线性插值)被使用(在这种情况下使用一些更高质量/高阶)。

XNA也有内置BlendStates你可以使用指定纹理如何重叠将被合并。 即BlendState.Additive(见更新原来的职位)。



文章来源: Drawing image with additive blending