Какой самый эффективный способ интерполировать между двумя цветами? (ожидается псевдокод и битовая операция) - PullRequest
2 голосов
/ 13 апреля 2010

Создание приложения для Blackberry, хочу класс Gradient. Какой самый эффективный способ (например, скорость и время автономной работы) для интерполяции двух цветов? Пожалуйста, будьте конкретны.

// Java, of course
int c1 = 0xFFAA0055   // color 1, ARGB
int c2 = 0xFF00CCFF   // color 2, ARGB
float st = 0          // the current step in the interpolation, between 0 and 1

Помощь с этого момента. Должен ли я разделить каждый канал каждого цвета, преобразовать их в десятичный и интерполировать? Есть ли более простой способ?

interpolatedChannel = red1+((red2-red1)*st)
interpolatedChannel = interpolatedChannel.toString(16)

^ Это правильно? Если скорость и эффективность важно в мобильном приложении, я должен использовать побитовые операции?

Помоги мне!

Ответы [ 4 ]

8 голосов
/ 13 апреля 2010

Вам придется разделять каналы, но нет необходимости преобразовывать их в десятичные.

Например, если вы разрешите 256 возможных градиентов:

red = red1 + ((red2 - red1) * stage / 256)

РЕДАКТИРОВАТЬ: Поскольку вы сказали, что вы не знаете много об управлении битами, вот быстрый способ разделения каналов:

red = color & 0x000000ff;
green = color & 0x0000ff00;
blue = color & 0x00ff0000;
alpha = color >> 24;

И объединяя их обратно:

color = (alpha << 24) | blue | green | red;

Отсюда детали обычно должны обрабатываться оптимизацией компилятора. Во всяком случае, вы ищете лучший алгоритм.

5 голосов
/ 25 января 2011
private function interpolateColorsCompact( a:int, b:int, lerp:Number ):int
{ 
   var MASK1:int = 0xff00ff; 
   var MASK2:int = 0x00ff00; 

   var f2:int = 256 * lerp;
   var f1:int = 256 - f2;

   return   ((((( a & MASK1 ) * f1 ) + ( ( b & MASK1 ) * f2 )) >> 8 ) & MASK1 ) 
          | ((((( a & MASK2 ) * f1 ) + ( ( b & MASK2 ) * f2 )) >> 8 ) & MASK2 );

} 

Не уверен, что это самый компактный способ сделать это, но он использует меньше локальных переменных и меньше операторов, чем классический метод, который сначала разбивает их на 3 канала.

О - и извините, что это Actionscript, но должно быть понятно, как преобразовать это в Java.

2 голосов
/ 13 апреля 2010

Обновлен мой ответ (найден лучший способ):

Следующая техника потеряет точность 1 бит на канал, но это очень быстро, так как вы выигралиНе нужно разбивать цвета на каналы:

int color1 = ...;
int color2 = ...;
int interpolatedColor = ((color1 & 0xFEFEFEFE) >> 1) + 
                        ((color2 & 0xFEFEFEFE) >> 1));

Итак, сначала вы И оба цвета на 0xFEFEFEFE.Это удаляет последний бит на канал (как я уже сказал, снижает точность).После этого вы можете безопасно разделить все значение на 2 (реализовано как сдвиг вправо на 1).Наконец, вы просто складываете два значения.

0 голосов
/ 06 сентября 2017

Только java-версия ответа / u / Quasimondo:

public static int mixColors(int a, int b, float ratio){
    int mask1 = 0x00ff00ff;
    int mask2 = 0xff00ff00;

    int f2 = (int)(256 * ratio);
    int f1 = 256 - f2;

    return (((((a & mask1) * f1) + ((b & mask1) * f2)) >> 8) & mask1) 
         | (((((a & mask2) * f1) + ((b & mask2) * f2)) >> 8) & mask2);
}

Если вам нужны только точные соотношения 50/50, вы можете вырезать битовое смещение:

public static int mixColors(int a, int b){
    int mask1 = 0x00ff00ff;
    int mask2 = 0xff00ff00;

    return (((a & mask1) + (b & mask1)) & mask1) 
         | (((a & mask2) + (b & mask2)) & mask2);
}
...