From 668e4aeafdf2ceb8fc7e5a66b38032cbbfeac0e6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Nov 2018 11:55:10 -0800 Subject: [PATCH 1/3] The Beginnings --- interface/src/Application.cpp | 30 +++++++++++++++- interface/src/SecondaryCamera.cpp | 58 +++++++++++++++++++++++++++++-- interface/src/SecondaryCamera.h | 2 ++ 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2faf8494a..a950030965 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5585,7 +5585,35 @@ void Application::updateSecondaryCameraViewFrustum() { } ViewFrustum secondaryViewFrustum; - if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) { + if (camera->portalProjection && !camera->attachedEntityId.isNull()) { + auto entityScriptingInterface = DependencyManager::get(); + auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); + glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition(); + glm::quat mirrorPropertiesRotation = entityProperties.getRotation(); + glm::vec3 mirrorPropertiesDimensions = entityProperties.getDimensions(); + glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + + glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation) * glm::scale(vec3(1.0f, 1.0f, 1.0f)); + glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); + glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; + glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + + glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); + glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, + mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + + glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); + secondaryViewFrustum.setPosition(mirrorCameraPositionWorld); + secondaryViewFrustum.setOrientation(mirrorCameraOrientation); + + float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; + glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); + secondaryViewFrustum.setProjection(frustum); + } else if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) { auto entityScriptingInterface = DependencyManager::get(); auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition(); diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index f99a373259..6d60b6ba43 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -40,7 +40,50 @@ public: _farClipPlaneDistance = config.farClipPlaneDistance; _textureWidth = config.textureWidth; _textureHeight = config.textureHeight; - _mirrorProjection = config.mirrorProjection; + _mirrorProjection = config.mirrorProjection; + _portalProjection = config.portalProjection; + } + + void setPortalProjection(ViewFrustum& srcViewFrustum) { + if (_attachedEntityId.isNull()) { + qWarning() << "ERROR: Cannot set mirror projection for SecondaryCamera without an attachedEntityId set."; + return; + } + EntityItemPointer attachedEntity = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId); + + if (!attachedEntity) { + qWarning() << "ERROR: Cannot get EntityItemPointer for _attachedEntityId."; + return; + } + + glm::vec3 mirrorPropertiesPosition = attachedEntity->getWorldPosition(); + glm::quat mirrorPropertiesRotation = attachedEntity->getWorldOrientation(); + glm::vec3 mirrorPropertiesDimensions = attachedEntity->getScaledDimensions(); + glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + + glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); + glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); + glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; + glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + + + glm::vec3 mainCameraPositionWorld = qApp->getCamera().getPosition(); + glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, + mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + + // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation + glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); + srcViewFrustum.setPosition(mirrorCameraPositionWorld); + srcViewFrustum.setOrientation(mirrorCameraOrientation); + + // build frustum using mirror space translation of mirrored camera + float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; + glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, _farClipPlaneDistance); + srcViewFrustum.setProjection(frustum); } void setMirrorProjection(ViewFrustum& srcViewFrustum) { @@ -109,7 +152,17 @@ public: auto srcViewFrustum = args->getViewFrustum(); if (_mirrorProjection) { - setMirrorProjection(srcViewFrustum); + if (_portalProjection) { + qWarning() << "ERROR: You can't set both _portalProjection and _mirrorProjection"; + } else { + setMirrorProjection(srcViewFrustum); + } + } else if (_portalProjection) { + if (_mirrorProjection) { + qWarning() << "ERROR: You can't set both _portalProjection and _mirrorProjection"; + } else { + setPortalProjection(srcViewFrustum); + } } else { if (!_attachedEntityId.isNull()) { EntityItemPointer attachedEntity = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId); @@ -149,6 +202,7 @@ private: int _textureWidth; int _textureHeight; bool _mirrorProjection; + bool _portalProjection; EntityPropertyFlags _attachedEntityPropertyFlags; }; diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 3c8540c081..7382c2322e 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -26,6 +26,7 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second 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 use attached mirror entity to build frustum for the mirror and set mirrored camera position/orientation. + Q_PROPERTY(bool portalProjection MEMBER portalProjection NOTIFY dirty) // Flag to use attached portal entity to build frustum for the portal and set portal camera position/orientation. public: QUuid attachedEntityId; glm::vec3 position; @@ -36,6 +37,7 @@ public: int textureWidth { TextureCache::DEFAULT_SPECTATOR_CAM_WIDTH }; int textureHeight { TextureCache::DEFAULT_SPECTATOR_CAM_HEIGHT }; bool mirrorProjection { false }; + bool portalProjection { false }; SecondaryCameraJobConfig() : render::Task::Config(false) {} signals: From d2d5132f7243e93e1fa0b2b650278daa64c02d3d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Nov 2018 14:51:19 -0800 Subject: [PATCH 2/3] It's working! --- interface/src/Application.cpp | 47 ++++++++++++---------- interface/src/SecondaryCamera.cpp | 66 ++++++++++++++++++------------- interface/src/SecondaryCamera.h | 2 + 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a950030965..926df2943e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5585,32 +5585,39 @@ void Application::updateSecondaryCameraViewFrustum() { } ViewFrustum secondaryViewFrustum; - if (camera->portalProjection && !camera->attachedEntityId.isNull()) { + if (camera->portalProjection && !camera->attachedEntityId.isNull() && !camera->portalEntranceEntityId.isNull()) { auto entityScriptingInterface = DependencyManager::get(); - auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); - glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition(); - glm::quat mirrorPropertiesRotation = entityProperties.getRotation(); - glm::vec3 mirrorPropertiesDimensions = entityProperties.getDimensions(); - glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + EntityItemPointer portalEntrance = qApp->getEntities()->getTree()->findEntityByID(camera->portalEntranceEntityId); + EntityItemPointer portalExit = qApp->getEntities()->getTree()->findEntityByID(camera->attachedEntityId); - glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation) * glm::scale(vec3(1.0f, 1.0f, 1.0f)); - glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); - glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; - glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + glm::vec3 portalEntrancePropertiesPosition = portalEntrance->getWorldPosition(); + glm::quat portalEntrancePropertiesRotation = portalEntrance->getWorldOrientation(); + glm::mat4 worldFromPortalEntranceRotation = glm::mat4_cast(portalEntrancePropertiesRotation); + glm::mat4 worldFromPortalEntranceTranslation = glm::translate(portalEntrancePropertiesPosition); + glm::mat4 worldFromPortalEntrance = worldFromPortalEntranceTranslation * worldFromPortalEntranceRotation; + glm::mat4 portalEntranceFromWorld = glm::inverse(worldFromPortalEntrance); + + glm::vec3 portalExitPropertiesPosition = portalExit->getWorldPosition(); + glm::quat portalExitPropertiesRotation = portalExit->getWorldOrientation(); + glm::vec3 portalExitPropertiesDimensions = portalExit->getScaledDimensions(); + glm::vec3 halfPortalExitPropertiesDimensions = 0.5f * portalExitPropertiesDimensions; + + glm::mat4 worldFromPortalExitRotation = glm::mat4_cast(portalExitPropertiesRotation); + glm::mat4 worldFromPortalExitTranslation = glm::translate(portalExitPropertiesPosition); + glm::mat4 worldFromPortalExit = worldFromPortalExitTranslation * worldFromPortalExitRotation; glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); - glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, - mainCameraPositionMirror.z); - glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f)); - glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); - secondaryViewFrustum.setPosition(mirrorCameraPositionWorld); - secondaryViewFrustum.setOrientation(mirrorCameraOrientation); + secondaryViewFrustum.setPosition(portalExitCameraPositionWorld); + secondaryViewFrustum.setOrientation(portalExitPropertiesRotation); - float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; - glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + float nearClip = mainCameraPositionPortalEntrance.z + portalExitPropertiesDimensions.z * 2.0f; + // `mainCameraPositionPortalEntrance` should technically be `mainCameraPositionPortalExit`, + // but the values are the same. + glm::vec3 upperRight = halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance; + glm::vec3 bottomLeft = -halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance; glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); secondaryViewFrustum.setProjection(frustum); } else if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) { diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 6d60b6ba43..ea485ebf40 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -33,6 +33,7 @@ public: void configure(const Config& config) { _attachedEntityId = config.attachedEntityId; + _portalEntranceEntityId = config.portalEntranceEntityId; _position = config.position; _orientation = config.orientation; _vFoV = config.vFoV; @@ -45,43 +46,51 @@ public: } void setPortalProjection(ViewFrustum& srcViewFrustum) { - if (_attachedEntityId.isNull()) { - qWarning() << "ERROR: Cannot set mirror projection for SecondaryCamera without an attachedEntityId set."; - return; - } - EntityItemPointer attachedEntity = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId); - - if (!attachedEntity) { - qWarning() << "ERROR: Cannot get EntityItemPointer for _attachedEntityId."; + if (_portalEntranceEntityId.isNull() || _attachedEntityId.isNull()) { + qWarning() << "ERROR: Cannot set portal projection for SecondaryCamera without an attachedEntityId AND portalEntranceEntityId set."; return; } - glm::vec3 mirrorPropertiesPosition = attachedEntity->getWorldPosition(); - glm::quat mirrorPropertiesRotation = attachedEntity->getWorldOrientation(); - glm::vec3 mirrorPropertiesDimensions = attachedEntity->getScaledDimensions(); - glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + EntityItemPointer portalEntrance = qApp->getEntities()->getTree()->findEntityByID(_portalEntranceEntityId); + if (!portalEntrance) { + qWarning() << "ERROR: Cannot get EntityItemPointer for portalEntrance."; + return; + } - glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); - glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); - glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; - glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + EntityItemPointer portalExit = qApp->getEntities()->getTree()->findEntityByID(_attachedEntityId); + if (!portalExit) { + qWarning() << "ERROR: Cannot get EntityItemPointer for portalExit."; + return; + } + glm::vec3 portalEntrancePropertiesPosition = portalEntrance->getWorldPosition(); + glm::quat portalEntrancePropertiesRotation = portalEntrance->getWorldOrientation(); + glm::mat4 worldFromPortalEntranceRotation = glm::mat4_cast(portalEntrancePropertiesRotation); + glm::mat4 worldFromPortalEntranceTranslation = glm::translate(portalEntrancePropertiesPosition); + glm::mat4 worldFromPortalEntrance = worldFromPortalEntranceTranslation * worldFromPortalEntranceRotation; + glm::mat4 portalEntranceFromWorld = glm::inverse(worldFromPortalEntrance); + + glm::vec3 portalExitPropertiesPosition = portalExit->getWorldPosition(); + glm::quat portalExitPropertiesRotation = portalExit->getWorldOrientation(); + glm::vec3 portalExitPropertiesDimensions = portalExit->getScaledDimensions(); + glm::vec3 halfPortalExitPropertiesDimensions = 0.5f * portalExitPropertiesDimensions; + + glm::mat4 worldFromPortalExitRotation = glm::mat4_cast(portalExitPropertiesRotation); + glm::mat4 worldFromPortalExitTranslation = glm::translate(portalExitPropertiesPosition); + glm::mat4 worldFromPortalExit = worldFromPortalExitTranslation * worldFromPortalExitRotation; glm::vec3 mainCameraPositionWorld = qApp->getCamera().getPosition(); - glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, - mainCameraPositionMirror.z); - glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f)); - // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation - glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); - srcViewFrustum.setPosition(mirrorCameraPositionWorld); - srcViewFrustum.setOrientation(mirrorCameraOrientation); + srcViewFrustum.setPosition(portalExitCameraPositionWorld); + srcViewFrustum.setOrientation(portalExitPropertiesRotation); - // build frustum using mirror space translation of mirrored camera - float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; - glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + float nearClip = mainCameraPositionPortalEntrance.z + portalExitPropertiesDimensions.z * 2.0f; + // `mainCameraPositionPortalEntrance` should technically be `mainCameraPositionPortalExit`, + // but the values are the same. + glm::vec3 upperRight = halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance; + glm::vec3 bottomLeft = -halfPortalExitPropertiesDimensions - mainCameraPositionPortalEntrance; glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, _farClipPlaneDistance); srcViewFrustum.setProjection(frustum); } @@ -194,6 +203,7 @@ protected: private: QUuid _attachedEntityId; + QUuid _portalEntranceEntityId; glm::vec3 _position; glm::quat _orientation; float _vFoV; diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 7382c2322e..941ccc5f93 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -20,6 +20,7 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes secondary camera parameters to JavaScript. Q_OBJECT Q_PROPERTY(QUuid attachedEntityId MEMBER attachedEntityId NOTIFY dirty) // entity whose properties define camera position and orientation + Q_PROPERTY(QUuid portalEntranceEntityId MEMBER portalEntranceEntityId NOTIFY dirty) // entity whose properties define a portal's entrance position and orientation Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) // of viewpoint to render from Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) // of viewpoint to render from Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees. @@ -29,6 +30,7 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second Q_PROPERTY(bool portalProjection MEMBER portalProjection NOTIFY dirty) // Flag to use attached portal entity to build frustum for the portal and set portal camera position/orientation. public: QUuid attachedEntityId; + QUuid portalEntranceEntityId; glm::vec3 position; glm::quat orientation; float vFoV { DEFAULT_FIELD_OF_VIEW_DEGREES }; From 1de4f9c3cc9e5c6668991abd76b8263eaf04a78b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Nov 2018 13:07:49 -0800 Subject: [PATCH 3/3] Correct portal math --- interface/src/Application.cpp | 2 ++ interface/src/SecondaryCamera.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 926df2943e..abe9d8a053 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5608,6 +5608,8 @@ void Application::updateSecondaryCameraViewFrustum() { glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + mainCameraPositionPortalEntrance = vec3(-mainCameraPositionPortalEntrance.x, mainCameraPositionPortalEntrance.y, + -mainCameraPositionPortalEntrance.z); glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f)); secondaryViewFrustum.setPosition(portalExitCameraPositionWorld); diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index ea485ebf40..aa5d9d7f58 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -81,6 +81,8 @@ public: glm::vec3 mainCameraPositionWorld = qApp->getCamera().getPosition(); glm::vec3 mainCameraPositionPortalEntrance = vec3(portalEntranceFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + mainCameraPositionPortalEntrance = vec3(-mainCameraPositionPortalEntrance.x, mainCameraPositionPortalEntrance.y, + -mainCameraPositionPortalEntrance.z); glm::vec3 portalExitCameraPositionWorld = vec3(worldFromPortalExit * vec4(mainCameraPositionPortalEntrance, 1.0f)); srcViewFrustum.setPosition(portalExitCameraPositionWorld);