Not logged in, Join Here! or Log In Below:  
News Articles Search    

 Home / 3D Theory & Graphics / Color Interpolation problem [software renderer] Account Manager
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.

April 22, 2005, 01:46 PM

Hi @ll

I am doing a software renderer 3D engine in C + WinAPI DIBs and i have a little problem with the color interpolation algorithm. No problem in 32 bits color mode but the 16 bits color is awful..although my color interpolation algorithm is classical ( works well in 32 bits TrueColor mode ).

I use fixed point maths for delta values, this is not the source of the problem, wich is the same with floating point values.

deltaR = (r2 - r1) / (d2 - d1)
deltaG = (g2 - g1) / (d2 - d1)
deltaB = (b2 - b1) / (d2 - d1)

r = r1;
g = g1;
b = b1;

r = r + i * deltaR;
g = r + i * deltaG;
b = r + i * deltaB;

y convert my values like this :

RGBTO565(r,g,b) (((r>>3)2)3)) in 16 bpp mode
RGBTO565(r,g,b) (((r>>3)3)3)) in 15 bpp mode
RGBTO888(r,g,b) ((r


April 22, 2005, 02:06 PM

The problem comes from the limited precision of the output... 16 bits is just too little to actually create smooth gradients (just think about it... if you have got 5 bits for each color, you got 2 ^ 5 different grey tones, which is 32 different colors)

You might however improve by using one of the various dither methods available, just google for dithering or similiar.

- Wernaeh

Julio Gorgé

April 22, 2005, 03:55 PM

I suggest you searching for dithering at the Wikipedia(.org)


April 22, 2005, 05:21 PM

Thank you all.
I am going to look for documentation about dithering.


April 22, 2005, 05:30 PM

One of the best ways to get good quality 16 bit output is to just render in 32 bit, and then convert to 16 bit during the blt to the frontbuffer (this can be done by most hardware).
Especially alphablending will be much better than with direct 16 bit rendering.


April 23, 2005, 06:00 AM

I use a software named C4D which has a software renderer engine and an opengl engine.

The software renderer engine displays beautiful smoothing even in 16 bit mode. I am not sure they use dithering, it doesnt look like dithering.

What is your opinion about their method, how do they do that :

Victor Widell

April 23, 2005, 07:15 AM

The dithering would probably not be visible in a JPG, since the fine details (the noise in this case) will be lost in the compression.

Anyway, it is impossible to display smooth gradients in 16 bits without some kind of dithering. Just open up that test image in photoshop (or similar) and convert it to indexed, 32 colors. Ugly.

The image you posted still seems to be dithered, but in 32 bits... (Maby just an artifact, but it would really be usefull for images with big areas of just a tiny gradient.)

Erik Faye-Lund

April 23, 2005, 10:15 AM

r = r + i * deltaR;
g = r + i * deltaG;
b = r + i * deltaB;

shouldn't this be

r = r + deltaR;
g = r + deltaG;
b = r + deltaB;


i'm assuming you're doing forward differencing of linear interpolation...


April 23, 2005, 12:37 PM

Oops i made a mistake in the posted code ( but none in my C code ).

You should read of course :

r = r1 + i * deltaR;
g = r1 + i * deltaG;
b = r1 + i * deltaB;


April 24, 2005, 04:41 AM

just to be sure:

the suggested code by Erik is a lot faster then the actual code by you (at least on a lot of architectures).

Having a multiplication (or even worse: a division) in an innerloop is something you typically want to avoid.

Your innerloop has 3 multiplications where a simple addition would have sufficed.

Both methods however suffer from a cumulative error, where the color at the end of the span might actually be somewhat different then the intended color. This is for a lot of purposes not relevant, but if you really want the best possible picture quality you should do it differently, but at an enormous speed penalty.

  3. //Your original version. suffers from cumulative error and slow
  4. FOR i = 0 to LINEWIDTH
  5. r = r1 + i * deltaR;
  6. g = g1 + i * deltaG;
  7. b = b1 + i * deltaB;
  8. END FOR
  10. //Same as above with cumulative error, yet a lot faster and perfect for realtime
  11. FOR i = 0 to LINEWIDTH
  12. r = r + deltaR;
  13. g = g + deltaG;
  14. b = b + deltaB;
  15. END FOR
  18. //incredibly slow yet accurate version (beware of number overflow)
  19. FOR i = 0 to LINEWIDTH
  20. r = ((r2-r1)*i)/(d2 - d1)
  21. g = ((g2-g1)*i)/(d2 - d1)
  22. b = ((b2-b1)*i)/(d2 - d1)
  23. END FOR



p.s. still this has allmost nothing to do with the 'banding' you see in your 16bit picture... The banding looks better with the accurte version posted above but that still will look like colorbanding... the only way around this on 16bit devices is to use dithering where intentional color errors will hide the sudden color changes


April 24, 2005, 11:43 AM


I tested a pretty simple dithering algorithm to test the smoothing performance, it's not so bad :

The first half of the window is not dithered, the second half of the window is dithered.

For now it works only with a 255 length line, I need to improve it for every situation. The technique I used is not very difficult, just an array of color like that :

  2. unsigned char grayscale[256] = { 0,1,0,1,0,1,0,1,
  3.                                  1,2,1,2,1,2,1,2,
  4.                                  2,3,2,3,2,3,2,3,
  5.                                  3,4,3,4,3,4,3,4,
  6.                                  4,5,4,5,4,5,4,5,
  7.                                  5,6,5,6,5,6,5,6,
  8.                                  6,7,6,7,6,7,6,7,
  9.                                  7,8,7,8,7,8,7,8,
  10.                                  8,9,8,9,8,9,8,9,
  11.                                  9,10,9,10,9,10,9,10,
  12.                                  10,11,10,11,10,11,10,11,
  13.                                  11,12,11,12,11,12,11,12,
  14.                                  12,13,12,13,12,13,12,13,
  15.                                  13,14,13,14,13,14,13,14,
  16.                                  14,15,14,15,14,15,14,15,
  17.                                  15,16,15,16,15,16,15,16,
  18.                                  16,17,16,17,16,17,16,17,
  19.                                  17,18,17,18,17,18,17,18,
  20.                                  18,19,18,19,18,19,18,19,
  21.                                  19,20,19,20,19,20,19,20,
  22.                                  20,21,20,21,20,21,20,21,
  23.                                  21,22,21,22,21,22,21,22,
  24.                                  22,23,22,23,22,23,22,23,
  25.                                  23,24,23,24,23,24,23,24,
  26.                                  24,25,24,25,24,25,24,25,
  27.                                  25,26,25,26,25,26,25,26,
  28.                                  26,27,26,27,26,27,26,27,
  29.                                  27,28,27,28,27,28,27,28,
  30.                                  28,29,28,29,28,29,28,29,
  31.                                  29,30,29,30,29,30,29,30,
  32.                                  30,31,30,31,30,31,30,31,
  33.                                  31,31,31,31,31,31,31,31 };

When drawing an horizontal line, the first line start at X offset 0, the second at X offset 4, the third at X offset 0, the fourth at X offset 4 etc...
The goal is to have a fast algorithm without any heavy computation.


April 24, 2005, 12:43 PM

I'm not sure, but doesn't this method give the same ugly banding results when zoomed in to extreme detail?

since your dither table is linked to the 255 gray values, when you zoom in to extreme levels, the dithering table is zoomed in too. This is something you don't want.

similarly, if you zoom out, you might get very strange dithering patterns going over the picture.



April 24, 2005, 12:49 PM

Yes you are right.

Nils Pipenbrinck

April 24, 2005, 12:49 PM

If you want something fast look for ordered dithering.

I would not mind to much about the banding artifacts though. Once you add textures and blend it with the diffuse color the artifacts will be a lot less visible.


April 24, 2005, 01:17 PM

I believe that there is something called super-smooth blending or something like that...

In that algorithm, you don't blend all the colors in one step, but you "take turns" blending the RGB values.

If you wanna go from 0,0,0 to 10,10,10:
normally you go
0,0,0 - 1,1,1 - 2,2,2 - 3,3,3 - ...

but you could also go

0,0,0 - 0,1,0 - 1,1,0 - 1,1,1 - 1,2,1, - 2,2,1 - 2,2,2 - ....

You get "more" steps this way, and I believe it gives a smoother effect.

I dunno for sure, but maybe you could give it a try...


April 24, 2005, 01:24 PM

Wouldn't that create color bands in an otherwise monochromatic gradient ?

Victor Widell

April 25, 2005, 05:21 AM

Theoretically, yes. But the slight difference in hue is much less noticable than the otherwise much more steep changes in light intensity. Especially if the image is dithered.

This thread contains 17 messages.
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.