RPGDXThe center of Indie-RPG gaming
Not logged in. [log in] [register]
 
 
Post new topic Reply to topic  
View previous topic - View next topic  
Author Message
tcaudilllg
Dragonmaster


Joined: 20 Jun 2002
Posts: 1731
Location: Cedar Bluff, VA

PostPosted: Sat Aug 02, 2014 10:12 pm    Post subject: New palette [quote]

Gonna make a new palette by interpolating the EGA colors. We'll see what happens.
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Sun Aug 03, 2014 10:25 pm    Post subject: [quote]

The old Sierra adventure games made extensive use of dithering to expand the range of the EGA colors - they just used regular checkerboard dithering. I did a test recently of what all the EGA colors looks like when dithered that way with each other, but also what it would look like if each dithered color was replaced with a solid color of the same perceived shade:



Perhaps it can be useful as a reference. I think it makes for a quite nice palette (though quite a lot of color entries)
_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
tcaudilllg
Dragonmaster


Joined: 20 Jun 2002
Posts: 1731
Location: Cedar Bluff, VA

PostPosted: Mon Aug 04, 2014 6:19 am    Post subject: [quote]

It doesn't have that many color entries... doesn't fill half the palette, in fact. Check this source and tell me if I erred:

Code:


<html>

<head>
<title>EGA Color Interpolator</title>

<script>

function makeColor (red, green, blue) {

   var newColor = {
      red: red,
      green: green,
      blue: blue
   };
   return newColor;
}

function searchRecord () {

   //alert(record.toSource());

   for (var index = 0; index < record.length; index++) {
      if (record[index] == dumpText) return false;
   }
   
   return true;

}

</script>


</head>

<canvas></canvas>

<pre id="Dump">

</pre>

<script>

   var palette = [];
   palette[0] = makeColor(0,0,0);
   palette[1] = makeColor(0,0,170);
   palette[2] = makeColor(0,170,0);
   palette[3] = makeColor(0,170,170);
   palette[4] = makeColor(170,0,0);
   palette[5] = makeColor(170,0,170);
   palette[6] = makeColor(170,85,0);
   palette[7] = makeColor(170,170,170);
   palette[8] = makeColor(85,85,85);
   palette[9] = makeColor(85,85,255);
   palette[10] = makeColor(85,255,85);
   palette[11] = makeColor(85,255,255);
   palette[12] = makeColor(255,85,85);
   palette[13] = makeColor(255,85,255);
   palette[14] = makeColor(255,255,85);
   palette[15] = makeColor(255,255,255);
   
   record = [];

   Painter = PaletteCanvas.getContext("2d");
   
   var x = 0;
   var y = 0;
   red = 0;
   green = 0;
   blue = 0;
   var colorStart = 0;
   var colorTotal = 0;
   dumpText = "";
   var dump = "";
   
   for (var EGAIndex = 0; EGAIndex < 16; EGAIndex++) {
 
      for (var colorIndex = EGAIndex; colorIndex < 16; colorIndex++) {
      
         //if (EGAIndex == colorIndex) continue;
         red = Math.floor((palette[EGAIndex].red + palette[colorIndex].red) / 2);
         green = Math.floor((palette[EGAIndex].green + palette[colorIndex].green) / 2);
         blue = Math.floor((palette[EGAIndex].blue + palette[colorIndex].blue) / 2);
         
         dumpText = red + "," + green + "," + blue;
         
         if (searchRecord()) {
         
            Painter.fillStyle = "rgb(" + red + "," + green + "," + blue + ")";
            Painter.fillRect(x, y, 2, 2);
            //x++;
            y += 2;
            colorTotal++;
            dumpText = red + "," + green + "," + blue;
            dump += dumpText + "<br>";
            record[record.length] = dumpText;
         }
      }
      //x = 0;
   }
   
   alert(colorTotal);
   Dump.innerHTML = dump;

</script>

</html>



This code produced 85 unique colors. But anyway you look at it, these palettes have major problems, particularly when it comes to grays. One thing I learned from studying Bahamut Lagoon is that the professionals use art shop tones: they take the time to try to tune their palettes to the colors of real paints. Increasingly I'm feeling. Now the palette above is probably excellent for high res art (much better than dither alone), but for low res it just doesn't look that great. Low res art is all about color and its blending... the beauty of the colors blending into each other unevenly, but clearly. Without vibrant color, low res art just looks bad, particularly at small scale (or else, cartoony).
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Mon Aug 04, 2014 3:46 pm    Post subject: [quote]

I totally agree, how you design your palette can be an essential component of the pixel art.

Your code looks fine - I think a simple average over R G B is what I did as well. However, it's worth keeping in mind that there's lots more ways it can be done - in linear instead of gamma corrected RGB, for examle. Or different color spaces all together, like HSV, HSB, YUV, Lab etc, all giving different results.
_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Mon Aug 04, 2014 3:54 pm    Post subject: [quote]

I find palettes fascinating, and have taken to saving interesting ones as I come across them. Not that this is a difficult reference to find, but thought I'd share anyway. Maybe it can serve as inspiration to someone.


_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
tcaudilllg
Dragonmaster


Joined: 20 Jun 2002
Posts: 1731
Location: Cedar Bluff, VA

PostPosted: Tue Aug 05, 2014 1:59 am    Post subject: [quote]

