From 6466a05740cc63980f4beab9e80579538a39af49 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 10 Nov 2017 17:15:47 -0800 Subject: [PATCH] alternate approach to mirror projection wip --- interface/src/SecondaryCamera.cpp | 89 ++++++++++++++++++++++++++++--- interface/src/SecondaryCamera.h | 2 + 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 9d19b8fb0f..768328a6b1 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include using RenderArgsPointer = std::shared_ptr; @@ -48,6 +51,63 @@ public: _farClipPlaneDistance = config.farClipPlaneDistance; _textureWidth = config.textureWidth; _textureHeight = config.textureHeight; + _mirrorProjection = config.mirrorProjection; + } + + void setMirrorProjection(ViewFrustum& srcViewFrustum) { + if (_attachedEntityId.isNull()) { + return; + } + + glm::vec3 mainCamPos = qApp->getCamera().getPosition(); + + EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_attachedEntityId, _attachedEntityPropertyFlags); + glm::vec3 mirrorPropsPos = entityProperties.getPosition(); + glm::quat mirrorPropsRot = entityProperties.getRotation(); + glm::vec3 mirrorPropsDim = entityProperties.getDimensions(); + + // get mirrored camera's position and rotation reflected about the mirror plane + glm::vec3 mirrorLocalPos = mirrorPropsRot * glm::vec3(0.f, 0.f, 0.f); + glm::vec3 mirrorWorldPos = mirrorPropsPos + mirrorLocalPos; + glm::vec3 mirrorToHeadVec = mainCamPos - mirrorWorldPos; + glm::vec3 zLocalVecNormalized = mirrorPropsRot * Vectors::UNIT_Z; + float distanceFromMirror = glm::dot(zLocalVecNormalized, mirrorToHeadVec); + glm::vec3 eyePos = mainCamPos - (2.f * distanceFromMirror * zLocalVecNormalized); + glm::quat eyeOrientation = glm::inverse(glm::lookAt(eyePos, mirrorWorldPos, mirrorPropsRot * Vectors::UP)); + srcViewFrustum.setPosition(eyePos); + srcViewFrustum.setOrientation(eyeOrientation); + + // setup world from mirrored camera transformation matrix + glm::mat4 worldFromEyeRot = glm::mat4_cast(eyeOrientation); + glm::mat4 worldFromEyeTrans = glm::translate(eyePos); + glm::mat4 worldFromEye = worldFromEyeTrans * worldFromEyeRot; + + // setup mirror from world inverse of world from mirror transformation matrices + glm::mat4 worldFromMirrorRot = glm::mat4_cast(mirrorPropsRot) * glm::scale(vec3(-1.f, 1.f, -1.f)); + glm::mat4 worldFromMirrorTrans = glm::translate(mirrorWorldPos); + glm::mat4 worldFromMirror = worldFromMirrorTrans * worldFromMirrorRot; + glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + + glm::mat4 mirrorFromEye = mirrorFromWorld * worldFromEye; + glm::vec4 mirrorCenterPos = vec4(mirrorFromEye[3]); + mirrorFromEye[3] = vec4(0.f, 0.f, 0.f, 1.f); + + float n = mirrorCenterPos.z + mirrorPropsDim.z * 2.f; + float f = _farClipPlaneDistance; + float r = -mirrorCenterPos.x + mirrorPropsDim.x / 2.f; + float l = -mirrorCenterPos.x - mirrorPropsDim.x / 2.f; + float t = mirrorCenterPos.y + mirrorPropsDim.y / 2.f; + float b = mirrorCenterPos.y - mirrorPropsDim.y / 2.f; + + glm::mat4 frustum = glm::frustum(l, r, b, t, n, f); + glm::mat4 projection = frustum * mirrorFromEye; + srcViewFrustum.setProjection(projection); + + glm::vec3 mirrorCenterPos3World = transformPoint(worldFromMirror, glm::vec3(mirrorCenterPos)); + qDebug() << "mirrorCenterPos3World " << mirrorCenterPos3World.x << " , " << mirrorCenterPos3World.y << " , " << mirrorCenterPos3World.z; + qDebug() << "mirrorWorldPos " << mirrorWorldPos.x << " , " << mirrorWorldPos.y << " , " << mirrorWorldPos.z; + DebugDraw::getInstance().drawRay(mirrorCenterPos3World, mirrorCenterPos3World + glm::vec3(0.f, 5.f, 0.f), glm::vec4(0.f, 1.f, 0.f, 1.f)); // green + DebugDraw::getInstance().drawRay(mirrorWorldPos, mirrorWorldPos + glm::vec3(0.f, 5.f, 0.f), glm::vec4(1.f, 0.5f, 0.f, 1.f)); // orange } void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { @@ -71,20 +131,34 @@ public: }); auto srcViewFrustum = args->getViewFrustum(); - if (!_attachedEntityId.isNull()) { - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_attachedEntityId, _attachedEntityPropertyFlags); - srcViewFrustum.setPosition(entityProperties.getPosition()); - srcViewFrustum.setOrientation(entityProperties.getRotation()); + if (_mirrorProjection && !_attachedEntityId.isNull()) { + setMirrorProjection(srcViewFrustum); } else { - srcViewFrustum.setPosition(_position); - srcViewFrustum.setOrientation(_orientation); + if (!_attachedEntityId.isNull()) { + EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_attachedEntityId, _attachedEntityPropertyFlags); + srcViewFrustum.setPosition(entityProperties.getPosition()); + srcViewFrustum.setOrientation(entityProperties.getRotation()); + } + else { + srcViewFrustum.setPosition(_position); + srcViewFrustum.setOrientation(_orientation); + } + srcViewFrustum.setProjection(glm::perspective(glm::radians(_vFoV), ((float)args->_viewport.z / (float)args->_viewport.w), _nearClipPlaneDistance, _farClipPlaneDistance)); } - srcViewFrustum.setProjection(glm::perspective(glm::radians(_vFoV), ((float)args->_viewport.z / (float)args->_viewport.w), _nearClipPlaneDistance, _farClipPlaneDistance)); // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, // which is not what we want here. srcViewFrustum.calculate(); args->pushViewFrustum(srcViewFrustum); cachedArgs = _cachedArgsPointer; + + glm::vec3 dirNorm = glm::normalize(srcViewFrustum.getDirection()); + glm::vec3 nearPos = srcViewFrustum.getPosition() + dirNorm * srcViewFrustum.getNearClip(); + + DebugDraw::getInstance().drawRay(srcViewFrustum.getPosition(), srcViewFrustum.getPosition() + dirNorm * srcViewFrustum.getNearClip(), glm::vec4(1.f, 0.f, 0.f, 1.f)); // red + DebugDraw::getInstance().drawRay(nearPos, nearPos + srcViewFrustum.getRight(), glm::vec4(0.f, 0.f, 1.f, 1.f)); // blue + DebugDraw::getInstance().drawRay(nearPos, nearPos + srcViewFrustum.getUp(), glm::vec4(0.5f, 0.f, 1.f, 1.f)); // purple + + srcViewFrustum.printDebugDetails(); } } @@ -101,6 +175,7 @@ private: float _farClipPlaneDistance; int _textureWidth; int _textureHeight; + bool _mirrorProjection; EntityPropertyFlags _attachedEntityPropertyFlags; QSharedPointer _entityScriptingInterface; }; diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index a9b438ec6f..a919429c39 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -35,6 +35,7 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees. Q_PROPERTY(float nearClipPlaneDistance MEMBER nearClipPlaneDistance NOTIFY dirty) // Secondary camera's near clip plane distance. In meters. Q_PROPERTY(float farClipPlaneDistance MEMBER farClipPlaneDistance NOTIFY dirty) // Secondary camera's far clip plane distance. In meters. + Q_PROPERTY(bool mirrorProjection MEMBER mirrorProjection NOTIFY dirty) // Flag to apply oblique near-plane clipping using perspective projection from attached mirror entity public: QUuid attachedEntityId; glm::vec3 position; @@ -44,6 +45,7 @@ public: float farClipPlaneDistance { DEFAULT_FAR_CLIP }; int textureWidth { TextureCache::DEFAULT_SPECTATOR_CAM_WIDTH }; int textureHeight { TextureCache::DEFAULT_SPECTATOR_CAM_HEIGHT }; + bool mirrorProjection { false }; SecondaryCameraJobConfig() : render::Task::Config(false) {} signals: