mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:53:52 +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/vrframebuffer.hpp
|
||||
mwvr/vrframebuffer.cpp
|
||||
mwvr/vrshadow.hpp
|
||||
mwvr/vrshadow.cpp
|
||||
mwvr/vrtypes.hpp
|
||||
mwvr/vrtypes.cpp
|
||||
mwvr/vrview.hpp
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace MWVR
|
|||
bool mSessionRunning = false;
|
||||
std::mutex mFrameStateMutex{};
|
||||
std::mutex mEventMutex{};
|
||||
std::set<const char*> mEnabledExtensions;
|
||||
std::set<std::string> mEnabledExtensions;
|
||||
|
||||
std::array<XrCompositionLayerDepthInfoKHR, 2> mLayerDepth;
|
||||
};
|
||||
|
|
|
@ -71,27 +71,9 @@ namespace MWVR
|
|||
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{};
|
||||
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;
|
||||
position = position * Environment::get().unitsPerMeter();
|
||||
|
||||
float y = position.y();
|
||||
float z = position.z();
|
||||
|
@ -106,10 +88,30 @@ namespace MWVR
|
|||
osg::Matrix viewMatrix;
|
||||
viewMatrix.setTrans(-position);
|
||||
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(pose.position, pose.orientation);
|
||||
}
|
||||
|
||||
bool VRSession::isRunning() const {
|
||||
auto* xr = Environment::get().getManager();
|
||||
return xr->xrSessionRunning();
|
||||
|
@ -228,10 +230,8 @@ namespace MWVR
|
|||
|
||||
void VRSession::prepareFrame()
|
||||
{
|
||||
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mFrames++;
|
||||
assert(!mPredrawFrame);
|
||||
|
||||
auto* xr = Environment::get().getManager();
|
||||
xr->handleEvents();
|
||||
|
@ -347,7 +347,6 @@ namespace MWVR
|
|||
|
||||
void VRSession::movementAngles(float& yaw, float& pitch)
|
||||
{
|
||||
assert(mPredrawFrame);
|
||||
if (!getFrame(FramePhase::Update))
|
||||
beginPhase(FramePhase::Update);
|
||||
auto frameMeta = getFrame(FramePhase::Update).get();
|
||||
|
@ -363,8 +362,6 @@ namespace MWVR
|
|||
getEulerAngles(frameMeta->mPredictedPoses.head.orientation, headYaw, headPitch, headsWillRoll);
|
||||
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;
|
||||
pitch = handPitch - headPitch;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace MWVR
|
|||
float playerScale() const { return mPlayerScale; }
|
||||
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 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();
|
||||
camera->setClearColor(clearColor);
|
||||
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
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->setAllowEventFocus(false);
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef OPENXR_VIEW_HPP
|
||||
#define OPENXR_VIEW_HPP
|
||||
#ifndef MWVR_VRVIEW_H
|
||||
#define MWVR_VRVIEW_H
|
||||
|
||||
#include <cassert>
|
||||
#include "openxrmanager.hpp"
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
#include <components/sceneutil/mwshadowtechnique.hpp>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
|
@ -32,6 +36,7 @@ namespace MWVR
|
|||
: mViewer(viewer)
|
||||
, mPreDraw(new PredrawCallback(this))
|
||||
, mPostDraw(new PostdrawCallback(this))
|
||||
, mVrShadow(viewer, 1)
|
||||
, mConfigured(false)
|
||||
{
|
||||
mViewer->setRealizeOperation(new RealizeOperation());
|
||||
|
@ -81,14 +86,17 @@ namespace MWVR
|
|||
osg::Vec4 clearColor = mainCamera->getClearColor();
|
||||
auto config = xr->getRecommendedSwapchainConfig();
|
||||
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.
|
||||
// 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++)
|
||||
{
|
||||
auto view = new VRView(sViewNames[i], config[i], context->getState());
|
||||
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->setFinalDrawCallback(mPostDraw);
|
||||
camera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
||||
|
@ -97,13 +105,17 @@ namespace MWVR
|
|||
camera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
||||
camera->setCullingMode(cullingMode);
|
||||
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)
|
||||
mMsaaResolveMirrorTexture[i].reset(new VRFramebuffer(context->getState(),
|
||||
view->swapchain().width(),
|
||||
view->swapchain().height(),
|
||||
0));
|
||||
|
||||
mVrShadow.configureShadowsForCamera(camera);
|
||||
}
|
||||
|
||||
if (mirror)
|
||||
|
@ -156,8 +168,10 @@ namespace MWVR
|
|||
resolveTexture.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
mViews[sViewNames[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef MWVR_OPENRXVIEWER_H
|
||||
#define MWVR_OPENRXVIEWER_H
|
||||
#ifndef MWVR_VRVIEWER_H
|
||||
#define MWVR_VRVIEWER_H
|
||||
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include <osgViewer/Viewer>
|
||||
|
||||
#include "openxrmanager.hpp"
|
||||
#include "vrshadow.hpp"
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
|
@ -92,10 +93,12 @@ namespace MWVR
|
|||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture[2]{ };
|
||||
std::unique_ptr<VRFramebuffer> mMirrorTexture{ nullptr };
|
||||
VrShadow mVrShadow;
|
||||
|
||||
std::mutex mMutex;
|
||||
std::mutex mMutex{};
|
||||
|
||||
bool mConfigured{ false };
|
||||
bool mFlipMirrorTextureOrder{ false };
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -900,6 +900,75 @@ MWShadowTechnique::ViewDependentData* MWShadowTechnique::getViewDependentData(os
|
|||
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)
|
||||
{
|
||||
OSG_INFO<<"MWShadowTechnique::update(osg::NodeVisitor& "<<&nv<<")"<<std::endl;
|
||||
|
@ -925,6 +994,29 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
vdd->setNumValidShadows(numValidShadows);
|
||||
|
||||
if (numValidShadows>0)
|
||||
{
|
||||
|
|
|
@ -139,6 +139,17 @@ namespace SceneUtil {
|
|||
// forward declare
|
||||
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
|
||||
{
|
||||
LightData(ViewDependentData* vdd);
|
||||
|
@ -193,7 +204,12 @@ namespace SceneUtil {
|
|||
|
||||
virtual void releaseGLObjects(osg::State* = 0) const;
|
||||
|
||||
unsigned int numValidShadows(void) const { return _numValidShadows; }
|
||||
|
||||
void setNumValidShadows(unsigned int numValidShadows) { _numValidShadows = numValidShadows; }
|
||||
|
||||
protected:
|
||||
friend class MWShadowTechnique;
|
||||
virtual ~ViewDependentData() {}
|
||||
|
||||
MWShadowTechnique* _viewDependentShadowMap;
|
||||
|
@ -202,11 +218,16 @@ namespace SceneUtil {
|
|||
|
||||
LightDataList _lightDataList;
|
||||
ShadowDataList _shadowDataList;
|
||||
|
||||
unsigned int _numValidShadows;
|
||||
};
|
||||
|
||||
virtual ViewDependentData* createViewDependentData(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();
|
||||
|
||||
typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr<ViewDependentData> > ViewDependentDataMap;
|
||||
typedef std::map< std::string, osg::ref_ptr<ViewDependentData> > ViewDependentDataShareMap;
|
||||
mutable OpenThreads::Mutex _viewDependentDataMapMutex;
|
||||
ViewDependentDataMap _viewDependentDataMap;
|
||||
ViewDependentDataShareMap _viewDependentDataShareMap;
|
||||
|
||||
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.
|
||||
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