Hi there! I was very excited to see that support for native sRGB handling was added to the repo a few weeks back. After doing some testing however I noticed that if you use sf::RenderTexture to draw anything anywhere between sampling the texture and drawing to the window, you get terrible color banding.
Here are three images rendered with different setups to illustrate the problem. The texture drawn is a simple 8 bits/channel gradient.
1. Texture is drawn to the RenderTexture via a Sprite, then the RenderTexture is drawn to the window via a Sprite.
ContextSettings.sRgbCapable is set to
false and
Texture.setSrgb is set to
false.
2. Texture is drawn directly to the window via a Sprite.
ContextSettings.sRgbCapable is set to
true and
Texture.setSrgb is set to
true.
3. Texture is drawn to the RenderTexture via a Sprite, then the RenderTexture is drawn to the window via a Sprite.
ContextSettings.sRgbCapable is set to
true and
Texture.setSrgb is set to
true.
As you can see the result suffers from banded colors, as expected of when storing gamma decoded values improperly.
I'm not that high on color space but it seems there is something missing where the RenderTexture should convert the input and output when rendering, just like the window does. I'm not sure if it can be remedied somehow, but I thought I should bring it to light.
Here's the code for the program shown above. Change the boolean at the top to toggle between using sRGB conversion or not.
#include <SFML/Graphics.hpp>
int main()
{
bool srgb = true;
sf::RenderWindow window;
sf::VideoMode videoMode;
videoMode.width = 720;
videoMode.height = 405;
sf::ContextSettings contextSettings;
contextSettings.sRgbCapable = srgb;
window.create(videoMode, "Linear Color Space Testing", sf::Style::Default, contextSettings);
sf::Texture texture;
texture.setSmooth(true);
texture.setSrgb(srgb);
texture.loadFromFile("Gradient.png");
sf::Sprite sprite;
sprite.setTexture(texture);
// Make sure the sprite fills the screen
float scale_x = (float)videoMode.width / (float)texture.getSize().x;
float scale_y = (float)videoMode.width / (float)texture.getSize().y;
sprite.setScale(scale_x, scale_y);
sf::RenderTexture renderTexture;
renderTexture.setSmooth(true);
renderTexture.create(videoMode.width, videoMode.height);
sf::Sprite renderTextureDrawable;
renderTextureDrawable.setTexture(renderTexture.getTexture());
while (window.isOpen())
{
// Poll events
sf::Event event;
while (window.pollEvent(event))
{
// Window closed
if (event.type == sf::Event::Closed || (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Key::Escape))
{
window.close();
}
}
// Clear render texture
renderTexture.clear(sf::Color(0, 0, 0, 255));
// Draw gradient sprite
renderTexture.draw(sprite);
// Finished drawing to render texture
renderTexture.display();
// Clear window
window.clear(sf::Color(0, 0, 0, 255));
// Draw render texture drawable
window.draw(renderTextureDrawable);
// Finished drawing to the window
window.display();
}
return 0;
}
And here's the gradient texture: