Super-fast volume (aka Downscaled Volume Rendering).

This commit is contained in:
Jonathas Costa
2019-11-10 14:17:23 -05:00
parent b591af3c2a
commit 0fce6a8d26
10 changed files with 310 additions and 7 deletions

View File

@@ -59,6 +59,10 @@ namespace {
"renderedTexture", "inverseScreenSize"
};
constexpr const std::array<const char*, 1> DownscaledVolumeUniformNames = {
"downscaledRenderedVolume"
};
constexpr const char* ExitFragmentShaderPath =
"${SHADERS}/framebuffer/exitframebuffer.frag";
constexpr const char* RaycastFragmentShaderPath =
@@ -184,6 +188,10 @@ void FramebufferRenderer::initialize() {
glGenFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer);
glGenTextures(1, &_fxaaBuffers.fxaaTexture);
// DownscaleVolumeRendering
glGenFramebuffers(1, &_downscaleVolumeRendering.framebuffer);
glGenTextures(1, &_downscaleVolumeRendering.colorTexture);
// Allocate Textures/Buffers Memory
updateResolution();
@@ -307,11 +315,29 @@ void FramebufferRenderer::initialize() {
LERROR("FXAA framebuffer is not complete");
}
//================================================//
//===== Downscale Volume Rendering Buffers =====//
//================================================//
glBindFramebuffer(GL_FRAMEBUFFER, _downscaleVolumeRendering.framebuffer);
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
_downscaleVolumeRendering.colorTexture,
0
);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LERROR("Downscale Volume Rendering framebuffer is not complete");
}
// JCC: Moved to here to avoid NVidia: "Program/shader state performance warning"
// Building programs
updateHDRAndFiltering();
updateFXAA();
updateDeferredcastData();
updateDownscaledVolume();
// Sets back to default FBO
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
@@ -326,6 +352,11 @@ void FramebufferRenderer::initialize() {
_fxaaUniformCache,
FXAAUniformNames
);
ghoul::opengl::updateUniformLocations(
*_downscaledVolumeProgram,
_writeDownscaledVolumeUniformCache,
DownscaledVolumeUniformNames
);
global::raycasterManager.addListener(*this);
global::deferredcasterManager.addListener(*this);
@@ -342,6 +373,7 @@ void FramebufferRenderer::deinitialize() {
glDeleteFramebuffers(1, &_hdrBuffers.hdrFilteringFramebuffer);
glDeleteFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer);
glDeleteFramebuffers(1, &_pingPongBuffers.framebuffer);
glDeleteFramebuffers(1, &_downscaleVolumeRendering.framebuffer);
glDeleteTextures(1, &_gBuffers.colorTexture);
glDeleteTextures(1, &_gBuffers.depthTexture);
@@ -350,7 +382,8 @@ void FramebufferRenderer::deinitialize() {
glDeleteTextures(1, &_fxaaBuffers.fxaaTexture);
glDeleteTextures(1, &_gBuffers.positionTexture);
glDeleteTextures(1, &_gBuffers.normalTexture);
glDeleteTextures(1, &_downscaleVolumeRendering.colorTexture);
glDeleteTextures(1, &_pingPongBuffers.colorTexture[1]);
glDeleteTextures(1, &_exitColorTexture);
@@ -447,6 +480,90 @@ void FramebufferRenderer::applyFXAA() {
_fxaaProgram->deactivate();
}
void FramebufferRenderer::updateDownscaleColorTexture() {
glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.colorTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x * _downscaleVolumeRendering.currentDownscaleFactor,
_resolution.y * _downscaleVolumeRendering.currentDownscaleFactor,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void FramebufferRenderer::writeDownscaledVolume() {
const bool doPerformanceMeasurements = global::performanceManager.isEnabled();
std::unique_ptr<performance::PerformanceMeasurement> perfInternal;
if (doPerformanceMeasurements) {
perfInternal = std::make_unique<performance::PerformanceMeasurement>(
"FramebufferRenderer::render::writeDownscaledVolume"
);
}
// Saving current OpenGL state
GLboolean blendEnabled = glIsEnabledi(GL_BLEND, 0);
GLenum blendEquationRGB;
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB);
GLenum blendEquationAlpha;
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
GLenum blendDestAlpha;
glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
GLenum blendDestRGB;
glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRGB);
GLenum blendSrcAlpha;
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
GLenum blendSrcRGB;
glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRGB);
glEnablei(GL_BLEND, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
_downscaledVolumeProgram->activate();
ghoul::opengl::TextureUnit downscaledTextureUnit;
downscaledTextureUnit.activate();
glBindTexture(
GL_TEXTURE_2D,
_downscaleVolumeRendering.colorTexture
);
_downscaledVolumeProgram->setUniform(
_writeDownscaledVolumeUniformCache.downscaledRenderedVolume,
downscaledTextureUnit
);
glEnablei(GL_BLEND, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBindVertexArray(_screenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
_downscaledVolumeProgram->deactivate();
// Restores blending state
glBlendEquationSeparate(blendEquationRGB, blendEquationAlpha);
glBlendFuncSeparate(blendSrcRGB, blendDestRGB, blendSrcAlpha, blendDestAlpha);
if (!blendEnabled) {
glDisablei(GL_BLEND, 0);
}
}
void FramebufferRenderer::update() {
if (_dirtyResolution) {
updateResolution();
@@ -480,6 +597,16 @@ void FramebufferRenderer::update() {
);
}
if (_downscaledVolumeProgram->isDirty()) {
_downscaledVolumeProgram->rebuildFromFile();
ghoul::opengl::updateUniformLocations(
*_downscaledVolumeProgram,
_writeDownscaledVolumeUniformCache,
DownscaledVolumeUniformNames
);
}
using K = VolumeRaycaster*;
using V = std::unique_ptr<ghoul::opengl::ProgramObject>;
for (const std::pair<const K, V>& program : _exitPrograms) {
@@ -639,6 +766,23 @@ void FramebufferRenderer::updateResolution() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Downscale Volume Rendering
glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.colorTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
_resolution.x * _downscaleVolumeRendering.currentDownscaleFactor,
_resolution.y * _downscaleVolumeRendering.currentDownscaleFactor,
0,
GL_RGBA,
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Volume Rendering Textures
glBindTexture(GL_TEXTURE_2D, _exitColorTexture);
glTexImage2D(
@@ -822,6 +966,17 @@ void FramebufferRenderer::updateFXAA() {
//_fxaaProgram->setIgnoreUniformLocationError(IgnoreError::Yes);
}
void FramebufferRenderer::updateDownscaledVolume() {
_downscaledVolumeProgram = ghoul::opengl::ProgramObject::Build(
"Write Downscaled Volume Program",
absPath("${SHADERS}/framebuffer/mergeDownscaledVolume.vert"),
absPath("${SHADERS}/framebuffer/mergeDownscaledVolume.frag")
);
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
//_downscaledVolumeProgram->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
//_downscaledVolumeProgram->setIgnoreUniformLocationError(IgnoreError::Yes);
}
void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFactor) {
// Set OpenGL default rendering state
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO);
@@ -945,7 +1100,20 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
exitProgram->deactivate();
}
glBindFramebuffer(GL_FRAMEBUFFER, _gBuffers.framebuffer);
if (raycaster->downscaleRender() != 1.f) {
float scaleDown = raycaster->downscaleRender();
glBindFramebuffer(GL_FRAMEBUFFER, _downscaleVolumeRendering.framebuffer);
glViewport(0, 0, _resolution.x * scaleDown, _resolution.y * scaleDown);
if (_downscaleVolumeRendering.currentDownscaleFactor != scaleDown) {
_downscaleVolumeRendering.currentDownscaleFactor = scaleDown;
updateDownscaleColorTexture();
}
glClear(GL_COLOR_BUFFER_BIT);
}
else {
glBindFramebuffer(GL_FRAMEBUFFER, _gBuffers.framebuffer);
}
glm::vec3 cameraPosition;
bool isCameraInside = raycaster->isCameraInside(
raycasterTask.renderData,
@@ -977,6 +1145,8 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
}
if (raycastProgram) {
raycastProgram->setUniform("rayCastSteps", raycaster->maxSteps());
raycaster->preRaycast(_raycastData[raycaster], *raycastProgram);
ghoul::opengl::TextureUnit exitColorTextureUnit;
@@ -994,7 +1164,16 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
glBindTexture(GL_TEXTURE_2D, _gBuffers.depthTexture);
raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit);
raycastProgram->setUniform("windowSize", static_cast<glm::vec2>(_resolution));
if (raycaster->downscaleRender() != 1.f) {
float scaleDown = raycaster->downscaleRender();
raycastProgram->setUniform(
"windowSize",
glm::vec2(_resolution.x * scaleDown, _resolution.y * scaleDown)
);
}
else {
raycastProgram->setUniform("windowSize", static_cast<glm::vec2>(_resolution));
}
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
@@ -1015,6 +1194,14 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
else {
LWARNING("Raycaster is not attached when trying to perform raycaster task");
}
if (raycaster->downscaleRender() != 1.f) {
float scaleDown = raycaster->downscaleRender();
glViewport(0, 0, _resolution.x, _resolution.y);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _gBuffers.framebuffer);
writeDownscaledVolume();
}
}
}