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

Add depth-of-field (Blurring rendering options) #1662

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
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
perminder-17 marked this conversation as resolved.
Show resolved Hide resolved
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);
}
Copy link

@vinayakjeet vinayakjeet Apr 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233)) + cos(dot(co.xy, vec2(93.9898,50.233)))) * 43758.5453);
}
//more complex pattern produced which helps in reducing the noise. @ghutchis your insights ?


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
Loading