frio Posted November 2 Posted November 2 Granted, the math to just do a linear interpolation between 2 colors is not difficult or cumbersome for the most basic blend, but I'm wondering if I'm missing some built in utility. I do know of the ColorBgra.Blend method, but reading the API docs it's more of a legacy thing and doesn't have support for the new more exotic color depths or anything, so I figured I should change that to something more modern while I'm updating an effect. Quote
Solution Rick Brewster Posted November 2 Solution Posted November 2 Everything in ColorBgra should be considered legacy and should not be used. Let's assume you're starting with a ColorBgra32: 1. Cast to ColorRgba128Float 2. Call ToPremultiplied(), giving you a ColorPrgba128Float. We premultiply because blending needs to operate in premultiplied alpha space, at which point the math gets really simple. 3. Cast to System.Numerics.Vector4 For a 50/50 blend, it's just c=(a+b)/2, there are operator overloads that really make it that easy. For a specific opacity, it'd be c=Vector4.Lerp(a, b, opacityOfB), where opacityOfB should be in the range [0, 1] inclusive. Remember we're working with values in the [0, 1] range, not [0, 255]! 4. Cast back to ColorPrgba128Float 5. Call ToUnpremultiplied() to get back to olorRgba128Float 6. To get back to ColorBgra32, use ColorBgra32.Round() Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
Rick Brewster Posted November 2 Posted November 2 Note that at step 3 you can also cast to PaintDotNet.Rendering.Vector4Float, or to System.Runtime.Intrinsics.Vector128<float>. Which one you use is up to you and which one looks more comfortable/useful/powerful. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
Rick Brewster Posted November 2 Posted November 2 Note that my instructions above do not convert to linear gamma. If you want to do that, which does produce better results, I can detail how to properly do that as well. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
frio Posted November 2 Author Posted November 2 Thanks, this should give me enough ideas to futureproof the code a bit while I'm at it! Quote
frio Posted November 2 Author Posted November 2 1 hour ago, Rick Brewster said: Note that my instructions above do not convert to linear gamma. If you want to do that, which does produce better results, I can detail how to properly do that as well. Actually, not sure if I need it for this particular case, but might be good to know for later anyway, so if you don't mind. Also re: using premultiplied alpha, that's not getting me the results I'm after: I'm often interested in the colors even in fully transparent pixels, so doing a blend between, say, RGBA 255, 0, 0, 0 and 0, 255, 0, 0 is meaningful to produce values that have 0 alpha but colors between red and green; if I use premultiplied, the color info is lost. Am I missing something? Quote
Rick Brewster Posted November 2 Posted November 2 For converting colors between color spaces, you can use Environment.ImagingFactory.ConvertColors(). // Get the color context we're actually rendering with // ("color context" is an object that describes a color space or something similar) IColorContext docColorContext = Environment.Document.ColorContext; // Linearize the color context IColorContext docColorContextLinear = docColorContext.CreateLinearizedColorContextOrScRgb(docColorContextLiner); // Make a list of colors ColorRgbaFloat[] colors = [ c1, c2, c3, ... ]; // Convert the colors ColorRgbaFloat[] colorsLinear = Environment.ImagingFactory.ConvertColors(colors, docColorContext, docColorContextLinear).ToArray(); // Do some processing on them? ... // And later we can convert them back to the original color context IReadOnlyList<ColorRgbaFloat> colors2 = Environment.ImagingFactory.ConvertColors(colorsLinear, docColorContextLinear, docColorContext); // And then convert back to ColorBgra32 IReadOnlyList<ColorBgra32> colors2Bgra32 = colors2.Select(c => ColorBgra32.Round(c)).ToArray(); If you only need to convert 1 color, it's reasonable to use ManagedColor // Obtain color contexts just like in the above snippet // Make 1 color ManagedColor color = ManagedColor.Create(..., colorContext); // Convert to linear ColorRgba128Float colorLinear = color.Get(colorContextLinear); 1 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
_koh_ Posted November 2 Posted November 2 2 hours ago, frio said: if I use premultiplied, the color info is lost. Yeah, pre-multiplied alpha doesn't preserve RGB when alpha = 0. But when you blend two colors, they are usually weighted with alpha, so blended result doesn't preserve RGB after all. Maybe what you want is per component interpolation in this case, which is just Lerp(). Quote
frio Posted November 2 Author Posted November 2 (edited) 11 hours ago, _koh_ said: Maybe what you want is per component interpolation in this case, which is just Lerp(). Yeah, I thought about it overnight and realized I'm using "blending" inaccurately here, since what I'm really interested in is interpolating between 2 colors based on an intensity 0-1 value which is why the Lerp on straight-alpha colors gets me what I'm expecting to see. Though, it's still good to have the right idea for any future effects where I may be dealing with proper blending! Thanks to you and Rick both. Edited November 2 by frio Quote
Rick Brewster Posted November 2 Posted November 2 If you just want to lerp then you can just skip ToPremultiplied/ToUnpremultiplied. The rest of what I described above is very applicable. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
frio Posted November 2 Author Posted November 2 Yup, that's what I went with and things are now looking good, once 5.1 releases I'm good to put out this updated version. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.