Commit e475b505 authored by Marc R.'s avatar Marc R.

raycaster improvement: DVR correctly terminates at current depth buffer position

parent 0eee285c
......@@ -153,7 +153,9 @@ MNWPVolumeRaycasterActor::OpenGL::OpenGL()
tex2DShadowImage(nullptr),
texUnitShadowImage(-1),
tex2DDepthBuffer(nullptr),
texUnitDepthBuffer(-1)
texUnitDepthBuffer(-1),
textureDepthBufferMirror(nullptr),
textureUnitDepthBufferMirror(-1)
{
}
......@@ -521,6 +523,12 @@ MNWPVolumeRaycasterActor::~MNWPVolumeRaycasterActor()
if (gl.texUnitShadowImage >=0) releaseTextureUnit(gl.texUnitShadowImage);
if (gl.texUnitDepthBuffer >=0) releaseTextureUnit(gl.texUnitDepthBuffer);
for (GLuint fbo : gl.fboDepthBuffer)
{
// Delete framebiffers allocated in mirrorDepthBufferToTexture().
glDeleteFramebuffers(1, &fbo); CHECK_GL_ERROR;
}
delete lightingSettings;
delete rayCasterSettings;
delete normalCurveSettings;
......@@ -1152,6 +1160,12 @@ void MNWPVolumeRaycasterActor::initializeActorResources()
if (gl.texUnitDepthBuffer >=0) releaseTextureUnit(gl.texUnitDepthBuffer);
gl.texUnitDepthBuffer = assignTextureUnit();
if (gl.textureUnitDepthBufferMirror >= 0)
{
releaseTextureUnit(gl.textureUnitDepthBufferMirror);
}
gl.textureUnitDepthBufferMirror = assignTextureUnit();
}
......@@ -2449,6 +2463,9 @@ void MNWPVolumeRaycasterActor::setCommonShaderVars(
shader->setUniformValue(
"mvpMatrix", *(sceneView->getModelViewProjectionMatrix())); CHECK_GL_ERROR;
shader->setUniformValue(
"mvpMatrixInverted",
*(sceneView->getModelViewProjectionMatrixInverted())); CHECK_GL_ERROR;
shader->setUniformValue(
"cameraPosition", sceneView->getCamera()->getOrigin()); CHECK_GL_ERROR;
shader->setUniformValue(
......@@ -2503,12 +2520,21 @@ void MNWPVolumeRaycasterActor::setRayCasterShaderVars(
// 1) Bind the depth buffer texture to the current program.
// Depth buffer for normal curves, rendered by renderToDepthTexture().
if (gl.tex2DDepthBuffer)
{
gl.tex2DDepthBuffer->bindToTextureUnit(gl.texUnitDepthBuffer);
shader->setUniformValue("depthTex", gl.texUnitDepthBuffer);
}
// OpenGL depth buffer, mirrored by mirrorDepthBufferToTexture(). [for DVR]
if (gl.textureDepthBufferMirror)
{
gl.textureDepthBufferMirror->bindToTextureUnit(gl.textureUnitDepthBufferMirror);
shader->setUniformValue("depthBufferMirror", gl.textureUnitDepthBufferMirror);
}
// 2) Set lighting params variables.
shader->setUniformValue("lightingMode", lightingSettings->lightingMode); CHECK_GL_ERROR;
......@@ -2550,6 +2576,11 @@ void MNWPVolumeRaycasterActor::setRayCasterShaderVars(
shader->setUniformValue(
"renderingMode", GLint(renderMode)); CHECK_GL_ERROR;
GLint width = sceneView->getViewPortWidth();
GLint height = sceneView->getViewPortHeight();
shader->setUniformValue("viewPortWidth", GLint(width) ); CHECK_GL_ERROR;
shader->setUniformValue("viewPortHeight", GLint(height) ); CHECK_GL_ERROR;
// 4) Set shadow setting variables.
if (rayCasterSettings->shadowMode == RenderMode::ShadowMap)
......@@ -2617,7 +2648,6 @@ void MNWPVolumeRaycasterActor::renderBoundingBox(
}
void MNWPVolumeRaycasterActor::renderPositionCross(
MSceneViewGLWidget *sceneView)
{
......@@ -2631,6 +2661,7 @@ void MNWPVolumeRaycasterActor::renderPositionCross(
glDrawArrays(GL_LINES, 0, 6); CHECK_GL_ERROR;
}
void MNWPVolumeRaycasterActor::renderRayCaster(
std::shared_ptr<GL::MShaderEffect>& effect, MSceneViewGLWidget* sceneView)
{
......@@ -2645,6 +2676,10 @@ void MNWPVolumeRaycasterActor::renderRayCaster(
effect->bindProgram("Volume");
// Mirror current depth buffer for access in shader (cannot be accessed
// directly) for correct ray termination in DVR.
mirrorDepthBufferToTexture(sceneView);
setRayCasterShaderVars(effect, sceneView); CHECK_GL_ERROR;
//pEffect->printSubroutineInformation(GL_FRAGMENT_SHADER);
......@@ -2860,6 +2895,16 @@ void MNWPVolumeRaycasterActor::createShadowImage(
}
pEffect->bindProgram("Shadow");
//NOTE: The glDrawArrays() call below fails if no "depth mirror" texture
// is bound to the shader, although the texture is not used for shadow
// mapping. Hence, we need to create and bind the texture by calling the
// mirror funtion. Since that function binds another framebuffer object,
// re-bind the shadow map framebuffer afterwards.
//TODO (mr, 18Feb2019) -- would be great if this could be avoided...
mirrorDepthBufferToTexture(sceneView);
glBindFramebuffer(GL_FRAMEBUFFER, tempFBO);
setRayCasterShaderVars(pEffect, sceneView);
pEffect->setUniformValue("shadowMode", GLint(RenderMode::ShadowMap));
pEffect->setUniformValue("stepSize", rayCasterSettings->stepSize);
......@@ -3653,4 +3698,73 @@ void MNWPVolumeRaycasterActor::renderToDepthTexture(
//sceneView->makeCurrent();
}
void MNWPVolumeRaycasterActor::mirrorDepthBufferToTexture(
MSceneViewGLWidget *sceneView)
{
// Get extent of current viewport.
const GLint width = sceneView->getViewPortWidth();
const GLint height = sceneView->getViewPortHeight();
if (!gl.textureDepthBufferMirror)
{
// First call: no framebuffer object and no mirror texture exists.
// Generate a texture into which the depth buffer is mirrored.
const QString depthBufferID = QString("textureDepthBuffer_#%1").arg(myID);
gl.textureDepthBufferMirror = new GL::MTexture(
depthBufferID, GL_TEXTURE_2D, GL_DEPTH_COMPONENT32,
width, height);
MGLResourcesManager *glRM = MGLResourcesManager::getInstance();
if (glRM->tryStoreGPUItem(gl.textureDepthBufferMirror))
{
gl.textureDepthBufferMirror = dynamic_cast<GL::MTexture *>(
glRM->getGPUItem(depthBufferID));
}
else
{
delete gl.textureDepthBufferMirror;
gl.textureDepthBufferMirror = nullptr;
}
}
if (!gl.fboDepthBuffer.contains(sceneView))
{
// If not yet existing, generate a framebuffer object for this scene's
// GL context to which the depth buffer can be bound.
// NOTE: Do we really need a separate FBO for each scene view (i.e.
// for each OpenGL context)?
// See: https://www.khronos.org/opengl/wiki/Framebuffer_Object
glGenFramebuffers(1, &gl.fboDepthBuffer[sceneView]);
CHECK_GL_ERROR;
}
if (gl.textureDepthBufferMirror)
{
// Depth buffer mirror already exists, delete its contents.
gl.textureDepthBufferMirror->bindToLastTextureUnit();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
CHECK_GL_ERROR;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
CHECK_GL_ERROR;
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0,
GL_DEPTH_COMPONENT, GL_FLOAT, 0);
CHECK_GL_ERROR;
glBindTexture(GL_TEXTURE_2D, 0);
}
// Attach the "mirror" texture to the depth buffer and copy its content,
// leaving all data on the GPU (we don't need the depth data on the CPU).
glBindFramebuffer(GL_FRAMEBUFFER, gl.fboDepthBuffer[sceneView]);
CHECK_GL_ERROR;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
gl.textureDepthBufferMirror->getTextureObject(), 0);
CHECK_GL_ERROR;
glBlitNamedFramebuffer(0, gl.fboDepthBuffer[sceneView], 0, 0, width, height, 0, 0,
width, height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
CHECK_GL_ERROR;
glBindFramebuffer(GL_FRAMEBUFFER,0); CHECK_GL_ERROR;
}
} // namespace Met3D
......@@ -41,6 +41,7 @@
#include <QVector>
#include <QVector3D>
#include <QMatrix4x4>
#include <QHash>
// local application imports
#include "gxfw/nwpmultivaractor.h"
......@@ -258,6 +259,8 @@ private:
void renderToDepthTexture(MSceneViewGLWidget* sceneView);
void mirrorDepthBufferToTexture(MSceneViewGLWidget* sceneView);
// Class members.
// ==============
......@@ -332,6 +335,14 @@ private:
GL::MTexture* tex2DDepthBuffer;
GLint texUnitDepthBuffer;
// Texture that mirrors the OpenGL depth buffer. Used for DVR to
// store the depths before the raycaster is started, so that the ray
// can be terminated at the corresponding fragment depth. Each scene
// view gets its own framebuffer object.
GL::MTexture* textureDepthBufferMirror;
GLint textureUnitDepthBufferMirror;
QHash<MSceneViewGLWidget*, GLuint> fboDepthBuffer;
// Subroutines.
// ============
......
......@@ -105,6 +105,8 @@ uniform sampler3D minMaxAccel3DShV;
#endif
uniform sampler2D depthTex; // for normal curve integration
uniform sampler2D depthBufferMirror; // mirrored OpenGL depth buffer for
// DVR ray termination
uniform sampler3D dataVolume;
uniform sampler3D dataVolumeShV; // shading var data
......@@ -114,6 +116,7 @@ uniform sampler1D lonLatLevAxesShV;
// matrices
// ========
uniform mat4 mvpMatrix;
uniform mat4 mvpMatrixInverted;
// vectors
// =======
......@@ -126,6 +129,10 @@ uniform vec3 volumeTopNWCrnr;
uniform float stepSize;
uniform uint bisectionSteps;
uniform int viewPortWidth;
uniform int viewPortHeight;
// Multi-isosurface settings
// =========================
uniform bool isoEnables[MAX_ISOSURFACES];
......@@ -921,6 +928,35 @@ shader FSmain(in VStoFS Input, out vec4 fragColor : 0)
vec3 crossingPosition;
vec3 depthPosition;
if ((renderingMode == RENDER_DVR) && (shadowMode != SHADOWS_MAP))
{
// For direct volume rendering (not necessary for shadow map generation
// and also breaks shadow map code..):
// Correct "far" lambda so that the raycaster terminates at the depth
// that is stored in the depth buffer *before* this raycaster shader is
// started. Read the current depth from the depth buffer texture that
// mirrors the depth buffer (see CPP code, method
// mirrorDepthBufferToTexture()), reconstruct its world space position
// (assuming that the existing "back" fragment is located on the ray)
// and compute its distance to the ray origin. Since ray.direction is
// if unit length, the distance is the lambda value.
// References:
// https://forums.khronos.org/showthread.php/79310-Convert-to-Worldspace-from-depth-buffer
// https://www.khronos.org/opengl/wiki/Compute_eye_space_from_window_space
vec2 texCoordDepthBuffer = vec2(gl_FragCoord.x / viewPortWidth,
gl_FragCoord.y / viewPortHeight);
float depthFromBuffer = texture(depthBufferMirror, texCoordDepthBuffer, 0).x;
// For DEBUG see: http://glampert.com/2014/01-26/visualizing-the-depth-buffer/
// rayColor = vec4((depthFromBuffer-0.95)/0.05, 0., 0., 1.); break;
vec4 posBackFragment = vec4(texCoordDepthBuffer.xy * 2. - 1.,
depthFromBuffer * 2. - 1., 1.);
posBackFragment = mvpMatrixInverted * posBackFragment;
posBackFragment /= posBackFragment.w;
float lambdaDepth = distance(posBackFragment.xyz, ray.origin);
lambdaNearFar.y = min(lambdaNearFar.y, lambdaDepth);
}
// Invoke Raycaster.
raycaster(h_gradient, ray, lambdaNearFar, rayColor, rayPosition,
crossingPosition);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment