diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4494203a49..2aa1a5ee96 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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,7 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/compositor"); PerformanceTimer perfTimer("compositor"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); + 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())); @@ -1361,23 +1432,12 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); - 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())); { 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)$>