Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a linear color space when rendering #3156

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions data/shaders/planet.frag
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ void main()
{
// We are drawing the Sun
vec4 texColor = texture2D(tex, texc);
texColor.rgb = srgbToLinear(texColor.rgb * sunInfo.rgb);
texColor.rgb = texColor.rgb * srgbToLinear(sunInfo.rgb);
// Reference: chapter 14.7 "Limb Darkening" in "Allen’s Astrophysical Quantities",
// A.N.Cox (ed.), 4th edition, New York: Springer-Verlag, 2002.
// DOI 10.1007/978-1-4612-1186-0
Expand All @@ -189,7 +189,7 @@ void main()
float cosTheta2 = cosTheta*cosTheta;
vec3 limbDarkeningCoef = a0 + a1*cosTheta + a2*cosTheta2;
vec3 color = texColor.rgb * limbDarkeningCoef;
FRAG_COLOR = vec4(linearToSRGB(color), texColor.a);
FRAG_COLOR = vec4(color, texColor.a);
return;
}
#endif
Expand Down Expand Up @@ -398,8 +398,6 @@ void main()
texColor = texture2D(tex, texc);
}

texColor.rgb = srgbToLinear(texColor.rgb);

mediump vec4 finalColor = texColor;
// apply (currently only Martian) pole caps. texc.t=0 at south pole, 1 at north pole.
if (texc.t>poleLat.x-0.01+0.001*sin(texc.s*18.*M_PI)) { // North pole near t=1
Expand All @@ -424,6 +422,7 @@ void main()
// FIXME: this should be calculated properly in linear space as
// extinction of sunlight, and with subsequent tone mapping.
// Current implementation is a legacy from older times.
// shadowColor is passed as a GL_RGBA texture, so the sample is sRGB-encoded
lowp vec4 color = vec4(linearToSRGB(finalColor.rgb), finalColor.a);
lowp float alpha = clamp(shadowColor.a, 0.0, 0.7); // clamp alpha to allow some maria detail
finalColor = eclipsePush * (1.0-0.75*shadowColor.a) * mix(color, shadowColor, alpha);
Expand All @@ -434,7 +433,5 @@ void main()
//apply white rimlight
finalColor.xyz = clamp( finalColor.xyz + vec3(outgas), 0.0, 1.0);

FRAG_COLOR = vec4(linearToSRGB(finalColor.rgb), finalColor.a);
//to debug texture issues, uncomment and reload shader
10110111 marked this conversation as resolved.
Show resolved Hide resolved
//FRAG_COLOR = texColor;
FRAG_COLOR = finalColor;
}
8 changes: 4 additions & 4 deletions data/shaders/xyYToRGB.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ vec3 xyYToRGB(highp float x, highp float y, highp float Y)
if (flagUseTmGamma)
{
Y = pow(abs(Y*pi*1e-4), alphaWaOverAlphaDa*oneOverGamma)* term2TimesOneOverMaxdLpOneOverGamma;
return vec3(0.787077, 0.9898434, 1.9256125) * Y * brightnessScale;
return srgbToLinear(vec3(0.787077, 0.9898434, 1.9256125) * Y * brightnessScale);
}else{
Y = pow(abs(Y*pi*1e-4), alphaWaOverAlphaDa) * term2TimesOneOverMaxdL;
return pow(vec3(0.787077, 0.9898434, 1.9256125) * abs(Y * brightnessScale), vec3(oneOverGamma));
return vec3(0.787077, 0.9898434, 1.9256125) * abs(Y * brightnessScale);
}
}
else
Expand Down Expand Up @@ -93,9 +93,9 @@ vec3 xyYToRGB(highp float x, highp float y, highp float Y)
vec3(-0.3446944, +0.0415560, +1.0154096));
}
if (flagUseTmGamma){
return XYZ2RGB * XYZ * brightnessScale;
return srgbToLinear(abs(XYZ2RGB * XYZ * brightnessScale));
}else{
return pow(abs(XYZ2RGB * XYZ * brightnessScale), vec3(oneOverGamma));
return XYZ2RGB * XYZ * brightnessScale;
}
}
}
43 changes: 40 additions & 3 deletions src/StelMainView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,10 +873,7 @@ void StelMainView::init()
glInfo.vendor = QString(reinterpret_cast<const char*>(glInfo.functions->glGetString(GL_VENDOR)));
glInfo.renderer = QString(reinterpret_cast<const char*>(glInfo.functions->glGetString(GL_RENDERER)));
const auto format = glInfo.mainContext->format();
glInfo.supportsLuminanceTextures = format.profile() == QSurfaceFormat::CompatibilityProfile ||
format.majorVersion() < 3;
glInfo.isGLES = format.renderableType()==QSurfaceFormat::OpenGLES;
qDebug().nospace() << "Luminance textures are " << (glInfo.supportsLuminanceTextures ? "" : "not ") << "supported";
glInfo.isCoreProfile = format.profile() == QSurfaceFormat::CoreProfile;

auto& gl = *QOpenGLContext::currentContext()->functions();
Expand Down Expand Up @@ -916,6 +913,46 @@ void StelMainView::init()
gl.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInfo.maxTextureSize);
qDebug() << "Maximum 2D texture size:" << glInfo.maxTextureSize;

// sRGB support in GLES is a mess
if(glInfo.isGLES)
{
if(format.majorVersion() >= 3 || glInfo.mainContext->hasExtension("GL_EXT_texture_sRGB"))
{
glInfo.srgbTextureFormatRGB = GL_RGB;
glInfo.srgbTextureFormatRGBA = GL_RGBA;
glInfo.srgbTextureInternalFormatRGB = GL_SRGB8;
glInfo.srgbTextureInternalFormatRGBA = GL_SRGB8_ALPHA8;
glInfo.supportsGenerateMipmapSRGB = false;
}
else if(glInfo.mainContext->hasExtension("GL_EXT_sRGB"))
{
glInfo.srgbTextureFormatRGB = GL_SRGB;
glInfo.srgbTextureFormatRGBA = GL_SRGB_ALPHA_EXT;
glInfo.srgbTextureInternalFormatRGB = GL_SRGB;
glInfo.srgbTextureInternalFormatRGBA = GL_SRGB_ALPHA_EXT;
glInfo.supportsGenerateMipmapSRGB = false;
}
else
{
qCritical() << "No support for sRGB textures found, expect rendering problems!";
// Let the user still have gamma-incorrect rendering if possible (though
// configurations without sRGB support would likely have other problems).
glInfo.srgbTextureFormatRGB = GL_RGB;
glInfo.srgbTextureFormatRGBA = GL_RGBA;
glInfo.srgbTextureInternalFormatRGB = GL_RGB;
glInfo.srgbTextureInternalFormatRGBA = GL_RGBA;
glInfo.supportsGenerateMipmapSRGB = true;
}
}
else
{
glInfo.srgbTextureFormatRGB = GL_RGB;
glInfo.srgbTextureFormatRGBA = GL_RGBA;
glInfo.srgbTextureInternalFormatRGB = GL_SRGB8;
glInfo.srgbTextureInternalFormatRGBA = GL_SRGB8_ALPHA8;
glInfo.supportsGenerateMipmapSRGB = true;
}

gui = new StelGui();

// Should be check of requirements disabled? -- NO! This is intentional here, and does no harm.
Expand Down
6 changes: 5 additions & 1 deletion src/StelMainView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ class StelMainView : public QGraphicsView
PFNGLMINSAMPLESHADINGPROC glMinSampleShading = nullptr;
GLint maxAnisotropy = 0;
GLint maxTextureSize = 2048;
bool supportsLuminanceTextures = false;
GLenum srgbTextureFormatRGB = GL_RGB;
GLenum srgbTextureFormatRGBA = GL_RGBA;
GLenum srgbTextureInternalFormatRGB = GL_SRGB8;
GLenum srgbTextureInternalFormatRGBA = GL_SRGB8_ALPHA8;
bool supportsGenerateMipmapSRGB = true;
bool isCoreProfile = false;
bool isGLES = false;
};
Expand Down
137 changes: 136 additions & 1 deletion src/core/StelApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "StelApp.hpp"

