I search for solutions in this order: Past Code, Unreal Source, Wiki, BUF, groups.yahoo, google, screaming at monitor. – RegularX

HSV-RGB Conversion

From Unreal Wiki, The Unreal Engine Documentation Site
Revision as of 15:24, 10 May 2010 by Wormbo (Talk | contribs) (added category so this orphan page can be reached from somewhere)

Jump to: navigation, search

HSV is a way of representing a color. It is used in UEd's color picker, but there are no functions exposed to UScript for handling colors in this form. HSV is useful though, so here are some functions for converting between HSV and RGB.

Struct

First a struct for containing the HSV color, equivalent to the LinearColor struct for RGB colors.

/**
 * A color represented by the four components Hue, Saturation, Value, and Alpha.
 * H must be between 0 and 360 (degrees).
 * S must be between 0 and 1.
 * V and A are normally between 0 and 1, but may exceed that range to give bloom.
 */
struct HSVColor
{
	var() float H, S, V, A;
 
	structdefaultproperties
	{
		A=1.0
	}
};

RGB to HSV

/**
 * Converts an RGB color to an HSV color, according to the algorithm described at http://en.wikipedia.org/wiki/HSL_and_HSV
 *
 * @param RGB the color to convert.
 * @return the HSV representation of the color.
 */
static final function HSVColor RGBToHSV(const out LinearColor RGB)
{
	local float Max;
	local float Min;
	local float Chroma;
	local HSVColor HSV;
 
	Min = FMin(FMin(RGB.R, RGB.G), RGB.B);
	Max = FMax(FMax(RGB.R, RGB.G), RGB.B);
	Chroma = Max - Min;
 
	//If Chroma is 0, then S is 0 by definition, and H is undefined but 0 by convention.
	if(Chroma != 0)
	{
		if(RGB.R == Max)
		{
			HSV.H = (RGB.G - RGB.B) / Chroma;
 
			if(HSV.H < 0.0)
			{
				HSV.H += 6.0;
			}
		}
		else if(RGB.G == Max)
		{
			HSV.H = ((RGB.B - RGB.R) / Chroma) + 2.0;
		}
		else //RGB.B == Max
		{
			HSV.H = ((RGB.R - RGB.G) / Chroma) + 4.0;
		}
 
		HSV.H *= 60.0;
		HSV.S = Chroma / Max;
	}
 
	HSV.V = Max;
	HSV.A = RGB.A;
 
	return HSV;
}

HSV to RGB

/**
 * Converts an HSV color to an RGB color, according to the algorithm described at http://en.wikipedia.org/wiki/HSL_and_HSV
 *
 * @param HSV the color to convert.
 * @return the RGB representation of the color.
 */
static final function LinearColor HSVToRGB(const out HSVColor HSV)
{
	local float Min;
	local float Chroma;
	local float Hdash;
	local float X;
	local LinearColor RGB;
 
	Chroma = HSV.S * HSV.V;
	Hdash = HSV.H / 60.0;
	X = Chroma * (1.0 - Abs((Hdash % 2.0) - 1.0));
 
	if(Hdash < 1.0)
	{
		RGB.R = Chroma;
		RGB.G = X;
	}
	else if(Hdash < 2.0)
	{
		RGB.R = X;
		RGB.G = Chroma;
	}
	else if(Hdash < 3.0)
	{
		RGB.G = Chroma;
		RGB.B = X;
	}
	else if(Hdash < 4.0)
	{
		RGB.G= X;
		RGB.B = Chroma;
	}
	else if(Hdash < 5.0)
	{
		RGB.R = X;
		RGB.B = Chroma;
	}
	else if(Hdash < 6.0)
	{
		RGB.R = Chroma;
		RGB.B = X;
	}
 
	Min = HSV.V - Chroma;
 
	RGB.R += Min;
	RGB.G += Min;
	RGB.B += Min;
	RGB.A = HSV.A;
 
	return RGB;
}

Example Use

HSV is useful because it allows colours to be manipulated in a way that better fits the way we think. For instance, it's quite common to want several colours that differ only in hue, like this HUD function which returns a colour that fades from red to green when passed a value from 0 to 1.

/* returns Red (0.f) -> Yellow -> Green (1.f) Color Ramp */
static function Color GetRYGColorRamp( float Pct )
{
	local Color GYRColor;
 
	GYRColor.A = 255;
 
	if ( Pct < 0.34 )
	{
    	GYRColor.R = 128 + 127 * FClamp(3.f*Pct, 0.f, 1.f);
		GYRColor.G = 0;
		GYRColor.B = 0;
	}
    else if ( Pct < 0.67 )
	{
    	GYRColor.R = 255;
		GYRColor.G = 255 * FClamp(3.f*(Pct-0.33), 0.f, 1.f);
		GYRColor.B = 0;
	}
    else
	{
		GYRColor.R = 255 * FClamp(3.f*(1.f-Pct), 0.f, 1.f);
		GYRColor.G = 255;
		GYRColor.B = 0;
	}
 
	return GYRColor;
}

As you can see, working in RGB results in relatively convoluted code for performing a simple task. Compare this to the equivalent using HSV

static function HSVColor GetRYGColorRampHSV(float Pct)
{
	local HSVColor HSV;
 
	HSV.H = 120.0 * FClamp(Pct, 0.0, 1.0); //0 is red, 60 is yellow, 120 is green.
	HSV.S = 1.0;
	HSV.V = 1.0;
 
	return HSVColor;
}

Much simpler.