2012-08-29 76 views
8

問題已回答。有關更多信息,請參閱本文末尾的編輯#4。添加劑混合的繪圖圖像

我們目前正在研發一款相當不錯的遊戲製作引擎。我正在研究動畫創作者,並想知道是否可以使用添加混合來繪製圖像。

讓我解釋一下。

我們使用C#的System.Drawing庫,並使用Windows窗體。目前,用戶能夠通過導入帶框的動畫圖像(包含動畫的每個幀的圖像)來創建他的動畫,並且用戶能夠將這些框架拖放到他想要的任何地方。

實際的問題是,我們無法弄清楚如何繪製一個框架與添加劑混合。

下面是添加劑混合的例子,如果你不太明白。我不會責怪你,我很難用英文寫作。 Additive blending exemple

我們使用以下方法在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); 
     } 

有沒有用添加劑繪圖如果是繪製圖像的一個可行的辦法,我會永遠感激,如果有人可以點我如何。謝謝。

EDIT#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:

剛剛發現this文章馬赫什昌。

在進一步瀏覽之後,即使色彩轉換可以完成很多工作,也可能無法使用色彩矩陣。 如果找到解決方案,我會回答我自己的問題。

謝謝你的幫助。

編輯#3:

XNA有很多關於混合文檔here的。我找到了用於在圖像的每個像素上完成疊加混合的公式。

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(); 
+1

我不確定這是可能的直接向上的winforms,而不訴諸於自己的像素值操縱。將使用WPF託管組件作爲圖紙是一個選項嗎?WPF有能力更容易地設置混合模式。 – Dervall

+0

@Dervall我們越搜索越多,我們開始認爲使用WPF託管組件是一個非常好的主意。也許沒有直接使用Winforms使用逐像素算法的解決方案。或者,也許有人會想出一些奇蹟? –

+0

[.DrawImage with opacity?]的可能重複?(http://stackoverflow.com/questions/5519956/drawimage-with-opacity) –

回答

7

既可以使用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); 

上述方法需要指針,並因此必須與「不安全」的指令進行編譯。對於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(請參閱更新的原始帖子)。

+0

明天我就跟團隊一起試試吧。這很有意義;您需要源圖像才能將像素與要繪製的像素混合。儘管我們決定不使用XNA,但我可以用你提供的這個非常完善的答案來說服他們。 –

+0

好的,所以團隊最終決定將XNA與WinForms結合使用。先生,你剛剛救了一天。謝謝!要等14個小時,直到我可以給你50pts。 –

+0

Nooo問題。祝你好運! – axon