#include "StelSRGB.hpp"
#include "Dithering.hpp"
#include "StelCore.hpp"
#include "StelMainView.hpp"
#include "StelSplashScreen.hpp"
Expand Down Expand Up @@ -79,7 +81,10 @@
#include <QNetworkDiskCache>
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLFramebufferObject>
#include <QString>
#include <QStringList>
Expand All @@ -103,6 +108,10 @@
#include "SpoutSender.hpp"
#endif

#ifndef GL_RGBA16
# define GL_RGBA16 0x805B
#endif

#ifdef USE_STATIC_PLUGIN_HELLOSTELMODULE
Q_IMPORT_PLUGIN(HelloStelModuleStelPluginInterface)
#endif
Expand Down Expand Up @@ -665,6 +674,9 @@ void StelApp::init(QSettings* conf)

// Animation
animationScale = confSettings->value("gui/pointer_animation_speed", 1.).toDouble();

ditherPatternTex = StelApp::getInstance().getTextureManager().getDitheringTexture(0);
setupLinearToSRGBBlitter();

#ifdef ENABLE_SPOUT
//qDebug() << "Property spout is" << qApp->property("spout").toString();
Expand Down Expand Up @@ -811,6 +823,62 @@ void StelApp::applyRenderBuffer(GLuint drawFbo)
viewportEffect->paintViewportBuffer(renderBuffer);
}

void StelApp::setupLinearToSRGBBlitter()
{
linearToSRGB_VBO.reset(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer));
linearToSRGB_VBO->create();
linearToSRGB_VBO->bind();
const GLfloat vertices[]=
{
// full screen quad
-1, -1,
1, -1,
-1, 1,
1, 1,
};
GL(gl->glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW));

linearToSRGB_VAO.reset(new QOpenGLVertexArrayObject);
linearToSRGB_VAO->create();
linearToSRGB_VAO->bind();
gl->glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
linearToSRGB_VBO->release();
gl->glEnableVertexAttribArray(0);
linearToSRGB_VAO->release();

linearToSRGB_Program.reset(new QOpenGLShaderProgram);
linearToSRGB_Program->addShaderFromSourceCode(QOpenGLShader::Vertex,
StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) + R"(
ATTRIBUTE vec3 vertex;
VARYING vec2 texcoord;
void main()
{
gl_Position = vec4(vertex, 1.);
texcoord = 0.5*vertex.xy+0.5;
}
)");
linearToSRGB_Program->addShaderFromSourceCode(QOpenGLShader::Fragment,
StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) + R"(
VARYING vec2 texcoord;
uniform sampler2D tex;

)" + makeDitheringShader() + makeSRGBUtilsShader() + R"(

void main()
{
vec4 rgba = texture2D(tex, texcoord);
vec3 srgb = linearToSRGB(clamp(rgba.rgb, vec3(0), vec3(1)));
FRAG_COLOR = vec4(dither(srgb), rgba.a);
}
)");
StelPainter::linkProg(linearToSRGB_Program.get(), "Linear RGB to sRGB conversion program");
linearToSRGB_Program->bind();
linearToSRGBUniformLocations.tex = linearToSRGB_Program->uniformLocation("tex");
linearToSRGBUniformLocations.ditherPattern = linearToSRGB_Program->uniformLocation("ditherPattern");
linearToSRGBUniformLocations.rgbMaxValue = linearToSRGB_Program->uniformLocation("rgbMaxValue");
linearToSRGB_Program->release();
}

//! Main drawing function called at each frame
void StelApp::draw()
{
Expand All @@ -828,10 +896,77 @@ void StelApp::draw()
core->preDraw();

const QList<StelModule*> modules = moduleMgr->getCallOrders(StelModule::ActionDraw);
for (auto* module : modules)

const auto srgbFBO = currentFbo;
StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
const auto w = params.viewportXywh[2] * params.devicePixelsPerPixel;
const auto h = params.viewportXywh[3] * params.devicePixelsPerPixel;
StelOpenGL::checkGLErrors(__FILE__, __LINE__);
if(!linearLightTexFBO || linearLightTexFBO->size() != QSize(w,h))
{
qDebug().nospace() << "Creating linear-light FBO with size " << w << "x" << h;
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(GL_RGBA16);
const auto samples = confSettings->value("video/multisampling", 0).toInt();
if(samples > 1)
{
linearLightTexFBO.reset(new QOpenGLFramebufferObject(w, h, format));
format.setSamples(samples);
linearLightMultisampledFBO.reset(new QOpenGLFramebufferObject(w, h, format));
}
else
{
linearLightTexFBO.reset(new QOpenGLFramebufferObject(w, h, format));
linearLightMultisampledFBO.reset();
}
}

if(linearLightMultisampledFBO)
{
linearLightMultisampledFBO->bind();
currentFbo = linearLightMultisampledFBO->handle();
}
else
{
linearLightTexFBO->bind();
currentFbo = linearLightTexFBO->handle();
}
StelOpenGL::checkGLErrors(__FILE__, __LINE__);

GL(gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));

