Drawing image with additive blending

前端 未结 1 1850
北海茫月
北海茫月 2021-01-11 21:18

Question was answered. For more information, check out EDIT #4 at the end of this text.

We are currently working on a gamemaking engine which is goi

1条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-11 22:06

    Either use 1) XNA (recommended for speed), or 2) use pixel-operations in C#. There may be other methods, but either of these work (I'm using each of them for 3D effects and image analysis apps (respectively) that I maintain).

    Pixel Operations in C#: Using 3 bitmaps; bmpA, bmpB, bmpC, where you want to store bmpA+bmpB in 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);
        }
    }
    

    The above code is very slow. A faster solution in C# could use pointers like this:

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

    The above method requires pointers and hence must be compiled with the "unsafe" directive. Also assumes 1-byte for each of R,G, and B. Change the code to suit your pixel format.

    Using XNA is a lot faster (performance) since it is hardware accelerated (by the GPU). It basically consists of the following: 1. Create the geometry needed to draw the image (a rectangle, most likely a full-screen quad). 2. Write a vertex-shader and pixel-shader. The vertex-shader can simply pass-through the geometry unmodified. Or you can apply an orthogonal projection (depending on what coordinates you want to work with for the quad). The pixel shader will have the following lines (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);
    }
    

    There are different methods available for accessing textures. The following will also work (depending on how you want the XNA code to bind to the shader parameters):

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

    Which of the above shaders you use will depend on whether you want to use the "sampler2D" or "texture" HLSL interfaces to access the textures.

    You should also be careful to use an appropriate sampler setting to ensure that no sampling (e.g. linear interpolation) is used when looking up colour values unless that's something you want (in which case use something higher-quality/higher-order).

    XNA also has built-in BlendStates you can use to specify how overlapped textures will be combined. I.e. BlendState.Additive (see updated original post).

    0 讨论(0)
提交回复
热议问题