Sunday, 14 November 2010
RGB/HSV in HLSL
float3 HSVtoRGB(float3 HSV)
{
float3 RGB = 0;
float C = HSV.z * HSV.y;
float H = HSV.x * 6;
float X = C * (1 - abs(fmod(H, 2) - 1));
if (HSV.y != 0)
{
float I = floor(H);
if (I == 0) { RGB = float3(C, X, 0); }
else if (I == 1) { RGB = float3(X, C, 0); }
else if (I == 2) { RGB = float3(0, C, X); }
else if (I == 3) { RGB = float3(0, X, C); }
else if (I == 4) { RGB = float3(X, 0, C); }
else { RGB = float3(C, 0, X); }
}
float M = HSV.z - C;
return RGB + M;
}
float3 RGBtoHSV(float3 RGB)
{
float3 HSV = 0;
float M = min(RGB.r, min(RGB.g, RGB.b));
HSV.z = max(RGB.r, max(RGB.g, RGB.b));
float C = HSV.z - M;
if (C != 0)
{
HSV.y = C / HSV.z;
float3 D = (((HSV.z - RGB) / 6) + (C / 2)) / C;
if (RGB.r == HSV.z)
HSV.x = D.b - D.g;
else if (RGB.g == HSV.z)
HSV.x = (1.0/3.0) + D.r - D.b;
else if (RGB.b == HSV.z)
HSV.x = (2.0/3.0) + D.g - D.r;
if ( HSV.x < 0.0 ) { HSV.x += 1.0; }
if ( HSV.x > 1.0 ) { HSV.x -= 1.0; }
}
return HSV;
}
Even to my eyes, these looked far than optimal. However, a quick glance at the HSV graph on the Wiki page suggests an optimisation for 'HSVtoRGB' which doesn't involve branching or conditional predicates.
float3 Hue(float H)
{
float R = abs(H * 6 - 3) - 1;
float G = 2 - abs(H * 6 - 2);
float B = 2 - abs(H * 6 - 4);
return saturate(float3(R,G,B));
}
float3 HSVtoRGB(in float3 HSV)
{
return ((Hue(HSV.x) - 1) * HSV.y + 1) * HSV.z;
}
This is particularly efficient because 'abs' and 'saturate' are "free" operations on a lot of GPU pipelines.
The reverse conversion is a bit more tricky, and if you're really obsessed with performance on Xbox360, or the like, you'll need to drop down into shader assembler to utilise the vector 'max4' instruction instead of the scalar alternatives:
float3 RGBtoHSV(in float3 RGB)
{
float3 HSV = 0;
#if NO_ASM
HSV.z = max(RGB.r, max(RGB.g, RGB.b));
float M = min(RGB.r, min(RGB.g, RGB.b));
float C = HSV.z - M;
#else
float4 RGBM = RGB.rgbr;
asm { max4 HSV.z, RGBM };
asm { max4 RGBM.w, -RGBM };
float C = HSV.z + RGBM.w;
#endif
if (C != 0)
{
HSV.y = C / HSV.z;
float3 Delta = (HSV.z - RGB) / C;
Delta.rgb -= Delta.brg;
Delta.rg += float2(2,4);
if (RGB.r >= HSV.z)
HSV.x = Delta.b;
else if (RGB.g >= HSV.z)
HSV.x = Delta.r;
else
HSV.x = Delta.g;
HSV.x = frac(HSV.x / 6);
}
return HSV;
}
Although we haven't managed to get rid of the 'if' statements, they typically compile down to one conditionally predicated block and two conditional assignments.
Even against the startlingly successful optimisations produced by the current batch of HLSL compilers, these refactorings produce excellent results. The round-trip conversions (RGB-to-HSV-to-RGB) are typically three times faster than the simplistic implementations. For a pixel shader, that's not to be sneezed at.
Sunday, 7 November 2010
SketchUp to Reality
The real-life results are surprisingly close to the plans I put together back in March 2010:
Saturday, 6 November 2010
ZX Spectrum Fine Art
But, even today, people still dabble in the arcane skills involved in getting something half-decent out of the huge constraints. As a quick exercise, I looked for an iconic painting to recreate in ZX Spectrum graphics. Something simplistic with blocks of solid colour would be ideal. I chose David Hockney's "A Bigger Splash":
Oh dear...

Sunday, 26 September 2010
Gratuitous Aphorism #3
Doctor: Well, don't do it, then!
Saturday, 4 September 2010
Samsung N220 Netbook
New hardware here at chez chilliant. I cute, little 10.1" netbook from Samsung. As is my wont, I researched the marketplace quite thoroughly, so I had to set myself a budget of £300 to prune the options. My requirements came down to:
- Small size,
- Good build quality,
- Enough computing power to pursue hobby programming,
- Ability to playback videos easily,
- Good battery life.
The UK version of the Samsung N220 ticks all the right boxes, not least because it has a Broadcom CrystalHD Decoder built-in, unlike its foreign cousins, bizarrely. It means I can copy recorded programmes directly from my Topfield TF5800 PVR and play them back at native resolution (720x576 or 1024x576) with no lost frames and good (backlit LED) display.
The keyboard is a little under-size, so takes a lot of getting use to, particularly the tiny cursor keys, but I'm typing this (on a train) with not too much trouble.
With a battery life of supposedly up to 12 hours (I get about 7 hours with my usage profile), it's not disastrous if I forget to plug it back into the mains of an evening after a few days of commuting. Interestingly, after punting around in the Control Panel and settings, I came across a BIOS setting to only charge the 6-cell battery to 80% capacity in order to extend the lifetime of the battery pack. The very fact that this is a BIOS setting suggests that modern computers do a lot more when "switched off" than I ever imagined.
Thursday, 8 July 2010
Thursday, 17 June 2010
Unifont

- Ian Taylor
- ...




