Skip to content
Snippets Groups Projects
Commit 93b66b7c authored by Adam Nyberg's avatar Adam Nyberg
Browse files

Filtered thickness + ligth atteniuation buffer

parent cac4739f
No related branches found
No related tags found
No related merge requests found
#version 330 core
in vec2 TexCoords;
out vec4 FragColor;
// The blurred thickness texture
uniform sampler2D uThicknessTex;
// Absorption coefficient
uniform float absorption; // e.g. 3.0 -> the higher, the more quickly light fades
// The color of the fluid (if you want tinted absorption)
uniform vec3 fluidColor; // e.g. vec3(0.3, 0.7, 1.0)
void main()
{
float thicknessVal = texture(uThicknessTex, TexCoords).r;
// Beer–Lambert law
float attenuation = exp(-absorption * thicknessVal);
// The fluid color modulated by that attenuation
// (This is a simplistic approach: if you want the fluid
// to be fully absorbing, you do: finalColor = fluidColor * (1 - attenuation), etc.)
vec3 color = fluidColor * (1 - attenuation);
FragColor = vec4(color, 1.0);
}
#version 330 core
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoord;
gl_Position = vec4(aPosition, 1.0);
}
#version 330 core
in vec2 TexCoords;
out vec4 FragColor;
// The original thickness texture (GL_R32F storing thickness in .r)
uniform sampler2D uThicknessTex;
// Parameters for blur
uniform vec2 passDirection; // e.g. (1.0/width, 0) or (0, 1.0/height)
uniform int kernelRadius; // e.g. 5, 10, etc.
uniform float gaussWeights[64]; // Precomputed half-kernel weights up to radius=63
void main()
{
// Sample center
float centerVal = texture(uThicknessTex, TexCoords).r;
// Accumulate for a 1D Gaussian blur
float sum = 0.0;
float wSum = 0.0;
for (int i = -kernelRadius; i <= kernelRadius; i++)
{
// offset in texture space
vec2 offset = passDirection * float(i);
vec2 sampleUV = TexCoords + offset;
float sampleVal = texture(uThicknessTex, sampleUV).r;
// Spatial weight from precomputed array
float w = gaussWeights[abs(i)];
sum += sampleVal * w;
wSum += w;
}
float blurredVal = sum / max(wSum, 1e-5);
FragColor = vec4(blurredVal, 0.0, 0.0, 1.0);
}
#version 330 core
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoord;
gl_Position = vec4(aPosition, 1.0);
}
...@@ -170,6 +170,30 @@ void FluidRenderer::initShaders() { ...@@ -170,6 +170,30 @@ void FluidRenderer::initShaders() {
glUseProgram(m_thicknessRenderProgram.programID); glUseProgram(m_thicknessRenderProgram.programID);
std::cout << "Thickness Render Shaders initialized successfully." << std::endl; std::cout << "Thickness Render Shaders initialized successfully." << std::endl;
// Thickness Filter Program
m_thicknessFilterProgram.programID = loadShaders(
"../shaders/thickness_filter.vert",
"../shaders/thickness_filter.frag"
);
if (m_thicknessFilterProgram.programID == 0) {
std::cerr << "Failed to load Thickness Filter Shaders." << std::endl;
exit(1);
}
glUseProgram(m_thicknessFilterProgram.programID);
std::cout << "Thickness Filter Shaders initialized successfully." << std::endl;
// Thickness Attenuation Program
m_thicknessAttenProgram.programID = loadShaders(
"../shaders/thickness_attenuation.vert",
"../shaders/thickness_attenuation.frag"
);
if (m_thicknessAttenProgram.programID == 0) {
std::cerr << "Failed to load Thickness Attenuation Shaders." << std::endl;
exit(1);
}
glUseProgram(m_thicknessAttenProgram.programID);
std::cout << "Thickness Attenuation Shaders initialized successfully." << std::endl;
// =================== Visulisation shader ========================= // =================== Visulisation shader =========================
// Visualization Shader // Visualization Shader
...@@ -266,6 +290,10 @@ void FluidRenderer::initShaderUniforms() ...@@ -266,6 +290,10 @@ void FluidRenderer::initShaderUniforms()
// Thickness buffer program: // Thickness buffer program:
setupShaderProgram(m_thicknessRenderProgram); setupShaderProgram(m_thicknessRenderProgram);
setupShaderProgram(m_thicknessFilterProgram);
setupShaderProgram(m_thicknessAttenProgram);
// Visualization program: // Visualization program:
setupShaderProgram(m_visualizationProgram); setupShaderProgram(m_visualizationProgram);
...@@ -347,6 +375,30 @@ void FluidRenderer::initFBOs() { ...@@ -347,6 +375,30 @@ void FluidRenderer::initFBOs() {
GL_RED, // texture format GL_RED, // texture format
GL_FLOAT); // data type GL_FLOAT); // data type
// Create thicknessFilterProgram FBO
initializeFramebuffer(m_thicknessFilterProgram, GL_R32F, GL_RED, GL_FLOAT);
// Create a temporary texture for pass 1
glGenTextures(1, &m_thicknessFilterTempTex);
glBindTexture(GL_TEXTURE_2D, m_thicknessFilterTempTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, m_fbWidth, m_fbHeight, 0, GL_RED, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Create extra FBO for pass 1
glGenFramebuffers(1, &m_thicknessFilterTempFBO);
glBindFramebuffer(GL_FRAMEBUFFER, m_thicknessFilterTempFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_thicknessFilterTempTex, 0);
GLenum drawBufs2[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawBufs2);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Temp FBO for thickness filter not complete!\n";
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
initializeFramebuffer(m_thicknessAttenProgram, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
// Initialize Visualization Render Shader FBO with GL_RGBA8 // Initialize Visualization Render Shader FBO with GL_RGBA8
initializeFramebuffer(m_visualizationProgram, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); initializeFramebuffer(m_visualizationProgram, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
...@@ -829,6 +881,117 @@ void FluidRenderer::renderThicknessFrame(size_t particleCount, size_t boundaryCo ...@@ -829,6 +881,117 @@ void FluidRenderer::renderThicknessFrame(size_t particleCount, size_t boundaryCo
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
void FluidRenderer::renderThicknessFilterFrame()
{
int radius = 6; // or something
std::vector<float> weights;
computeGaussianWeights(radius, weights);
// 1) Horizontal pass -> m_thicknessFilterTempFBO
{
glBindFramebuffer(GL_FRAMEBUFFER, m_thicknessFilterTempFBO);
glViewport(0, 0, m_fbWidth, m_fbHeight);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(m_thicknessFilterProgram.programID);
// Bind the original thickness texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_thicknessRenderProgram.fboTexture);
glUniform1i(glGetUniformLocation(m_thicknessFilterProgram.programID, "uThicknessTex"), 0);
// set passDirection horizontally
float passDirX = 1.0f / m_fbWidth;
float passDirY = 0.0f;
glUniform2f(glGetUniformLocation(m_thicknessFilterProgram.programID, "passDirection"), passDirX, passDirY);
// kernelRadius
glUniform1i(glGetUniformLocation(m_thicknessFilterProgram.programID, "kernelRadius"), radius);
// upload weights
glUniform1fv(glGetUniformLocation(m_thicknessFilterProgram.programID, "gaussWeights"), radius+1, weights.data());
// Render quad
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// 2) Vertical pass -> m_thicknessFilterProgram.fbo
{
glBindFramebuffer(GL_FRAMEBUFFER, m_thicknessFilterProgram.fbo);
glViewport(0, 0, m_fbWidth, m_fbHeight);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(m_thicknessFilterProgram.programID);
// Now the input is m_thicknessFilterTempTex
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_thicknessFilterTempTex);
glUniform1i(glGetUniformLocation(m_thicknessFilterProgram.programID, "uThicknessTex"), 0);
// passDirection vertically
float passDirX2 = 0.0f;
float passDirY2 = 1.0f / m_fbHeight;
glUniform2f(glGetUniformLocation(m_thicknessFilterProgram.programID, "passDirection"), passDirX2, passDirY2);
glUniform1i(glGetUniformLocation(m_thicknessFilterProgram.programID, "kernelRadius"), radius);
glUniform1fv(glGetUniformLocation(m_thicknessFilterProgram.programID, "gaussWeights"), radius+1, weights.data());
// Draw
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
void FluidRenderer::renderThicknessAttenFrame()
{
// 1) Bind some FBO to store the attenuation result
// If you want a new FBO, e.g. m_thicknessAttenProgram
glBindFramebuffer(GL_FRAMEBUFFER, m_thicknessAttenProgram.fbo);
glViewport(0, 0, m_fbWidth, m_fbHeight);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(m_thicknessAttenProgram.programID);
// 2) Bind blurred thickness
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_thicknessFilterProgram.fboTexture);
glUniform1i(glGetUniformLocation(m_thicknessAttenProgram.programID, "uThicknessTex"), 0);
// 3) Set uniform: absorption, fluidColor, etc.
float absorption = 1.0f; // tweak to taste
GLuint absorpLoc = glGetUniformLocation(m_thicknessAttenProgram.programID, "absorption");
glUniform1f(absorpLoc, absorption);
// color
float fluidR = 0.2f, fluidG = 0.7f, fluidB = 1.0f;
glUniform3f(glGetUniformLocation(m_thicknessAttenProgram.programID, "fluidColor"),
fluidR, fluidG, fluidB);
// 4) Render a fullscreen quad
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Visualize Buffer // Visualize Buffer
void FluidRenderer::visualizeBuffer(RenderStage stage) void FluidRenderer::visualizeBuffer(RenderStage stage)
...@@ -881,6 +1044,10 @@ GLuint FluidRenderer::getTexture(RenderStage stage) const { ...@@ -881,6 +1044,10 @@ GLuint FluidRenderer::getTexture(RenderStage stage) const {
return m_depthFilterProgram.fboTexture; return m_depthFilterProgram.fboTexture;
case RenderStage::DepthNormals: case RenderStage::DepthNormals:
return m_depthNormalsProgram.fboTexture; return m_depthNormalsProgram.fboTexture;
case RenderStage::FilteredThickness:
return m_thicknessFilterProgram.fboTexture;
case RenderStage::LightAttenuation:
return m_thicknessAttenProgram.fboTexture;
default: default:
return 0; // Return 0 if no valid stage was selected return 0; // Return 0 if no valid stage was selected
} }
......
...@@ -177,10 +177,11 @@ namespace FluidSimulation { ...@@ -177,10 +177,11 @@ namespace FluidSimulation {
const char* stageOptions[] = { const char* stageOptions[] = {
"Normal", "Normal",
"Depth Buffer", "Depth Buffer",
"Thickness Buffer",
"Filtered Depth", "Filtered Depth",
"Depth Normals", "Depth Normals",
"Filtered Thickness" "Thickness Buffer",
"Filtered Thickness",
"Light Attenuation"
}; };
if (ImGui::Combo("Rendering Stage", reinterpret_cast<int*>(&selectedStage), stageOptions, IM_ARRAYSIZE(stageOptions))) if (ImGui::Combo("Rendering Stage", reinterpret_cast<int*>(&selectedStage), stageOptions, IM_ARRAYSIZE(stageOptions)))
...@@ -248,7 +249,21 @@ namespace FluidSimulation { ...@@ -248,7 +249,21 @@ namespace FluidSimulation {
m_fluidRenderer->renderThicknessFrame(particleCount, boundaryCount); m_fluidRenderer->renderThicknessFrame(particleCount, boundaryCount);
m_fluidRenderer->visualizeBuffer(RenderStage::ThicknessBuffer); m_fluidRenderer->visualizeBuffer(RenderStage::ThicknessBuffer);
break; break;
case RenderStage::FilteredThickness:
printf("Render Filtered Thickness \n");
m_fluidRenderer->renderThicknessFrame(particleCount, boundaryCount);
m_fluidRenderer->renderThicknessFilterFrame();
m_fluidRenderer->visualizeBuffer(RenderStage::FilteredThickness);
break;
case RenderStage::LightAttenuation:
printf("Render Filtered Thickness \n");
m_fluidRenderer->renderThicknessFrame(particleCount, boundaryCount);
m_fluidRenderer->renderThicknessFilterFrame();
m_fluidRenderer->renderThicknessAttenFrame();
break;
default: default:
std::cerr << "Unknown RenderStage selected." << std::endl; std::cerr << "Unknown RenderStage selected." << std::endl;
break; break;
...@@ -262,13 +277,15 @@ namespace FluidSimulation { ...@@ -262,13 +277,15 @@ namespace FluidSimulation {
GLuint textureID = 0; GLuint textureID = 0;
if (selectedStage == RenderStage::FinalOutput if (selectedStage == RenderStage::FinalOutput
|| selectedStage == RenderStage::DepthNormals) || selectedStage == RenderStage::DepthNormals
|| selectedStage == RenderStage::LightAttenuation)
{ {
textureID = m_fluidRenderer->getTexture(selectedStage); // RGBA8 textureID = m_fluidRenderer->getTexture(selectedStage); // RGBA8
} }
else if (selectedStage == RenderStage::DepthBuffer else if (selectedStage == RenderStage::DepthBuffer
|| selectedStage == RenderStage::ThicknessBuffer || selectedStage == RenderStage::ThicknessBuffer
|| selectedStage == RenderStage::FilteredDepth) || selectedStage == RenderStage::FilteredDepth
|| selectedStage == RenderStage::FilteredThickness)
{ {
// Use the visualization texture // Use the visualization texture
textureID = m_fluidRenderer->getVisualizationTexture(); textureID = m_fluidRenderer->getVisualizationTexture();
......
...@@ -13,10 +13,11 @@ namespace FluidSimulation { ...@@ -13,10 +13,11 @@ namespace FluidSimulation {
enum class RenderStage { enum class RenderStage {
FinalOutput, FinalOutput,
DepthBuffer, DepthBuffer,
ThicknessBuffer,
FilteredDepth, FilteredDepth,
DepthNormals, DepthNormals,
FilteredThickness ThicknessBuffer,
FilteredThickness,
LightAttenuation
}; };
// Structure to encapsulate shader program details // Structure to encapsulate shader program details
...@@ -72,12 +73,17 @@ private: ...@@ -72,12 +73,17 @@ private:
ShaderProgram m_depthNormalsProgram; ShaderProgram m_depthNormalsProgram;
ShaderProgram m_thicknessRenderProgram; // For thickness shaders ShaderProgram m_thicknessRenderProgram; // For thickness shaders
ShaderProgram m_thicknessFilterProgram;
ShaderProgram m_thicknessAttenProgram;
ShaderProgram m_visualizationProgram; // For visualization shaders ShaderProgram m_visualizationProgram; // For visualization shaders
GLuint m_depthFilterTempTex; GLuint m_depthFilterTempTex;
GLuint m_depthFilterTempFBO; // temporary fbo forfilter passes GLuint m_depthFilterTempFBO; // temporary fbo forfilter passes
GLuint m_thicknessFilterTempTex;
GLuint m_thicknessFilterTempFBO;
// VBOs for particles and boundaries // VBOs for particles and boundaries
GLuint m_particleVBO; GLuint m_particleVBO;
GLuint m_boundaryVBO; GLuint m_boundaryVBO;
...@@ -145,7 +151,8 @@ public: ...@@ -145,7 +151,8 @@ public:
void renderDepthNormalsFrame(); void renderDepthNormalsFrame();
void renderThicknessFrame(size_t particleCount, size_t boundaryCount); void renderThicknessFrame(size_t particleCount, size_t boundaryCount);
void renderThicknessFilterFrame();
void renderThicknessAttenFrame();
void visualizeBuffer(RenderStage stage); // Visualize selected render stage void visualizeBuffer(RenderStage stage); // Visualize selected render stage
// Methods to retrieve textures based on RenderStage // Methods to retrieve textures based on RenderStage
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment