问题已得到解答。有关详细信息,请查看本文末尾的编辑#4。
我们目前正在开发一款相当不错的游戏制作引擎。我正在制作动画创作者,并想知道是否可以使用添加剂混合绘制图像。
让我解释一下。
我们使用C#的System.Drawing库,我们使用Windows Forms。目前,用户可以通过导入带框架的动画图像(包含动画的每一帧的图像)来创建动画,并且用户可以将这些帧拖放到他想要的任何地方。
实际问题是我们无法弄清楚如何使用添加剂混合绘制框架。
如果你没有得到它,那么这是Additive Blending的例子。我不会责怪你,我很难用英语写作。
我们使用以下方法在Panel上绘图或直接在表单上绘图。例如,这里是为地图编辑器绘制平铺地图的代码。由于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:
对于绘制图像,我们使用颜色矩阵来设置hue和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:
刚刚找到了Mahesh Chand撰写的this文章。
在进一步浏览之后,即使它可以在颜色转换方面做很多事情,也可能无法使用颜色矩阵。 如果找到解决方案,我会回答我自己的问题。
谢谢你的帮助。
编辑#3:
XNA有很多关于混合的文档here。我发现用于在图像的每个像素上完成添加剂混合的公式。
PixelColor =(来源* [1,1,1,1])+(目的地* [1,1,1,1])
也许有一种方法可以在当前的上下文中使用这个公式? 我将在下次编辑时开始获得50分,我们真的需要这个才能工作。
再次感谢您的时间。
编辑#4
感谢axon,现在问题解决了。使用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();
答案 0 :(得分:8)
使用1)XNA(推荐用于速度),或2)在C#中使用像素操作。可能还有其他方法,但这些方法中的任何一种(我将它们分别用于我维护的3D效果和图像分析应用程序)。
C#中的像素操作: 使用3位图; bmpA,bmpB,bmpC,你想在bmpC中存储bmpA + bmpB。
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);
上述方法需要指针,因此必须使用“unsafe”指令进行编译。还假设R,G和B中的每一个都是1字节。更改代码以适合您的像素格式。
使用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(参见更新的原始帖子)。