alternate approach to mirror projection wip

This commit is contained in:
David Back 2017-11-10 17:15:47 -08:00
parent ea38b32dea
commit 6466a05740
2 changed files with 84 additions and 7 deletions

View file

@ -14,6 +14,9 @@
#include <TextureCache.h>
#include <gpu/Context.h>
#include <EntityScriptingInterface.h>
#include <EntityTree.h>
#include <glm/gtx/transform.hpp>
#include <DebugDraw.h>
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
@ -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> _entityScriptingInterface;
};

View file

@ -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: