Merge pull request #954 from OpenSpace/feature/FXAA

Feature/fxaa
This commit is contained in:
Alexander Bock
2019-08-23 16:21:59 +02:00
committed by GitHub
13 changed files with 666 additions and 349 deletions

View File

@@ -69,16 +69,16 @@ public:
void updateRaycastData();
void updateDeferredcastData();
void updateHDRAndFiltering();
void updateFXAA();
void setResolution(glm::ivec2 res) override;
void setNAaSamples(int nAaSamples) override;
void setHDRExposure(float hdrExposure) override;
void setGamma(float gamma) override;
void setHue(float hue) override;
void setValue(float value) override;
void setSaturation(float sat) override;
int nAaSamples() const override;
void enableFXAA(bool enable) override;
void setDisableHDR(bool disable) override;
void update() override;
@@ -109,6 +109,7 @@ private:
void resolveMSAA(float blackoutFactor);
void applyTMO(float blackoutFactor);
void applyFXAA();
std::map<VolumeRaycaster*, RaycastData> _raycastData;
RaycasterProgObjMap _exitPrograms;
@@ -120,12 +121,13 @@ private:
std::unique_ptr<ghoul::opengl::ProgramObject> _hdrFilteringProgram;
std::unique_ptr<ghoul::opengl::ProgramObject> _tmoProgram;
std::unique_ptr<ghoul::opengl::ProgramObject> _resolveProgram;
UniformCache(mainColorTexture, blackoutFactor, nAaSamples) _uniformCache;
std::unique_ptr<ghoul::opengl::ProgramObject> _fxaaProgram;
UniformCache(mainColorTexture, blackoutFactor) _uniformCache;
UniformCache(hdrFeedingTexture, blackoutFactor, hdrExposure, gamma,
Hue, Saturation, Value, nAaSamples) _hdrUniformCache;
Hue, Saturation, Value) _hdrUniformCache;
UniformCache(renderedTexture, inverseScreenSize) _fxaaUniformCache;
GLint _defaultFBO;
GLuint _screenQuad;
@@ -148,19 +150,24 @@ private:
} _pingPongBuffers;
struct {
GLuint _hdrFilteringFramebuffer;
GLuint _hdrFilteringTexture;
GLuint hdrFilteringFramebuffer;
GLuint hdrFilteringTexture;
} _hdrBuffers;
struct {
GLuint fxaaFramebuffer;
GLuint fxaaTexture;
} _fxaaBuffers;
unsigned int _pingPongIndex = 0u;
bool _dirtyDeferredcastData;
bool _dirtyRaycastData;
bool _dirtyResolution;
bool _dirtyMsaaSamplingPattern;
glm::ivec2 _resolution = glm::ivec2(0);
int _nAaSamples;
bool _enableFXAA = true;
bool _disableHDR = false;
float _hdrExposure = 3.7f;

View File

@@ -208,8 +208,9 @@ private:
properties::BoolProperty _disableMasterRendering;
properties::FloatProperty _globalBlackOutFactor;
properties::IntProperty _nAaSamples;
properties::BoolProperty _enableFXAA;
properties::BoolProperty _disableHDRPipeline;
properties::FloatProperty _hdrExposure;
properties::FloatProperty _gamma;

View File

