9

質問に答えました。詳細については、このテキストの最後にある編集#4を確認してください。

現在、かなり順調に進んでいるゲーム作成エンジンに取り組んでいます。私はアニメーションクリエーターに取り組んでおり、アディティブブレンディングで画像を描くことができるかどうか疑問に思っていました。

説明させてください。

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:

画像を描画するために、カラーマトリックスを使用して、次のように色相とアルファ(不透明度)を設定しています。

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:

MaheshChandによるこの記事を見つけました。

さらにブラウジングした後、カラー変換に関して多くのことを達成できたとしても、カラーマトリックスでは不可能な場合があります。解決策が見つかったら、私自身の質問に答えます。

助けてくれてありがとう。

編集#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();
4

1 に答える 1

8

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、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」または「texture」HLSLインターフェイスを使用してテクスチャにアクセスするかどうかによって異なります。

また、適切なサンプラー設定を使用して、必要な場合(この場合は高品質/高次のものを使用)でない限り、カラー値を検索するときにサンプリング(線形補間など)が使用されないように注意する必要があります。

XNAには、オーバーラップしたテクスチャを組み合わせる方法を指定するために使用できる組み込みのBlendStatesもあります。つまり、BlendState.Additive(更新された元の投稿を参照)。

于 2012-08-31T06:52:59.487 に答える