for(auto* module : modules)
module->draw(core);

if(linearLightMultisampledFBO)
{
// Resolve multisamples into the texture
QOpenGLFramebufferObject::blitFramebuffer(linearLightTexFBO.get(), linearLightMultisampledFBO.get(),
GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
}

GL(gl->glBindFramebuffer(GL_FRAMEBUFFER, srgbFBO));
linearToSRGB_Program->bind();

const int linearTexSampler = 0;
GL(gl->glActiveTexture(GL_TEXTURE0 + linearTexSampler));
GL(gl->glBindTexture(GL_TEXTURE_2D, linearLightTexFBO->texture()));
linearToSRGB_Program->setUniformValue(linearToSRGBUniformLocations.tex, linearTexSampler);

const int ditherTexSampler = 1;
ditherPatternTex->bind(ditherTexSampler);
linearToSRGB_Program->setUniformValue(linearToSRGBUniformLocations.ditherPattern, ditherTexSampler);
const auto rgbMaxValue=calcRGBMaxValue(core->getDitheringMode());
linearToSRGB_Program->setUniformValue(linearToSRGBUniformLocations.rgbMaxValue, rgbMaxValue[0], rgbMaxValue[1], rgbMaxValue[2]);

linearToSRGB_VAO->bind();
GL(gl->glEnable(GL_BLEND));
GL(gl->glBlendFunc(GL_ONE,GL_ONE));
GL(gl->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
GL(gl->glDisable(GL_BLEND));
linearToSRGB_VAO->release();

core->postDraw();
#ifdef ENABLE_SPOUT
// At this point, the sky scene has been drawn, but no GUI panels.
Expand Down
19 changes: 19 additions & 0 deletions src/core/StelApp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
#ifndef STELAPP_HPP
#define STELAPP_HPP

#include <memory>
#include <qguiapplication.h>
#include <QString>
#include <QObject>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
#include <QRandomGenerator>
#endif
#include "StelTextureTypes.hpp"
#include "StelModule.hpp"
#include "VecMath.hpp"

Expand All @@ -39,6 +41,9 @@ class StelMainView;
class StelSkyCultureMgr;
class StelViewportEffect;
class QOpenGLFramebufferObject;
class QOpenGLVertexArrayObject;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class QOpenGLFunctions;
class QSettings;
class QNetworkAccessManager;
Expand Down Expand Up @@ -372,6 +377,8 @@ public slots:
//! @param drawFbo the OpenGL fbo we need to render into.
void applyRenderBuffer(quint32 drawFbo=0);

void setupLinearToSRGBBlitter();

QString getVersion() const;

// The StelApp singleton
Expand Down Expand Up @@ -479,6 +486,18 @@ public slots:

// Framebuffer object used for viewport effects.
QOpenGLFramebufferObject* renderBuffer;
std::unique_ptr<QOpenGLBuffer> linearToSRGB_VBO;
std::unique_ptr<QOpenGLVertexArrayObject> linearToSRGB_VAO;
std::unique_ptr<QOpenGLShaderProgram> linearToSRGB_Program;
std::unique_ptr<QOpenGLFramebufferObject> linearLightTexFBO;
std::unique_ptr<QOpenGLFramebufferObject> linearLightMultisampledFBO;
StelTextureSP ditherPatternTex;
struct LinearToSRGBUniformLocations
{
int tex;
int ditherPattern;
int rgbMaxValue;
} linearToSRGBUniformLocations;
StelViewportEffect* viewportEffect;
QOpenGLFunctions* gl;

Expand Down
Loading
Loading