@@ -49,13 +49,12 @@ public:
virtual void deinitialize() = 0;
virtual void setResolution(glm::ivec2 res) = 0;
virtual void setNAaSamples(int nAaSamples) = 0;
virtual void setHDRExposure(float hdrExposure) = 0;
virtual void setGamma(float gamma) = 0;
virtual void setHue(float hue) = 0;
virtual void setValue(float value) = 0;
virtual void setSaturation(float sat) = 0;
virtual int nAaSamples() const = 0;
virtual void enableFXAA(bool enable) = 0;
virtual void setDisableHDR(bool disable) = 0;
/**

View File

@@ -65,15 +65,16 @@
out vec4 renderTarget;
in vec3 interpolatedNDCPos;
in vec2 texCoord;
uniform int nAaSamples;
uniform int cullAtmosphere;
uniform sampler2D irradianceTexture;
uniform sampler3D inscatterTexture;
uniform sampler2DMS mainPositionTexture;
uniform sampler2DMS mainNormalTexture;
uniform sampler2DMS mainColorTexture;
uniform sampler2D mainPositionTexture;
uniform sampler2D mainNormalTexture;
uniform sampler2D mainColorTexture;
uniform dmat4 dInverseModelTransformMatrix;
uniform dmat4 dModelTransformMatrix;
@@ -230,7 +231,7 @@ bool dAtmosphereIntersection(const dvec3 planetPosition, const dRay ray, const d
* This method avoids matrices multiplications
* wherever is possible.
*/
void dCalculateRayRenderableGlobe(in int mssaSample, out dRay ray,
void dCalculateRayRenderableGlobe(out dRay ray,
out dvec4 planetPositionObjectCoords,
out dvec4 cameraPositionInObject) {
dvec4 clipCoords = dvec4(interpolatedNDCPos.xy, 1.0, 1.0);
@@ -529,8 +530,6 @@ vec3 sunColor(const vec3 x, const float t, const vec3 v, const vec3 s, const flo
}
void main() {
ivec2 fragCoords = ivec2(gl_FragCoord);
if (cullAtmosphere == 0) {
vec4 atmosphereFinalColor = vec4(0.0f);
int nSamples = 1;
@@ -538,153 +537,141 @@ void main() {
// First we determine if the pixel is complex (different fragments on it)
bool complex = false;
vec4 oldColor, currentColor;
vec4 colorArray[16];
vec4 colorTexture;
colorArray[0] = texelFetch(mainColorTexture, fragCoords, 0);
for (int i = 1; i < nAaSamples; i++) {
colorArray[i] = texelFetch(mainColorTexture, fragCoords, i);
if (colorArray[i] != colorArray[i-1]) {
complex = true;
}
}
nSamples = complex ? nAaSamples / 2 : 1;
colorTexture = texture(mainColorTexture, texCoord);
for (int i = 0; i < nSamples; i++) {
// Color from G-Buffer
vec4 color = colorArray[i];
// Ray in object space
dRay ray;
dvec4 planetPositionObjectCoords = dvec4(0.0);
dvec4 cameraPositionInObject = dvec4(0.0);
// Color from G-Buffer
vec4 color = colorTexture;
// Ray in object space
dRay ray;
dvec4 planetPositionObjectCoords = dvec4(0.0);
dvec4 cameraPositionInObject = dvec4(0.0);
// Get the ray from camera to atm in object space
dCalculateRayRenderableGlobe(ray, planetPositionObjectCoords,
cameraPositionInObject);
bool insideATM = false;
double offset = 0.0; // in Km
double maxLength = 0.0; // in Km
bool intersectATM = false;
intersectATM = dAtmosphereIntersection(planetPositionObjectCoords.xyz, ray,
Rt - (ATM_EPSILON * 0.001), insideATM, offset, maxLength);
// Get the ray from camera to atm in object space
dCalculateRayRenderableGlobe(i * 3, ray, planetPositionObjectCoords,
cameraPositionInObject);
bool insideATM = false;
double offset = 0.0; // in Km
double maxLength = 0.0; // in Km
if ( intersectATM ) {
// Now we check is if the atmosphere is occluded, i.e., if the distance to the pixel
// in the G-Buffer positions is less than the distance to the atmosphere then the atmosphere
// is occluded
// Fragments positions into G-Buffer are written in SGCT Eye Space (View plus Camera Rig Coords)
// when using their positions later, one must convert them to the planet's coords
// Get data from G-Buffer
vec4 normal = texture(mainNormalTexture, texCoord);
// Data in the mainPositionTexture are written in view space (view plus camera rig)
vec4 position = texture(mainPositionTexture, texCoord);
bool intersectATM = false;
// OS Eye to World coords
dvec4 positionWorldCoords = dSGCTViewToWorldMatrix * position;
intersectATM = dAtmosphereIntersection(planetPositionObjectCoords.xyz, ray,
Rt - (ATM_EPSILON * 0.001), insideATM, offset, maxLength);
if ( intersectATM ) {
// Now we check is if the atmosphere is occluded, i.e., if the distance to the pixel
// in the G-Buffer positions is less than the distance to the atmosphere then the atmosphere
// is occluded
// Fragments positions into G-Buffer are written in SGCT Eye Space (View plus Camera Rig Coords)
// when using their positions later, one must convert them to the planet's coords
// Get data from G-Buffer
vec4 normal = texelFetch(mainNormalTexture, fragCoords, i);
// Data in the mainPositionTexture are written in view space (view plus camera rig)
vec4 position = texelFetch(mainPositionTexture, fragCoords, i);
// World to Object (Normal and Position in meters)
dvec4 positionObjectsCoords = dInverseModelTransformMatrix * positionWorldCoords;
// OS Eye to World coords
dvec4 positionWorldCoords = dSGCTViewToWorldMatrix * position;
// Distance of the pixel in the gBuffer to the observer
// JCC (12/12/2017): AMD distance function is buggy.
//double pixelDepth = distance(cameraPositionInObject.xyz, positionObjectsCoords.xyz);
double pixelDepth = length(cameraPositionInObject.xyz - positionObjectsCoords.xyz);
// JCC (12/13/2017): Trick to remove floating error in texture.
// We see a squared noise on planet's surface when seeing the planet
// from far away.
float dC = float(length(cameraPositionInObject.xyz));
float x1 = 1e8;
if (dC > x1) {
pixelDepth += 1000.0;
float alpha = 1000.0;
float beta = 1000000.0;
float x2 = 1e9;
float diffGreek = beta - alpha;
float diffDist = x2 - x1;
float varA = diffGreek/diffDist;
float varB = (alpha - varA * x1);
pixelDepth += double(varA * dC + varB);
}
// World to Object (Normal and Position in meters)
dvec4 positionObjectsCoords = dInverseModelTransformMatrix * positionWorldCoords;
// Distance of the pixel in the gBuffer to the observer
// JCC (12/12/2017): AMD distance function is buggy.
//double pixelDepth = distance(cameraPositionInObject.xyz, positionObjectsCoords.xyz);
double pixelDepth = length(cameraPositionInObject.xyz - positionObjectsCoords.xyz);
// JCC (12/13/2017): Trick to remove floating error in texture.
// We see a squared noise on planet's surface when seeing the planet
// from far away.
float dC = float(length(cameraPositionInObject.xyz));
float x1 = 1e8;
if (dC > x1) {
pixelDepth += 1000.0;
float alpha = 1000.0;
float beta = 1000000.0;
float x2 = 1e9;
float diffGreek = beta - alpha;
float diffDist = x2 - x1;
float varA = diffGreek/diffDist;
float varB = (alpha - varA * x1);
pixelDepth += double(varA * dC + varB);
}
// All calculations are done in Km:
pixelDepth *= 0.001;
positionObjectsCoords.xyz *= 0.001;
if (pixelDepth < offset) {
// ATM Occluded - Something in fron of ATM.
atmosphereFinalColor += color;
} else {
// Following paper nomenclature
double t = offset;
vec3 attenuation;
// Moving observer from camera location to top atmosphere
// If the observer is already inside the atm, offset = 0.0
// and no changes at all.
vec3 x = vec3(ray.origin.xyz + t*ray.direction.xyz);
float r = 0.0f;//length(x);
vec3 v = vec3(ray.direction.xyz);
float mu = 0.0f;//dot(x, v) / r;
vec3 s = vec3(sunDirectionObj);
float tF = float(maxLength - t);
// Because we may move the camera origin to the top of atmosphere
// we also need to adjust the pixelDepth for tdCalculateRayRenderableGlobe' offset so the
// next comparison with the planet's ground make sense:
pixelDepth -= offset;
dvec4 onATMPos = dModelTransformMatrix * dvec4(x * 1000.0, 1.0);
vec4 eclipseShadowATM = calcShadow(shadowDataArray, onATMPos.xyz, false);
float sunIntensityInscatter = sunRadiance * eclipseShadowATM.x;
float irradianceFactor = 0.0;
bool groundHit = false;
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v,
s, r, mu, attenuation,
vec3(positionObjectsCoords.xyz),
groundHit, maxLength, pixelDepth,
color, sunIntensityInscatter);
vec3 groundColorV = vec3(0.0);
vec3 sunColorV = vec3(0.0);
if (groundHit) {
vec4 eclipseShadowPlanet = calcShadow(shadowDataArray, positionWorldCoords.xyz, true);
float sunIntensityGround = sunRadiance * eclipseShadowPlanet.x;
groundColorV = groundColor(x, tF, v, s, r, mu, attenuation,
color, normal.xyz, irradianceFactor,
normal.a, sunIntensityGround);
} else {
// In order to get better performance, we are not tracing
// multiple rays per pixel when the ray doesn't intersect
// the ground.
sunColorV = sunColor(x, tF, v, s, r, mu, irradianceFactor);
}
// Final Color of ATM plus terrain:
vec4 finalRadiance = vec4(inscatterColor + groundColorV + sunColorV, 1.0);
atmosphereFinalColor += finalRadiance;
}
}
else { // no intersection
// Buffer color
// All calculations are done in Km:
pixelDepth *= 0.001;
positionObjectsCoords.xyz *= 0.001;
if (pixelDepth < offset) {
// ATM Occluded - Something in fron of ATM.
atmosphereFinalColor += color;
}
}
} else {
// Following paper nomenclature
double t = offset;
vec3 attenuation;
renderTarget = atmosphereFinalColor / float(nSamples);
// Moving observer from camera location to top atmosphere
// If the observer is already inside the atm, offset = 0.0
// and no changes at all.
vec3 x = vec3(ray.origin.xyz + t*ray.direction.xyz);
float r = 0.0f;//length(x);
vec3 v = vec3(ray.direction.xyz);
float mu = 0.0f;//dot(x, v) / r;
vec3 s = vec3(sunDirectionObj);
float tF = float(maxLength - t);
// Because we may move the camera origin to the top of atmosphere
// we also need to adjust the pixelDepth for tdCalculateRayRenderableGlobe' offset so the
// next comparison with the planet's ground make sense:
pixelDepth -= offset;
dvec4 onATMPos = dModelTransformMatrix * dvec4(x * 1000.0, 1.0);
vec4 eclipseShadowATM = calcShadow(shadowDataArray, onATMPos.xyz, false);
float sunIntensityInscatter = sunRadiance * eclipseShadowATM.x;
float irradianceFactor = 0.0;
bool groundHit = false;
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v,
s, r, mu, attenuation,
vec3(positionObjectsCoords.xyz),
groundHit, maxLength, pixelDepth,
color, sunIntensityInscatter);
vec3 groundColorV = vec3(0.0);
vec3 sunColorV = vec3(0.0);
if (groundHit) {
vec4 eclipseShadowPlanet = calcShadow(shadowDataArray, positionWorldCoords.xyz, true);
float sunIntensityGround = sunRadiance * eclipseShadowPlanet.x;
groundColorV = groundColor(x, tF, v, s, r, mu, attenuation,
color, normal.xyz, irradianceFactor,
normal.a, sunIntensityGround);
} else {
// In order to get better performance, we are not tracing
// multiple rays per pixel when the ray doesn't intersect
// the ground.
sunColorV = sunColor(x, tF, v, s, r, mu, irradianceFactor);
}
// Final Color of ATM plus terrain:
vec4 finalRadiance = vec4(inscatterColor + groundColorV + sunColorV, 1.0);
atmosphereFinalColor += finalRadiance;
}
}
else { // no intersection
// Buffer color
atmosphereFinalColor += color;
}
renderTarget = atmosphereFinalColor;
}
else { // culling
vec4 bColor = vec4(0.0f);
for (int f = 0; f < nAaSamples; f++) {
bColor += texelFetch(mainColorTexture, fragCoords, f);
}
bColor /= float(nAaSamples);
vec4 bColor = texture(mainColorTexture, texCoord);
renderTarget = bColor;
}
}

View File

@@ -27,9 +27,11 @@
layout(location = 0) in vec4 in_position;
out vec3 interpolatedNDCPos;
out vec2 texCoord;
void main()
{
texCoord = 0.5 + in_position.xy * 0.5;
interpolatedNDCPos = in_position.xyz;
gl_Position = in_position;
}

View File

@@ -361,6 +361,8 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) {
glBindVertexArray(info._vaoID);
if (renderLines) {
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
p->setUniform(c.renderPhase, RenderPhaseLines);
// Subclasses of this renderer might be using the index array or might now be
// so we check if there is data available and if there isn't, we use the
@@ -380,6 +382,7 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) {
reinterpret_cast<void*>(info.first * sizeof(unsigned int))
);
}
glDisable(GL_LINE_SMOOTH);
}
if (renderPoints) {
// Subclasses of this renderer might be using the index array or might now be

View File

@@ -0,0 +1,233 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#version __CONTEXT__
#define EDGE_THRESHOLD_MIN 0.0312f
#define EDGE_THRESHOLD_MAX 0.125f
#define ITERATIONS 12
#define SUBPIXEL_QUALITY 0.75f
const float[12] QUALITY = {1.f, 1.f, 1.f, 1.f, 1.f, 1.5f, 2.f, 2.f, 2.f, 2.f, 4.f, 8.f};
// const float[24] QUALITY = {2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 12.f, 12.f, 12.f, 12.f, 14.f, 18.f,
// 18.f, 18.f, 18.f, 18.f, 18.f, 18.f, 18.f, 18.f, 18.f, 18.f,
// 18.f, 18.f};
layout (location = 0) out vec4 aaFinalColor;
uniform vec2 inverseScreenSize;
uniform sampler2D renderedTexture;
in vec2 texCoord;
// Relative luminance
float getLum(vec3 rgb){
return dot(vec3(0.2126, 0.7152, 0.0722), rgb);
}
void main() {
vec4 colorCenter = texture(renderedTexture,texCoord);
// ============================
// Detecting where to apply AA:
// ============================
float pixelLumCenter = getLum(colorCenter.rgb);
float pixelLumDown = getLum(textureOffset(renderedTexture, texCoord, ivec2(0,-1)).rgb);
float pixelLumUp = getLum(textureOffset(renderedTexture, texCoord, ivec2(0,1)).rgb);
float pixelLumLeft = getLum(textureOffset(renderedTexture, texCoord, ivec2(-1,0)).rgb);
float pixelLumRight = getLum(textureOffset(renderedTexture, texCoord, ivec2(1,0)).rgb);
float pixelLumMin = min(pixelLumCenter, min(min(pixelLumDown, pixelLumUp), min(pixelLumLeft, pixelLumRight)));
float pixelLumMax = max(pixelLumCenter, max(max(pixelLumDown, pixelLumUp), max(pixelLumLeft, pixelLumRight)));
// Delta.
float pixelLumRange = pixelLumMax - pixelLumMin;
// If the pixelLum variation is lower that a threshold (or if we are in a really dark area),
// we are not on an edge, don't perform any AA.
if (pixelLumRange < max(EDGE_THRESHOLD_MIN, pixelLumMax * EDGE_THRESHOLD_MAX)) {
aaFinalColor = colorCenter;
return;
}
// ============================
// Estimating the gradient:
// ============================
float pixelLumDownLeft = getLum(textureOffset(renderedTexture, texCoord, ivec2(-1,-1)).rgb);
float pixelLumUpRight = getLum(textureOffset(renderedTexture, texCoord, ivec2(1,1)).rgb);
float pixelLumUpLeft = getLum(textureOffset(renderedTexture, texCoord, ivec2(-1,1)).rgb);
float pixelLumDownRight = getLum(textureOffset(renderedTexture, texCoord, ivec2(1,-1)).rgb);
float pixelLumDownUp = pixelLumDown + pixelLumUp;
float pixelLumLeftRight = pixelLumLeft + pixelLumRight;
float pixelLumLeftCorners = pixelLumDownLeft + pixelLumUpLeft;
float pixelLumDownCorners = pixelLumDownLeft + pixelLumDownRight;
float pixelLumRightCorners = pixelLumDownRight + pixelLumUpRight;
float pixelLumUpCorners = pixelLumUpRight + pixelLumUpLeft;
// Compute an estimation of the gradient
float edgeHorizontal = abs(-2.0 * pixelLumLeft + pixelLumLeftCorners) +
abs(-2.0 * pixelLumCenter + pixelLumDownUp ) * 2.0 + abs(-2.0 * pixelLumRight + pixelLumRightCorners);
float edgeVertical = abs(-2.0 * pixelLumUp + pixelLumUpCorners) +
abs(-2.0 * pixelLumCenter + pixelLumLeftRight) * 2.0 + abs(-2.0 * pixelLumDown + pixelLumDownCorners);
// ============================
// Choosing Edge Orientation:
// ============================
bool isHorizontal = (edgeHorizontal >= edgeVertical);
float pixelLum1 = isHorizontal ? pixelLumDown : pixelLumLeft;
float pixelLum2 = isHorizontal ? pixelLumUp : pixelLumRight;
// Gradients
float gradient1 = pixelLum1 - pixelLumCenter;
float gradient2 = pixelLum2 - pixelLumCenter;
bool is1Steepest = abs(gradient1) >= abs(gradient2);
float gradientScaled = 0.25 * max(abs(gradient1), abs(gradient2));
// Step size (one pixel) according to the edge direction.
float stepLength = isHorizontal ? inverseScreenSize.y : inverseScreenSize.x;
float pixelLumLocalAverage = 0.0;
if (is1Steepest) {
stepLength = - stepLength;
pixelLumLocalAverage = 0.5 * (pixelLum1 + pixelLumCenter);
} else {
pixelLumLocalAverage = 0.5 * (pixelLum2 + pixelLumCenter);
}
vec2 currentUv = texCoord;
if (isHorizontal) {
currentUv.y += stepLength * 0.5;
} else {
currentUv.x += stepLength * 0.5;
}
// ============================
// Iterations:
// ============================
vec2 offset = isHorizontal ? vec2(inverseScreenSize.x, 0.0) : vec2(0.0, inverseScreenSize.y);
vec2 uv1 = currentUv - offset;
vec2 uv2 = currentUv + offset;
// Read the pixelLums at both current extremities of the exploration segment,
// and compute the delta wrt to the local average pixelLum.
float pixelLumEnd1 = getLum(texture(renderedTexture, uv1).rgb);
float pixelLumEnd2 = getLum(texture(renderedTexture, uv2).rgb);
pixelLumEnd1 -= pixelLumLocalAverage;
pixelLumEnd2 -= pixelLumLocalAverage;
bool reached1 = abs(pixelLumEnd1) >= gradientScaled;
bool reached2 = abs(pixelLumEnd2) >= gradientScaled;
bool reachedBoth = reached1 && reached2;
if (!reached1) {
uv1 -= offset;
}
if (!reached2) {
uv2 += offset;
}
// Still exploring
if (!reachedBoth) {
for (int i = 2; i < ITERATIONS; i++) {
// If needed, read pixelLum in 1st direction, compute delta.
if (!reached1) {
pixelLumEnd1 = getLum(texture(renderedTexture, uv1).rgb);
pixelLumEnd1 = pixelLumEnd1 - pixelLumLocalAverage;
}
// If needed, read pixelLum in opposite direction, compute delta.
if (!reached2) {
pixelLumEnd2 = getLum(texture(renderedTexture, uv2).rgb);
pixelLumEnd2 = pixelLumEnd2 - pixelLumLocalAverage;
}
reached1 = abs(pixelLumEnd1) >= gradientScaled;
reached2 = abs(pixelLumEnd2) >= gradientScaled;
reachedBoth = reached1 && reached2;
// If the side is not reached
if (!reached1) {
uv1 -= offset * QUALITY[i];
}
if (!reached2) {
uv2 += offset * QUALITY[i];
}
// If both sides have been reached
if (reachedBoth) {
break;
}
}
}
// ============================
// Estimating the offset:
// ============================
float distance1 = isHorizontal ? (texCoord.x - uv1.x) : (texCoord.y - uv1.y);
float distance2 = isHorizontal ? (uv2.x - texCoord.x) : (uv2.y - texCoord.y);
bool isDirection1 = distance1 < distance2;
float distanceFinal = min(distance1, distance2);
float edgeThickness = (distance1 + distance2);
// Read in the direction of the closest side of the edge.
float pixelOffset = - distanceFinal / edgeThickness + 0.5;
bool ispixelLumCenterSmaller = pixelLumCenter < pixelLumLocalAverage;
// If the pixelLum at center is smaller than at its neighbour, the delta pixelLum at
// each end should be positive (same variation).
bool correctVariation = ((isDirection1 ? pixelLumEnd1 : pixelLumEnd2) < 0.0) != ispixelLumCenterSmaller;
// If the pixelLum variation is incorrect, do not offset.
float finalOffset = correctVariation ? pixelOffset : 0.0;
// ============================
// Subpixel antialiasing:
// ============================
float pixelLumAverage = (1.0/12.0) * (2.0 * (pixelLumDownUp + pixelLumLeftRight) +
pixelLumLeftCorners + pixelLumRightCorners);
float subPixelOffset1 = clamp(abs(pixelLumAverage - pixelLumCenter) / pixelLumRange, 0.0, 1.0);
float subPixelOffset2 = (-2.0 * subPixelOffset1 + 3.0) * subPixelOffset1 * subPixelOffset1;
float subPixelOffsetFinal = subPixelOffset2 * subPixelOffset2 * SUBPIXEL_QUALITY;
// Biggest of the two offsets.
finalOffset = max(finalOffset, subPixelOffsetFinal);
vec2 finalUV = texCoord;
if (isHorizontal) {
finalUV.y += finalOffset * stepLength;
} else {
finalUV.x += finalOffset * stepLength;
}
aaFinalColor = texture(renderedTexture, finalUV);
}

View File

@@ -0,0 +1,33 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2019 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#version __CONTEXT__
layout(location = 0) in vec4 position;
out vec2 texCoord;
void main() {
texCoord = 0.5 + position.xy * 0.5;
gl_Position = position;
}

View File

@@ -40,19 +40,12 @@ uniform float Value;
uniform float Lightness;
uniform int nAaSamples;
uniform sampler2DMS hdrFeedingTexture;
uniform sampler2D hdrFeedingTexture;
in vec2 texCoord;
void main() {
vec4 color = vec4(0.0);
// Resolving...
for (int i = 0; i < nAaSamples; i++) {
color += texelFetch(hdrFeedingTexture, ivec2(gl_FragCoord), i);
}
color /= nAaSamples;
vec4 color = texture(hdrFeedingTexture, texCoord);
color.rgb *= blackoutFactor;
// Applies TMO

View File

@@ -26,7 +26,7 @@
uniform sampler2D exitColorTexture;
uniform sampler2D exitDepthTexture;
uniform sampler2DMS mainDepthTexture;
uniform sampler2D mainDepthTexture;
uniform bool insideRaycaster;
uniform vec3 cameraPosInRaycaster;
@@ -46,9 +46,6 @@ out vec4 finalColor;
#define ALPHA_LIMIT 0.99
#define RAYCAST_MAX_STEPS 1000
#define MAX_AA_SAMPLES 8
uniform int nAaSamples;
#include <#{getEntryPath}>
@@ -76,25 +73,12 @@ void main() {
vec3 direction = normalize(diff);
float raycastDepth = length(diff);
float raycastDepths[MAX_AA_SAMPLES];
int i, j;
float tmp;
for (i = 0; i < nAaSamples; i++) {
float geoDepth = denormalizeFloat(texelFetch(mainDepthTexture, ivec2(gl_FragCoord), i).x);
float geoRatio = clamp((geoDepth - entryDepth) / (exitDepth - entryDepth), 0.0, 1.0);
raycastDepths[i] = geoRatio * raycastDepth;
}
for(i = 1; i < nAaSamples; ++i) {
tmp = raycastDepths[i];
for(j = i; j > 0 && tmp < raycastDepths[j - 1]; --j) {
raycastDepths[j] = raycastDepths[j-1];
}
raycastDepths[j] = tmp;
}
float geoDepth = denormalizeFloat(texelFetch(mainDepthTexture, ivec2(gl_FragCoord), 0).x);
float geoRatio = clamp((geoDepth - entryDepth) / (exitDepth - entryDepth), 0.0, 1.0);
raycastDepth = geoRatio * raycastDepth;
float currentDepth = 0.0;
// todo: shorten depth if geometry is intersecting!
@@ -106,20 +90,20 @@ void main() {
float aaOpacity = 1.0;
int sampleIndex = 0;
float opacityDecay = 1.0 / nAaSamples;
float opacityDecay = 1.0;
vec3 accumulatedColor = vec3(0.0);
vec3 accumulatedAlpha = vec3(0.0);
for (steps = 0; (accumulatedAlpha.r < ALPHA_LIMIT || accumulatedAlpha.g < ALPHA_LIMIT || accumulatedAlpha.b < ALPHA_LIMIT) && steps < RAYCAST_MAX_STEPS; ++steps) {
while (sampleIndex < nAaSamples && currentDepth + nextStepSize * jitterFactor > raycastDepths[sampleIndex]) {
sampleIndex++;
for (steps = 0; (accumulatedAlpha.r < ALPHA_LIMIT || accumulatedAlpha.g < ALPHA_LIMIT ||
accumulatedAlpha.b < ALPHA_LIMIT) && steps < RAYCAST_MAX_STEPS; ++steps) {
if (currentDepth + nextStepSize * jitterFactor > raycastDepth) {
aaOpacity -= opacityDecay;
}
bool shortStepSize = nextStepSize < raycastDepth / 10000000000.0;
if (sampleIndex >= nAaSamples || shortStepSize) {
if (shortStepSize) {
break;
}
@@ -139,7 +123,7 @@ void main() {
previousJitterDistance = currentStepSize - jitteredStepSize;
float maxStepSize = raycastDepths[nAaSamples - 1] - currentDepth;
float maxStepSize = raycastDepth - currentDepth;
nextStepSize = min(nextStepSize, maxStepSize);

View File

@@ -33,7 +33,6 @@
layout(location = 0) out vec4 _out_color_;
layout(location = 1) out vec4 gPosition;
layout(location = 2) out vec4 gNormal;
layout(location = 3) out vec4 filterBuffer;
void main() {
Fragment f = getFragment();

View File

@@ -50,13 +50,17 @@
namespace {
constexpr const char* _loggerCat = "FramebufferRenderer";
constexpr const std::array<const char*, 3> UniformNames = {
"mainColorTexture", "blackoutFactor", "nAaSamples"
constexpr const std::array<const char*, 2> UniformNames = {
"mainColorTexture", "blackoutFactor"
};
constexpr const std::array<const char*, 8> HDRUniformNames = {
constexpr const std::array<const char*, 7> HDRUniformNames = {
"hdrFeedingTexture", "blackoutFactor", "hdrExposure", "gamma",
"Hue", "Saturation", "Value", "nAaSamples"
"Hue", "Saturation", "Value"
};
constexpr const std::array<const char*, 2> FXAAUniformNames = {
"renderedTexture", "inverseScreenSize"
};
constexpr const char* ExitFragmentShaderPath =
@@ -177,8 +181,12 @@ void FramebufferRenderer::initialize() {
glGenFramebuffers(1, &_exitFramebuffer);
// HDR / Filtering Buffers
glGenFramebuffers(1, &_hdrBuffers._hdrFilteringFramebuffer);
glGenTextures(1, &_hdrBuffers._hdrFilteringTexture);
glGenFramebuffers(1, &_hdrBuffers.hdrFilteringFramebuffer);
glGenTextures(1, &_hdrBuffers.hdrFilteringTexture);
// FXAA Buffers
glGenFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer);
glGenTextures(1, &_fxaaBuffers.fxaaTexture);
// Allocate Textures/Buffers Memory
updateResolution();
@@ -190,31 +198,27 @@ void FramebufferRenderer::initialize() {
//===== GBuffers Buffers =====//
//==============================//
glBindFramebuffer(GL_FRAMEBUFFER, _gBuffers.framebuffer);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_MULTISAMPLE,
_gBuffers.colorTexture,
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D_MULTISAMPLE,
_gBuffers.positionTexture,
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT2,
GL_TEXTURE_2D_MULTISAMPLE,
_gBuffers.normalTexture,
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D_MULTISAMPLE,
_gBuffers.depthTexture,
0
);
@@ -228,24 +232,21 @@ void FramebufferRenderer::initialize() {
//===== PingPong Buffers =====//
//==============================//
glBindFramebuffer(GL_FRAMEBUFFER, _pingPongBuffers.framebuffer);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_MULTISAMPLE,
_pingPongBuffers.colorTexture[0],
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D_MULTISAMPLE,
_pingPongBuffers.colorTexture[1],
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D_MULTISAMPLE,
_gBuffers.depthTexture,
0
);
@@ -260,17 +261,15 @@ void FramebufferRenderer::initialize() {
//======================================//
// Builds Exit Framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
_exitColorTexture,
0
);
glFramebufferTexture2D(
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D,
_exitDepthTexture,
0
);
@@ -283,12 +282,11 @@ void FramebufferRenderer::initialize() {
//===================================//
//===== HDR/Filtering Buffers =====//
//===================================//
glBindFramebuffer(GL_FRAMEBUFFER, _hdrBuffers._hdrFilteringFramebuffer);
glFramebufferTexture2D(
glBindFramebuffer(GL_FRAMEBUFFER, _hdrBuffers.hdrFilteringFramebuffer);
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
_hdrBuffers._hdrFilteringTexture,
_hdrBuffers.hdrFilteringTexture,
0
);
@@ -297,13 +295,28 @@ void FramebufferRenderer::initialize() {
LERROR("HDR/Filtering framebuffer is not complete");
}
//===================================//
//========== FXAA Buffers =========//
//===================================//
glBindFramebuffer(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer);
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
_fxaaBuffers.fxaaTexture,
0
);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LERROR("FXAA framebuffer is not complete");
}
// JCC: Moved to here to avoid NVidia: "Program/shader state performance warning"
// Building programs
updateHDRAndFiltering();
updateFXAA();
updateDeferredcastData();
_dirtyMsaaSamplingPattern = true;
// Sets back to default FBO
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
@@ -323,13 +336,17 @@ void FramebufferRenderer::initialize() {
_hdrUniformCache,
HDRUniformNames
);
ghoul::opengl::updateUniformLocations(
*_fxaaProgram,
_fxaaUniformCache,
FXAAUniformNames
);
global::raycasterManager.addListener(*this);
global::deferredcasterManager.addListener(*this);
// Default GL State for Blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void FramebufferRenderer::deinitialize() {
@@ -337,13 +354,15 @@ void FramebufferRenderer::deinitialize() {
glDeleteFramebuffers(1, &_gBuffers.framebuffer);
glDeleteFramebuffers(1, &_exitFramebuffer);
glDeleteFramebuffers(1, &_hdrBuffers._hdrFilteringFramebuffer);
glDeleteFramebuffers(1, &_hdrBuffers.hdrFilteringFramebuffer);
glDeleteFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer);
glDeleteFramebuffers(1, &_pingPongBuffers.framebuffer);
glDeleteTextures(1, &_gBuffers.colorTexture);
glDeleteTextures(1, &_gBuffers.depthTexture);
glDeleteTextures(1, &_hdrBuffers._hdrFilteringTexture);
glDeleteTextures(1, &_hdrBuffers.hdrFilteringTexture);
glDeleteTextures(1, &_fxaaBuffers.fxaaTexture);
glDeleteTextures(1, &_gBuffers.positionTexture);
glDeleteTextures(1, &_gBuffers.normalTexture);
@@ -371,23 +390,6 @@ void FramebufferRenderer::deferredcastersChanged(Deferredcaster&,
_dirtyDeferredcastData = true;
}
void FramebufferRenderer::resolveMSAA(float blackoutFactor) {
_resolveProgram->activate();
ghoul::opengl::TextureUnit mainColorTextureUnit;
mainColorTextureUnit.activate();
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.colorTexture);
_resolveProgram->setUniform(_uniformCache.mainColorTexture, mainColorTextureUnit);
_resolveProgram->setUniform(_uniformCache.blackoutFactor, blackoutFactor);
_resolveProgram->setUniform(_uniformCache.nAaSamples, _nAaSamples);
glBindVertexArray(_screenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
_resolveProgram->deactivate();
}
void FramebufferRenderer::applyTMO(float blackoutFactor) {
const bool doPerformanceMeasurements = global::performanceManager.isEnabled();
std::unique_ptr<performance::PerformanceMeasurement> perfInternal;
@@ -402,7 +404,7 @@ void FramebufferRenderer::applyTMO(float blackoutFactor) {
ghoul::opengl::TextureUnit hdrFeedingTextureUnit;
hdrFeedingTextureUnit.activate();
glBindTexture(
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_2D,
_pingPongBuffers.colorTexture[_pingPongIndex]
);
@@ -418,8 +420,6 @@ void FramebufferRenderer::applyTMO(float blackoutFactor) {
_hdrFilteringProgram->setUniform(_hdrUniformCache.Hue, _hue);
_hdrFilteringProgram->setUniform(_hdrUniformCache.Saturation, _saturation);
_hdrFilteringProgram->setUniform(_hdrUniformCache.Value, _value);
_hdrFilteringProgram->setUniform(_hdrUniformCache.nAaSamples, _nAaSamples);
glBindVertexArray(_screenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
@@ -428,6 +428,40 @@ void FramebufferRenderer::applyTMO(float blackoutFactor) {
_hdrFilteringProgram->deactivate();
}
void FramebufferRenderer::applyFXAA() {
const bool doPerformanceMeasurements = global::performanceManager.isEnabled();
std::unique_ptr<performance::PerformanceMeasurement> perfInternal;
if (doPerformanceMeasurements) {
perfInternal = std::make_unique<performance::PerformanceMeasurement>(
"FramebufferRenderer::render::FXAA"
);
}
_fxaaProgram->activate();
ghoul::opengl::TextureUnit renderedTextureUnit;
renderedTextureUnit.activate();
glBindTexture(
GL_TEXTURE_2D,
_fxaaBuffers.fxaaTexture
);
_fxaaProgram->setUniform(
_fxaaUniformCache.renderedTexture,
renderedTextureUnit
);
glm::vec2 inverseScreenSize(1.f/_resolution.x, 1.f/_resolution.y);
_fxaaProgram->setUniform(_fxaaUniformCache.inverseScreenSize, inverseScreenSize);
glBindVertexArray(_screenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
_fxaaProgram->deactivate();
}
void FramebufferRenderer::update() {
if (_dirtyResolution) {
updateResolution();
@@ -460,6 +494,16 @@ void FramebufferRenderer::update() {
);
}
if (_fxaaProgram->isDirty()) {
_fxaaProgram->rebuildFromFile();
ghoul::opengl::updateUniformLocations(
*_fxaaProgram,
_fxaaUniformCache,
FXAAUniformNames
);
}
using K = VolumeRaycaster*;
using V = std::unique_ptr<ghoul::opengl::ProgramObject>;
for (const std::pair<const K, V>& program : _exitPrograms) {
@@ -512,61 +556,7 @@ void FramebufferRenderer::update() {
}
void FramebufferRenderer::updateResolution() {
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.colorTexture);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE,
_nAaSamples,
GL_RGBA32F,
_resolution.x,
_resolution.y,
GL_TRUE
);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.positionTexture);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE,
_nAaSamples,
GL_RGBA32F,
_resolution.x,
_resolution.y,
GL_TRUE
);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.normalTexture);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE,
_nAaSamples,
GL_RGBA32F,
_resolution.x,
_resolution.y,
GL_TRUE
);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.depthTexture);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE,
_nAaSamples,
GL_DEPTH_COMPONENT32F,
_resolution.x,
_resolution.y,
GL_TRUE
);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _pingPongBuffers.colorTexture[1]);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE,
_nAaSamples,
GL_RGBA32F,
_resolution.x,
_resolution.y,
GL_TRUE
);
// HDR / Filtering
glBindTexture(GL_TEXTURE_2D, _hdrBuffers._hdrFilteringTexture);
glBindTexture(GL_TEXTURE_2D, _gBuffers.colorTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
@@ -578,7 +568,98 @@ void FramebufferRenderer::updateResolution() {
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, _gBuffers.positionTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x,
_resolution.y,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, _gBuffers.normalTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x,
_resolution.y,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, _gBuffers.depthTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_DEPTH_COMPONENT32F,
_resolution.x,
_resolution.y,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, _pingPongBuffers.colorTexture[1]);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x,
_resolution.y,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// HDR / Filtering
glBindTexture(GL_TEXTURE_2D, _hdrBuffers.hdrFilteringTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x,
_resolution.y,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// FXAA
glBindTexture(GL_TEXTURE_2D, _fxaaBuffers.fxaaTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
_resolution.x,
_resolution.y,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -754,6 +835,17 @@ void FramebufferRenderer::updateHDRAndFiltering() {
//_hdrFilteringProgram->setIgnoreUniformLocationError(IgnoreError::Yes);
}
void FramebufferRenderer::updateFXAA() {
_fxaaProgram = ghoul::opengl::ProgramObject::Build(
"FXAA Program",
absPath("${SHADERS}/framebuffer/fxaa.vert"),
absPath("${SHADERS}/framebuffer/fxaa.frag")
);
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
//_fxaaProgram->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
//_fxaaProgram->setIgnoreUniformLocationError(IgnoreError::Yes);
}
void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFactor) {
// Set OpenGL default rendering state
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO);
@@ -842,18 +934,25 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
// Disabling depth test for filtering and hdr
glDisable(GL_DEPTH_TEST);
// When applying the TMO, the result is saved to the default FBO to be displayed
// by the Operating System. Also, the resolve procedure is executed in this step.
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
glViewport(0, 0, _resolution.x, _resolution.y);
if (_disableHDR) {
resolveMSAA(blackoutFactor);
if (_enableFXAA) {
glBindFramebuffer(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer);
}
else {
// Apply the selected TMO on the results and resolve the result for the default FBO
applyTMO(blackoutFactor);
// When applying the TMO, the result is saved to the default FBO to be displayed
// by the Operating System. Also, the resolve procedure is executed in this step.
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
}
glViewport(0, 0, _resolution.x, _resolution.y);
// Apply the selected TMO on the results and resolve the result for the default FBO
applyTMO(blackoutFactor);
if (_enableFXAA) {
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
applyFXAA();
}
}
void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>& tasks) {
@@ -916,10 +1015,9 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
ghoul::opengl::TextureUnit mainDepthTextureUnit;
mainDepthTextureUnit.activate();
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.depthTexture);
glBindTexture(GL_TEXTURE_2D, _gBuffers.depthTexture);
raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit);
raycastProgram->setUniform("nAaSamples", _nAaSamples);
raycastProgram->setUniform("windowSize", static_cast<glm::vec2>(_resolution));
glDisable(GL_DEPTH_TEST);
@@ -971,9 +1069,8 @@ void FramebufferRenderer::performDeferredTasks(
// adding G-Buffer
ghoul::opengl::TextureUnit mainDColorTextureUnit;
mainDColorTextureUnit.activate();
//glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers._colorTexture);
glBindTexture(
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_2D,
_pingPongBuffers.colorTexture[fromIndex]
);
deferredcastProgram->setUniform(
@@ -983,7 +1080,7 @@ void FramebufferRenderer::performDeferredTasks(
ghoul::opengl::TextureUnit mainPositionTextureUnit;
mainPositionTextureUnit.activate();
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.positionTexture);
glBindTexture(GL_TEXTURE_2D, _gBuffers.positionTexture);
deferredcastProgram->setUniform(
"mainPositionTexture",
mainPositionTextureUnit
@@ -991,14 +1088,12 @@ void FramebufferRenderer::performDeferredTasks(
ghoul::opengl::TextureUnit mainNormalTextureUnit;
mainNormalTextureUnit.activate();
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _gBuffers.normalTexture);
glBindTexture(GL_TEXTURE_2D, _gBuffers.normalTexture);
deferredcastProgram->setUniform(
"mainNormalTexture",
mainNormalTextureUnit
);
deferredcastProgram->setUniform("nAaSamples", _nAaSamples);
deferredcaster->preRaycast(
deferredcasterTask.renderData,
_deferredcastData[deferredcaster],
@@ -1036,22 +1131,6 @@ void FramebufferRenderer::setResolution(glm::ivec2 res) {
_dirtyResolution = true;
}
void FramebufferRenderer::setNAaSamples(int nAaSamples) {
ghoul_assert(
nAaSamples >= 1 && nAaSamples <= 8,
"Number of AA samples has to be between 1 and 8"
);
_nAaSamples = nAaSamples;
if (_nAaSamples == 0) {
_nAaSamples = 1;
}
if (_nAaSamples > 8) {
LERROR("Framebuffer renderer does not support more than 8 MSAA samples.");
_nAaSamples = 8;
}
_dirtyMsaaSamplingPattern = true;
}
void FramebufferRenderer::setDisableHDR(bool disable) {
_disableHDR = std::move(disable);
}
@@ -1079,8 +1158,8 @@ void FramebufferRenderer::setSaturation(float sat) {
_saturation = std::move(sat);
}
int FramebufferRenderer::nAaSamples() const {
return _nAaSamples;
void FramebufferRenderer::enableFXAA(bool enable) {
_enableFXAA = std::move(enable);
}
void FramebufferRenderer::updateRendererData() {

View File

@@ -192,13 +192,6 @@ namespace {
"direction for tilted display systems in clustered immersive environments."
};
constexpr openspace::properties::Property::PropertyInfo AaSamplesInfo = {
"AaSamples",
"Number of Anti-aliasing samples",
"This value determines the number of anti-aliasing samples to be used in the "
"rendering for the MSAA method."
};
constexpr openspace::properties::Property::PropertyInfo DisableHDRPipelineInfo = {
"DisableHDRPipeline",
"Disable HDR Rendering",
@@ -253,6 +246,12 @@ namespace {
"The blackout factor of the rendering. This can be used for fading in or out the "
"rendering window"
};
constexpr openspace::properties::Property::PropertyInfo FXAAInfo = {
"FXAA",
"Enable FXAA",
"Enable FXAA"
};
} // namespace
@@ -273,7 +272,7 @@ RenderEngine::RenderEngine()
#endif // OPENSPACE_WITH_INSTRUMENTATION
, _disableMasterRendering(DisableMasterInfo, false)
, _globalBlackOutFactor(GlobalBlackoutFactorInfo, 1.f, 0.f, 1.f)
, _nAaSamples(AaSamplesInfo, 4, 1, 8)
, _enableFXAA(FXAAInfo, true)
, _disableHDRPipeline(DisableHDRPipelineInfo, false)
, _hdrExposure(HDRExposureInfo, 3.7f, 0.01f, 10.0f)
, _gamma(GammaInfo, 0.95f, 0.01f, 5.0f)
@@ -310,12 +309,12 @@ RenderEngine::RenderEngine()
addProperty(_showVersionInfo);
addProperty(_showCameraInfo);
_nAaSamples.onChange([this](){
_enableFXAA.onChange([this]() {
if (_renderer) {
_renderer->setNAaSamples(_nAaSamples);
_renderer->enableFXAA(_enableFXAA);
}
});
addProperty(_nAaSamples);
});
addProperty(_enableFXAA);
_disableHDRPipeline.onChange([this]() {
if (_renderer) {
@@ -457,8 +456,6 @@ void RenderEngine::initialize() {
void RenderEngine::initializeGL() {
LTRACE("RenderEngine::initializeGL(begin)");
_nAaSamples = global::windowDelegate.currentNumberOfAaSamples();
std::string renderingMethod = global::configuration.renderingMethod;
if (renderingMethod == "ABuffer") {
using Version = ghoul::systemcapabilities::Version;
@@ -1086,7 +1083,7 @@ void RenderEngine::setRenderer(std::unique_ptr<Renderer> renderer) {
_renderer = std::move(renderer);
_renderer->setResolution(renderingResolution());
_renderer->setNAaSamples(_nAaSamples);
_renderer->enableFXAA(true);
_renderer->setHDRExposure(_hdrExposure);
_renderer->initialize();
}