Render the rear view mirror in a separate target and then display it during overlay pass

This commit is contained in:
Sam Gateau 2015-07-23 14:56:14 -07:00
parent f86c064059
commit a561874ce3
10 changed files with 147 additions and 28 deletions

View file

@ -875,6 +875,33 @@ void Application::paintGL() {
PerformanceWarning warn(showWarnings, "Application::paintGL()");
resizeGL();
// Before anything else, let's sync up the gpuContext with the true glcontext used in case anything happened
renderArgs._context->syncCache();
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
{
gpu::Batch batch;
batch.setFramebuffer(nullptr);
batch.setFramebuffer(primaryFbo);
renderArgs._context->render(batch);
}
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
renderRearViewMirror(&renderArgs, _mirrorViewRect);
renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE;
{
auto mirrorViewport = glm::ivec4(0, 0, _mirrorViewRect.width(), _mirrorViewRect.height());
float ratio = 1.0f / ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale());
auto mirrorViewportDest = glm::ivec4(0, 0, ratio * mirrorViewport.z, ratio * mirrorViewport.w);
auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
gpu::Batch batch;
batch.blit(primaryFbo, mirrorViewport, selfieFbo, mirrorViewportDest);
renderArgs._context->render(batch);
}
}
{
PerformanceTimer perfTimer("renderOverlay");
@ -936,7 +963,7 @@ void Application::paintGL() {
}
// Sync up the View Furstum with the camera
loadViewFrustum(_myCamera, _viewFrustum);
// loadViewFrustum(_myCamera, _viewFrustum);
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
@ -974,19 +1001,17 @@ void Application::paintGL() {
displaySide(&renderArgs, _myCamera);
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
renderRearViewMirror(&renderArgs, _mirrorViewRect);
renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE;
}
{
auto geometryCache = DependencyManager::get<GeometryCache>();
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
gpu::Batch batch;
batch.blit(primaryFbo, glm::ivec4(0, 0, _renderResolution.x, _renderResolution.y),
nullptr, glm::ivec4(0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height()));
batch.setFramebuffer(nullptr);
renderArgs._context->render(batch);
}
_compositor.displayOverlayTexture(&renderArgs);
@ -2958,7 +2983,7 @@ PickRay Application::computePickRay(float x, float y) const {
}
QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
auto primaryFramebuffer = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
/* auto primaryFramebuffer = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
// clear the alpha channel so the background is transparent
@ -2966,17 +2991,41 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
*/
const int BILLBOARD_SIZE = 64;
// TODO: Pass a RenderArgs to renderAvatarBillboard
renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
// const int BILLBOARD_SIZE = 64;
const int BILLBOARD_SIZE = 256;
_glWidget->makeCurrent();
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
{
gpu::Batch batch;
batch.setFramebuffer(nullptr);
batch.setFramebuffer(primaryFbo);
renderArgs->_context->render(batch);
}
renderArgs->_renderMode = RenderArgs::MIRROR_RENDER_MODE;
renderRearViewMirror(renderArgs, QRect(0, /*_glWidget->getDeviceHeight() - BILLBOARD_SIZE*/ 0,
BILLBOARD_SIZE, BILLBOARD_SIZE),
true);
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
false);
renderArgs->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
{
auto mirrorViewport = glm::ivec4(0, 0,BILLBOARD_SIZE, BILLBOARD_SIZE);
gpu::Batch batch;
// batch.blit(primaryFbo, mirrorViewport, selfieFbo, mirrorViewport);
batch.setFramebuffer(nullptr);
renderArgs->_context->render(batch);
}
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo));
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return image;
}
@ -3390,13 +3439,18 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
gpu::Vec4i viewport;
if (billboard) {
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
viewport = gpu::Vec4i(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
// viewport = gpu::Vec4i(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
viewport = gpu::Vec4i(0, 0, region.width(), region.height());
} else {
// if not rendering the billboard, the region is in device independent coordinates; must convert to device
QSize size = DependencyManager::get<FramebufferCache>()->getFrameBufferSize();
float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;
viewport = gpu::Vec4i(x, size.height() - y - height, width, height);
int x = region.x() * ratio;
int y = region.y() * ratio;
int width = region.width() * ratio;
int height = region.height() * ratio;
// viewport = gpu::Vec4i(x, size.height() - y - height, width, height);
viewport = gpu::Vec4i(0, 0, width, height);
}
renderArgs->_viewport = viewport;
@ -3414,8 +3468,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
renderArgs->_context->render(batch);
}
bool updateViewFrustum = false;
loadViewFrustum(_mirrorCamera, _viewFrustum);
// loadViewFrustum(_mirrorCamera, _viewFrustum);
// render rear mirror view
displaySide(renderArgs, _mirrorCamera, true, billboard);

View file

@ -328,6 +328,8 @@ public:
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
signals:
/// Fired when we're simulating; allows external parties to hook in.

View file

@ -1539,6 +1539,7 @@ void MyAvatar::maybeUpdateBillboard() {
QBuffer buffer(&_billboard);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG");
image.save("billboard.png", "PNG");
_billboardValid = true;
sendBillboardPacket();

View file

@ -16,6 +16,7 @@
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <gpu/GLBackendShared.h>
#include <FramebufferCache.h>
#include <GLMHelpers.h>
#include <OffscreenUi.h>
#include <CursorManager.h>
@ -96,6 +97,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
renderStatsAndLogs(renderArgs); // currently renders nothing
renderRearView(renderArgs); // renders the mirror view selfie
renderArgs->_context->syncCache();
renderArgs->_context->render(batch);
@ -167,6 +169,34 @@ void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
auto framebuffer = DependencyManager::get<FramebufferCache>();
auto selfieTexture = framebuffer->getSelfieFramebuffer()->getRenderBuffer(0);
int width = renderArgs->_viewport.z;
int height = renderArgs->_viewport.w;
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
batch.setProjectionTransform(legacyProjection);
batch.setModelTransform(Transform());
batch.setViewTransform(Transform());
auto viewport = qApp->getMirrorViewRect();
glm::vec2 bottomLeft(viewport.left(), viewport.bottom());
glm::vec2 topRight(viewport.right(), viewport.top());
glm::vec2 texCoordMinCorner(0.0f, 0.0f);
glm::vec2 texCoordMaxCorner(viewport.width() / float(selfieTexture->getWidth()), viewport.height() / float(selfieTexture->getHeight()));
geometryCache->useSimpleDrawPipeline(batch, false);
batch.setResourceTexture(0, renderArgs->_whiteTexture);
geometryCache->renderQuad(batch, bottomLeft, topRight, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
geometryCache->useSimpleDrawPipeline(batch, true);
batch.setResourceTexture(0, selfieTexture);
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
}
}
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {

View file

@ -184,4 +184,10 @@ void GLBackend::do_blit(Batch& batch, uint32 paramOffset) {
glBlitFramebuffer(srcvp.x, srcvp.y, srcvp.z, srcvp.w,
dstvp.x, dstvp.y, dstvp.z, dstvp.w,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
(void) CHECK_GL_ERROR();
if (_output._framebuffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFramebufferID(_output._framebuffer));
}
}

View file

@ -217,11 +217,12 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
void DeferredLightingEffect::prepare(RenderArgs* args) {
gpu::Batch batch;
batch.setStateScissorRect(args->_viewport);
// clear the normal and specular buffers
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
const float MAX_SPECULAR_EXPONENT = 128.0f;
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT));
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true);
args->_context->syncCache();
args->_context->render(batch);
@ -242,8 +243,9 @@ void DeferredLightingEffect::render(RenderArgs* args) {
batch.setFramebuffer(_copyFBO);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());

View file

@ -39,6 +39,7 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
_primaryColorTexture.reset();
_primaryNormalTexture.reset();
_primarySpecularTexture.reset();
_selfieFramebuffer.reset();
_cachedFramebuffers.clear();
}
}
@ -112,7 +113,6 @@ gpu::FramebufferPointer FramebufferCache::getFramebuffer() {
return result;
}
void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebuffer) {
if (QSize(framebuffer->getSize().x, framebuffer->getSize().y) == _frameBufferSize) {
_cachedFramebuffers.push_back(framebuffer);
@ -126,3 +126,10 @@ gpu::FramebufferPointer FramebufferCache::getShadowFramebuffer() {
}
return _shadowFramebuffer;
}
gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() {
if (!_selfieFramebuffer) {
_selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()));
}
return _selfieFramebuffer;
}

View file

@ -39,8 +39,12 @@ public:
/// Returns the framebuffer object used to render shadow maps;
gpu::FramebufferPointer getShadowFramebuffer();
/// Returns the framebuffer object used to render selfie maps;
gpu::FramebufferPointer getSelfieFramebuffer();
/// Returns a free framebuffer with a single color attachment for temp or intra-frame operations
gpu::FramebufferPointer getFramebuffer();
// TODO add sync functionality to the release, so we don't reuse a framebuffer being read from
/// Releases a free framebuffer back for reuse
void releaseFramebuffer(const gpu::FramebufferPointer& framebuffer);
@ -58,6 +62,9 @@ private:
gpu::TexturePointer _primarySpecularTexture;
gpu::FramebufferPointer _shadowFramebuffer;
gpu::FramebufferPointer _selfieFramebuffer;
QSize _frameBufferSize{ 100, 100 };
};

View file

@ -1749,7 +1749,7 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS
return geometry.staticCast<Resource>();
}
void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
if (!_standardDrawPipeline) {
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
@ -1762,8 +1762,18 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
auto stateNoBlend = std::make_shared<gpu::State>();
stateNoBlend->setColorWriteMask(true, true, true, false);
stateNoBlend->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_standardDrawPipelineNoBlend.reset(gpu::Pipeline::create(program, stateNoBlend));
}
if (noBlend) {
batch.setPipeline(_standardDrawPipelineNoBlend);
} else {
batch.setPipeline(_standardDrawPipeline);
}
batch.setPipeline(_standardDrawPipeline);
}
const float NetworkGeometry::NO_HYSTERESIS = -1.0f;

View file

@ -248,7 +248,7 @@ public:
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
/// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch);
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
protected:
@ -263,6 +263,7 @@ private:
typedef QPair<unsigned int, unsigned int> VerticesIndices;
gpu::PipelinePointer _standardDrawPipeline;
gpu::PipelinePointer _standardDrawPipelineNoBlend;
QHash<float, gpu::BufferPointer> _cubeVerticies;
QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
gpu::BufferPointer _wireCubeIndexBuffer;