From 7e230e33cb56e3af378458ac00b666c11e281719 Mon Sep 17 00:00:00 2001 From: Perminder Date: Fri, 10 Jan 2025 23:42:43 +0530 Subject: [PATCH] volume-rendering Signed-off-by: Perminder --- avogadro/qtplugins/surfaces/surfaces.h | 2 + avogadro/rendering/CMakeLists.txt | 2 + avogadro/rendering/glrenderer.h | 1 + avogadro/rendering/solidBox_fs.glsl | 6 + avogadro/rendering/solidBox_vs.glsl | 6 + avogadro/rendering/solid_first_fs.glsl | 199 ++++++------ avogadro/rendering/solid_vs.glsl | 2 +- avogadro/rendering/solidpipeline.cpp | 431 +++++++++++++++++++++---- avogadro/rendering/solidpipeline.h | 18 ++ 9 files changed, 505 insertions(+), 162 deletions(-) create mode 100644 avogadro/rendering/solidBox_fs.glsl create mode 100644 avogadro/rendering/solidBox_vs.glsl diff --git a/avogadro/qtplugins/surfaces/surfaces.h b/avogadro/qtplugins/surfaces/surfaces.h index ee476ca3da..c41d6fedd8 100644 --- a/avogadro/qtplugins/surfaces/surfaces.h +++ b/avogadro/qtplugins/surfaces/surfaces.h @@ -85,6 +85,8 @@ class Surfaces : public QtGui::ExtensionPlugin public slots: bool handleCommand(const QString& command, const QVariantMap& options) override; + + // void updateGLWidget(QtOpenGL::GLWidget* widget); void moleculeChanged(unsigned int changes); private slots: diff --git a/avogadro/rendering/CMakeLists.txt b/avogadro/rendering/CMakeLists.txt index ddebfe8483..508e406ce9 100644 --- a/avogadro/rendering/CMakeLists.txt +++ b/avogadro/rendering/CMakeLists.txt @@ -108,6 +108,8 @@ set(shader_files "mesh_vs.glsl" "solid_vs.glsl" "solid_first_fs.glsl" + "solidBox_vs.glsl" + "solidBox_fs.glsl" "spheres_fs.glsl" "spheres_vs.glsl" "sphere_ao_depth_vs.glsl" diff --git a/avogadro/rendering/glrenderer.h b/avogadro/rendering/glrenderer.h index 86642a2ae3..ba8118dd6b 100644 --- a/avogadro/rendering/glrenderer.h +++ b/avogadro/rendering/glrenderer.h @@ -17,6 +17,7 @@ #include "solidpipeline.h" #include +#include #include #include // For member variables. diff --git a/avogadro/rendering/solidBox_fs.glsl b/avogadro/rendering/solidBox_fs.glsl new file mode 100644 index 0000000000..e186f3e350 --- /dev/null +++ b/avogadro/rendering/solidBox_fs.glsl @@ -0,0 +1,6 @@ +#version 120 + +void main() { + // Just write out any color, we only care about depth in FBO + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/avogadro/rendering/solidBox_vs.glsl b/avogadro/rendering/solidBox_vs.glsl new file mode 100644 index 0000000000..d2aacf7870 --- /dev/null +++ b/avogadro/rendering/solidBox_vs.glsl @@ -0,0 +1,6 @@ +#version 120 +attribute vec3 aPosition; +uniform mat4 uMVP; +void main() { + gl_Position = uMVP * vec4(aPosition, 1.0); +} \ No newline at end of file diff --git a/avogadro/rendering/solid_first_fs.glsl b/avogadro/rendering/solid_first_fs.glsl index b95274fdc6..a6d9ce7a9e 100644 --- a/avogadro/rendering/solid_first_fs.glsl +++ b/avogadro/rendering/solid_first_fs.glsl @@ -1,125 +1,110 @@ -////////////////////////////////////////////////////////////////////// -// -// First-stage screen-space fragment shader for the solid pipeline -// -// It offers ambient occlusion and edge detection capabilities. -// -////////////////////////////////////////////////////////////////////// - #version 120 -// -// Input -// - -// texture coordinates +// Interpolated UV from the vertex shader varying vec2 UV; -// -// Uniforms -// - -// RGB rendered texture +// Scene textures uniform sampler2D inRGBTex; -// Depth rendered texture -uniform sampler2D inDepthTex; -// 1.0 if enabled, 0.0 if disabled +uniform sampler2D inFrontDepthTex; +uniform sampler2D inBackDepthTex; + +// The 3D volume data +uniform sampler3D uVolumeData; + +// A 2D colormap texture (the “transfer function”) +// uniform sampler2D colormap; + +// Some toggles from your pipeline (if needed) uniform float inAoEnabled; -// Shadow strength for SSAO uniform float inAoStrength; -// 1.0 if enabled, 0.0 if disabled uniform float inEdStrength; -// 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); -} +// Screen size (passed in from C++ code, if needed) +uniform float width; +uniform float height; -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); -} +// Transfer-function range +uniform float transferMin; +uniform float transferMax; -float lerp(float a, float b, float f) -{ - return a + f * (b - a); -} +// How many steps to take, etc. +uniform int numSteps; // e.g., 128 +uniform float alphaScale; // e.g., 0.1 or something similar -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) -); - -float computeSSAOLuminosity(vec3 normal) +void main() { - 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; + // 1) Fetch the scene color + vec4 sceneColor = texture2D(inRGBTex, UV); + + // 2) Fetch front and back depths + float frontDepth = texture2D(inFrontDepthTex, UV).r; + float backDepth = texture2D(inBackDepthTex, UV).r; + + // Basic sanity checks: if the box is clipped or if front/back are invalid + if (frontDepth >= 1.0 || backDepth >= 1.0 || backDepth <= frontDepth) { + gl_FragColor = sceneColor; + return; } - - 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)); -} + // 3) Compute the total “thickness” in normalized [0..1] Z + float thickness = backDepth - frontDepth; -void main() -{ - float luminosity = 1.0; - luminosity *= max(1.2 * (1.0 - inAoEnabled), computeSSAOLuminosity(getNormalNear(UV))); - luminosity *= max(1.0 - inEdStrength, computeEdgeLuminosity(getNormalAt(UV))); + // Step size for the raymarch + float stepSize = thickness / float(numSteps); + + // 4) Accumulate color over the ray + vec4 accumulatedColor = vec4(0.0); + + // Raymarch from frontDepth to backDepth + for (int i = 0; i < numSteps; i++) { + // Parametric Z coordinate in [frontDepth..backDepth] + float z = frontDepth + (float(i) + 0.5) * stepSize; + + // UVW in volume texture: XY from screen, Z in [0..1] (assuming the volume + // is also in [0..1] for that axis). You may need to invert or shift if + // your volume is mapped differently. + vec3 uvw = vec3(UV, -z); + + // Sample the raw density or intensity from the volume + float rawVal = texture3D(uVolumeData, uvw).r; + + // Map that raw value to [0..1] for a colormap lookup + float cval = (rawVal - transferMin) / (transferMax - transferMin); + cval = clamp(cval, 0.0, 1.0); + + // Fetch a color from the colormap — assume 1D colormap along X, + // picking the center of Y=0.5 if it’s just a 1D gradient stored in a 2D texture + vec4 sampleColor = vec4(1.0,0.0,1.0,0.5); + + // Scale alpha if you want the volume to be more or less transparent + // (like your ALPHA_SCALE from the original code) + sampleColor.a *= alphaScale; + + // Standard “over” alpha compositing: + float remainingAlpha = 1.0 - accumulatedColor.a; + accumulatedColor.rgb += sampleColor.rgb * sampleColor.a * remainingAlpha; + accumulatedColor.a += sampleColor.a * remainingAlpha; + + // Optional early-out if almost fully opaque: + if (accumulatedColor.a >= 0.5) + break; + } + + // 5) (Optional) If you have toggles for AO or edges: + // For demonstration, we do something simple: + if (inAoEnabled < 0.5) { + // Example: make the volume darker if AO is disabled + accumulatedColor.rgb *= 0.5; + } + // Scale by AO strength (could be done differently) + accumulatedColor.rgb *= inAoStrength; + + // 6) Composite final volume color over the original scene + // Similar to “1 - alpha” logic you had: + float oneMinusA = 1.0 - accumulatedColor.a; + vec3 finalRGB = accumulatedColor.rgb + oneMinusA * sceneColor.rgb; + float finalA = sceneColor.a + oneMinusA * accumulatedColor.a; - vec4 color = texture2D(inRGBTex, UV); - gl_FragColor = vec4(color.xyz * luminosity, color.w); - gl_FragDepth = texture2D(inDepthTex, UV).x; + // Write out final pixel color + gl_FragColor = vec4(finalRGB, finalA); } diff --git a/avogadro/rendering/solid_vs.glsl b/avogadro/rendering/solid_vs.glsl index 098abbf9bb..6bf7ad939c 100644 --- a/avogadro/rendering/solid_vs.glsl +++ b/avogadro/rendering/solid_vs.glsl @@ -20,6 +20,6 @@ varying vec2 UV; void main() { - gl_Position = vec4(inXYZ.xyz, 1.0); + gl_Position = vec4(inXYZ.xyz, 0.5); UV = inXYZ.xy * vec2(0.5, 0.5) + vec2(0.5, 0.5); } diff --git a/avogadro/rendering/solidpipeline.cpp b/avogadro/rendering/solidpipeline.cpp index a313d99b82..4513ea9b69 100644 --- a/avogadro/rendering/solidpipeline.cpp +++ b/avogadro/rendering/solidpipeline.cpp @@ -9,11 +9,20 @@ #include "shader.h" #include "shaderprogram.h" -#include "solid_vs.h" +// Box pass ke liye simple vertex shader (neeche define kiya hai) +#include "solidBox_vs.h" +#include "solidBox_fs.h" +// Tumhara fullscreen pass vertex shader (jo Quad ke liye use hota hai) +#include "solid_vs.h" #include "solid_first_fs.h" +#include +#include "camera.h" + #include +#include +#include namespace Avogadro::Rendering { @@ -22,71 +31,187 @@ class SolidPipeline::Private public: Private() {} - void attachStage(ShaderProgram& prog, const GLchar* nameRGB, GLuint texRGB, - const GLchar* nameDepth, GLuint texDepth, int w, int h) + /** Attach the main scene stage (color+depth). */ + void attachStage(ShaderProgram& prog, + const GLchar* nameRGB, GLuint texRGB, + const GLchar* nameDepth, GLuint texDepth, + int w, int h) { prog.bind(); GLuint programID; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&programID); + // Scene color GLuint attrRGB = glGetUniformLocation(programID, nameRGB); - glActiveTexture(GL_TEXTURE0 + 1); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texRGB); glUniform1i(attrRGB, 1); + // Scene depth GLuint attrDepth = glGetUniformLocation(programID, nameDepth); - glActiveTexture(GL_TEXTURE0 + 2); + glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, texDepth); glUniform1i(attrDepth, 2); - prog.setUniformValue("width", float(w)); + // Pass screen size + prog.setUniformValue("width", float(w)); + prog.setUniformValue("height", float(h)); + } + + /** Attach front/back depth passes for the volume bounding box. */ + void attachVolumeStage(ShaderProgram& prog, + const GLchar* frontDepthName, GLuint frontDepthTex, + const GLchar* backDepthName, GLuint backDepthTex, + int w, int h) + { + prog.bind(); + GLuint programID; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&programID); + + // Front face depth + GLuint frontLoc = glGetUniformLocation(programID, frontDepthName); + glActiveTexture(GL_TEXTURE4); + glBindTexture(GL_TEXTURE_2D, frontDepthTex); + glUniform1i(frontLoc, 4); + + // Back face depth + GLuint backLoc = glGetUniformLocation(programID, backDepthName); + glActiveTexture(GL_TEXTURE5); + glBindTexture(GL_TEXTURE_2D, backDepthTex); + glUniform1i(backLoc, 5); + + // Pass screen size + prog.setUniformValue("width", float(w)); prog.setUniformValue("height", float(h)); } - GLuint defaultFBO; - GLuint renderFBO; - GLuint renderTexture; - GLuint depthTexture; - GLuint screenVBO; - ShaderProgram firstStageShaders; + /** Our FBOs and textures. */ + GLuint defaultFBO; // The system FBO (screen) + GLuint renderFBO; // Main scene FBO + GLuint renderTexture; // Main scene color + GLuint depthTexture; // Main scene depth + + // Front/back passes + GLuint frontFBO; + GLuint frontColorTexture; + GLuint frontDepthTexture; + + GLuint backFBO; + GLuint backColorTexture; + GLuint backDepthTexture; + + // Volume rendering data + GLuint volumeTexture; // 3D volume + GLuint screenVBO; // Fullscreen quad VBO + + // Shaders + ShaderProgram boxShaders; // <-- For drawing the bounding box + Shader boxVertexShader; + Shader boxFragmentShader; + + ShaderProgram firstStageShaders; // <-- For compositing Shader screenVertexShader; Shader firstFragmentShader; + + // Box geometry for front/back pass + GLuint volumeBoxVao; + GLuint volumeBoxVbo; + GLuint volumeBoxEbo; }; +// Fullscreen quad vertices static const GLfloat s_fullscreenQuad[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, + -1.f, -1.f, 0.f, + 1.f, -1.f, 0.f, + -1.f, 1.f, 0.f, + + -1.f, 1.f, 0.f, + 1.f, -1.f, 0.f, + 1.f, 1.f, 0.f, +}; + +// A simple cube bounding box +static const GLfloat boxVertices[] = { + // x y z + // Front face + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + + // Back face + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, }; +static const GLuint boxIndices[] = { + // Front face + 0, 1, 2, + 2, 3, 0, + // Back face + 4, 5, 6, + 6, 7, 4, + // Left face + 4, 0, 3, + 3, 7, 4, + // Right face + 1, 5, 6, + 6, 2, 1, + // Top face + 3, 2, 6, + 6, 7, 3, + // Bottom face + 4, 5, 1, + 1, 0, 4 +}; + +// Helper to create an FBO void initializeFramebuffer(GLuint* outFBO, GLuint* texRGB, GLuint* texDepth) { glGenFramebuffers(1, outFBO); glBindFramebuffer(GL_FRAMEBUFFER, *outFBO); + // Color glGenTextures(1, texRGB); glBindTexture(GL_TEXTURE_2D, *texRGB); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - *texRGB, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, *texRGB, 0); + // Depth glGenTextures(1, texDepth); glBindTexture(GL_TEXTURE_2D, *texDepth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 1, 1, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - *texDepth, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, *texDepth, 0); + + GLenum drawBuffersList[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, drawBuffersList); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + std::cerr << "Error: FBO not complete!" << std::endl; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); } SolidPipeline::SolidPipeline() - : m_pixelRatio(1.0f), m_aoEnabled(true), m_aoStrength(1.0f), - m_edEnabled(true), m_edStrength(1.0f), m_width(0), m_height(0), + : m_pixelRatio(1.0f), + m_aoEnabled(true), + m_aoStrength(1.0f), + m_edEnabled(true), + m_edStrength(1.0f), + m_width(0), + m_height(0), d(new Private) { } @@ -98,83 +223,280 @@ SolidPipeline::~SolidPipeline() void SolidPipeline::initialize() { + // 1) Create FBOs initializeFramebuffer(&d->renderFBO, &d->renderTexture, &d->depthTexture); + initializeFramebuffer(&d->backFBO, &d->backColorTexture, &d->backDepthTexture); + initializeFramebuffer(&d->frontFBO, &d->frontColorTexture,&d->frontDepthTexture); + + // 2) Make a 3D volume texture + glGenTextures(1, &d->volumeTexture); + glBindTexture(GL_TEXTURE_3D, d->volumeTexture); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + int size = 64; + std::vector volumeData(size * size * size); + for (int z = 0; z < size; ++z) { + for (int y = 0; y < size; ++y) { + for (int x = 0; x < size; ++x) { + float dx = (x - size / 2.0f) / (size / 2.0f); + float dy = (y - size / 2.0f) / (size / 2.0f); + float dz = (z - size / 2.0f) / (size / 2.0f); + float dist = std::sqrt(dx*dx + dy*dy + dz*dz); + volumeData[z*size*size + y*size + x] = std::exp(-3.0f * dist); + } + } + } + glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, + size, size, size, 0, + GL_RED, GL_FLOAT, + volumeData.data()); + + // 3) Create box geometry VAO + glGenVertexArrays(1, &d->volumeBoxVao); + glBindVertexArray(d->volumeBoxVao); + + glGenBuffers(1, &d->volumeBoxVbo); + glBindBuffer(GL_ARRAY_BUFFER, d->volumeBoxVbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(boxVertices), + boxVertices, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + 3*sizeof(GLfloat), (GLvoid*)0); + glGenBuffers(1, &d->volumeBoxEbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d->volumeBoxEbo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(boxIndices), + boxIndices, GL_STATIC_DRAW); + + glBindVertexArray(0); + + // 4) Fullscreen quad glGenBuffers(1, &d->screenVBO); glBindBuffer(GL_ARRAY_BUFFER, d->screenVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(s_fullscreenQuad), s_fullscreenQuad, - GL_STATIC_DRAW); - + glBufferData(GL_ARRAY_BUFFER, sizeof(s_fullscreenQuad), + s_fullscreenQuad, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // 5) Box pass ke liye simple shaders + d->boxVertexShader.setType(Shader::Vertex); + d->boxVertexShader.setSource(solidBox_vs); // string with simple VS + if (!d->boxVertexShader.compile()) + std::cerr << d->boxVertexShader.error() << std::endl; + + d->boxFragmentShader.setType(Shader::Fragment); + d->boxFragmentShader.setSource(solidBox_fs); // string with simple FS + if (!d->boxFragmentShader.compile()) + std::cerr << d->boxFragmentShader.error() << std::endl; + + d->boxShaders.attachShader(d->boxVertexShader); + d->boxShaders.attachShader(d->boxFragmentShader); + if (!d->boxShaders.link()) + std::cerr << d->boxShaders.error() << std::endl; + + // 6) Fullscreen pass (tumhare hi vs + fs) d->screenVertexShader.setType(Shader::Vertex); d->screenVertexShader.setSource(solid_vs); if (!d->screenVertexShader.compile()) - std::cout << d->screenVertexShader.error() << std::endl; + std::cerr << d->screenVertexShader.error() << std::endl; d->firstFragmentShader.setType(Shader::Fragment); d->firstFragmentShader.setSource(solid_first_fs); if (!d->firstFragmentShader.compile()) - std::cout << d->firstFragmentShader.error() << std::endl; + std::cerr << d->firstFragmentShader.error() << std::endl; d->firstStageShaders.attachShader(d->screenVertexShader); d->firstStageShaders.attachShader(d->firstFragmentShader); if (!d->firstStageShaders.link()) - std::cout << d->firstStageShaders.error() << std::endl; + std::cerr << d->firstStageShaders.error() << std::endl; +} + +void SolidPipeline::renderVolumeFaces(const Camera& cam) +{ + // Simple approach: use boxShaders to set up MVP + d->boxShaders.bind(); + + // Get the combined projection * modelView + Eigen::Matrix4f projView = cam.projection().matrix() * cam.modelView().matrix(); + d->boxShaders.setUniformValue("uMVP", projView); + + // BACK FACES + glBindFramebuffer(GL_FRAMEBUFFER, d->backFBO); + { + GLenum drawBuffersList[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, drawBuffersList); + + glViewport(0, 0, m_width, m_height); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); // cull front, show back + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindVertexArray(d->volumeBoxVao); + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + } + + // FRONT FACES + glBindFramebuffer(GL_FRAMEBUFFER, d->frontFBO); + { + GLenum drawBuffersList[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, drawBuffersList); + + glViewport(0, 0, m_width, m_height); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); // cull back, show front + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindVertexArray(d->volumeBoxVao); + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + } + + glUseProgram(0); } void SolidPipeline::begin() { + // Save default FBO glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&d->defaultFBO); + + // Bind main scene FBO glBindFramebuffer(GL_FRAMEBUFFER, d->renderFBO); GLenum drawBuffersList[1] = { GL_COLOR_ATTACHMENT0 }; glDrawBuffers(1, drawBuffersList); - GLfloat tmp[5]; - glGetFloatv(GL_COLOR_CLEAR_VALUE, tmp); - glGetFloatv(GL_DEPTH_CLEAR_VALUE, tmp + 4); + // Clear + GLfloat oldClearColor[4]; + glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColor); + GLfloat oldDepthClear; + glGetFloatv(GL_DEPTH_CLEAR_VALUE, &oldDepthClear); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glClearColor(tmp[0], tmp[1], tmp[2], tmp[3]); - glClearDepth(tmp[4]); + + // Restore old clear color + glClearColor(oldClearColor[0], oldClearColor[1], + oldClearColor[2], oldClearColor[3]); + glClearDepth(oldDepthClear); + + // Enable blending + depth + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_DEPTH_TEST); } void SolidPipeline::end() { - // Draw fullscreen quad - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, d->screenVBO); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - // Draw to screen + // Bind default FBO again if (glIsFramebuffer(d->defaultFBO)) { glBindFramebuffer(GL_FRAMEBUFFER, d->defaultFBO); GLenum drawBuffersList[1] = { GL_COLOR_ATTACHMENT0 }; glDrawBuffers(1, drawBuffersList); - } else { + } + else { glBindFramebuffer(GL_FRAMEBUFFER, 0); glDrawBuffer(GL_BACK); } - d->attachStage(d->firstStageShaders, "inRGBTex", d->renderTexture, "inDepthTex", - d->depthTexture, m_width, m_height); - d->firstStageShaders.setUniformValue("inAoEnabled", m_aoEnabled ? 1.0f : 0.0f); + + // Composite pass + d->attachStage(d->firstStageShaders, + "inRGBTex", d->renderTexture, + "inDepthTex", d->depthTexture, + m_width, m_height); + + d->attachVolumeStage(d->firstStageShaders, + "inFrontDepthTex", d->frontDepthTexture, + "inBackDepthTex", d->backDepthTexture, + m_width, m_height); + + d->firstStageShaders.bind(); + // Basic user uniforms + d->firstStageShaders.setUniformValue("inAoEnabled", (m_aoEnabled ? 1.0f : 0.0f)); d->firstStageShaders.setUniformValue("inAoStrength", m_aoStrength); d->firstStageShaders.setUniformValue("inEdStrength", m_edStrength); + d->firstStageShaders.setUniformValue("transferMin", 0.0f); + d->firstStageShaders.setUniformValue("transferMax", 1.0f); + d->firstStageShaders.setUniformValue("numSteps", 128); + d->firstStageShaders.setUniformValue("alphaScale", 0.02f); + + // Bind volume + GLint progID = 0; + glGetIntegerv(GL_CURRENT_PROGRAM, &progID); + GLint volLoc = glGetUniformLocation(progID, "uVolumeData"); + if (volLoc >= 0) { + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_3D, d->volumeTexture); + glUniform1i(volLoc, 3); + } + + // Fullscreen quad + glBindBuffer(GL_ARRAY_BUFFER, d->screenVBO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + 3*sizeof(GLfloat), (GLvoid*)0); + glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); } void SolidPipeline::resize(int width, int height) { - m_width = width * m_pixelRatio; - m_height = height * m_pixelRatio; + m_width = static_cast(width * m_pixelRatio); + m_height = static_cast(height * m_pixelRatio); + // Re-allocate FBO textures glBindTexture(GL_TEXTURE_2D, d->renderTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, d->depthTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_width, m_height, 0, - GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_width, m_height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + + glBindTexture(GL_TEXTURE_2D, d->backColorTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + glBindTexture(GL_TEXTURE_2D, d->backDepthTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_width, m_height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + + glBindTexture(GL_TEXTURE_2D, d->frontColorTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + glBindTexture(GL_TEXTURE_2D, d->frontDepthTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_width, m_height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); +} + +void SolidPipeline::adjustOffset(const Camera& cam) +{ + // Yeh function agar tumhe extra uniform set karni ho to use karo + // Warna abhi ke liye zyada zaroorat nahi, kyunki volume faces ke liye + // main alag se MVP pass kar raha hoon (renderVolumeFaces()) mein. + // + // Example: + // Eigen::Matrix4f projectView = cam.projection().matrix() * cam.modelView().matrix(); + // d->firstStageShaders.setUniformValue("uPV", projectView); } void SolidPipeline::setPixelRatio(float ratio) @@ -182,4 +504,5 @@ void SolidPipeline::setPixelRatio(float ratio) m_pixelRatio = ratio; } -} // End namespace Avogadro::Rendering +} // end namespace + diff --git a/avogadro/rendering/solidpipeline.h b/avogadro/rendering/solidpipeline.h index 8c982bdc2d..1bc01148a1 100644 --- a/avogadro/rendering/solidpipeline.h +++ b/avogadro/rendering/solidpipeline.h @@ -6,6 +6,8 @@ #ifndef AVOGADRO_RENDERING_SOLIDPIPELINE_H #define AVOGADRO_RENDERING_SOLIDPIPELINE_H +#include +#include "camera.h" namespace Avogadro { namespace Rendering { @@ -26,6 +28,7 @@ class SolidPipeline */ void initialize(); + void renderVolumeFaces(const Camera& cam); /** * @brief Begin solid geometry rendering. */ @@ -41,15 +44,24 @@ class SolidPipeline */ void resize(int width, int height); + void adjustOffset(const Camera& camera); + /** * @brief Set pixel ratio (1.0 on standard displays, 2.0 on Retina, etc.). */ void setPixelRatio(float ratio); + /** * @brief Get or set whether Ambient Occlusion is enabled. */ bool getAoEnabled() { return m_aoEnabled; } + + void setData(float data); + + float getData() const; + + void setAoEnabled(bool enabled) { m_aoEnabled = enabled; } /** @@ -57,6 +69,10 @@ class SolidPipeline */ float getAoStrength() { return m_aoStrength; } void setAoStrength(float strength) { m_aoStrength = strength; } + + float getBackground() { return background; } + + void setBackground(float strength) { background = strength; } /** * @brief Get or set whether Edge Detection is enabled. @@ -82,6 +98,8 @@ class SolidPipeline float m_edStrength; int m_width; int m_height; + float m_currentCube; + float background; class Private; Private* d;