Hi, I'm curently trying to develop a software renderer. For now i'm using a 256 color palette and it's fine for rendering flat triangles. Now i'm adding gouraud shading and i face a new problem :

I have one color per vertex in my triangles. But as the color is just an index in the palette, how can i interpolate these colors across the triangle ? Can i interpolate the indices ? Do i need to setup a special palette ? Or is it just impossible ?

PS: If you know some good tutorials/resources about software rendering i'm interested too.

Reedbeta
—
2007-05-11T13:59:11Z —
#2

You can't really do Gouraud shading with a palette.

Why are you working with a palette, anyway? Today's computers have more than enough memory, bandwidth, etc to work in full 32-bit color with no trouble. Honestly, palettes are kind of a throwback to 20 years ago.

EddyCharly
—
2007-05-11T14:08:33Z —
#3

I'm developing under DOS Lol, i'm kidding of course.

In fact i'm developing the renderer for an embedded device. I probably could use a 16, 24 or 32 bits true color format but i don't really need so much colors in my application. And as the memory capacity of the hardware is pretty low, i'd be happy if i could work with 8 bit color palettes.

Also, i would like to know if it's possible or not, just for my personnal knowledge. It seems to me that even in the old DOS days shading was possible. And in these old days, palette colors were frequently used. So there must be a way to do it.

Thanks.

Nils_Pipenbrinck
—
2007-05-11T14:22:08Z —
#4

You can load a special palette and treat your 8 bit per pixel as a color in packed 323 format. Exactly in the same way as you pack colors with 16 bit in the 565 format.

It will look ugly unless you add some dithering though.

SigKILL
—
2007-05-11T14:30:15Z —
#5

You typically use specialized pallettes that allow a few steps of gourard shading. An example would be Q1's palette (see http://www.gamers.org/dEngine/quake/wad\_conv/palette.html)). In the ol'days a few demos would do everything greyscaled to get good looking vertex lighting and gourard shading.

EddyCharly
—
2007-05-11T14:31:39Z —
#6

Hi nils. I'm going to give your solution a try. As you say i fear the result will look ugly. I'll have to read about dithering to see if it's practical because i don't really know what it is.

Thanks.

EddyCharly
—
2007-05-11T15:02:13Z —
#7

Hi SigKILL, I don't really see how the Q1's palette can be used for shading. Imagine i want to interpolate between green and red, how can the Q1's palette let me do this ? Could you elaborate a little bit please ?

Thanks.

Reedbeta
—
2007-05-11T15:11:55Z —
#8

You clearly can't interpolate between red and green with that palette. What you can do is interpolate between different shades of the same hue. As you see, there are enough colors to allow sort-of-decent interpolation from black to any of the basic hues in the palette. So, you can do white lights and give those hues to your triangles, but you probably can't really do colored lights, unless you pick a different palette.

SigKILL
—
2007-05-11T15:29:53Z —
#9

Ooops, sorry I was mistaking gouraud shading with smooth shades of the same color. My bad, just a freudian slip. The original message reminded me of a chat I had with an old demo-coder a few weeks ago...

EddyCharly
—
2007-05-11T18:57:39Z —
#10

Hi again. Now i'm back home, i reread this again and i have an idea

Well, in fact my problem is not directly related to lighting. I just want to interpolate between two random colors. What is interesting in the Q1's palette method is that it precomputes the transition from an indexed color to the black color. It's just what i want but only for 1 color, the black one. Now, if i precompute 256 of these maps, i have the shading transitions for all the pairs of colors. Generating the tables is easy with the fitting color algorithm, it's not fast but it's done only once at initialization. After that i just have a fixed steps of indexes for each pair of colors suposed to be shading nicely. Of course it's expensive. 1 meg of memory for just 16 transition steps for each pair of color... But with a 256 color palette, 16 is probably already too much.

Anyway, thanks for the great help. I don't know if i have the best method for doing what i wanted but at least now i have one

geon
—
2007-05-12T16:12:11Z —
#11

You should probably do what Nils sugested. But use a 332 palette instead of a 323, since the bit-depth really matters when you have so few colors.

I took the time to make a little comparision of the different palette options. Note how a 332 palette looks considerably better than the other options:

Hi geon. Thanks, i didn't think about that. I implemented the three formats (233, 323, and 332) and can't really decide wich one is better. It seems that the 332 format produces less "patterning", but the lack of precision in blue colors is uncomfortable to the eye. The 323 format is more comfortable to the eye, but it produces a lot of patterns.

The result is not bad, but it's a color cube, so it's tha best case for all faces, if i pick random colors for each vertex, the result is worse.

One question, at the moment, i propagate the color conversion error along the horyzontal spans from left to right. Would it be better to propagate it from top to bottom (or bottom to top) also ? Is it dithering ?

Once again, thanks.

Sol_HSA
—
2007-05-14T10:39:58Z —
#13

The way I did it Back In The Day would be to generate a (more or less) optimal palette for the target usage (for instance by rendering truecolor images and deriving the palette using median cut from those images), and then use a 64k lookup table to find the desired color in the palette from a 'virtual' truecolor value.

Ok, so basicly it's a table transforming colors from something like a color in RGB 656 format (64k -> 16 bits colors) into a color index in my palette, right ?

Sounds great, 64k of memory is not a problem, dithering is easy, and i can use any palette i want. I wonder how it will look when trying to interpolate between too rare colors in the palette though. Especially with dithering..

Thanks.

Rubicon
—
2007-05-14T14:33:59Z —
#16

Another option is to use only 16 main colours in your textures. You can make a single palette that then crossfades to all the other 16 colours just by addressing source colour as the first nibble nad dest colour as the second nibble.

Limits the source textures, but you'll get lovely fades. I guess it depends on where you want your fidelity. Working with a palette isn't going to give you much anywhere!

Look at older games such as speedball. The artists went with about 3 or 4 main colours and relied on nice fades for shading and it worked very well.

Nils_Pipenbrinck
—
2007-05-14T19:27:27Z —
#17

It looks like you're using some kind of error diffusion dithering. Try out ordered dithering with a 4x4 dither-kernel instead.

It'll look better. You get less weird patterns that way.

geon
—
2007-05-16T09:36:18Z —
#18

The method you use with the propagated error is indeed dithering. It's commonly known as error diffusion.

You can try 4x4 ordered ditherig also, like Nils sugests. I don't like the regular patterns it produces, but it might work better for you. (It's supposed to be faster, too.)

Also, make sure you you use realistic test-cases, and optimize for them.

While we're at dithering: I'd like to share my 16x16 optimized pseudo error diffusion dither-tables. I've calculated them with simulated annealing some years ago, and they are optimized for a flat frequency spectrum (e.g they make sure the dithered result has as least repeatable patterns as possible).

If you want an overkill of quality use a different one for each color channel