Skip to content

Commit

Permalink
Merge pull request #1662 from perminder-17/depth-blur
Browse files Browse the repository at this point in the history
Add depth-of-field (Blurring rendering options)
  • Loading branch information
ghutchis authored Oct 12, 2024
2 parents c27a681 + ef20d54 commit 818c059
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 87 deletions.
2 changes: 1 addition & 1 deletion avogadro/rendering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,4 @@ target_link_libraries(Rendering

if(USE_3DCONNEXION AND (WIN32 OR APPLE))
target_compile_definitions(Rendering PUBLIC _3DCONNEXION)
endif()
endif()
247 changes: 168 additions & 79 deletions avogadro/rendering/solid_first_fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -38,116 +38,205 @@ uniform float inFogStrength;
uniform float inAoStrength;
// 1.0 if enabled, 0.0 if disabled
uniform float inEdStrength;
// offset for zoom-in and zoom-out
// amount of offset when zoom-in or zoom-out.
uniform float uoffset;
// Dof strength
uniform float inDofStrength;
// Dof position
uniform float inDofPosition;
// position for other molecules.
uniform float inFogPosition;
// Rendering surface dimensions, in pixels
uniform float width, height;

vec3 getNormalAt(vec2 normalUV)
{
float xpos = texture2D(inDepthTex, normalUV + vec2(1.0 / width, 0.0)).x;
float xneg = texture2D(inDepthTex, normalUV - vec2(1.0 / width, 0.0)).x;
float ypos = texture2D(inDepthTex, normalUV + vec2(0.0, 1.0 / height)).x;
float yneg = texture2D(inDepthTex, normalUV - vec2(0.0, 1.0 / height)).x;
float xdelta = xpos - xneg;
float ydelta = ypos - yneg;
vec3 r = vec3(xdelta, ydelta, 1.0 / width + 1.0 / height);
return normalize(r);
float xpos = texture2D(inDepthTex, normalUV + vec2(1.0 / width, 0.0)).x;
float xneg = texture2D(inDepthTex, normalUV - vec2(1.0 / width, 0.0)).x;
float ypos = texture2D(inDepthTex, normalUV + vec2(0.0, 1.0 / height)).x;
float yneg = texture2D(inDepthTex, normalUV - vec2(0.0, 1.0 / height)).x;
float xdelta = xpos - xneg;
float ydelta = ypos - yneg;
vec3 r = vec3(xdelta, ydelta, 1.0 / width + 1.0 / height);
return normalize(r);
}

vec3 getNormalNear(vec2 normalUV)
{
float cent = texture2D(inDepthTex, normalUV).x;
float xpos = texture2D(inDepthTex, normalUV + vec2(1.0 / width, 0.0)).x;
float xneg = texture2D(inDepthTex, normalUV - vec2(1.0 / width, 0.0)).x;
float ypos = texture2D(inDepthTex, normalUV + vec2(0.0, 1.0 / height)).x;
float yneg = texture2D(inDepthTex, normalUV - vec2(0.0, 1.0 / height)).x;
float xposdelta = xpos - cent;
float xnegdelta = cent - xneg;
float yposdelta = ypos - cent;
float ynegdelta = cent - yneg;
float xdelta = abs(xposdelta) > abs(xnegdelta) ? xnegdelta : xposdelta;
float ydelta = abs(yposdelta) > abs(ynegdelta) ? ynegdelta : yposdelta;
vec3 r = vec3(xdelta, ydelta, 0.5 / width + 0.5 / height);
return normalize(r);
float cent = texture2D(inDepthTex, normalUV).x;
float xpos = texture2D(inDepthTex, normalUV + vec2(1.0 / width, 0.0)).x;
float xneg = texture2D(inDepthTex, normalUV - vec2(1.0 / width, 0.0)).x;
float ypos = texture2D(inDepthTex, normalUV + vec2(0.0, 1.0 / height)).x;
float yneg = texture2D(inDepthTex, normalUV - vec2(0.0, 1.0 / height)).x;
float xposdelta = xpos - cent;
float xnegdelta = cent - xneg;
float yposdelta = ypos - cent;
float ynegdelta = cent - yneg;
float xdelta = abs(xposdelta) > abs(xnegdelta) ? xnegdelta : xposdelta;
float ydelta = abs(yposdelta) > abs(ynegdelta) ? ynegdelta : yposdelta;
vec3 r = vec3(xdelta, ydelta, 0.5 / width + 0.5 / height);
return normalize(r);
}

float lerp(float a, float b, float f)
{
return a + f * (b - a);
}

float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

float depthToZ(float depth) {
float eyeZ = ((height * 0.57735) / 2.0);
float near = 2.0;
float far = 8000.0;
float depthNormalized = 2.0 * depth - 1.0;
return 2.0 * near * far / (far + near - depthNormalized * (far - near));
}

float calcBlur(float z, float pixelScale) {
return clamp(abs(z - 39.0), 0.0, 0.5 * pixelScale);
}

vec4 applyBlur(vec2 texCoord) {
float pixelScale = max(width, height);
float origZ = depthToZ(texture2D(inDepthTex, texCoord).x);
float blurAmt = calcBlur(origZ, pixelScale);
// Skip blurring if the original depth is less than the threshold
if (origZ < uoffset * inDofPosition) {
return texture2D(inRGBTex, texCoord);
}
float total = 1.0;
vec4 color = texture2D(inRGBTex, texCoord);
for (int i = 0; i < 32; i++) {
float t = (float(i) / float(64));
float angle = (t * 4.0) * 6.28319;
float radius = (t * 2. - 1.);
angle += 1.0 * rand(gl_FragCoord.xy);
vec2 offset = (vec2(cos(angle), sin(angle)) * radius * 0.05 * inDofStrength) / pixelScale;
float z = depthToZ(texture2D(inDepthTex, texCoord + offset).x);
float sampleBlur = calcBlur(z, pixelScale);
float weight = 1.0 - smoothstep(0.0, 1.0, abs(z - origZ) / blurAmt);
vec4
sample = texture2D(inRGBTex, texCoord+offset);
color += weight * sample;
total += weight;
}
return color / total;
}

vec4 applyFog(vec2 texCoord) {
vec4 finalColor = mix(
texture2D(inRGBTex, texCoord),
vec4(vec3(fogR, fogG, fogB), 1.),
pow(texture2D(inDepthTex, texCoord.xy).r, uoffset * inFogPosition/10.0)
) + inFogStrength / 100.0;
return finalColor;
vec4 finalColor = mix(
texture2D(inRGBTex, texCoord),
vec4(vec3(fogR, fogG, fogB), 1.),
pow(texture2D(inDepthTex, texCoord.xy).r, uoffset * inFogPosition / 10.0)
) + inFogStrength / 100.0;
return finalColor;
}

const vec2 SSAOkernel[16] = vec2[16](
vec2(0.072170, 0.081556),
vec2(-0.035126, 0.056701),
vec2(-0.034186, -0.083598),
vec2(-0.056102, -0.009235),
vec2(0.017487, -0.099822),
vec2(0.071065, 0.015921),
vec2(0.040950, 0.079834),
vec2(-0.087751, 0.065326),
vec2(0.061108, -0.025829),
vec2(0.081262, -0.025854),
vec2(-0.063816, 0.083857),
vec2(0.043747, -0.068586),
vec2(-0.089848, 0.049046),
vec2(-0.065370, 0.058761),
vec2(0.099581, -0.089322),
vec2(-0.032077, -0.042826)
);
vec2(0.072170, 0.081556),
vec2(-0.035126, 0.056701),
vec2(-0.034186, -0.083598),
vec2(-0.056102, -0.009235),
vec2(0.017487, -0.099822),
vec2(0.071065, 0.015921),
vec2(0.040950, 0.079834),
vec2(-0.087751, 0.065326),
vec2(0.061108, -0.025829),
vec2(0.081262, -0.025854),
vec2(-0.063816, 0.083857),
vec2(0.043747, -0.068586),
vec2(-0.089848, 0.049046),
vec2(-0.065370, 0.058761),
vec2(0.099581, -0.089322),
vec2(-0.032077, -0.042826)
);

float computeSSAOLuminosity(vec3 normal)
{
float totalOcclusion = 0.0;
float depth = texture2D(inDepthTex, UV).x;
float A = (width * UV.x + 10 * height * UV.y) * 2.0 * 3.14159265358979 * 5.0 / 16.0;
float S = sin(A);
float C = cos(A);
mat2 rotation = mat2(
C, -S,
S, C
);
for (int i = 0; i < 16; i++) {
vec2 samplePoint = rotation * SSAOkernel[i];
float occluderDepth = texture2D(inDepthTex, UV + samplePoint).x;
vec3 occluder = vec3(samplePoint.xy, depth - occluderDepth);
float d = length(occluder);
float occlusion = max(0.0, dot(normal, occluder)) * (1.0 / (1.0 + d));
totalOcclusion += occlusion;
}
return max(0.0, 1.2 - inAoStrength * totalOcclusion);
float totalOcclusion = 0.0;
float depth = texture2D(inDepthTex, UV).x;
float A = (width * UV.x + 10 * height * UV.y) * 2.0 * 3.14159265358979 * 5.0 / 16.0;
float S = sin(A);
float C = cos(A);
mat2 rotation = mat2(
C, -S,
S, C
);
for (int i = 0; i < 16; i++) {
vec2 samplePoint = rotation * SSAOkernel[i];
float occluderDepth = texture2D(inDepthTex, UV + samplePoint).x;
vec3 occluder = vec3(samplePoint.xy, depth - occluderDepth);
float d = length(occluder);
float occlusion = max(0.0, dot(normal, occluder)) * (1.0 / (1.0 + d));
totalOcclusion += occlusion;
}

return max(0.0, 1.2 - inAoStrength * totalOcclusion);
}

