#include "vrenvironment.hpp" #include "vrsession.hpp" #include "vrshadow.hpp" #include "../mwrender/vismask.hpp" #include #include namespace MWVR { VrShadow::VrShadow() : mMasterConfig(new SharedShadowMapConfig) , mSlaveConfig(new SharedShadowMapConfig) { mMasterConfig->_id = "VR"; mMasterConfig->_master = true; mSlaveConfig->_id = "VR"; mSlaveConfig->_master = false; } void VrShadow::configureShadowsForCamera(osg::Camera* camera, bool master) { if(master) camera->setUserData(mMasterConfig); else camera->setUserData(mSlaveConfig); } void VrShadow::updateShadowConfig(osg::View& view) { 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_); if (mMasterConfig->_projection == nullptr) mMasterConfig->_projection = new osg::RefMatrix; if (mMasterConfig->_modelView == nullptr) mMasterConfig->_modelView = new osg::RefMatrix; mMasterConfig->_referenceFrame = view.getCamera()->getReferenceFrame(); mMasterConfig->_modelView->set(modifiedViewMatrix); mMasterConfig->_projection->set(projectionMatrix); } }