- Home /
Color a greyscale image using a gradient [SOLVED]
I asked this question on the forum aswell but i thought i might do it here as well.
Lets say i have a heightmap(greyscale) and i want to apply color to it using a gradient, like they do on this site HERE, in the middle of the page.
I got an answer on the forum which pointed me in what I think is the right direction. He said that i should make my gradient texture 1 pixel wide and 256 pixels tall (FIRST PROBLEM) and then load both my heightmap and gradient into seperate color arrays using GetPixels. Next he gave me a line of code to use:
for(var i=0; i<heightmapColors.Length; i++){
heightmapColors[i]=gradientColors[heightmapColors[i].r];
}
with this description: "read each pixel in your height map and replace it with a pixel that many bytes into the second array."
My problem is that when i try it his way i only end up with the lowest parts of the gradients color scale. Where 0.0 is blue and 256 is supposed to be grey (but now when the texture has to be 2x256 it is 512).
So my question is where do i go from here? And is there some other way to do this?
Answer by jester · Jun 29, 2011 at 06:36 PM
i haven't played with heightmaps yet, but my guess would be that if your heightmap doesn't span the entire range of its possible values, you'll only get the lowest color range from your gradient (or some contiguous band of color from within the gradient).
you could find the min/max height values you have in the heightmap and then normalize them from 0..1 and then multiply that by the number of colors in your gradient (256 for example) and then use those values when looking up the color. that should get you the entire range of colors from your gradient.
Answer by Ardan · Jun 29, 2011 at 07:31 PM
This is what i did, and the result isnt what i hoped for: using UnityEngine; using System.Collections; using System.IO;
public class terrainmap : MonoBehaviour {
public Texture2D heightmap;
public Texture2D gradient;
private Color[] heightmapColors;
private Color[] gradientColors;
void Start (){
heightmapColors = heightmap.GetPixels(0);
gradientColors = gradient.GetPixels(0);
colorize();
}
void colorize (){
Texture2D image= new Texture2D(heightmap.width, heightmap.height,TextureFormat.RGB24, false);
for(int i=0; i<heightmapColors.Length; i++){
float he = heightmapColors[i].g;
for(int j= 0; j<gradientColors.Length; j++) {
float gr = gradientColors[j].g;
if(he == gr) {
heightmapColors[i] = gradientColors[j];
heightmapColors[i].a = 1.0f;
}
}
}
image.SetPixels(heightmapColors, 0);
image.Apply();
byte[] bytes = image.EncodeToPNG();
Destroy(image);
File.WriteAllBytes("C:\\test.png", bytes);
}
}
And the result is this: Picture
Maybe i could make two gradients. One with the color, and that just goes from black to white. And then just take the cordinate of the current grey color and use the same position in the colored gradient?
just so i understand better, are you trying to reproduce the effect in that linked page exactly?
it looks like with the getpixels function (http://unity3d.com/support/documentation/ScriptReference/Texture2D.GetPixels.html), you should use a gradient that is 256 pixels wide and 2 pixels tall. but when you go back to reference that for a color, you should still use 256 as your max color index, not 512. using numbers greater than 256 would have you wrapping around from the last color to the first one, and that's not the effect you want.
in your colorize function, using just the G channel of the heightmap colors is fine because the R, G and B channels should all be the same value, but that won't be the case in the colored gradient.
ins$$anonymous$$d, i think you want to do something like: - get the heightmap G channel value (a value from 0..1) - get a color index by multiply that by your max color number (256 for example) - get the color from your gradient array at the color index number from above (you'll have to round or mathf.floor() that value)
that way, all of the pixels in your heightmap that are at the same height value will all end up with the same color from the gradient.
Answer by Ardan · Jun 29, 2011 at 10:17 PM
For anyone trying to figure this out aswell, here is my code:
using UnityEngine;
using System.Collections;
using System.IO;
public class terrainmap : MonoBehaviour {
public Texture2D heightmap;
public Texture2D gradientColor;
private Color[] heightmapArray;
private Color[] gradientArray;
void Start (){
heightmapArray = heightmap.GetPixels(0);
gradientArray = gradientColor.GetPixels(0);
colorize();
}
void colorize (){
Texture2D image= new Texture2D(heightmap.width, heightmap.height,TextureFormat.RGB24, false);
for(int i=0; i<heightmapArray.Length; i++){
float he = heightmapArray[i].b;
int color = (int)(he * 255.0f);
heightmapArray[i] = gradientArray[color];
}
image.SetPixels(heightmapArray, 0);
image.Apply();
Destroy(image);
File.WriteAllBytes("C:\\test.png", image.EncodeToPNG());
}
}
Answer by Rs · Nov 30, 2015 at 11:30 AM
There's this free resource that could be very useful in this particular case. https://github.com/rstecca/ColorBands
This will give you the chance to create your own color bands as assets and call an Evaluate method to get the color at position t, being t=0 the leftmost color and t=1 the rightmost color. It's ideal to remap values between 0 and 1 to a sequence of colors. Just make sure you normalize your values before giving them in.