Merge pull request #7752 from Geenz/master

Correction To sRGB Conversions
This commit is contained in:
Brad Hefta-Gaub 2016-05-03 08:01:51 -07:00
commit eb209c7483
9 changed files with 91 additions and 34 deletions

View file

@ -49,7 +49,7 @@ public:
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
glm::vec3 getColorRGB() const { return ColorUtils::toLinearVec3(toGlm(getXColor())); }
glm::vec3 getColorRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(getXColor())); }
static const xColor DEFAULT_COLOR;
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
@ -62,17 +62,17 @@ public:
bool _isColorStartInitialized = false;
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorStart)) : getColorRGB(); }
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_colorStart)) : getColorRGB(); }
bool _isColorFinishInitialized = false;
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorFinish)) : getColorRGB(); }
glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::sRGBToLinearVec3(toGlm(_colorFinish)) : getColorRGB(); }
static const xColor DEFAULT_COLOR_SPREAD;
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
xColor getColorSpread() const { return _colorSpread; }
glm::vec3 getColorSpreadRGB() const { return ColorUtils::toLinearVec3(toGlm(_colorSpread)); }
glm::vec3 getColorSpreadRGB() const { return ColorUtils::sRGBToLinearVec3(toGlm(_colorSpread)); }
static const float MAXIMUM_ALPHA;
static const float MINIMUM_ALPHA;

View file

@ -11,9 +11,14 @@
<@if not GPU_COLOR_SLH@>
<@def GPU_COLOR_SLH@>
float sRGBFloatToLinear(float value) {
const float SRGB_ELBOW = 0.04045;
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
}
vec3 colorToLinearRGB(vec3 srgb) {
const float GAMMA_22 = 2.2;
return pow(srgb, vec3(GAMMA_22));
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b));
}
vec4 colorToLinearRGBA(vec4 srgba) {

View file

@ -11,6 +11,7 @@
using namespace gpu;
const Element Element::COLOR_RGBA_32{ VEC4, NUINT8, RGBA };
const Element Element::COLOR_SRGBA_32{ VEC4, NUINT8, SRGBA };
const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA };
const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };

View file

@ -245,6 +245,7 @@ public:
}
static const Element COLOR_RGBA_32;
static const Element COLOR_SRGBA_32;
static const Element VEC4F_COLOR_RGBA;
static const Element VEC2F_UV;
static const Element VEC2F_XY;

View file

@ -18,6 +18,8 @@
#include "GPULogging.h"
#include "Context.h"
#include "ColorUtils.h"
using namespace gpu;
static int TexturePointerMetaTypeId = qRegisterMetaType<TexturePointer>();
@ -637,18 +639,6 @@ void SphericalHarmonics::assignPreset(int p) {
}
}
glm::vec3 sRGBToLinear(glm::vec3& color) {
const float GAMMA_CORRECTION = 2.2f;
return glm::pow(color, glm::vec3(GAMMA_CORRECTION));
}
glm::vec3 linearTosRGB(glm::vec3& color) {
const float GAMMA_CORRECTION_INV = 1.0f / 2.2f;
return glm::pow(color, glm::vec3(GAMMA_CORRECTION_INV));
}
// Originial code for the Spherical Harmonics taken from "Sun and Black Cat- Igor Dykhta (igor dykhta email) <20> 2007-2014 "
void sphericalHarmonicsAdd(float * result, int order, const float * inputA, const float * inputB) {
const int numCoeff = order * order;
@ -803,7 +793,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
float(data[pixOffsetIndex+2]) * UCHAR_TO_FLOAT);
// Gamma correct
clr = sRGBToLinear(clr);
clr = ColorUtils::sRGBToLinearVec3(clr);
// scale color and add to previously accumulated coefficients
sphericalHarmonicsScale(shBuffB.data(), order,

View file

@ -65,7 +65,7 @@ Material::~Material() {
void Material::setEmissive(const Color& emissive, bool isSRGB) {
_key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f))));
_schemaBuffer.edit<Schema>()._key = (uint32) _key._flags.to_ulong();
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive);
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::sRGBToLinearVec3(emissive) : emissive);
}
void Material::setOpacity(float opacity) {
@ -77,7 +77,7 @@ void Material::setOpacity(float opacity) {
void Material::setAlbedo(const Color& albedo, bool isSRGB) {
_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
_schemaBuffer.edit<Schema>()._albedo = (isSRGB ? ColorUtils::toLinearVec3(albedo) : albedo);
_schemaBuffer.edit<Schema>()._albedo = (isSRGB ? ColorUtils::sRGBToLinearVec3(albedo) : albedo);
}
void Material::setRoughness(float roughness) {
@ -89,7 +89,7 @@ void Material::setRoughness(float roughness) {
void Material::setFresnel(const Color& fresnel, bool isSRGB) {
//_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
_schemaBuffer.edit<Schema>()._fresnel = (isSRGB ? ColorUtils::toLinearVec3(fresnel) : fresnel);
_schemaBuffer.edit<Schema>()._fresnel = (isSRGB ? ColorUtils::sRGBToLinearVec3(fresnel) : fresnel);
}
void Material::setMetallic(float metallic) {

View file

@ -245,16 +245,16 @@ public:
const MaterialKey& getKey() const { return _key; }
void setEmissive(const Color& emissive, bool isSRGB = true);
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
void setOpacity(float opacity);
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
void setAlbedo(const Color& albedo, bool isSRGB = true);
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
void setFresnel(const Color& fresnel, bool isSRGB = true);
Color getFresnel(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._fresnel) : _schemaBuffer.get<Schema>()._fresnel); }
Color getFresnel(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._fresnel) : _schemaBuffer.get<Schema>()._fresnel); }
void setMetallic(float metallic);
float getMetallic() const { return _schemaBuffer.get<Schema>()._metallic; }

View file

@ -363,7 +363,7 @@ void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, c
batch._glUniform1i(_outlineLoc, (effectType == OUTLINE_EFFECT));
// need the gamma corrected color here
glm::vec4 lrgba = glm::vec4(ColorUtils::toLinearVec3(glm::vec3(*color)), color->a);
glm::vec4 lrgba = ColorUtils::sRGBToLinearVec4(*color);
batch._glUniform4fv(_colorLoc, 1, (const float*)&lrgba);
batch.setInputFormat(_format);

View file

@ -21,9 +21,19 @@ class ColorUtils {
public:
inline static glm::vec3 toVec3(const xColor& color);
// Convert from gamma 2.2 space to linear
inline static glm::vec3 toLinearVec3(const glm::vec3& srgb);
// Convert to gamma 2.2 space from linear
inline static glm::vec3 toGamma22Vec3(const glm::vec3& linear);
// Convert from sRGB gamma space to linear.
// This is pretty different from converting from 2.2.
inline static glm::vec3 sRGBToLinearVec3(const glm::vec3& srgb);
inline static glm::vec3 tosRGBVec3(const glm::vec3& srgb);
inline static glm::vec4 sRGBToLinearVec4(const glm::vec4& srgb);
inline static glm::vec4 tosRGBVec4(const glm::vec4& srgb);
inline static float sRGBToLinearFloat(const float& srgb);
inline static float tosRGBFloat(const float& linear);
};
inline glm::vec3 ColorUtils::toVec3(const xColor& color) {
@ -31,16 +41,66 @@ inline glm::vec3 ColorUtils::toVec3(const xColor& color) {
return glm::vec3(color.red * ONE_OVER_255, color.green * ONE_OVER_255, color.blue * ONE_OVER_255);
}
inline glm::vec3 ColorUtils::toLinearVec3(const glm::vec3& srgb) {
const float GAMMA_22 = 2.2f;
// Couldn't find glm::pow(vec3, vec3) ? so did it myself...
return glm::vec3(glm::pow(srgb.x, GAMMA_22), glm::pow(srgb.y, GAMMA_22), glm::pow(srgb.z, GAMMA_22));
}
inline glm::vec3 ColorUtils::toGamma22Vec3(const glm::vec3& linear) {
const float INV_GAMMA_22 = 1.0f / 2.2f;
// Couldn't find glm::pow(vec3, vec3) ? so did it myself...
return glm::vec3(glm::pow(linear.x, INV_GAMMA_22), glm::pow(linear.y, INV_GAMMA_22), glm::pow(linear.z, INV_GAMMA_22));
}
// Convert from sRGB color space to linear color space.
inline glm::vec3 ColorUtils::sRGBToLinearVec3(const glm::vec3& srgb) {
return glm::vec3(sRGBToLinearFloat(srgb.x), sRGBToLinearFloat(srgb.y), sRGBToLinearFloat(srgb.z));
}
// Convert from linear color space to sRGB color space.
inline glm::vec3 ColorUtils::tosRGBVec3(const glm::vec3& linear) {
return glm::vec3(tosRGBFloat(linear.x), tosRGBFloat(linear.y), tosRGBFloat(linear.z));
}
// Convert from sRGB color space with alpha to linear color space with alpha.
inline glm::vec4 ColorUtils::sRGBToLinearVec4(const glm::vec4& srgb) {
return glm::vec4(sRGBToLinearFloat(srgb.x), sRGBToLinearFloat(srgb.y), sRGBToLinearFloat(srgb.z), srgb.w);
}
// Convert from linear color space with alpha to sRGB color space with alpha.
inline glm::vec4 ColorUtils::tosRGBVec4(const glm::vec4& linear) {
return glm::vec4(tosRGBFloat(linear.x), tosRGBFloat(linear.y), tosRGBFloat(linear.z), linear.w);
}
// This is based upon the conversions found in section 8.24 of the OpenGL 4.4 4.4 specification.
// glm::pow(color, 2.2f) is approximate, and will cause subtle differences when used with sRGB framebuffers.
inline float ColorUtils::sRGBToLinearFloat(const float &srgb) {
const float SRGB_ELBOW = 0.04045f;
float linearValue = 0.0f;
// This should mirror the conversion table found in section 8.24: sRGB Texture Color Conversion
if (srgb <= SRGB_ELBOW) {
linearValue = srgb / 12.92f;
} else {
linearValue = powf(((srgb + 0.055f) / 1.055f), 2.4f);
}
return linearValue;
}
// This is based upon the conversions found in section 17.3.9 of the OpenGL 4.4 specification.
// glm::pow(color, 1.0f/2.2f) is approximate, and will cause subtle differences when used with sRGB framebuffers.
inline float ColorUtils::tosRGBFloat(const float &linear) {
const float SRGB_ELBOW_INV = 0.0031308f;
float sRGBValue = 0.0f;
// This should mirror the conversion table found in section 17.3.9: sRGB Conversion
if (linear <= 0.0f) {
sRGBValue = 0.0f;
} else if (0 < linear && linear < SRGB_ELBOW_INV) {
sRGBValue = 12.92f * linear;
} else if (SRGB_ELBOW_INV <= linear && linear < 1) {
sRGBValue = 1.055f * powf(linear, 0.41666f - 0.055f);
} else {
sRGBValue = 1.0f;
}
return sRGBValue;
}
#endif // hifi_ColorUtils_h