I took the algorithmic route myself. Those fail unless they are large, because luminosity gain is uneven across gradients due to the imperfection of VGA hardware. For example, 32 hue is barely even distinguishable from 0 hue, except in the case of gray. In the case of gray, hue differences are clearly perceptible. I think this is why there are so many spots dedicated to gray in most of the palettes you supplied, Mattias.

The Sierra palette's greens don't flow very well together, which makes their gradient for grass kind of uneven. It's much harder to describe grass and other plant life using 85-point luminosity jumps than with 32-point jumps. All in all, I'm finding that I spend more and more time just trying to compensate for limited color depth, when I could instead just go to the 4096 color palette and get my work looking pretty natural with near-zero effort.
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Tue Aug 05, 2014 6:25 am    Post subject: [quote]

Yes, the luminosity is not linear - thats because of the gamma ramp. To do the algoritmic approach, you should really work in linear color space for more accurate results. The difference can be quite big. For example, the grey value half way between white and black is 187, not 128 as one might think (luminosity-wise that is).

More details here http://filmicgames.com/archives/299
_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
tcaudilllg
Dragonmaster


Joined: 20 Jun 2002
Posts: 1731
Location: Cedar Bluff, VA

PostPosted: Thu Aug 07, 2014 2:51 am    Post subject: [quote]

Matthias that's very interesting. My takeaway from it is that a perfectly even gradient at low color depth would require a lot of mathematical analysis to create.


I created an HTML5 tool to generate palettes. Source is below.

Code:

<HTML><head><title>Palette Generator</title>

<script>


function generatePalette (factor) {

   var width = parseInt(Width.value);
   var height = parseInt(Height.value);
   
   var colorCount = (factor * width) + (factor * width);
   
   step = Math.floor(256 / factor);

      
   realFactor = factor + 1;
   paletteCanvas.width = width * (realFactor * realFactor);
   
var x = 0;
   var xStart = 0;
   var y = 0;
   var red = 0;
   var green = 0;
   var blue = 0;



   /* First formula: creates cubes of increasing red. Efficient and concise, but difficult to pick colors from along many gradients.
   for (red = 0; red < 257; red += step) {
   
      for (green = 0; green < 257; green += step) {
   
         for (blue = 0; blue < 257; blue += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y, width, height);
            x += width;
            //alert();
         }
         
         //alert();
      }
      x = 0;
//      xStart += width * (factor + 1);
      y += height;
    
   }*/
   
   
   var y1 = 0;
   var y2 = realFactor * width;
   var y3 = (realFactor * 2) * width;
   var y4 = (realFactor * 3) * width;
   var y5 = (realFactor * 4) * width;
   var y6 = (realFactor * 5) * width;
   var y7 = ((realFactor * 6) * width) + width;
   
   var x1 = 0;
   var x2 = 0;
   var x3 = 0;
   var x4 = 0;
   var x5 = 0;
   var x6 = 0;
   var x7 = 0;
   

   
      
      hue = 256;
      
      for (green = 0; green <= hue; green += step) {
   
         for (blue = 0; blue <= hue; blue += step) {
            x1 += width;
         }
      }

   paletteCanvas.width = x1;
   paletteCanvas.height = y7 + width;
   
   x1 = 0;
   
   
   for (hue = 0; hue < 257; hue += step) {
      
      red = hue;
      
      for (green = 0; green <= hue; green += step) {
   
         for (blue = 0; blue <= hue; blue += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y1, width, height);
            x += width;
            //x1 += width;
         }
      }
      y1 += width;
      x = 0;
      
      green = hue;
            
      for (red = 0; red <= hue; red += step) {
   
         for (blue = 0; blue <= hue; blue += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y2, width, height);
            x += width;
         }
      }
      y2 += width;
      x = 0;

      blue = hue;
            
      for (green = 0; green <= hue; green += step) {
   
         for (red = 0; red <= hue; red += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y3, width, height);
            x += width;
         }
      }
      y3 += width;
      x = 0;
      
      red = hue;
      green = hue;
            
         for (blue = 0; blue <= hue; blue += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y4, width, height);
            x += width;
         }
      y4 += width;
      x = 0;
         
      blue = hue;
      green = hue;
            
         for (red = 0; red <= hue; red += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y5, width, height);
            x += width;
         }
      y5 += width;
      x = 0;
         
      blue = hue;
      red = hue;
            
         for (green = 0; green <= hue; green += step) {

            paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
            paletteCanvas.context.fillRect(x, y6, width, height);
            x += width;
         }
      
      x = 0;
      y6 += width;
         
      blue = hue;
      red = hue;
      green = hue;
      
      paletteCanvas.context.fillStyle = "rgb(" + red + ", " + green + ", " + blue + ")";
      paletteCanvas.context.fillRect(x2, y7, width, height);
      x2 += width;
   }
   
}


</script></head>


Factor <input> Width <input> Height <input>

<input>
<input>
<br>
<div>
<canvas></canvas><script>paletteCanvas.context = paletteCanvas.getContext("2d");</script>

</div>


</HTML>


After some reflection, I realized that I do not have an objection to using large palettes. What I do have is an aversion to having to do a lot of cognitive calculation to perform simple tasks, such as choosing a color. I realized that I needed to separate the luminosity levels and the bands of color. This allows me to get the most color access with the least effort.
Back to top  
Post new topic Reply to topic Page 1 of 1 All times are GMT
 



Display posts from previous:   
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum