RGBHeightMap

Here is a terrain height map class I put together that uses an RGB index of 1537 colors instead of the usual 256 B&W range.  It produces nice, smooth terrains when scaled down a little.  I used blender to make the map.  Here is an example blend file: http://www.irishgrin.com/progs/heightmodelRGB.zip



The code is in two classes.

Here is the first one.


package (YOUR PACKAGE HERE)

import com.jmex.terrain.util.AbstractHeightMap;

import java.awt.Image;
import java.awt.Color;
import java.awt.image.PixelGrabber;

/**
 * RGBHeightMap creates a height map from an RGB image created with a specific heightmap gradient. 
 * It requires a square image.  Height values are read as follows:<br>
 * Black is the lowest value.  Then, the values ascend starting from black to
 * red, red to yellow, yellow to green, green to cyan, cyan to blue, blue to
 * white.  These values are indexed in the RGBIndexer.  There isn't much error
 * checking for the time being (bad programmer, no cookie).
 */
public class RGBHeightMap extends AbstractHeightMap
{
 
    public RGBHeightMap(Image RGBImage)
    {
        super();
       
        int width = 0, height = 0;
        int[] pixels;
       
        /* Don't mess with media tracker, just kep looking for the width and
           height until thry are > 0.  Not good if the image doesn't exist, but
           this is what I felt like to doing just to get it working. */
        while(width < 1 || height < 1)
        {
            width = RGBImage.getWidth(null);
            height = RGBImage.getHeight(null);
        }
       
        PixelGrabber pg = new PixelGrabber(RGBImage, 0, 0, -1, -1, true);
        try
        {
            pg.grabPixels();  
        }
        catch (InterruptedException e) {}
       
        size = width;
       
        pixels = (int[])pg.getPixels();
        heightData = new int[pixels.length];
       
        for(int i = 0; i < heightData.length; i++)
        {
            heightData[i] = RGBIndexer.getIndexer().getIndex(pixels[i]);
        }
       
    }
   
    public boolean load()
    {
        return true;
    }
}



and put this in the same package


package (YOUR PACKAGE HERE)

import java.awt.Color;
import java.awt.image.PixelGrabber;

import java.util.HashMap;

public class RGBIndexer
{
    private static final RGBIndexer indexer = new RGBIndexer();
   
    private HashMap colorIndexes = new HashMap();
   
    public static RGBIndexer getIndexer()
    {
        return indexer;
    }
   
    private RGBIndexer()
    {

        initHashMap();
       
    }
   
    private void initHashMap()
    {
        int r = 0, g = 0, b = 0;
        int iteration = 0;
        int index = 0;
       
        do
        {
            switch(iteration)
            {
                case 0: // Increase red values (black to red)
                    if(r <= 255)
                    {
                        setColorIndex(r, g, b, index);
                        r++;
                    }
                    else
                    {
                        iteration++;
                        r = 255;
                    }
                    break;
                case 1: // Increase green values
                    if(g < 255)
                    {
                        g++;
                        setColorIndex(r, g, b, index);
                    }
                    else
                    {
                        iteration++;
                    }
                    break;
                case 2: // Decrease red values
                    if(r > 0)
                    {
                        r--;
                        setColorIndex(r, g, b, index);
                    }
                    else
                    {
                        iteration++;
                    }
                    break;
                case 3: // Increase blue values
                    if(b < 255)
                    {
                        b++;
                        setColorIndex(r, g, b, index);
                    }
                    else
                    {
                        iteration++;
                    }
                    break;  
                case 4: // Decrease green values
                    if(g > 0)
                    {
                        g--;
                        setColorIndex(r, g, b, index);
                    }
                    else
                    {
                        iteration++;
                    }
                    break;
                case 5: // Increase red and green values
                    if((r < 255) && (g < 255))
                    {
                        r++; g++;
                        setColorIndex(r, g, b, index);
                    }
                    else
                    {
                        iteration++;
                    }
                    break;                    
            }
           
            index++;
        }
        while(iteration < 6);
        System.out.println(index);
    }
   
    private void setColorIndex(int r, int g, int b, int index)
    {
        Color c = new Color(r, g, b);
        colorIndexes.put(c.getRGB(),index);
    }
   
    public int getIndex(int rgb)
    {
        if(colorIndexes.containsKey(rgb))
        {
            Integer val = (Integer)colorIndexes.get(rgb);
            return val.intValue();
        }
       
        return -1;
    }
   
}



It may not be the most efficient right now, but it gets the job done.
I might make a blender tutorial if anyone is interested in how to make terrains for use with these classes (for those who can't figure it out from the example file).

just wondering… are there many programs using/generating rgb heigtmaps? it seems a little bit hard to work with them or edit them.

why not use 16 bit grayscale?

the most common formats for simple terrainheights are 8,16 and 32(float) -bit .raw files…many terrain editors exports and imports those formats…

the problem with raw is that you have to know the size of the image. that's the reason why i don't like them. they also aren't compressed.

mostly terrains are square so it's easy to find out, but if you want something else I understand your point…

This was more of an experiment for me.  Yeah, I could have used a 16-bit RAW exported from something like Terragen.  For someone a little strapped for cash right now though, I wrote this so I could export bigger than 512x512.

how is using rgb better than using a grayscale image?

they make for prettier pictures. :-p



darkfrog

Yeah, what darkfrog said. And It produces smoother terrains compared to 8bit greyscale.  If people don't want to use it, that's fine with me  :slight_smile:

That last statement drew a pretty gross picture in my head I'd give anything to forget…  :cry:



darkfrog

Ok, I changed it for you  XD

Could somebody take your code and do something like store normals on the RGB and on a alpha store a 8 bit hieght map.  Wouldn't that make a pretty picture and store the hieght map?  Just thinking outside the box

Glombool, thanks. :o

Patrick said:

Could somebody take your code and do something like store normals on the RGB and on a alpha store a 8 bit hieght map.  Wouldn't that make a pretty picture and store the hieght map?  Just thinking outside the box


Yea, why not?  I posted it here so people could use it as they wish (sorry for the late reply).