From Terry Welsh, "As I mentioned here
http://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg33967.html , interpolating through HSV space gives a rainbow color effect which does not mimic the simple RGB color interpolation that OpenGL does. It's overkill and causes unexpected visual artifacts. In the attached files I've removed the conversion to HSV so that interpolation happens in RGB space."
This commit is contained in:
@@ -397,10 +397,8 @@ protected:
|
||||
osg::Vec4 _colorGradientBottomRight;
|
||||
osg::Vec4 _colorGradientTopRight;
|
||||
|
||||
// Helper functions for color interpolation
|
||||
// Helper function for color interpolation
|
||||
float bilinearInterpolate(float x1, float x2, float y1, float y2, float x, float y, float q11, float q12, float q21, float q22) const;
|
||||
void convertHsvToRgb( float hsv[], float rgb[] ) const;
|
||||
void convertRgbToHsv( float rgb[], float hsv[] ) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1064,17 +1064,6 @@ void Text::computeColorGradientsOverall() const
|
||||
float max_x = FLT_MIN;
|
||||
float max_y = FLT_MIN;
|
||||
|
||||
float rgb_q11[3];
|
||||
float hsv_q11[3];
|
||||
float rgb_q12[3];
|
||||
float hsv_q12[3];
|
||||
float rgb_q21[3];
|
||||
float hsv_q21[3];
|
||||
float rgb_q22[3];
|
||||
float hsv_q22[3];
|
||||
|
||||
float rgb[3];
|
||||
float hsv[3];
|
||||
unsigned int i;
|
||||
|
||||
for(TextureGlyphQuadMap::const_iterator const_titr=_textureGlyphQuadMap.begin();
|
||||
@@ -1107,36 +1096,6 @@ void Text::computeColorGradientsOverall() const
|
||||
}
|
||||
}
|
||||
|
||||
rgb_q11[0] = _colorGradientBottomLeft[0];
|
||||
rgb_q11[1] = _colorGradientBottomLeft[1];
|
||||
rgb_q11[2] = _colorGradientBottomLeft[2];
|
||||
|
||||
rgb_q12[0] = _colorGradientTopLeft[0];
|
||||
rgb_q12[1] = _colorGradientTopLeft[1];
|
||||
rgb_q12[2] = _colorGradientTopLeft[2];
|
||||
|
||||
rgb_q21[0] = _colorGradientBottomRight[0];
|
||||
rgb_q21[1] = _colorGradientBottomRight[1];
|
||||
rgb_q21[2] = _colorGradientBottomRight[2];
|
||||
|
||||
rgb_q22[0] = _colorGradientTopRight[0];
|
||||
rgb_q22[1] = _colorGradientTopRight[1];
|
||||
rgb_q22[2] = _colorGradientTopRight[2];
|
||||
|
||||
// for linear interpolation to look correct
|
||||
// for colors and imitate what OpenGL does,
|
||||
// we need to convert over to Hue-Saturation-Value
|
||||
// and linear interpolate in that space.
|
||||
// HSV will interpolate through the color spectrum.
|
||||
// Now that I think about this, perhaps we could
|
||||
// extend this to use function pointers or something
|
||||
// so users may specify their own color interpolation
|
||||
// scales such as Intensity, or Heated Metal, etc.
|
||||
convertRgbToHsv(rgb_q11, hsv_q11);
|
||||
convertRgbToHsv(rgb_q12, hsv_q12);
|
||||
convertRgbToHsv(rgb_q21, hsv_q21);
|
||||
convertRgbToHsv(rgb_q22, hsv_q22);
|
||||
|
||||
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
||||
titr!=_textureGlyphQuadMap.end();
|
||||
++titr)
|
||||
@@ -1153,43 +1112,43 @@ void Text::computeColorGradientsOverall() const
|
||||
|
||||
for(i=0;i<numCoords;++i)
|
||||
{
|
||||
float hue = bilinearInterpolate(
|
||||
float red = bilinearInterpolate(
|
||||
min_x,
|
||||
max_x,
|
||||
min_y,
|
||||
max_y,
|
||||
coords2[i].x(),
|
||||
coords2[i].y(),
|
||||
hsv_q11[0],
|
||||
hsv_q12[0],
|
||||
hsv_q21[0],
|
||||
hsv_q22[0]
|
||||
_colorGradientBottomLeft[0],
|
||||
_colorGradientTopLeft[0],
|
||||
_colorGradientBottomRight[0],
|
||||
_colorGradientTopRight[0]
|
||||
);
|
||||
|
||||
float saturation = bilinearInterpolate(
|
||||
float green = bilinearInterpolate(
|
||||
min_x,
|
||||
max_x,
|
||||
min_y,
|
||||
max_y,
|
||||
coords2[i].x(),
|
||||
coords2[i].y(),
|
||||
hsv_q11[1],
|
||||
hsv_q12[1],
|
||||
hsv_q21[1],
|
||||
hsv_q22[1]
|
||||
_colorGradientBottomLeft[1],
|
||||
_colorGradientTopLeft[1],
|
||||
_colorGradientBottomRight[1],
|
||||
_colorGradientTopRight[1]
|
||||
);
|
||||
|
||||
float value = bilinearInterpolate(
|
||||
float blue = bilinearInterpolate(
|
||||
min_x,
|
||||
max_x,
|
||||
min_y,
|
||||
max_y,
|
||||
coords2[i].x(),
|
||||
coords2[i].y(),
|
||||
hsv_q11[2],
|
||||
hsv_q12[2],
|
||||
hsv_q21[2],
|
||||
hsv_q22[2]
|
||||
_colorGradientBottomLeft[2],
|
||||
_colorGradientTopLeft[2],
|
||||
_colorGradientBottomRight[2],
|
||||
_colorGradientTopRight[2]
|
||||
);
|
||||
// Alpha does not convert to HSV
|
||||
float alpha = bilinearInterpolate(
|
||||
@@ -1205,12 +1164,7 @@ void Text::computeColorGradientsOverall() const
|
||||
_colorGradientTopRight[3]
|
||||
);
|
||||
|
||||
hsv[0] = hue;
|
||||
hsv[1] = saturation;
|
||||
hsv[2] = value;
|
||||
// Convert back to RGB
|
||||
convertHsvToRgb(hsv, rgb);
|
||||
colorCoords[i] = osg::Vec4(rgb[0],rgb[1],rgb[2],alpha);
|
||||
colorCoords[i] = osg::Vec4(red,green,blue,alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1619,191 +1573,6 @@ float Text::bilinearInterpolate(float x1, float x2, float y1, float y2, float x,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** routines to convert between RGB and HSV
|
||||
**
|
||||
** Reference: Foley, van Dam, Feiner, Hughes,
|
||||
** "Computer Graphics Principles and Practices,"
|
||||
** Additon-Wesley, 1990, pp592-593.
|
||||
**/
|
||||
/*
|
||||
* FUNCTION
|
||||
* HsvRgb( hsv, rgb )
|
||||
*
|
||||
* DESCRIPTION
|
||||
* convert a hue-saturation-value into a red-green-blue value
|
||||
*
|
||||
* NOTE
|
||||
* Array sizes are 3
|
||||
* Values are between 0.0 and 1.0
|
||||
*/
|
||||
|
||||
void Text::convertHsvToRgb( float hsv[], float rgb[] ) const
|
||||
{
|
||||
float h, s, v; /* hue, sat, value */
|
||||
/* double delta; */ /* change in color value */
|
||||
float r, g, b; /* red, green, blue */
|
||||
float i, f, p, q, t; /* interim values */
|
||||
|
||||
|
||||
/* guarantee valid input: */
|
||||
|
||||
h = hsv[0] / 60.f;
|
||||
while( h >= 6.f ) h -= 6.f;
|
||||
while( h < 0.f ) h += 6.f;
|
||||
|
||||
s = hsv[1];
|
||||
if( s < 0.f )
|
||||
s = 0.f;
|
||||
if( s > 1.f )
|
||||
s = 1.f;
|
||||
|
||||
v = hsv[2];
|
||||
if( v < 0.f )
|
||||
v = 0.f;
|
||||
if( v > 1.f )
|
||||
v = 1.f;
|
||||
|
||||
|
||||
/* if sat==0, then is a gray: */
|
||||
|
||||
if( s == 0.0f )
|
||||
{
|
||||
rgb[0] = rgb[1] = rgb[2] = v;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* get an rgb from the hue itself: */
|
||||
|
||||
i = floor( h );
|
||||
f = h - i;
|
||||
p = v * ( 1.f - s );
|
||||
q = v * ( 1.f - s*f );
|
||||
t = v * ( 1.f - ( s * (1.f-f) ) );
|
||||
|
||||
switch( (int) i )
|
||||
{
|
||||
case 0:
|
||||
r = v; g = t; b = p;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
r = q; g = v; b = p;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
r = p; g = v; b = t;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
r = p; g = q; b = v;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
r = t; g = p; b = v;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
r = v; g = p; b = q;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* never happens? */
|
||||
r = 0; g = 0; b = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
rgb[0] = r;
|
||||
rgb[1] = g;
|
||||
rgb[2] = b;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* FUNCTION
|
||||
* RgbHsv
|
||||
*
|
||||
* DESCRIPTION
|
||||
* convert a red-green-blue value into hue-saturation-value
|
||||
*
|
||||
* NOTE
|
||||
* Array sizes are 3
|
||||
* Values are between 0.0 and 1.0
|
||||
*/
|
||||
|
||||
void Text::convertRgbToHsv( float rgb[], float hsv[] ) const
|
||||
{
|
||||
float r, g, b; /* red, green, blue */
|
||||
float min, max; /* min and max rgb values */
|
||||
float fmin, fmax, diff; /* min, max, and range of rgb vals */
|
||||
float hue, sat, value; /* h s v */
|
||||
float cr, cg, cb; /* coefficients for computing hue */
|
||||
|
||||
|
||||
/* determine min and max color primary values: */
|
||||
|
||||
r = rgb[0]; g = rgb[1]; b = rgb[2];
|
||||
min = r; max = r;
|
||||
if( g < min ) min = g;
|
||||
if( g > max ) max = g;
|
||||
if( b < min ) min = b;
|
||||
if( b > max ) max = b;
|
||||
|
||||
fmin = min;
|
||||
fmax = max;
|
||||
diff = fmax - fmin;
|
||||
|
||||
|
||||
/* get value and saturation: */
|
||||
|
||||
value = fmax;
|
||||
if( max == 0.f )
|
||||
sat = 0.0f;
|
||||
else
|
||||
sat = diff/fmax;
|
||||
|
||||
|
||||
|
||||
/* compute hue: */
|
||||
|
||||
if( sat == 0.0f )
|
||||
hue = 0.0f;
|
||||
else
|
||||
{
|
||||
float inv_diff = 1.0f / diff;
|
||||
cr = ( fmax-r ) * inv_diff;
|
||||
cg = ( fmax-g ) * inv_diff;
|
||||
cb = ( fmax-b ) * inv_diff;
|
||||
|
||||
if( max == r )
|
||||
hue = (g-b) * inv_diff;
|
||||
else if( max == g )
|
||||
hue = 2.f + (b-r) * inv_diff;
|
||||
else if( max == b )
|
||||
hue = 4.f + (r-g) * inv_diff;
|
||||
else
|
||||
hue = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
hue *= 60.0f;
|
||||
if( hue < 0.0f )
|
||||
hue += 360.0f;
|
||||
if( hue > 360.0f )
|
||||
hue -= 360.0f;
|
||||
|
||||
|
||||
/* store output values: */
|
||||
|
||||
hsv[0] = hue;
|
||||
hsv[1] = sat;
|
||||
hsv[2] = value;
|
||||
|
||||
}
|
||||
|
||||
void Text::drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const
|
||||
{
|
||||
unsigned int contextID = state.getContextID();
|
||||
|
||||
Reference in New Issue
Block a user