mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-04-01 10:06:42 +00:00
Sharing shadow maps across eyes.
Does not yet expand frustum.
This commit is contained in:
parent
b7bda3544b
commit
e0b51af395
13 changed files with 323 additions and 38 deletions
|
@ -173,6 +173,8 @@ if(BUILD_VR_OPENXR)
|
||||||
mwvr/vrsession.cpp
|
mwvr/vrsession.cpp
|
||||||
mwvr/vrframebuffer.hpp
|
mwvr/vrframebuffer.hpp
|
||||||
mwvr/vrframebuffer.cpp
|
mwvr/vrframebuffer.cpp
|
||||||
|
mwvr/vrshadow.hpp
|
||||||
|
mwvr/vrshadow.cpp
|
||||||
mwvr/vrtypes.hpp
|
mwvr/vrtypes.hpp
|
||||||
mwvr/vrtypes.cpp
|
mwvr/vrtypes.cpp
|
||||||
mwvr/vrview.hpp
|
mwvr/vrview.hpp
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace MWVR
|
||||||
bool mSessionRunning = false;
|
bool mSessionRunning = false;
|
||||||
std::mutex mFrameStateMutex{};
|
std::mutex mFrameStateMutex{};
|
||||||
std::mutex mEventMutex{};
|
std::mutex mEventMutex{};
|
||||||
std::set<const char*> mEnabledExtensions;
|
std::set<std::string> mEnabledExtensions;
|
||||||
|
|
||||||
std::array<XrCompositionLayerDepthInfoKHR, 2> mLayerDepth;
|
std::array<XrCompositionLayerDepthInfoKHR, 2> mLayerDepth;
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,27 +71,9 @@ namespace MWVR
|
||||||
return fov.perspectiveMatrix(near_, far_);
|
return fov.perspectiveMatrix(near_, far_);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Matrix VRSession::viewMatrix(FramePhase phase, Side side)
|
osg::Matrix VRSession::viewMatrix(osg::Vec3 position, osg::Quat orientation)
|
||||||
{
|
{
|
||||||
MWVR::Pose pose{};
|
position = position * Environment::get().unitsPerMeter();
|
||||||
pose = predictedPoses(phase).view[(int)side].pose;
|
|
||||||
|
|
||||||
|
|
||||||
if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame)
|
|
||||||
{
|
|
||||||
pose = predictedPoses(phase).eye[(int)side];
|
|
||||||
osg::Vec3 position = pose.position * Environment::get().unitsPerMeter();
|
|
||||||
osg::Quat orientation = pose.orientation;
|
|
||||||
osg::Vec3d forward = orientation * osg::Vec3d(0, 1, 0);
|
|
||||||
osg::Vec3d up = orientation * osg::Vec3d(0, 0, 1);
|
|
||||||
osg::Matrix viewMatrix;
|
|
||||||
viewMatrix.makeLookAt(position, position + forward, up);
|
|
||||||
|
|
||||||
return viewMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Vec3 position = pose.position * Environment::get().unitsPerMeter();
|
|
||||||
osg::Quat orientation = pose.orientation;
|
|
||||||
|
|
||||||
float y = position.y();
|
float y = position.y();
|
||||||
float z = position.z();
|
float z = position.z();
|
||||||
|
@ -106,10 +88,30 @@ namespace MWVR
|
||||||
osg::Matrix viewMatrix;
|
osg::Matrix viewMatrix;
|
||||||
viewMatrix.setTrans(-position);
|
viewMatrix.setTrans(-position);
|
||||||
viewMatrix.postMultRotate(orientation.conj());
|
viewMatrix.postMultRotate(orientation.conj());
|
||||||
|
return viewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrix VRSession::viewMatrix(FramePhase phase, Side side)
|
||||||
|
{
|
||||||
|
MWVR::Pose pose{};
|
||||||
|
pose = predictedPoses(phase).view[(int)side].pose;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame)
|
||||||
|
{
|
||||||
|
pose = predictedPoses(phase).eye[(int)side];
|
||||||
|
osg::Vec3 position = pose.position * Environment::get().unitsPerMeter();
|
||||||
|
osg::Quat orientation = pose.orientation;
|
||||||
|
osg::Vec3d forward = orientation * osg::Vec3d(0, 1, 0);
|
||||||
|
osg::Vec3d up = orientation * osg::Vec3d(0, 0, 1);
|
||||||
|
osg::Matrix viewMatrix;
|
||||||
|
viewMatrix.makeLookAt(position, position + forward, up);
|
||||||
|
|
||||||
return viewMatrix;
|
return viewMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return viewMatrix(pose.position, pose.orientation);
|
||||||
|
}
|
||||||
|
|
||||||
bool VRSession::isRunning() const {
|
bool VRSession::isRunning() const {
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
return xr->xrSessionRunning();
|
return xr->xrSessionRunning();
|
||||||
|
@ -228,10 +230,8 @@ namespace MWVR
|
||||||
|
|
||||||
void VRSession::prepareFrame()
|
void VRSession::prepareFrame()
|
||||||
{
|
{
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
mFrames++;
|
mFrames++;
|
||||||
assert(!mPredrawFrame);
|
|
||||||
|
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
xr->handleEvents();
|
xr->handleEvents();
|
||||||
|
@ -347,7 +347,6 @@ namespace MWVR
|
||||||
|
|
||||||
void VRSession::movementAngles(float& yaw, float& pitch)
|
void VRSession::movementAngles(float& yaw, float& pitch)
|
||||||
{
|
{
|
||||||
assert(mPredrawFrame);
|
|
||||||
if (!getFrame(FramePhase::Update))
|
if (!getFrame(FramePhase::Update))
|
||||||
beginPhase(FramePhase::Update);
|
beginPhase(FramePhase::Update);
|
||||||
auto frameMeta = getFrame(FramePhase::Update).get();
|
auto frameMeta = getFrame(FramePhase::Update).get();
|
||||||
|
@ -363,8 +362,6 @@ namespace MWVR
|
||||||
getEulerAngles(frameMeta->mPredictedPoses.head.orientation, headYaw, headPitch, headsWillRoll);
|
getEulerAngles(frameMeta->mPredictedPoses.head.orientation, headYaw, headPitch, headsWillRoll);
|
||||||
getEulerAngles(frameMeta->mPredictedPoses.hands[(int)Side::LEFT_SIDE].orientation, handYaw, handPitch, handRoll);
|
getEulerAngles(frameMeta->mPredictedPoses.hands[(int)Side::LEFT_SIDE].orientation, handYaw, handPitch, handRoll);
|
||||||
|
|
||||||
//Log(Debug::Verbose) << "lhandViewYaw=" << yaw << ", headYaw=" << headYaw << ", handYaw=" << handYaw << ", diff=" << (handYaw - headYaw);
|
|
||||||
//Log(Debug::Verbose) << "lhandViewPitch=" << pitch << ", headPitch=" << headPitch << ", handPitch=" << handPitch << ", diff=" << (handPitch - headPitch);
|
|
||||||
yaw = handYaw - headYaw;
|
yaw = handYaw - headYaw;
|
||||||
pitch = handPitch - headPitch;
|
pitch = handPitch - headPitch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace MWVR
|
||||||
float playerScale() const { return mPlayerScale; }
|
float playerScale() const { return mPlayerScale; }
|
||||||
float setPlayerScale(float scale) { return mPlayerScale = scale; }
|
float setPlayerScale(float scale) { return mPlayerScale = scale; }
|
||||||
|
|
||||||
|
osg::Matrix viewMatrix(osg::Vec3 position, osg::Quat orientation);
|
||||||
osg::Matrix viewMatrix(FramePhase phase, Side side);
|
osg::Matrix viewMatrix(FramePhase phase, Side side);
|
||||||
osg::Matrix projectionMatrix(FramePhase phase, Side side);
|
osg::Matrix projectionMatrix(FramePhase phase, Side side);
|
||||||
|
|
||||||
|
|
111
apps/openmw/mwvr/vrshadow.cpp
Normal file
111
apps/openmw/mwvr/vrshadow.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include "vrenvironment.hpp"
|
||||||
|
#include "vrsession.hpp"
|
||||||
|
#include "vrshadow.hpp"
|
||||||
|
|
||||||
|
#include "../mwrender/vismask.hpp"
|
||||||
|
|
||||||
|
#include <components/sceneutil/mwshadowtechnique.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace MWVR
|
||||||
|
{
|
||||||
|
VrShadow::VrShadow(osgViewer::Viewer* viewer, int renderOrder)
|
||||||
|
: mViewer(viewer)
|
||||||
|
, mRenderOrder(renderOrder)
|
||||||
|
, mShadowMapCamera(nullptr)
|
||||||
|
, mUpdateCallback(new UpdateShadowMapSlaveCallback)
|
||||||
|
, mMasterConfig(new SharedShadowMapConfig)
|
||||||
|
, mSlaveConfig(new SharedShadowMapConfig)
|
||||||
|
{
|
||||||
|
mMasterConfig->_id = "VR";
|
||||||
|
mMasterConfig->_master = true;
|
||||||
|
mSlaveConfig->_id = "VR";
|
||||||
|
mSlaveConfig->_master = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VrShadow::configureShadowsForCamera(osg::Camera* camera)
|
||||||
|
{
|
||||||
|
camera->setUserData(mSlaveConfig);
|
||||||
|
if (camera->getRenderOrderNum() < mRenderOrder)
|
||||||
|
camera->setRenderOrder(camera->getRenderOrder(), mRenderOrder + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VrShadow::configureShadows(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
if (!mShadowMapCamera)
|
||||||
|
{
|
||||||
|
mShadowMapCamera = new osg::Camera();
|
||||||
|
mShadowMapCamera->setName("ShadowMap");
|
||||||
|
mShadowMapCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
mShadowMapCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||||
|
mShadowMapCamera->setRenderOrder(osg::Camera::PRE_RENDER, mRenderOrder);
|
||||||
|
mShadowMapCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
||||||
|
mShadowMapCamera->setAllowEventFocus(false);
|
||||||
|
mShadowMapCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||||
|
mShadowMapCamera->setViewport(0, 0, 640, 360);
|
||||||
|
mShadowMapCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
|
||||||
|
mShadowMapCamera->setCullMask(0);
|
||||||
|
mShadowMapCamera->setUserData(mMasterConfig);
|
||||||
|
mViewer->addSlave(mShadowMapCamera, true);
|
||||||
|
auto* slave = mViewer->findSlaveForCamera(mShadowMapCamera);
|
||||||
|
assert(slave);
|
||||||
|
slave->_updateSlaveCallback = mUpdateCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mShadowMapCamera)
|
||||||
|
{
|
||||||
|
mViewer->removeSlave(mViewer->findSlaveIndexForCamera(mShadowMapCamera));
|
||||||
|
mShadowMapCamera = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateShadowMapSlaveCallback::updateSlave(osg::View& view, osg::View::Slave& slave)
|
||||||
|
{
|
||||||
|
auto* camera = slave._camera.get();
|
||||||
|
auto* session = Environment::get().getSession();
|
||||||
|
auto viewMatrix = view.getCamera()->getViewMatrix();
|
||||||
|
|
||||||
|
auto& poses = session->predictedPoses(VRSession::FramePhase::Update);
|
||||||
|
auto& leftView = poses.view[(int)Side::LEFT_SIDE];
|
||||||
|
auto& rightView = poses.view[(int)Side::RIGHT_SIDE];
|
||||||
|
osg::Vec3d leftEye = leftView.pose.position;
|
||||||
|
osg::Vec3d rightEye = rightView.pose.position;
|
||||||
|
|
||||||
|
// The shadow map will be computed from a position P slightly behind the eyes L and R
|
||||||
|
// where it creates the minimum frustum encompassing both eyes' frustums.
|
||||||
|
|
||||||
|
// Compute Frustum angles. A simple min/max.
|
||||||
|
FieldOfView fov;
|
||||||
|
fov.angleLeft = std::min(leftView.fov.angleLeft, rightView.fov.angleLeft);
|
||||||
|
fov.angleRight = std::max(leftView.fov.angleRight, rightView.fov.angleRight);
|
||||||
|
fov.angleDown = std::min(leftView.fov.angleDown, rightView.fov.angleDown);
|
||||||
|
fov.angleUp = std::max(leftView.fov.angleUp, rightView.fov.angleUp);
|
||||||
|
|
||||||
|
// Use the law of sines on the triangle spanning PLR to determine P
|
||||||
|
double angleLeft = std::abs(fov.angleLeft);
|
||||||
|
double angleRight = std::abs(fov.angleRight);
|
||||||
|
double lengthRL = (rightEye - leftEye).length();
|
||||||
|
double ratioRL = lengthRL / std::sin(osg::PI - angleLeft - angleRight);
|
||||||
|
double lengthLP = ratioRL * std::sin(angleRight);
|
||||||
|
osg::Vec3d directionLP = osg::Vec3(std::cos(-angleLeft), std::sin(-angleLeft), 0);
|
||||||
|
osg::Vec3d P = leftEye + directionLP * lengthLP;
|
||||||
|
|
||||||
|
// Generate the matrices
|
||||||
|
float near_ = Settings::Manager::getFloat("near clip", "Camera");
|
||||||
|
float far_ = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||||
|
|
||||||
|
auto modifiedViewMatrix = viewMatrix * session->viewMatrix(P, osg::Quat(0, 0, 0, 1));
|
||||||
|
auto projectionMatrix = fov.perspectiveMatrix(near_, far_);
|
||||||
|
|
||||||
|
camera->setViewMatrix(modifiedViewMatrix);
|
||||||
|
camera->setProjectionMatrix(projectionMatrix);
|
||||||
|
slave.updateSlaveImplementation(view);
|
||||||
|
}
|
||||||
|
}
|
38
apps/openmw/mwvr/vrshadow.hpp
Normal file
38
apps/openmw/mwvr/vrshadow.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef MWVR_VRSHADOW_H
|
||||||
|
#define MWVR_VRSHADOW_H
|
||||||
|
|
||||||
|
#include <osg/Camera>
|
||||||
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
|
#include <components/sceneutil/mwshadowtechnique.hpp>
|
||||||
|
|
||||||
|
namespace MWVR
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpdateShadowMapSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void updateSlave(osg::View& view, osg::View::Slave& slave) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VrShadow
|
||||||
|
{
|
||||||
|
using SharedShadowMapConfig = SceneUtil::MWShadowTechnique::SharedShadowMapConfig;
|
||||||
|
public:
|
||||||
|
VrShadow(osgViewer::Viewer* viewer, int renderOrder = 0);
|
||||||
|
|
||||||
|
void configureShadowsForCamera(osg::Camera* camera);
|
||||||
|
|
||||||
|
void configureShadows(bool enabled);
|
||||||
|
|
||||||
|
private:
|
||||||
|
osgViewer::Viewer* mViewer;
|
||||||
|
int mRenderOrder;
|
||||||
|
osg::ref_ptr<osg::Camera> mShadowMapCamera;
|
||||||
|
osg::ref_ptr< UpdateShadowMapSlaveCallback > mUpdateCallback;
|
||||||
|
osg::ref_ptr<SharedShadowMapConfig> mMasterConfig;
|
||||||
|
osg::ref_ptr<SharedShadowMapConfig> mSlaveConfig;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -36,13 +36,13 @@ namespace MWVR {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::Camera* VRView::createCamera(int eye, const osg::Vec4& clearColor, osg::GraphicsContext* gc)
|
osg::Camera* VRView::createCamera(int order, const osg::Vec4& clearColor, osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Camera> camera = new osg::Camera();
|
osg::ref_ptr<osg::Camera> camera = new osg::Camera();
|
||||||
camera->setClearColor(clearColor);
|
camera->setClearColor(clearColor);
|
||||||
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||||
camera->setRenderOrder(osg::Camera::PRE_RENDER, eye + 2);
|
camera->setRenderOrder(osg::Camera::PRE_RENDER, order);
|
||||||
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
||||||
camera->setAllowEventFocus(false);
|
camera->setAllowEventFocus(false);
|
||||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef OPENXR_VIEW_HPP
|
#ifndef MWVR_VRVIEW_H
|
||||||
#define OPENXR_VIEW_HPP
|
#define MWVR_VRVIEW_H
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include "openxrmanager.hpp"
|
#include "openxrmanager.hpp"
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
#include "../mwrender/vismask.hpp"
|
#include "../mwrender/vismask.hpp"
|
||||||
|
|
||||||
|
#include <osgViewer/Renderer>
|
||||||
|
|
||||||
|
#include <components/sceneutil/mwshadowtechnique.hpp>
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -32,6 +36,7 @@ namespace MWVR
|
||||||
: mViewer(viewer)
|
: mViewer(viewer)
|
||||||
, mPreDraw(new PredrawCallback(this))
|
, mPreDraw(new PredrawCallback(this))
|
||||||
, mPostDraw(new PostdrawCallback(this))
|
, mPostDraw(new PostdrawCallback(this))
|
||||||
|
, mVrShadow(viewer, 1)
|
||||||
, mConfigured(false)
|
, mConfigured(false)
|
||||||
{
|
{
|
||||||
mViewer->setRealizeOperation(new RealizeOperation());
|
mViewer->setRealizeOperation(new RealizeOperation());
|
||||||
|
@ -81,14 +86,17 @@ namespace MWVR
|
||||||
osg::Vec4 clearColor = mainCamera->getClearColor();
|
osg::Vec4 clearColor = mainCamera->getClearColor();
|
||||||
auto config = xr->getRecommendedSwapchainConfig();
|
auto config = xr->getRecommendedSwapchainConfig();
|
||||||
bool mirror = Settings::Manager::getBool("mirror texture", "VR");
|
bool mirror = Settings::Manager::getBool("mirror texture", "VR");
|
||||||
|
mFlipMirrorTextureOrder = Settings::Manager::getBool("flip mirror texture order", "VR");
|
||||||
// TODO: If mirror is false either hide the window or paste something meaningful into it.
|
// TODO: If mirror is false either hide the window or paste something meaningful into it.
|
||||||
// E.g. Fanart of Dagoth UR wearing a VR headset
|
// E.g. Fanart of Dagoth UR wearing a VR headset
|
||||||
|
|
||||||
|
mVrShadow.configureShadows(Settings::Manager::getBool("enable shadows", "Shadows"));
|
||||||
|
|
||||||
for (unsigned i = 0; i < sViewNames.size(); i++)
|
for (unsigned i = 0; i < sViewNames.size(); i++)
|
||||||
{
|
{
|
||||||
auto view = new VRView(sViewNames[i], config[i], context->getState());
|
auto view = new VRView(sViewNames[i], config[i], context->getState());
|
||||||
mViews[sViewNames[i]] = view;
|
mViews[sViewNames[i]] = view;
|
||||||
auto camera = mCameras[sViewNames[i]] = view->createCamera(i, clearColor, context);
|
auto camera = mCameras[sViewNames[i]] = view->createCamera(i + 2, clearColor, context);
|
||||||
camera->setPreDrawCallback(mPreDraw);
|
camera->setPreDrawCallback(mPreDraw);
|
||||||
camera->setFinalDrawCallback(mPostDraw);
|
camera->setFinalDrawCallback(mPostDraw);
|
||||||
camera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
camera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
||||||
|
@ -97,13 +105,17 @@ namespace MWVR
|
||||||
camera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
camera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
||||||
camera->setCullingMode(cullingMode);
|
camera->setCullingMode(cullingMode);
|
||||||
mViewer->addSlave(camera, true);
|
mViewer->addSlave(camera, true);
|
||||||
mViewer->getSlave(i)._updateSlaveCallback = new VRView::UpdateSlaveCallback(view, context);
|
auto* slave = mViewer->findSlaveForCamera(camera);
|
||||||
|
assert(slave);
|
||||||
|
slave->_updateSlaveCallback = new VRView::UpdateSlaveCallback(view, context);
|
||||||
|
|
||||||
if (mirror)
|
if (mirror)
|
||||||
mMsaaResolveMirrorTexture[i].reset(new VRFramebuffer(context->getState(),
|
mMsaaResolveMirrorTexture[i].reset(new VRFramebuffer(context->getState(),
|
||||||
view->swapchain().width(),
|
view->swapchain().width(),
|
||||||
view->swapchain().height(),
|
view->swapchain().height(),
|
||||||
0));
|
0));
|
||||||
|
|
||||||
|
mVrShadow.configureShadowsForCamera(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mirror)
|
if (mirror)
|
||||||
|
@ -156,8 +168,10 @@ namespace MWVR
|
||||||
resolveTexture.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
resolveTexture.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
mViews[sViewNames[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height());
|
mViews[sViewNames[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height());
|
||||||
mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
// Mirror the index when rendering to the mirror texture to allow cross eye mirror textures.
|
|
||||||
unsigned mirrorIndex = sViewNames.size() - 1 - i;
|
unsigned mirrorIndex = i;
|
||||||
|
if (mFlipMirrorTextureOrder)
|
||||||
|
mirrorIndex = sViewNames.size() - 1 - i;
|
||||||
resolveTexture.blit(gc, mirrorIndex * mirrorWidth, 0, (mirrorIndex + 1) * mirrorWidth, screenHeight);
|
resolveTexture.blit(gc, mirrorIndex * mirrorWidth, 0, (mirrorIndex + 1) * mirrorWidth, screenHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef MWVR_OPENRXVIEWER_H
|
#ifndef MWVR_VRVIEWER_H
|
||||||
#define MWVR_OPENRXVIEWER_H
|
#define MWVR_VRVIEWER_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
#include "openxrmanager.hpp"
|
#include "openxrmanager.hpp"
|
||||||
|
#include "vrshadow.hpp"
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
|
@ -92,10 +93,12 @@ namespace MWVR
|
||||||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||||
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture[2]{ };
|
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture[2]{ };
|
||||||
std::unique_ptr<VRFramebuffer> mMirrorTexture{ nullptr };
|
std::unique_ptr<VRFramebuffer> mMirrorTexture{ nullptr };
|
||||||
|
VrShadow mVrShadow;
|
||||||
|
|
||||||
std::mutex mMutex;
|
std::mutex mMutex{};
|
||||||
|
|
||||||
bool mConfigured{ false };
|
bool mConfigured{ false };
|
||||||
|
bool mFlipMirrorTextureOrder{ false };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -900,6 +900,75 @@ MWShadowTechnique::ViewDependentData* MWShadowTechnique::getViewDependentData(os
|
||||||
return vdd.release();
|
return vdd.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWShadowTechnique::ViewDependentData* MWShadowTechnique::getSharedVdd(const SharedShadowMapConfig& config)
|
||||||
|
{
|
||||||
|
auto it = _viewDependentDataShareMap.find(config._id);
|
||||||
|
if (it != _viewDependentDataShareMap.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWShadowTechnique::addSharedVdd(const SharedShadowMapConfig& config, ViewDependentData* vdd)
|
||||||
|
{
|
||||||
|
_viewDependentDataShareMap[config._id] = vdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneUtil::MWShadowTechnique::shareShadowMap(osgUtil::CullVisitor& cv, ViewDependentData* lhs, ViewDependentData* rhs)
|
||||||
|
{
|
||||||
|
// Prepare for rendering shadows using the shadow map owned by rhs.
|
||||||
|
|
||||||
|
// To achieve this i first copy all data that is not specific to this cv's camera and thus read-only,
|
||||||
|
// trusting openmw and osg won't overwrite that data before this frame is done rendering.
|
||||||
|
// This works due to the double buffering of CullVisitors by osg, but also requires that cull passes are serialized (relative to one another).
|
||||||
|
// Then initialize new copies of the data that will be written with view-specific data
|
||||||
|
// (the stateset and the texgens).
|
||||||
|
|
||||||
|
lhs->_viewDependentShadowMap = rhs->_viewDependentShadowMap;
|
||||||
|
lhs->_stateset->clear();
|
||||||
|
lhs->_lightDataList = rhs->_lightDataList;
|
||||||
|
lhs->_numValidShadows = rhs->_numValidShadows;
|
||||||
|
|
||||||
|
ShadowDataList& sdl = lhs->getShadowDataList();
|
||||||
|
ShadowDataList previous_sdl;
|
||||||
|
previous_sdl.swap(sdl);
|
||||||
|
for (auto rhs_sd : rhs->getShadowDataList())
|
||||||
|
{
|
||||||
|
osg::ref_ptr<ShadowData> lhs_sd;
|
||||||
|
|
||||||
|
if (previous_sdl.empty())
|
||||||
|
{
|
||||||
|
OSG_INFO << "Create new ShadowData" << std::endl;
|
||||||
|
lhs_sd = new ShadowData(lhs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSG_INFO << "Taking ShadowData from from of previous_sdl" << std::endl;
|
||||||
|
lhs_sd = previous_sdl.front();
|
||||||
|
previous_sdl.erase(previous_sdl.begin());
|
||||||
|
}
|
||||||
|
lhs_sd->_camera = rhs_sd->_camera;
|
||||||
|
lhs_sd->_textureUnit = rhs_sd->_textureUnit;
|
||||||
|
lhs_sd->_texture = rhs_sd->_texture;
|
||||||
|
sdl.push_back(lhs_sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cv.pushStateSet(_shadowRecievingPlaceholderStateSet.get());
|
||||||
|
osg::ref_ptr<osgUtil::StateGraph> decoratorStateGraph = cv.getCurrentStateGraph();
|
||||||
|
cullShadowReceivingScene(&cv);
|
||||||
|
cv.popStateSet();
|
||||||
|
|
||||||
|
for (auto sd : sdl)
|
||||||
|
{
|
||||||
|
assignTexGenSettings(&cv, sd->_camera, sd->_textureUnit, sd->_texgen.get());
|
||||||
|
}
|
||||||
|
if (lhs->numValidShadows() > 0)
|
||||||
|
{
|
||||||
|
decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*lhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MWShadowTechnique::update(osg::NodeVisitor& nv)
|
void MWShadowTechnique::update(osg::NodeVisitor& nv)
|
||||||
{
|
{
|
||||||
OSG_INFO<<"MWShadowTechnique::update(osg::NodeVisitor& "<<&nv<<")"<<std::endl;
|
OSG_INFO<<"MWShadowTechnique::update(osg::NodeVisitor& "<<&nv<<")"<<std::endl;
|
||||||
|
@ -925,6 +994,29 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
|
||||||
|
|
||||||
ViewDependentData* vdd = getViewDependentData(&cv);
|
ViewDependentData* vdd = getViewDependentData(&cv);
|
||||||
|
|
||||||
|
// Use shared shadow map if applicable
|
||||||
|
auto* sharedConfig = dynamic_cast<SharedShadowMapConfig*>(cv.getCurrentCamera()->getUserData());
|
||||||
|
if (sharedConfig)
|
||||||
|
{
|
||||||
|
if (sharedConfig->_master)
|
||||||
|
{
|
||||||
|
addSharedVdd(*sharedConfig, vdd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto* sharedVdd = getSharedVdd(*sharedConfig);
|
||||||
|
if (sharedVdd)
|
||||||
|
{
|
||||||
|
OSG_INFO << "Using shared shadow map" << std::endl;
|
||||||
|
return shareShadowMap(cv, vdd, sharedVdd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSG_INFO << "Warning, view configured to reuse shared shadow map but no shadow map has been shared. Shadows will be generated instead." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!vdd)
|
if (!vdd)
|
||||||
{
|
{
|
||||||
OSG_INFO<<"Warning, now ViewDependentData created, unable to create shadows."<<std::endl;
|
OSG_INFO<<"Warning, now ViewDependentData created, unable to create shadows."<<std::endl;
|
||||||
|
@ -1397,6 +1489,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
|
||||||
_debugHud->draw(sd->_texture, sm_i, camera->getViewMatrix() * camera->getProjectionMatrix(), cv);
|
_debugHud->draw(sd->_texture, sm_i, camera->getViewMatrix() * camera->getProjectionMatrix(), cv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vdd->setNumValidShadows(numValidShadows);
|
||||||
|
|
||||||
if (numValidShadows>0)
|
if (numValidShadows>0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,6 +139,17 @@ namespace SceneUtil {
|
||||||
// forward declare
|
// forward declare
|
||||||
class ViewDependentData;
|
class ViewDependentData;
|
||||||
|
|
||||||
|
/// Configuration of shadow maps shared by multiple views
|
||||||
|
struct SharedShadowMapConfig : public osg::Referenced
|
||||||
|
{
|
||||||
|
virtual ~SharedShadowMapConfig() {}
|
||||||
|
|
||||||
|
/// String identifier of the shared shadow map
|
||||||
|
std::string _id;
|
||||||
|
|
||||||
|
bool _master;
|
||||||
|
};
|
||||||
|
|
||||||
struct LightData : public osg::Referenced
|
struct LightData : public osg::Referenced
|
||||||
{
|
{
|
||||||
LightData(ViewDependentData* vdd);
|
LightData(ViewDependentData* vdd);
|
||||||
|
@ -193,7 +204,12 @@ namespace SceneUtil {
|
||||||
|
|
||||||
virtual void releaseGLObjects(osg::State* = 0) const;
|
virtual void releaseGLObjects(osg::State* = 0) const;
|
||||||
|
|
||||||
|
unsigned int numValidShadows(void) const { return _numValidShadows; }
|
||||||
|
|
||||||
|
void setNumValidShadows(unsigned int numValidShadows) { _numValidShadows = numValidShadows; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class MWShadowTechnique;
|
||||||
virtual ~ViewDependentData() {}
|
virtual ~ViewDependentData() {}
|
||||||
|
|
||||||
MWShadowTechnique* _viewDependentShadowMap;
|
MWShadowTechnique* _viewDependentShadowMap;
|
||||||
|
@ -202,11 +218,16 @@ namespace SceneUtil {
|
||||||
|
|
||||||
LightDataList _lightDataList;
|
LightDataList _lightDataList;
|
||||||
ShadowDataList _shadowDataList;
|
ShadowDataList _shadowDataList;
|
||||||
|
|
||||||
|
unsigned int _numValidShadows;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv);
|
virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv);
|
||||||
|
|
||||||
ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv);
|
ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv);
|
||||||
|
ViewDependentData* getSharedVdd(const SharedShadowMapConfig& config);
|
||||||
|
void addSharedVdd(const SharedShadowMapConfig& config, ViewDependentData* vdd);
|
||||||
|
void shareShadowMap(osgUtil::CullVisitor& cv, ViewDependentData* lhs, ViewDependentData* rhs);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,8 +255,10 @@ namespace SceneUtil {
|
||||||
virtual ~MWShadowTechnique();
|
virtual ~MWShadowTechnique();
|
||||||
|
|
||||||
typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr<ViewDependentData> > ViewDependentDataMap;
|
typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr<ViewDependentData> > ViewDependentDataMap;
|
||||||
|
typedef std::map< std::string, osg::ref_ptr<ViewDependentData> > ViewDependentDataShareMap;
|
||||||
mutable OpenThreads::Mutex _viewDependentDataMapMutex;
|
mutable OpenThreads::Mutex _viewDependentDataMapMutex;
|
||||||
ViewDependentDataMap _viewDependentDataMap;
|
ViewDependentDataMap _viewDependentDataMap;
|
||||||
|
ViewDependentDataShareMap _viewDependentDataShareMap;
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> _shadowRecievingPlaceholderStateSet;
|
osg::ref_ptr<osg::StateSet> _shadowRecievingPlaceholderStateSet;
|
||||||
|
|
||||||
|
|
|
@ -896,3 +896,6 @@ realistic combat maximum swing velocity = 4.0
|
||||||
|
|
||||||
# Enables controller vibrations when you hit or are hit.
|
# Enables controller vibrations when you hit or are hit.
|
||||||
haptics enabled = true
|
haptics enabled = true
|
||||||
|
|
||||||
|
# Flip the order of eyes in the mirror texture (to allow cross eyed view)
|
||||||
|
flip mirror texture order = false
|
Loading…
Reference in a new issue