Самый быстрый способ рассчитать цвета для градиента?
Я делаю небольшую коллекцию типов/функций, связанных с градиентами для использования в будущем. Я хотел бы убедиться, что есть по крайней мере две процедуры: ColorBetween и ColorsBetween. Я могу просто получить массив TColor между любыми 2 цветами (ColorsBetween), и мне также может потребоваться знать одно значение цвета в процентах между двумя цветами (ColorBetween).
Я уже сделал это в основном ниже. Кроме того, у меня есть два основных вопроса:
- как я вычислить промежуточный цвет каждого канала RGB на заданный процент? (См. ниже, где я
[???]
) - какой самый быстрый способ выполнить то, что я делаю (сохраняя при этом две разные функции)?
вот код:
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
StrUtils, StdCtrls, Math;
type
TColorArray = array of TColor;
implementation
function ColorsBetween(const ColorA, ColorB: TColor; const Count: Integer): TColorArray;
var
X: Integer; //Loop counter
begin
SetLength(Result, Count);
for X:= 0 to Count - 1 do
Result[X]:= ColorBetween(ColorA, ColorB, Round((X / Count) * 100)); //Correct?
end;
function ColorBetween(const ColorA, ColorB: TColor; const Percent: Single): TColor;
var
R1, G1, B1: Byte;
R2, G2, B2: Byte;
begin
R1:= GetRValue(ColorA);
G1:= GetGValue(ColorA);
B1:= GetBValue(ColorA);
R2:= GetRValue(ColorB);
G2:= GetGValue(ColorB);
B2:= GetBValue(ColorB);
Result:= RGB(
EnsureRange(([???]), 0, 255),
EnsureRange(([???]), 0, 255),
EnsureRange(([???]), 0, 255)
);
end;
EDIT: изменить Percent: Integer
to Percent: Single
чтобы получить более плавный эффект-не ограничивается 100 возможных значений.
2 ответов
похоже, вы хотите заменить свой ??? с
Round((R1*Percent + R2*(100-Percent))/100.0)
на EnsureRange
в коде не надо, потому что эта функция должна возвращать значения в диапазоне от 0 до 255 при условии, что Percent
находится в диапазоне от 0 до 100. Я думаю, что я бы применил EnsureRange
до Percent
(заставить его в диапазоне от 0.0 до 100.0), а затем использовать следующий код:
Result := RGB(
Round((R1*Percent + R2*(100-Percent))/100.0),
Round((G1*Percent + G2*(100-Percent))/100.0),
Round((B1*Percent + B2*(100-Percent))/100.0),
);
ваша первая функция возвращает массив, первый цвет ColorA
. Может быть, тебе было бы лучше ... это:
for X:= 0 to Count - 1 do
Result[X]:= ColorBetween(ColorA, ColorB, (X+1) / (Count+1) * 100.0);
это дает одинаковое поведение на обоих концах массива. Или возможно, вы хотите как ColorA
и ColorB
включено. Тогда вы бы использовали:
X / (Count-1) * 100.0
но если вы это сделаете, помните, что количество должно быть больше 1, иначе вы будете делить на ноль. Что Невер работает!!
не беспокойтесь о производительности. Код можно сделать немного быстрее, без сомнения, но это, безусловно, не будет узким местом. Вы будете принимать эти цвета и рисовать с ними. Это потребляет гораздо больше ресурсов, чем эти простые процедуры.
один последний момент. Интерполяция в пространстве RGB не будет выглядеть особенно гладкой или линейной для человеческого глаза. Использование процента с плавающей запятой не может обойти этот факт. Для достижения наилучших результатов при просмотре нужно интерполировать в другом цветовом пространстве.
Я не знаю, если это быстрый способ, но он работает:
function ColorBetween(const ColorA, ColorB: TColor; const Percent: Integer): TColor;
var
R1, G1, B1: Byte;
R2, G2, B2: Byte;
begin
R1:= GetRValue(ColorA);
G1:= GetGValue(ColorA);
B1:= GetBValue(ColorA);
R2:= GetRValue(ColorB);
G2:= GetGValue(ColorB);
B2:= GetBValue(ColorB);
Result:= RGB(
Percent * (R2-R1) div 100 + R1,
Percent * (G2-G1) div 100 + G1,
Percent * (B2-B1) div 100 + B1
);
end;
function ColorsBetween(const ColorA, ColorB: TColor; const Count: Integer): TColorArray;
var
X : integer;
begin
SetLength(Result, Count);
for X := 0 to Count - 1 do
Result[X] := ColorBetween(ColorA, ColorB, Round((X / (Count-1)) * 100)); //Note: Divide by count-1
end;