diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 948f472118..d7863cfb0c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1150,7 +1150,7 @@ void Application::paintGL() { if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { PerformanceTimer perfTimer("Mirror"); - auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); + auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; renderRearViewMirror(&renderArgs, _mirrorViewRect); @@ -1231,15 +1231,28 @@ void Application::paintGL() { } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { if (isHMDMode()) { + auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); + glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + // Mirror HMD yaw and roll + glm::vec3 mirrorHmdEulers = glm::eulerAngles(hmdRotation); + mirrorHmdEulers.y = -mirrorHmdEulers.y; + mirrorHmdEulers.z = -mirrorHmdEulers.z; + glm::quat mirrorHmdRotation = glm::quat(mirrorHmdEulers); + + glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation; + + _myCamera.setRotation(worldMirrorRotation); + glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); + // Mirror HMD lateral offsets + hmdOffset.x = -hmdOffset.x; + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + mirrorBodyOrientation * hmdOffset); + } else { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); @@ -1273,6 +1286,10 @@ void Application::paintGL() { // Primary rendering pass auto framebufferCache = DependencyManager::get(); const QSize size = framebufferCache->getFrameBufferSize(); + + // Final framebuffer that will be handled to the display-plugin + auto finalFramebuffer = framebufferCache->getFramebuffer(); + { PROFILE_RANGE(__FUNCTION__ "/mainRender"); PerformanceTimer perfTimer("mainRender"); @@ -1326,9 +1343,63 @@ void Application::paintGL() { } displaySide(&renderArgs, _myCamera); renderArgs._context->enableStereo(false); - gpu::doInBatch(renderArgs._context, [](gpu::Batch& batch) { - batch.setFramebuffer(nullptr); - }); + + // Blit primary to final FBO + auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); + + if (renderArgs._renderMode == RenderArgs::MIRROR_RENDER_MODE) { + if (displayPlugin->isStereo()) { + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i srcRectLeft; + srcRectLeft.z = size.width() / 2; + srcRectLeft.w = size.height(); + + gpu::Vec4i srcRectRight; + srcRectRight.x = size.width() / 2; + srcRectRight.z = size.width(); + srcRectRight.w = size.height(); + + gpu::Vec4i destRectLeft; + destRectLeft.x = srcRectLeft.z; + destRectLeft.z = srcRectLeft.x; + destRectLeft.y = srcRectLeft.y; + destRectLeft.w = srcRectLeft.w; + + gpu::Vec4i destRectRight; + destRectRight.x = srcRectRight.z; + destRectRight.z = srcRectRight.x; + destRectRight.y = srcRectRight.y; + destRectRight.w = srcRectRight.w; + + batch.setFramebuffer(finalFramebuffer); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)); + // BLit left to right and right to left in stereo + batch.blit(primaryFbo, srcRectRight, finalFramebuffer, destRectLeft); + batch.blit(primaryFbo, srcRectLeft, finalFramebuffer, destRectRight); + }); + } else { + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i srcRect; + srcRect.z = size.width(); + srcRect.w = size.height(); + gpu::Vec4i destRect; + destRect.x = size.width(); + destRect.y = 0; + destRect.z = 0; + destRect.w = size.height(); + batch.setFramebuffer(finalFramebuffer); + batch.blit(primaryFbo, srcRect, finalFramebuffer, destRect); + }); + } + } else { + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i rect; + rect.z = size.width(); + rect.w = size.height(); + batch.setFramebuffer(finalFramebuffer); + batch.blit(primaryFbo, rect, finalFramebuffer, rect); + }); + } } // Overlay Composition, needs to occur after screen space effects have completed @@ -1336,7 +1407,9 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/compositor"); PerformanceTimer perfTimer("compositor"); - auto primaryFbo = framebufferCache->getPrimaryFramebufferDepthColor(); + + auto primaryFbo = finalFramebuffer; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo)); if (displayPlugin->isStereo()) { QRect currentViewport(QPoint(0, 0), QSize(size.width() / 2, size.height())); @@ -1362,23 +1435,13 @@ void Application::paintGL() { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFramebuffer = framebufferCache->getPrimaryFramebufferDepthColor(); - auto scratchFramebuffer = framebufferCache->getFramebuffer(); - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - gpu::Vec4i rect; - rect.z = size.width(); - rect.w = size.height(); - batch.setFramebuffer(scratchFramebuffer); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - batch.blit(primaryFramebuffer, rect, scratchFramebuffer, rect); - batch.setFramebuffer(nullptr); - }); - auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); + auto finalTexturePointer = finalFramebuffer->getRenderBuffer(0); + GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); Q_ASSERT(0 != finalTexture); Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); - _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + _lockedFramebufferMap[finalTexture] = finalFramebuffer; Q_ASSERT(isCurrentContext(_offscreenContext->getContext())); { @@ -3331,7 +3394,7 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { renderArgs->_renderMode = RenderArgs::DEFAULT_RENDER_MODE; renderRearViewMirror(renderArgs, QRect(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), true); - auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); + auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); renderArgs->_context->downloadFramebuffer(primaryFbo, glm::ivec4(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), image); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b3f6b4c238..cd761f8cd2 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -441,14 +441,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) { estimatedPosition = tracker->getHeadTranslation(); _trackedHeadPosition = estimatedPosition; estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); - if (qApp->getCamera()->getMode() == CAMERA_MODE_MIRROR) { - // Invert yaw and roll when in mirror mode - // NOTE: this is kinda a hack, it's the same hack we use to make the head tilt. But it's not really a mirror - // it just makes you feel like you're looking in a mirror because the body movements of the avatar appear to - // match your body movements. - YAW(estimatedRotation) *= -1.0f; - ROLL(estimatedRotation) *= -1.0f; - } } // Rotate the body if the head is turned beyond the screen @@ -489,14 +481,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) { const float TORSO_LENGTH = 0.5f; glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f); - // Invert left/right lean when in mirror mode - // NOTE: this is kinda a hack, it's the same hack we use to make the head tilt. But it's not really a mirror - // it just makes you feel like you're looking in a mirror because the body movements of the avatar appear to - // match your body movements. - if ((inHmd || inFacetracker) && qApp->getCamera()->getMode() == CAMERA_MODE_MIRROR) { - relativePosition.x = -relativePosition.x; - } - const float MAX_LEAN = 45.0f; head->setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); @@ -1401,12 +1385,6 @@ void MyAvatar::updateOrientation(float deltaTime) { // ... so they need to be converted to degrees before we do math... glm::vec3 euler = glm::eulerAngles(localOrientation) * DEGREES_PER_RADIAN; - //Invert yaw and roll when in mirror mode - if (qApp->getCamera()->getMode() == CAMERA_MODE_MIRROR) { - YAW(euler) *= -1.0f; - ROLL(euler) *= -1.0f; - } - Head* head = getHead(); head->setBaseYaw(YAW(euler)); head->setBasePitch(PITCH(euler)); diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index bd61de7338..ce6f29c3d5 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -47,18 +47,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, Skybox::render(batch, viewFrustum, skybox); } - static gpu::BufferPointer theBuffer; - static gpu::Stream::FormatPointer theFormat; - if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) { - if (!theBuffer) { - const float CLIP = 1.0f; - const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } }; - theBuffer = std::make_shared(sizeof(vertices), (const gpu::Byte*) vertices); - theFormat = std::make_shared(); - theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); - } - glm::mat4 projMat; viewFrustum.evalProjectionMatrix(projMat); @@ -67,8 +56,6 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setProjectionTransform(projMat); batch.setViewTransform(viewTransform); batch.setModelTransform(Transform()); // only for Mac - batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); - batch.setInputFormat(theFormat); if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { batch.setResourceTexture(0, skybox.getCubemap()); diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.slv b/libraries/procedural/src/procedural/ProceduralSkybox.slv index d1b9a20a66..810afb1033 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.slv +++ b/libraries/procedural/src/procedural/ProceduralSkybox.slv @@ -11,21 +11,26 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - -<@include gpu/Inputs.slh@> - <@include gpu/Transform.slh@> <$declareStandardTransform()$> out vec3 _normal; -void main(void) { +void main(void) { + const float depth = 0.0; + const vec4 UNIT_QUAD[4] = vec4[4]( + vec4(-1.0, -1.0, depth, 1.0), + vec4(1.0, -1.0, depth, 1.0), + vec4(-1.0, 1.0, depth, 1.0), + vec4(1.0, 1.0, depth, 1.0) + ); + vec4 inPosition = UNIT_QUAD[gl_VertexID]; + // standard transform TransformCamera cam = getTransformCamera(); vec3 clipDir = vec3(inPosition.xy, 0.0); vec3 eyeDir; - <$transformClipToEyeDir(cam, clipDir, eyeDir)$> <$transformEyeToWorldDir(cam, eyeDir, _normal)$> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 3f5d53dcc7..4c05111006 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -701,7 +701,7 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) { QSize framebufferSize = framebufferCache->getFrameBufferSize(); auto lightingBuffer = framebufferCache->getLightingTexture(); - auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); + auto destFbo = framebufferCache->getPrimaryFramebuffer(); batch.setFramebuffer(destFbo); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 2d3884d81d..ba87e56a52 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -33,7 +33,7 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { //If the size changed, we need to delete our FBOs if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; - _primaryFramebufferDepthColor.reset(); + _primaryFramebuffer.reset(); _primaryDepthTexture.reset(); _primaryColorTexture.reset(); _deferredFramebuffer.reset(); @@ -49,7 +49,7 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { } void FramebufferCache::createPrimaryFramebuffer() { - _primaryFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); @@ -60,7 +60,7 @@ void FramebufferCache::createPrimaryFramebuffer() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primaryFramebufferDepthColor->setRenderBuffer(0, _primaryColorTexture); + _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); @@ -76,7 +76,7 @@ void FramebufferCache::createPrimaryFramebuffer() { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); - _primaryFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + _primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); @@ -95,11 +95,11 @@ void FramebufferCache::createPrimaryFramebuffer() { _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } -gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() { - if (!_primaryFramebufferDepthColor) { +gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { + if (!_primaryFramebuffer) { createPrimaryFramebuffer(); } - return _primaryFramebufferDepthColor; + return _primaryFramebuffer; } gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() { diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index 6633301d0c..7ac5e4af63 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -29,7 +29,7 @@ public: /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is /// used for scene rendering. - gpu::FramebufferPointer getPrimaryFramebufferDepthColor(); + gpu::FramebufferPointer getPrimaryFramebuffer(); gpu::TexturePointer getPrimaryDepthTexture(); gpu::TexturePointer getPrimaryColorTexture(); @@ -64,7 +64,7 @@ private: void createPrimaryFramebuffer(); - gpu::FramebufferPointer _primaryFramebufferDepthColor; + gpu::FramebufferPointer _primaryFramebuffer; gpu::TexturePointer _primaryDepthTexture; gpu::TexturePointer _primaryColorTexture;