float computeEdgeLuminosity(vec3 normal)
{
return max(0.0, pow(normal.z - 0.1, 1.0 / 3.0));
return max(0.0, pow(normal.z - 0.1, 1.0 / 3.0));
}

void main() {
float luminosity = 1.0;
luminosity *= max(1.2 * (1.0 - inAoEnabled), computeSSAOLuminosity(getNormalNear(UV)));
luminosity *= max(1.0 - inEdStrength, computeEdgeLuminosity(getNormalAt(UV)));
vec4 color = texture2D(inRGBTex, UV);
if (inFogStrength == 0.0) {
gl_FragColor = vec4(color.xyz * luminosity, color.w);
}
else {
// Apply fog to the color texture
vec4 foggedColor = applyFog(UV);
vec4 fogColor = vec4(luminosity * foggedColor.xyz, foggedColor.w);
gl_FragColor = fogColor;
}
gl_FragDepth = texture2D(inDepthTex, UV).x;
float luminosity = 1.0;
vec4 color = texture2D(inRGBTex, UV);
vec4 finalColor = color; // Initialize finalColor with base color

// Compute luminosity based on Ambient Occlusion (AO) and Edge Detection
if (inAoEnabled != 0.0) {
luminosity *= max(1.2 * (1.0 - inAoEnabled), computeSSAOLuminosity(getNormalNear(UV)));
}
if (inEdStrength != 0.0) {
luminosity *= max(1.0 - inEdStrength, computeEdgeLuminosity(getNormalAt(UV)));
}

// Compute foggedColor if Fog is enabled
vec4 foggedColor = color;
if (inFogStrength != 0.0) {
foggedColor = applyFog(UV);
}

// Compute blurredColor if DOF is enabled
vec4 blurredColor = color;
if (inDofStrength != 0.0) {
blurredColor = applyBlur(UV);
}

// Determine finalColor based on enabled effects
if (inAoEnabled != 0.0 || inEdStrength != 0.0 || inDofStrength != 0.0) {
if (inFogStrength != 0.0 && inDofStrength != 0.0) {
// Both Fog and DOF are enabled
vec4 mixedColor = mix(foggedColor, blurredColor, 0.5);
finalColor = vec4(mixedColor.rgb * luminosity, mixedColor.a);
} else if (inFogStrength != 0.0) {
// Only Fog is enabled with ao/edge-detection
finalColor = vec4(foggedColor.rgb * luminosity, foggedColor.a);
} else if (inDofStrength != 0.0) {
// Only DOF is enabled with/without ao/edge
finalColor = vec4(blurredColor.rgb * luminosity, blurredColor.a);
} else {
// Only AO and/or Edge Detection are enabled
finalColor = vec4(color.rgb * luminosity, color.a);
}
} else {
// Neither AO, DOF, nor Edge Detection is enabled
if (inFogStrength != 0.0) {
// Only Fog is enabled
finalColor = foggedColor;
} else {
// No effects are enabled
finalColor = color;
}
}

// Set the final fragment color
gl_FragColor = finalColor;

// Set fragment depth
gl_FragDepth = texture2D(inDepthTex, UV).x;
}
11 changes: 7 additions & 4 deletions avogadro/rendering/solidpipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ void initializeFramebuffer(GLuint* outFBO, GLuint* texRGB, GLuint* texDepth)
}

SolidPipeline::SolidPipeline()
: m_pixelRatio(1.0f), m_aoEnabled(true), m_aoStrength(1.0f),
m_fogStrength(1.0f), m_fogPosition(1.0), m_fogEnabled(true), m_edEnabled(true), m_edStrength(1.0f),
m_width(0), m_height(0), d(new Private), m_backgroundColor(0,0,0,0)
: m_pixelRatio(1.0f), m_aoEnabled(true), m_dofEnabled(true), m_aoStrength(1.0f),
m_fogStrength(1.0f), m_fogPosition(1.0), m_fogEnabled(true), m_edEnabled(true),
m_edStrength(1.0f), m_width(0), m_height(0), m_dofStrength(1.0f),
m_dofPosition(1.0), m_backgroundColor(0,0,0,0), d(new Private)
{
}

Expand Down Expand Up @@ -159,6 +160,9 @@ void SolidPipeline::end()
d->attachStage(d->firstStageShaders, "inRGBTex", d->renderTexture, "inDepthTex",
d->depthTexture, m_width, m_height);
d->firstStageShaders.setUniformValue("inAoEnabled", m_aoEnabled ? 1.0f : 0.0f);
d->firstStageShaders.setUniformValue("inDofEnabled", m_dofEnabled ? 1.0f : 0.0f);
d->firstStageShaders.setUniformValue("inDofStrength", m_dofEnabled ? (m_dofStrength * 100.0f) : 0.0f);
d->firstStageShaders.setUniformValue("inDofPosition", ((m_dofPosition) /10.0f));
d->firstStageShaders.setUniformValue("inAoStrength", m_aoStrength);
d->firstStageShaders.setUniformValue("inEdStrength", m_edStrength);
d->firstStageShaders.setUniformValue("inFogEnabled", m_fogEnabled ? 1.0f : 0.0f);
Expand All @@ -177,7 +181,6 @@ void SolidPipeline::adjustOffset(const Camera& cam) {
// They help define an offset with the projection-matrix
// to make the fog dynamic as the molecule moves away
// from the camera or come closer.

Eigen::Matrix4f projectView = cam.projection().matrix();

float project = ((((5000 + projectView(2,3) * 1000)/6) + 55) * 100);
Expand Down
27 changes: 24 additions & 3 deletions avogadro/rendering/solidpipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SolidPipeline
* @brief Begin solid geometry rendering.
*/
void begin();

void adjustOffset(const Camera& camera);
/**
* @brief End solid geometry rendering and apply screen-space shaders.
Expand All @@ -55,6 +55,12 @@ class SolidPipeline
bool getAoEnabled() { return m_aoEnabled; }
void setAoEnabled(bool enabled) { m_aoEnabled = enabled; }

/**
* @brief Get or set whether Depth-of-feild is enabled.
*/
bool getDofEnabled() { return m_dofEnabled; }
void setDofEnabled(bool enabled) { m_dofEnabled = enabled; }

/**
* @brief Get or set whether Fog is enabled.
*/
Expand Down Expand Up @@ -95,6 +101,18 @@ class SolidPipeline
m_edStrength = (m_edEnabled) ? 1.0 : 0.0;
}

/**
* @brief Get or set dof strength.
*/
float getDofStrength() { return m_dofStrength; }
void setDofStrength(float strength) { m_dofStrength = strength; }

/**
* @brief Set positon of dof
*/
float getDofPosition(){ return m_dofPosition;}
void setDofPosition(float position) { m_dofPosition = position; }

/**
* @brief Get or set the strength of the edge effect
*/
Expand All @@ -104,9 +122,12 @@ class SolidPipeline
private:
float m_pixelRatio;
bool m_aoEnabled;
float m_dofStrength;
float m_dofPosition;
bool m_dofEnabled;
float m_fogPosition;
Vector4ub m_backgroundColor;
Eigen::Affine3f modelView;
Eigen::Affine3f modelView;
bool m_fogEnabled;
float m_aoStrength;
float m_fogStrength;
Expand All @@ -122,4 +143,4 @@ class SolidPipeline
} // End namespace Rendering
} // End namespace Avogadro

#endif
#endif

0 comments on commit 818c059

Please sign in to comment.