Hi! I'm trying to implemente Valve's paper about improved alpha testing (http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf) but unfortunately I'm not getting the results I was expecting. Have a look at the following image:
[attachment=35993:Screenshot_3.png]
I borrowed the image from here [http://www.codersnotes.com/notes/signed-distance-fields/]. At the right we have the source image. At the left we have the expected result. And in the middle my results. At first look it may seem as if the middle image is just overall darker than the correct one, but if you look closely you will notice some harsh transitions where the edge (the 'middle value', 0.5) should be. I can't really tell if it's a problem of how the value mapping is being done, or how the distance are being calculated. Below I leave a few of the key functions that I'm using:
Here is the main loop, InputData is an array of floats representing the grey values of an image (monochrome single channel).
void GenerateSDF()
{
for(int i=0; i< InputData.Length; i++)
{
int y = i/image_width;
int x = i % image_width;
float dist = findClosest(x,y);
//this writes the computed distance to an array of floats
set_output(x,y, dist);
}
}
Here is the function that calculates the minimum distance to a texel of the oposite color (as the paper indicates)
float findClosest(int current_x, int current_y)
{
float min_distance = 9999f;
//sample_raw_image just samples the InputData array, converting <x,y> coordinates into array index.
bool texel_outside = sample_raw_image(current_x, current_y) < 0.5f;
// texel_outside = true = black
// texel_outside = false = white
for(int i=0; i< image_width * image_height; i++)
{
int y = i /image_width;
int x = i % image_width;
// This function determines if the current texel being processed is of the oposite color
// than the reference pixel from the main loop. If it is then we calculate the nearest distance.
if(texel_is_oposite(texel_outside, x,y))
{
min_distance = get_min_distance(current_x, current_y, x, y, min_distance);
}
}
// if the texel is outside (is black) of the shape then we use positive distance.
return texel_outside? min_distance : -min_distance;
}
For clarity I also leave here the texel_is_oposite and the get_min_distance functions:
bool texel_is_oposite(bool texel_is_outside, int x, int y)
{
if(texel_is_outside && sample_raw_image(x,y)> 0.5f) //outside = black
return true;
if(!texel_is_outside && sample_raw_image(x,y)< 0.5f)//inside = white
return true;
return false;
}
float get_min_distance(float x1, float y1, float x2, float y2, float current_min)
{
float x = x2 - x1;
float y = y2 - y1;
float length = (float)Math.Sqrt(x * x + y * y);
return Math.Min(length, current_min);
}
Then after the output array is calculated, I proceed to calculte the minimum and maximum values of the entire output array, and map the values from the range minimum..maximum to -1..1 and then 0..1
float[] remap(float[] values)
{
float minimum = 9999f;
float maximum = -9999f;
float[] new_values = new float[values.Length];
for(int i=0; i< values.Length; i++)
{
minimum = Mathf.Min(values[i], minimum);
maximum = Mathf.Max(values[i], maximum);
}
for(int i=0; i< values.Length; i++)
{
// map converts a value from an initial range to a target range,
// in this case from minimum..maximum to -1..1
new_values[i] = map(minimum, maximum, -1f, 1f, values[i]) * 0.5f + 0.5f;
}
return new_values;
}
All that remains is to create an image with that array and display it on screen. Is there anything wrong with the code? Any help is greatly apreciated.
Also note that I'm using a brute-force approach, this is mainly because I want to understand with my own hands how the algorithm works, that's why I haven't used the algorithm described in the link I posted which is more efficient.
Cheers