mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 12:39:39 +00:00
More refactoring / cleanup. Code policies.
This commit is contained in:
parent
60ffaea195
commit
91de6392ca
36 changed files with 3877 additions and 3927 deletions
|
@ -120,6 +120,10 @@ else ()
|
|||
endif ()
|
||||
|
||||
if(BUILD_VR_OPENXR)
|
||||
# TODO: Move this into something akin to add_openmw_dir instead of breaking pattern.
|
||||
# Later, openmw and openmw_vr should preferrably share game code as a static or shared library
|
||||
# instead of being compiled separately, though for now that's not possible as i depend on
|
||||
# USE_OPENXR preprocessor switches.
|
||||
set(OPENMW_VR_FILES
|
||||
vrengine.cpp
|
||||
mwvr/openxraction.hpp
|
||||
|
@ -165,7 +169,7 @@ if(BUILD_VR_OPENXR)
|
|||
${APPLE_BUNDLE_RESOURCES}
|
||||
)
|
||||
|
||||
# Preprocessor variable used to control code paths between the vr port and non-vr.
|
||||
# Preprocessor variable used to control code paths to vr code
|
||||
target_compile_options(openmw_vr PUBLIC -DUSE_OPENXR -DXR_USE_GRAPHICS_API_OPENGL -DXR_USE_PLATFORM_WIN32)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -555,7 +555,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
MWInput::InputManager* input =
|
||||
#ifdef USE_OPENXR
|
||||
new MWVR::OpenXRInputManager(mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
||||
new MWVR::VRInputManager(mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
||||
#else
|
||||
new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
||||
#endif
|
||||
|
|
|
@ -1076,10 +1076,6 @@ namespace MWRender
|
|||
// TODO: It's difficult to design a good override system when
|
||||
// I don't have a good understanding of the animation code. So for
|
||||
// now i just hardcode blocking of updaters for nodes that should not be animated in VR.
|
||||
|
||||
// TODO: Some overrides cause NaN during cull.
|
||||
// I aassume this happens if an override causes a bone to never receive a valid matrix
|
||||
|
||||
// Add any bone+groupname pair that is messing with Vr comfort here.
|
||||
using Overrides = std::set<std::string>;
|
||||
using GroupOverrides = std::map<std::string, Overrides>;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
/// \brief C++ wrapper for the XrAction type
|
||||
struct OpenXRAction
|
||||
{
|
||||
private:
|
||||
|
|
|
@ -205,7 +205,6 @@ OpenXRInput::createXRAction(
|
|||
const std::string& actionName,
|
||||
const std::string& localName)
|
||||
{
|
||||
ActionPtr actionPtr = nullptr;
|
||||
std::vector<XrPath> subactionPaths;
|
||||
XrActionCreateInfo createInfo{ XR_TYPE_ACTION_CREATE_INFO };
|
||||
createInfo.actionType = actionType;
|
||||
|
|
|
@ -8,20 +8,7 @@
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
struct SuggestedBindings
|
||||
{
|
||||
struct Binding
|
||||
{
|
||||
int action;
|
||||
ActionPath path;
|
||||
Side side;
|
||||
};
|
||||
|
||||
std::string controllerPath;
|
||||
std::vector<Binding> bindings;
|
||||
};
|
||||
|
||||
/// \brief Generates and manages OpenXR Actions and ActionSets by generating openxr bindings from a list of SuggestedBindings structs.
|
||||
class OpenXRInput
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,24 +1,9 @@
|
|||
#include "vrenvironment.hpp"
|
||||
#include "openxrmanager.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
#include "../mwinput/inputmanagerimp.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <openxr/openxr_platform_defines.h>
|
||||
#include <openxr/openxr_reflection.h>
|
||||
|
||||
#include <osg/Camera>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
|
|
|
@ -20,9 +20,9 @@ struct XrCompositionLayerBaseHeader;
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
// Use the pimpl pattern to avoid cluttering the namespace with openxr dependencies.
|
||||
class OpenXRManagerImpl;
|
||||
|
||||
/// \brief Manage the openxr runtime and session
|
||||
class OpenXRManager : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "openxrmanagerimpl.hpp"
|
||||
|
||||
#include "openxrswapchain.hpp"
|
||||
#include "openxrswapchainimpl.hpp"
|
||||
#include "vrtexture.hpp"
|
||||
|
|
|
@ -48,6 +48,7 @@ XrQuaternionf toXR(osg::Quat quat);
|
|||
|
||||
XrCompositionLayerProjectionView toXR(MWVR::CompositionLayerProjectionView layer);
|
||||
|
||||
/// \brief Implementation of OpenXRManager
|
||||
struct OpenXRManagerImpl
|
||||
{
|
||||
OpenXRManagerImpl(void);
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace MWVR
|
|||
{
|
||||
class OpenXRSwapchainImpl;
|
||||
|
||||
/// \brief Creation and management of openxr swapchains
|
||||
class OpenXRSwapchain
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include <openxr/openxr_reflection.h>
|
||||
|
||||
namespace MWVR {
|
||||
|
||||
|
||||
OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, SwapchainConfig config)
|
||||
: mWidth((int)config.recommendedWidth)
|
||||
, mHeight((int)config.recommendedHeight)
|
||||
|
@ -33,27 +31,45 @@ namespace MWVR {
|
|||
std::vector<int64_t> swapchainFormats(swapchainFormatCount);
|
||||
CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data()));
|
||||
|
||||
// List of supported color swapchain formats.
|
||||
constexpr int64_t SupportedColorSwapchainFormats[] = {
|
||||
// Find supported color swapchain format.
|
||||
constexpr int64_t RequestedColorSwapchainFormats[] = {
|
||||
GL_RGBA8,
|
||||
GL_RGBA8_SNORM,
|
||||
};
|
||||
|
||||
auto swapchainFormatIt =
|
||||
std::find_first_of(swapchainFormats.begin(), swapchainFormats.end(), std::begin(SupportedColorSwapchainFormats),
|
||||
std::end(SupportedColorSwapchainFormats));
|
||||
std::find_first_of(swapchainFormats.begin(), swapchainFormats.end(), std::begin(RequestedColorSwapchainFormats),
|
||||
std::end(RequestedColorSwapchainFormats));
|
||||
if (swapchainFormatIt == swapchainFormats.end()) {
|
||||
Log(Debug::Error) << "No swapchain format supported at runtime";
|
||||
throw std::runtime_error("Swapchain color format not supported");
|
||||
}
|
||||
|
||||
mSwapchainColorFormat = *swapchainFormatIt;
|
||||
|
||||
// Find supported depth swapchain format.
|
||||
constexpr int64_t RequestedDepthSwapchainFormats[] = {
|
||||
GL_DEPTH_COMPONENT32F,
|
||||
GL_DEPTH_COMPONENT24,
|
||||
GL_DEPTH_COMPONENT16,
|
||||
};
|
||||
|
||||
swapchainFormatIt =
|
||||
std::find_first_of(swapchainFormats.begin(), swapchainFormats.end(), std::begin(RequestedDepthSwapchainFormats),
|
||||
std::end(RequestedDepthSwapchainFormats));
|
||||
if (swapchainFormatIt == swapchainFormats.end()) {
|
||||
throw std::runtime_error("Swapchain depth format not supported");
|
||||
}
|
||||
mSwapchainDepthFormat = *swapchainFormatIt;
|
||||
|
||||
mSamples = Settings::Manager::getInt("antialiasing", "Video");
|
||||
// OpenXR requires a non-zero value
|
||||
if (mSamples < 1)
|
||||
mSamples = 1;
|
||||
|
||||
|
||||
while (mSamples > 0)
|
||||
{
|
||||
Log(Debug::Verbose) << "Creating swapchain with dimensions Width=" << mWidth << " Heigh=" << mHeight << " SampleCount=" << mSamples;
|
||||
// Create the swapchain.
|
||||
// First create the swapchain of color buffers.
|
||||
XrSwapchainCreateInfo swapchainCreateInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO };
|
||||
swapchainCreateInfo.arraySize = 1;
|
||||
swapchainCreateInfo.format = mSwapchainColorFormat;
|
||||
|
@ -61,30 +77,38 @@ namespace MWVR {
|
|||
swapchainCreateInfo.height = mHeight;
|
||||
swapchainCreateInfo.mipCount = 1;
|
||||
swapchainCreateInfo.faceCount = 1;
|
||||
swapchainCreateInfo.sampleCount = 1;
|
||||
swapchainCreateInfo.sampleCount = mSamples;
|
||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
//CHECK_XRCMD(xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain));
|
||||
auto res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain);
|
||||
if (XR_SUCCEEDED(res))
|
||||
break;
|
||||
else
|
||||
if (!XR_SUCCEEDED(res))
|
||||
{
|
||||
Log(Debug::Verbose) << "Failed to create swapchain with SampleCount=" << mSamples << ": " << XrResultString(res);
|
||||
mSamples /= 2;
|
||||
if (mSamples == 0)
|
||||
std::runtime_error(XrResultString(res));
|
||||
throw std::runtime_error(XrResultString(res));
|
||||
continue;
|
||||
}
|
||||
// Now create the swapchain of depth buffers.
|
||||
swapchainCreateInfo.format = mSwapchainDepthFormat;
|
||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mDepthSwapchain);
|
||||
if (XR_SUCCEEDED(res))
|
||||
break;
|
||||
else
|
||||
throw std::runtime_error(XrResultString(res));
|
||||
}
|
||||
|
||||
uint32_t imageCount = 0;
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
||||
|
||||
mSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mSwapchainImageBuffers.data())));
|
||||
//for (const auto& swapchainImage : mSwapchainImageBuffers)
|
||||
// mTextureBuffers.push_back(new VRTexture(state, swapchainImage.image, mWidth, mHeight, 0));
|
||||
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, 0, &imageCount, nullptr));
|
||||
mDepthSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mDepthSwapchainImageBuffers.data())));
|
||||
|
||||
for (unsigned i = 0; i < imageCount; i++)
|
||||
mRenderBuffers.emplace_back(new VRTexture(state, mWidth, mHeight, mSamples));
|
||||
mRenderBuffers.emplace_back(new VRTexture(state, mWidth, mHeight, mSamples, mSwapchainImageBuffers[i].image, mDepthSwapchainImageBuffers[i].image));
|
||||
|
||||
mSubImage.swapchain = mSwapchain;
|
||||
mSubImage.imageRect.offset = { 0, 0 };
|
||||
|
@ -99,7 +123,9 @@ namespace MWVR {
|
|||
|
||||
VRTexture* OpenXRSwapchainImpl::renderBuffer() const
|
||||
{
|
||||
return mRenderBuffers[mRenderBuffer].get();
|
||||
if (isAcquired())
|
||||
return mRenderBuffers[mAcquiredImageIndex].get();
|
||||
throw std::logic_error("Swapbuffer not acquired before use");
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::acquiredImage() const
|
||||
|
@ -116,7 +142,7 @@ namespace MWVR {
|
|||
|
||||
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
|
||||
{
|
||||
mRenderBuffer = (mRenderBuffer + 1) % mRenderBuffers.size();
|
||||
acquire(gc);
|
||||
renderBuffer()->beginFrame(gc);
|
||||
}
|
||||
|
||||
|
@ -124,29 +150,34 @@ namespace MWVR {
|
|||
|
||||
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc)
|
||||
{
|
||||
// Blit frame to swapchain
|
||||
acquire(gc);
|
||||
renderBuffer()->endFrame(gc, acquiredImage());
|
||||
release(gc);
|
||||
}
|
||||
|
||||
void OpenXRSwapchainImpl::acquire(osg::GraphicsContext* gc)
|
||||
void OpenXRSwapchainImpl::acquire(osg::GraphicsContext*)
|
||||
{
|
||||
XrSwapchainImageAcquireInfo acquireInfo{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO };
|
||||
// I am trusting that the openxr runtime won't diverge these indices so long as these are always called together.
|
||||
// If some dumb ass implementation decides to violate this we'll just have to work around that if it actually happens.
|
||||
CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchain, &acquireInfo, &mAcquiredImageIndex));
|
||||
uint32_t depthIndex = 0;
|
||||
CHECK_XRCMD(xrAcquireSwapchainImage(mDepthSwapchain, &acquireInfo, &depthIndex));
|
||||
if (depthIndex != mAcquiredImageIndex)
|
||||
Log(Debug::Warning) << "Depth and color indices diverged";
|
||||
|
||||
XrSwapchainImageWaitInfo waitInfo{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO };
|
||||
waitInfo.timeout = XR_INFINITE_DURATION;
|
||||
CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo));
|
||||
CHECK_XRCMD(xrWaitSwapchainImage(mDepthSwapchain, &waitInfo));
|
||||
|
||||
mIsAcquired = true;
|
||||
}
|
||||
|
||||
void OpenXRSwapchainImpl::release(osg::GraphicsContext* gc)
|
||||
void OpenXRSwapchainImpl::release(osg::GraphicsContext*)
|
||||
{
|
||||
mIsAcquired = false;
|
||||
|
||||
XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
|
||||
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
||||
CHECK_XRCMD(xrReleaseSwapchainImage(mDepthSwapchain, &releaseInfo));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ struct XrSwapchainSubImage;
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
/// \brief Implementation of OpenXRSwapchain
|
||||
class OpenXRSwapchainImpl
|
||||
{
|
||||
public:
|
||||
|
@ -32,13 +32,15 @@ public:
|
|||
int samples() const { return mSamples; };
|
||||
|
||||
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
||||
XrSwapchain mDepthSwapchain = XR_NULL_HANDLE;
|
||||
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
|
||||
//std::vector<osg::ref_ptr<VRTexture> > mTextureBuffers{};
|
||||
std::vector<XrSwapchainImageOpenGLKHR> mDepthSwapchainImageBuffers{};
|
||||
XrSwapchainSubImage mSubImage{};
|
||||
int32_t mWidth = -1;
|
||||
int32_t mHeight = -1;
|
||||
int32_t mSamples = -1;
|
||||
int64_t mSwapchainColorFormat = -1;
|
||||
int64_t mSwapchainDepthFormat = -1;
|
||||
uint32_t mFBO = 0;
|
||||
std::vector<std::unique_ptr<VRTexture> > mRenderBuffers{};
|
||||
int mRenderBuffer{ 0 };
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
#include <iomanip>
|
||||
|
||||
namespace MWVR { namespace RealisticCombat {
|
||||
namespace MWVR {
|
||||
namespace RealisticCombat {
|
||||
|
||||
static const char* stateToString(SwingState florida)
|
||||
{
|
||||
|
@ -353,4 +354,5 @@ void StateMachine::transition_impactToCooldown()
|
|||
transition(SwingState_Cooldown);
|
||||
}
|
||||
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
#include "vrenvironment.hpp"
|
||||
#include "vrsession.hpp"
|
||||
|
||||
namespace MWVR { namespace RealisticCombat {
|
||||
namespace MWVR {
|
||||
namespace RealisticCombat {
|
||||
enum SwingState
|
||||
{
|
||||
SwingState_Ready,
|
||||
|
@ -75,6 +76,7 @@ struct StateMachine
|
|||
void transition_impactToCooldown();
|
||||
};
|
||||
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,10 +33,9 @@
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
// Some weapon types, such as spellcast, are classified as melee even though they are not.
|
||||
// All the fake melee types have negative type enum, but also so does hand to hand.
|
||||
// I think this covers all the cases
|
||||
// Some weapon types, such as spellcast, are classified as melee even though they are not. At least not in the way i want.
|
||||
// All the false melee types have negative enum values, but also so does hand to hand.
|
||||
// I think this covers all cases
|
||||
static bool isMeleeWeapon(int type)
|
||||
{
|
||||
if (MWMechanics::getWeaponType(type)->mWeaponClass != ESM::WeaponType::Melee)
|
||||
|
@ -70,17 +69,16 @@ void ForearmController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
}
|
||||
|
||||
osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node);
|
||||
auto* camera = MWBase::Environment::get().getWorld()->getRenderingManager().getCamera();
|
||||
|
||||
auto* session = Environment::get().getSession();
|
||||
auto* xrViewer = Environment::get().getViewer();
|
||||
int side = (int)Side::RIGHT_SIDE;
|
||||
if (node->getName().find_first_of("L") != std::string::npos)
|
||||
{
|
||||
side = (int)Side::LEFT_SIDE;
|
||||
// We base ourselves on the world position of the camera
|
||||
// Ensure it is updated before placing the hands
|
||||
// I'm sure this can be achieved properly by managing the scene graph better.
|
||||
MWBase::Environment::get().getWorld()->getRenderingManager().getCamera()->updateCamera();
|
||||
// Therefore we have to make sure the camera is updated for this frame first.
|
||||
camera->updateCamera();
|
||||
}
|
||||
|
||||
MWVR::Pose handStage = session->predictedPoses(VRSession::FramePhase::Update).hands[side];
|
||||
|
@ -91,10 +89,6 @@ void ForearmController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
auto position = handStage.position - headStage.position;
|
||||
position = position * Environment::get().unitsPerMeter();
|
||||
|
||||
auto camera = xrViewer->mViewer->getCamera();
|
||||
auto viewMatrix = camera->getViewMatrix();
|
||||
|
||||
|
||||
// Align orientation with the game world
|
||||
auto* inputManager = Environment::get().getInputManager();
|
||||
if (inputManager)
|
||||
|
@ -106,14 +100,15 @@ void ForearmController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
|
||||
// Add camera offset
|
||||
osg::Vec3 viewPosition;
|
||||
osg::Vec3 center;
|
||||
osg::Vec3 up;
|
||||
osg::Vec3 center; // dummy
|
||||
osg::Vec3 up; // dummy
|
||||
|
||||
auto viewMatrix = camera->getOsgCamera()->getViewMatrix();
|
||||
viewMatrix.getLookAt(viewPosition, center, up, 1.0);
|
||||
position += viewPosition;
|
||||
|
||||
//// Morrowind's meshes do not point forward by default.
|
||||
//// Declare the offsets static since they do not need to be recomputed.
|
||||
// Morrowind's meshes do not point forward by default.
|
||||
// Declare the offsets static since they do not need to be recomputed.
|
||||
static float VRbias = osg::DegreesToRadians(-90.f);
|
||||
static osg::Quat yaw(-VRbias, osg::Vec3f(0, 0, 1));
|
||||
static osg::Quat pitch(2.f * VRbias, osg::Vec3f(0, 1, 0));
|
||||
|
@ -169,33 +164,10 @@ void FingerController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// Since morrowinds assets do not do a particularly good job of imitating natural hands and poses,
|
||||
// the best i can do for pointing is to just make it point straight forward. While not
|
||||
// totally natural, it works.
|
||||
osg::Quat rotate{ 0,0,0,1 };
|
||||
|
||||
// TODO:
|
||||
// To make finger pointing more natural each joint should angle down roughly 5-6 degrees per joint.
|
||||
// But this creates obvious visual conflicts with the hand and the rest of the fingers which are not posed naturally,
|
||||
// and looks particularly riddiculous when a weapon is drawn.
|
||||
// Therefore, for the time being i will simply have them point straight forward relative to the current hand rotation.
|
||||
// This leads to particularly awkward finger pointing while a weapon is drawn and should be replaced by a
|
||||
// complete override of all hand animations by the end of 2090.
|
||||
|
||||
//////// Add a slight rotation down of the fingers to naturalize the pointing.
|
||||
//////rotate = osg::Quat(osg::PI_4 / 8, osg::Vec3{ 0,1,0 }) * rotate;
|
||||
//////if (node->getName() == "Bip01 R Finger1")
|
||||
//////{
|
||||
////// auto* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
////// // Morrowind models do not hold weapons at a natural angle, so i rotate the hand forward
|
||||
////// // to get a more natural angle on the weapon to allow more comfortable combat.
|
||||
////// // Fingers need to angle back up to keep pointing natural.
|
||||
////// if (world->getActiveWeaponType() >= 0)
|
||||
////// {
|
||||
////// rotate = osg::Quat(-osg::PI_4, osg::Vec3{ 0,1,0 }) * rotate;
|
||||
////// }
|
||||
//////}
|
||||
|
||||
// First, update the base of the finger to the overriding orientation
|
||||
auto matrixTransform = node->asTransform()->asMatrixTransform();
|
||||
auto matrix = matrixTransform->getMatrix();
|
||||
matrix.setRotate(rotate);
|
||||
|
@ -208,7 +180,7 @@ void FingerController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
traverse(node, nv);
|
||||
setNestedCallback(ncb);
|
||||
|
||||
// Update where the player is currently pointing
|
||||
// Recompute pointer target
|
||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||
if (anim && node->getName() == "Bip01 R Finger1")
|
||||
{
|
||||
|
@ -390,7 +362,7 @@ void WeaponPointerController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
VRAnimation::VRAnimation(
|
||||
const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
|
||||
bool disableSounds, std::shared_ptr<VRSession> xrSession)
|
||||
// Note that i let it construct as 3rd person and then later update it to VM_VRHeadless
|
||||
// Note that i let it construct as 3rd person and then later update it to VM_VRFirstPerson
|
||||
// when the character controller updates
|
||||
: MWRender::NpcAnimation(ptr, parentNode, resourceSystem, disableSounds, VM_Normal, 55.f)
|
||||
, mSession(xrSession)
|
||||
|
@ -649,13 +621,6 @@ void VRAnimation::addControllers()
|
|||
group->addChild(mModelOffset);
|
||||
mModelOffset->addChild(mObjectRoot);
|
||||
}
|
||||
|
||||
//auto wb = mNodeMap.find("weapon bone");
|
||||
//if (wb != mNodeMap.end())
|
||||
//{
|
||||
// wb->second->removeChild(mWeaponPointerTransform);
|
||||
// wb->second->addChild(mWeaponPointerTransform);
|
||||
//}
|
||||
}
|
||||
void VRAnimation::enableHeadAnimation(bool)
|
||||
{
|
||||
|
|
|
@ -54,18 +54,23 @@ public:
|
|||
|
||||
/// Overrides finger animations to point forward
|
||||
void setFingerPointingMode(bool enabled);
|
||||
|
||||
/// @return Whether animation is currently in finger pointing mode
|
||||
bool fingerPointingMode() const { return mFingerPointingMode; }
|
||||
|
||||
/// @return true if it is possible to place on object where the player is currently pointing
|
||||
bool canPlaceObject();
|
||||
///< @return true if it is possible to place on object where the player is currently pointing
|
||||
|
||||
/// @return pointer to the object the player's melee weapon is currently intersecting.
|
||||
const MWRender::RayResult& getPointerTarget() const;
|
||||
///< @return pointer to the object the player's melee weapon is currently intersecting.
|
||||
|
||||
/// Update what object this vr animation is currently pointing at.
|
||||
void updatePointerTarget();
|
||||
|
||||
/// @return whatever ref is the current pointer target, if any
|
||||
MWWorld::Ptr getTarget(const std::string& directorNode);
|
||||
|
||||
/// @return world transform that yields the position and orientation of the current weapon
|
||||
osg::Matrix getWeaponTransformMatrix() const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -46,11 +46,11 @@ MWVR::Environment& MWVR::Environment::get()
|
|||
return *sThis;
|
||||
}
|
||||
|
||||
MWVR::OpenXRInputManager* MWVR::Environment::getInputManager() const
|
||||
MWVR::VRInputManager* MWVR::Environment::getInputManager() const
|
||||
{
|
||||
auto* inputManager = MWBase::Environment::get().getInputManager();
|
||||
assert(inputManager);
|
||||
auto xrInputManager = dynamic_cast<MWVR::OpenXRInputManager*>(inputManager);
|
||||
auto xrInputManager = dynamic_cast<MWVR::VRInputManager*>(inputManager);
|
||||
assert(xrInputManager);
|
||||
return xrInputManager;
|
||||
}
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
namespace MWVR
|
||||
{
|
||||
class VRAnimation;
|
||||
class OpenXRInputManager;
|
||||
class VRInputManager;
|
||||
class VRSession;
|
||||
class VRGUIManager;
|
||||
class VRViewer;
|
||||
class OpenXRManager;
|
||||
|
||||
/// \brief Central hub for mw openxr subsystems
|
||||
/// \brief Central hub for mw vr/openxr subsystems
|
||||
///
|
||||
/// This class allows each mw openxr subsystem to access any others subsystem's top-level manager class.
|
||||
/// This class allows each mw subsystem to access any vr subsystem's top-level manager class.
|
||||
///
|
||||
/// \attention Environment takes ownership of the manager class instances it is handed over in
|
||||
/// the set* functions.
|
||||
|
@ -39,7 +39,7 @@ namespace MWVR
|
|||
static Environment& get();
|
||||
///< Return instance of this class.
|
||||
|
||||
MWVR::OpenXRInputManager* getInputManager() const;
|
||||
MWVR::VRInputManager* getInputManager() const;
|
||||
|
||||
// The OpenXRInputManager supplants the regular input manager
|
||||
// which is stored in MWBase::Environment
|
||||
|
|
|
@ -1,28 +1,35 @@
|
|||
#include "vrgui.hpp"
|
||||
|
||||
#include "vrenvironment.hpp"
|
||||
#include "vrsession.hpp"
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
#include "openxrinput.hpp"
|
||||
#include "vranimation.hpp"
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/ClipNode>
|
||||
#include <osg/FrontFace>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Depth>
|
||||
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
#include <components/sceneutil/shadow.hpp>
|
||||
#include <components/myguiplatform/myguirendermanager.hpp>
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
#include "../mwrender/util.hpp"
|
||||
#include "../mwrender/renderbin.hpp"
|
||||
#include "../mwrender/renderingmanager.hpp"
|
||||
#include "../mwrender/camera.hpp"
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwgui/windowbase.hpp"
|
||||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
|
|
|
@ -10,10 +10,7 @@ namespace MWVR
|
|||
{
|
||||
|
||||
|
||||
// The OpenMW input manager iterates from 0 to A_Last in its actions enum.
|
||||
// I don't know that it would cause any ill effects, but i nonetheless do not
|
||||
// want to contaminate the input manager with my OpenXR specific actions.
|
||||
// Therefore i add them here to a separate enum whose values start past A_Last.
|
||||
/// Extension of MWInput's set of actions.
|
||||
enum VrActions
|
||||
{
|
||||
A_VrFirst = MWInput::A_Last + 1,
|
||||
|
@ -30,6 +27,10 @@ enum VrActions
|
|||
A_VrLast
|
||||
};
|
||||
|
||||
/// \brief Enum representation of action paths in openxr.
|
||||
///
|
||||
/// OpenXR allows a lot of generics, consequentially this will most likely be changed/expanded
|
||||
/// in the future as we need it. This set was added based on what the Oculus needed.
|
||||
enum class ActionPath
|
||||
{
|
||||
Pose = 0,
|
||||
|
@ -48,9 +49,21 @@ enum class ActionPath
|
|||
Last
|
||||
};
|
||||
|
||||
//class OpenXRAction;
|
||||
/// \brief Suggest a binding by binding an action to a path on a given hand (left or right).
|
||||
struct SuggestedBindings
|
||||
{
|
||||
struct Binding
|
||||
{
|
||||
int action;
|
||||
ActionPath path;
|
||||
Side side;
|
||||
};
|
||||
|
||||
//! Action for applying haptics
|
||||
std::string controllerPath;
|
||||
std::vector<Binding> bindings;
|
||||
};
|
||||
|
||||
/// \brief Action for applying haptics
|
||||
class HapticsAction
|
||||
{
|
||||
public:
|
||||
|
@ -67,7 +80,7 @@ private:
|
|||
float mAmplitude{ 0.f };
|
||||
};
|
||||
|
||||
//! Action for capturing tracking information
|
||||
/// \brief Action for capturing tracking information
|
||||
class PoseAction
|
||||
{
|
||||
public:
|
||||
|
@ -92,7 +105,8 @@ private:
|
|||
Pose mPrevious{};
|
||||
};
|
||||
|
||||
//! Generic action
|
||||
/// \brief Generic action
|
||||
/// \sa ButtonPressAction ButtonLongPressAction ButtonHoldAction AxisAction
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
|
@ -141,9 +155,6 @@ protected:
|
|||
bool mOnDeactivate{ false };
|
||||
};
|
||||
|
||||
//! Convenience
|
||||
using ActionPtr = std::unique_ptr<Action>;
|
||||
|
||||
//! Action that activates once on release.
|
||||
//! Times out if the button is held longer than gHoldDelay.
|
||||
class ButtonPressAction : public Action
|
||||
|
|
|
@ -37,12 +37,12 @@
|
|||
namespace MWVR
|
||||
{
|
||||
|
||||
Pose OpenXRInputManager::getLimbPose(int64_t time, TrackedLimb limb)
|
||||
Pose VRInputManager::getLimbPose(int64_t time, TrackedLimb limb)
|
||||
{
|
||||
return mXRInput->getLimbPose(time, limb);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::updateActivationIndication(void)
|
||||
void VRInputManager::updateActivationIndication(void)
|
||||
{
|
||||
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
bool show = guiMode | mActivationIndication;
|
||||
|
@ -86,7 +86,7 @@ private:
|
|||
MWRender::RayResult mIntersection;
|
||||
};
|
||||
|
||||
void OpenXRInputManager::pointActivation(bool onPress)
|
||||
void VRInputManager::pointActivation(bool onPress)
|
||||
{
|
||||
auto* world = MWBase::Environment::get().getWorld();
|
||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||
|
@ -122,7 +122,7 @@ void OpenXRInputManager::pointActivation(bool onPress)
|
|||
}
|
||||
}
|
||||
|
||||
void OpenXRInputManager::injectMousePress(int sdlButton, bool onPress)
|
||||
void VRInputManager::injectMousePress(int sdlButton, bool onPress)
|
||||
{
|
||||
SDL_MouseButtonEvent arg;
|
||||
if (onPress)
|
||||
|
@ -131,7 +131,7 @@ void OpenXRInputManager::injectMousePress(int sdlButton, bool onPress)
|
|||
mMouseManager->mouseReleased(arg, sdlButton);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::injectChannelValue(
|
||||
void VRInputManager::injectChannelValue(
|
||||
MWInput::Actions action,
|
||||
float value)
|
||||
{
|
||||
|
@ -140,22 +140,22 @@ void OpenXRInputManager::injectChannelValue(
|
|||
}
|
||||
|
||||
// TODO: Configurable haptics: on/off + max intensity
|
||||
void OpenXRInputManager::applyHapticsLeftHand(float intensity)
|
||||
void VRInputManager::applyHapticsLeftHand(float intensity)
|
||||
{
|
||||
mXRInput->applyHaptics(TrackedLimb::LEFT_HAND, intensity);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::applyHapticsRightHand(float intensity)
|
||||
void VRInputManager::applyHapticsRightHand(float intensity)
|
||||
{
|
||||
mXRInput->applyHaptics(TrackedLimb::RIGHT_HAND, intensity);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::requestRecenter()
|
||||
void VRInputManager::requestRecenter()
|
||||
{
|
||||
mShouldRecenter = true;
|
||||
}
|
||||
|
||||
OpenXRInputManager::OpenXRInputManager(
|
||||
VRInputManager::VRInputManager(
|
||||
SDL_Window* window,
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler,
|
||||
|
@ -270,11 +270,11 @@ OpenXRInputManager::OpenXRInputManager(
|
|||
mXRInput.reset(new OpenXRInput(suggestedBindings));
|
||||
}
|
||||
|
||||
OpenXRInputManager::~OpenXRInputManager()
|
||||
VRInputManager::~VRInputManager()
|
||||
{
|
||||
}
|
||||
|
||||
void OpenXRInputManager::changeInputMode(bool mode)
|
||||
void VRInputManager::changeInputMode(bool mode)
|
||||
{
|
||||
// VR mode has no concept of these
|
||||
//mGuiCursorEnabled = false;
|
||||
|
@ -283,7 +283,7 @@ void OpenXRInputManager::changeInputMode(bool mode)
|
|||
MWBase::Environment::get().getWindowManager()->setCursorVisible(false);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::update(
|
||||
void VRInputManager::update(
|
||||
float dt,
|
||||
bool disableControls,
|
||||
bool disableEvents)
|
||||
|
@ -357,7 +357,7 @@ void OpenXRInputManager::update(
|
|||
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
|
||||
}
|
||||
|
||||
void OpenXRInputManager::processAction(const Action* action, float dt, bool disableControls)
|
||||
void VRInputManager::processAction(const Action* action, float dt, bool disableControls)
|
||||
{
|
||||
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||
auto* xrGUIManager = Environment::get().getGUIManager();
|
||||
|
@ -636,12 +636,12 @@ void OpenXRInputManager::processAction(const Action* action, float dt, bool disa
|
|||
}
|
||||
}
|
||||
|
||||
osg::Quat OpenXRInputManager::stageRotation()
|
||||
osg::Quat VRInputManager::stageRotation()
|
||||
{
|
||||
return osg::Quat(mYaw, osg::Vec3(0, 0, -1));
|
||||
}
|
||||
|
||||
void OpenXRInputManager::updateHead()
|
||||
void VRInputManager::updateHead()
|
||||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
auto currentHeadPose = session->predictedPoses(VRSession::FramePhase::Update).head;
|
||||
|
|
|
@ -17,10 +17,10 @@ struct OpenXRInput;
|
|||
|
||||
/// As far as I can tell, SDL does not support VR controllers.
|
||||
/// So I subclass the input manager and insert VR controls.
|
||||
class OpenXRInputManager : public MWInput::InputManager
|
||||
class VRInputManager : public MWInput::InputManager
|
||||
{
|
||||
public:
|
||||
OpenXRInputManager(
|
||||
VRInputManager(
|
||||
SDL_Window* window,
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler,
|
||||
|
@ -29,7 +29,7 @@ public:
|
|||
const std::string& userControllerBindingsFile,
|
||||
const std::string& controllerBindingsFile, bool grab);
|
||||
|
||||
virtual ~OpenXRInputManager();
|
||||
virtual ~VRInputManager();
|
||||
|
||||
/// Overriden to force vr modes such as hiding cursors and crosshairs
|
||||
virtual void changeInputMode(bool guiMode);
|
||||
|
|
|
@ -107,8 +107,8 @@ void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
|||
|
||||
if (frameMeta->mShouldRender && isRunning())
|
||||
{
|
||||
auto leftView = viewer.mViews["LeftEye"];
|
||||
auto rightView = viewer.mViews["RightEye"];
|
||||
auto leftView = viewer.getView("LeftEye");
|
||||
auto rightView = viewer.getView("RightEye");
|
||||
|
||||
viewer.blitEyesToMirrorTexture(gc);
|
||||
gc->swapBuffersImplementation();
|
||||
|
|
|
@ -17,8 +17,8 @@ namespace MWVR
|
|||
|
||||
extern void getEulerAngles(const osg::Quat& quat, float& yaw, float& pitch, float& roll);
|
||||
|
||||
//! Manages VR logic, such as managing frames, predicting their poses, and handling frame synchronization.
|
||||
//! Should not be confused with the openxr session object.
|
||||
/// \brief Manages VR logic, such as managing frames, predicting their poses, and handling frame synchronization with the VR runtime.
|
||||
/// Should not be confused with the openxr session object.
|
||||
class VRSession
|
||||
{
|
||||
public:
|
||||
|
@ -79,6 +79,7 @@ public:
|
|||
int mFramesInFlight{ 0 };
|
||||
std::array<std::unique_ptr<VRFrameMeta>, (int)FramePhase::NumPhases> mFrame{ nullptr };
|
||||
|
||||
private:
|
||||
std::mutex mMutex{};
|
||||
std::condition_variable mCondition{};
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#include "vrviewer.hpp"
|
||||
#include "vrtexture.hpp"
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <osgDB/Registry>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#ifndef GL_TEXTURE_MAX_LEVEL
|
||||
#define GL_TEXTURE_MAX_LEVEL 0x813D
|
||||
|
@ -18,9 +15,9 @@ namespace MWVR
|
|||
: mState(state)
|
||||
, mWidth(width)
|
||||
, mHeight(height)
|
||||
, mSamples(msaaSamples)
|
||||
, mColorBuffer(colorBuffer)
|
||||
, mDepthBuffer(depthBuffer)
|
||||
, mColorBuffer(colorBuffer)
|
||||
, mSamples(msaaSamples)
|
||||
{
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "vrtypes.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace MWVR
|
||||
|
|
|
@ -115,10 +115,6 @@ std::ostream& operator <<(std::ostream& os, const PoseSet& poseSet);
|
|||
std::ostream& operator <<(std::ostream& os, TrackedLimb limb);
|
||||
std::ostream& operator <<(std::ostream& os, ReferenceSpace space);
|
||||
std::ostream& operator <<(std::ostream& os, Side side);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I put these in the global namespace to guarantee lookup.
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,11 @@
|
|||
#include "vrview.hpp"
|
||||
#include "vrsession.hpp"
|
||||
|
||||
#include "openxrmanager.hpp"
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
#include "../mwinput/inputmanagerimp.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwrender/renderingmanager.hpp"
|
||||
#include "../mwrender/water.hpp"
|
||||
#include "vrsession.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <openxr/openxr_platform_defines.h>
|
||||
#include <openxr/openxr_reflection.h>
|
||||
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ struct XrSwapchainSubImage;
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
/// \brief Manipulates a slave camera by replacing its framebuffer with one destined for openxr
|
||||
class VRView : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
@ -48,7 +48,7 @@ namespace MWVR
|
|||
osg::Camera* createCamera(int order, const osg::Vec4& clearColor, osg::GraphicsContext* gc);
|
||||
//! Get the view surface
|
||||
OpenXRSwapchain& swapchain(void) { return *mSwapchain; }
|
||||
|
||||
//! Present to the openxr swapchain
|
||||
void swapBuffers(osg::GraphicsContext* gc);
|
||||
|
||||
public:
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
#include "vrviewer.hpp"
|
||||
#include "vrsession.hpp"
|
||||
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
#include "openxrinput.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
#include "Windows.h"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "vrsession.hpp"
|
||||
|
||||
#include "../mwrender/vismask.hpp"
|
||||
#include <components/esm/loadrace.hpp>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
|
||||
const std::array<const char*, 2> VRViewer::sViewNames = {
|
||||
"LeftEye",
|
||||
"RightEye"
|
||||
};
|
||||
|
||||
VRViewer::VRViewer(
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer)
|
||||
: mRealizeOperation(new RealizeOperation())
|
||||
|
@ -48,81 +45,56 @@ namespace MWVR
|
|||
return;
|
||||
}
|
||||
|
||||
if (!context->isCurrent())
|
||||
if (!context->makeCurrent())
|
||||
{
|
||||
throw std::logic_error("VRViewer::configure() failed to make graphics context current.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Give the main camera an initial draw callback that disables camera setup (we don't want it)
|
||||
auto mainCamera = mCameras["MainCamera"] = mViewer->getCamera();
|
||||
mainCamera->setName("Main");
|
||||
mainCamera->setInitialDrawCallback(new VRView::InitialDrawCallback());
|
||||
|
||||
osg::Vec4 clearColor = mainCamera->getClearColor();
|
||||
|
||||
auto* xr = Environment::get().getManager();
|
||||
if (!xr->realized())
|
||||
xr->realize(context);
|
||||
|
||||
// Run through initial events to start session
|
||||
// For the rest of runtime this is handled by vrsession
|
||||
xr->handleEvents();
|
||||
|
||||
// Small feature culling
|
||||
bool smallFeatureCulling = Settings::Manager::getBool("small feature culling", "Camera");
|
||||
auto smallFeatureCullingPixelSize = Settings::Manager::getFloat("small feature culling pixel size", "Camera");
|
||||
osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING | osg::Camera::FAR_PLANE_CULLING;
|
||||
if (!smallFeatureCulling)
|
||||
cullingMode &= ~osg::CullStack::SMALL_FEATURE_CULLING;
|
||||
else
|
||||
cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING;
|
||||
|
||||
// Configure eyes, their cameras, and their enslavement.
|
||||
osg::Vec4 clearColor = mainCamera->getClearColor();
|
||||
auto config = xr->getRecommendedSwapchainConfig();
|
||||
|
||||
auto leftView = new VRView("LeftEye", config[(int)Side::LEFT_SIDE], context->getState());
|
||||
auto rightView = new VRView("RightEye", config[(int)Side::RIGHT_SIDE], context->getState());
|
||||
|
||||
mViews["LeftEye"] = leftView;
|
||||
mViews["RightEye"] = rightView;
|
||||
|
||||
auto leftCamera = mCameras["LeftEye"] = leftView->createCamera(0, clearColor, context);
|
||||
auto rightCamera = mCameras["RightEye"] = rightView->createCamera(1, clearColor, context);
|
||||
|
||||
leftCamera->setPreDrawCallback(mPreDraw);
|
||||
rightCamera->setPreDrawCallback(mPreDraw);
|
||||
|
||||
leftCamera->setFinalDrawCallback(mPostDraw);
|
||||
rightCamera->setFinalDrawCallback(mPostDraw);
|
||||
|
||||
// Stereo cameras should only draw the scene
|
||||
leftCamera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
||||
rightCamera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
||||
|
||||
leftCamera->setName("LeftEye");
|
||||
rightCamera->setName("RightEye");
|
||||
|
||||
|
||||
osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING;
|
||||
|
||||
if (!Settings::Manager::getBool("small feature culling", "Camera"))
|
||||
cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING);
|
||||
else
|
||||
for (unsigned i = 0; i < sViewNames.size(); i++)
|
||||
{
|
||||
auto smallFeatureCullingPixelSize = Settings::Manager::getFloat("small feature culling pixel size", "Camera");
|
||||
leftCamera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
||||
rightCamera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
||||
cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING;
|
||||
auto view = new VRView(sViewNames[i], config[i], context->getState());
|
||||
mViews[sViewNames[i]] = view;
|
||||
auto camera = mCameras[sViewNames[i]] = view->createCamera(i, clearColor, context);
|
||||
camera->setPreDrawCallback(mPreDraw);
|
||||
camera->setFinalDrawCallback(mPostDraw);
|
||||
camera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor);
|
||||
camera->setName(sViewNames[i]);
|
||||
if (smallFeatureCulling)
|
||||
camera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize);
|
||||
camera->setCullingMode(cullingMode);
|
||||
mViewer->addSlave(camera, true);
|
||||
mViewer->getSlave(i)._updateSlaveCallback = new VRView::UpdateSlaveCallback(view, context);
|
||||
|
||||
mMsaaResolveMirrorTexture[i].reset(new VRTexture(context->getState(),
|
||||
view->swapchain().width(),
|
||||
view->swapchain().height(),
|
||||
0));
|
||||
}
|
||||
leftCamera->setCullingMode(cullingMode);
|
||||
rightCamera->setCullingMode(cullingMode);
|
||||
|
||||
mViewer->addSlave(leftCamera, true);
|
||||
mViewer->addSlave(rightCamera, true);
|
||||
|
||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||
|
||||
mMirrorTexture.reset(new VRTexture(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
||||
mMsaaResolveMirrorTexture[(int)Side::LEFT_SIDE].reset(new VRTexture(context->getState(),
|
||||
leftView->swapchain().width(),
|
||||
leftView->swapchain().height(),
|
||||
0));
|
||||
mMsaaResolveMirrorTexture[(int)Side::RIGHT_SIDE].reset(new VRTexture(context->getState(),
|
||||
rightView->swapchain().width(),
|
||||
rightView->swapchain().height(),
|
||||
0));
|
||||
|
||||
mViewer->getSlave(0)._updateSlaveCallback = new VRView::UpdateSlaveCallback(leftView, context);
|
||||
mViewer->getSlave(1)._updateSlaveCallback = new VRView::UpdateSlaveCallback(rightView, context);
|
||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||
|
||||
mMainCameraGC = mainCamera->getGraphicsContext();
|
||||
mMainCameraGC->setSwapCallback(new VRViewer::SwapBuffersCallback(this));
|
||||
|
@ -132,6 +104,14 @@ namespace MWVR
|
|||
Log(Debug::Verbose) << "Realized";
|
||||
}
|
||||
|
||||
VRView* VRViewer::getView(std::string name)
|
||||
{
|
||||
auto it = mViews.find(name);
|
||||
if (it != mViews.end())
|
||||
return it->second.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VRViewer::enableMainCamera(void)
|
||||
{
|
||||
mCameras["MainCamera"]->setGraphicsContext(mMainCameraGC);
|
||||
|
@ -150,18 +130,16 @@ namespace MWVR
|
|||
int screenWidth = mCameras["MainCamera"]->getViewport()->width();
|
||||
int mirrorWidth = screenWidth / 2;
|
||||
int screenHeight = mCameras["MainCamera"]->getViewport()->height();
|
||||
const char* viewNames[] = {
|
||||
"RightEye",
|
||||
"LeftEye"
|
||||
};
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (unsigned i = 0; i < sViewNames.size(); i++)
|
||||
{
|
||||
auto& resolveTexture = *mMsaaResolveMirrorTexture[i];
|
||||
resolveTexture.beginFrame(gc);
|
||||
mViews[viewNames[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->beginFrame(gc);
|
||||
resolveTexture.blit(gc, i * mirrorWidth, 0, (i + 1) * mirrorWidth, screenHeight);
|
||||
// Mirror the index when rendering to the mirror texture to allow cross eye mirror textures.
|
||||
unsigned mirrorIndex = sViewNames.size() - 1 - i;
|
||||
resolveTexture.blit(gc, mirrorIndex * mirrorWidth, 0, (mirrorIndex + 1) * mirrorWidth, screenHeight);
|
||||
}
|
||||
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
@ -206,7 +184,8 @@ namespace MWVR
|
|||
|
||||
view->postrenderCallback(info);
|
||||
|
||||
// OSG will sometimes overwrite the predraw callback.
|
||||
// This happens sometimes, i've not been able to catch it when as happens
|
||||
// to see why and how i can stop it.
|
||||
if (camera->getPreDrawCallback() != mPreDraw)
|
||||
{
|
||||
camera->setPreDrawCallback(mPreDraw);
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
/// \brief Manages stereo rendering and mirror texturing.
|
||||
///
|
||||
/// Manipulates the osgViewer by disabling main camera rendering, and instead rendering to
|
||||
/// two slave cameras, each connected to and manipulated by a VRView class.
|
||||
class VRViewer
|
||||
{
|
||||
public:
|
||||
|
@ -65,25 +69,27 @@ namespace MWVR
|
|||
VRViewer* mViewer;
|
||||
};
|
||||
|
||||
|
||||
static const std::array<const char*, 2> sViewNames;
|
||||
|
||||
public:
|
||||
VRViewer(
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer);
|
||||
|
||||
~VRViewer(void);
|
||||
|
||||
const XrCompositionLayerBaseHeader* layer();
|
||||
|
||||
void traversals();
|
||||
void preDrawCallback(osg::RenderInfo& info);
|
||||
void postDrawCallback(osg::RenderInfo& info);
|
||||
void blitEyesToMirrorTexture(osg::GraphicsContext* gc);
|
||||
void realize(osg::GraphicsContext* gc);
|
||||
bool realized() { return mConfigured; }
|
||||
VRView* getView(std::string name);
|
||||
|
||||
void enableMainCamera(void);
|
||||
void disableMainCamera(void);
|
||||
|
||||
public:
|
||||
private:
|
||||
osg::ref_ptr<OpenXRManager::RealizeOperation> mRealizeOperation = nullptr;
|
||||
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
||||
std::map<std::string, osg::ref_ptr<VRView> > mViews{};
|
||||
|
@ -91,7 +97,6 @@ namespace MWVR
|
|||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||
//std::unique_ptr<VRTexture> mMirrorTexture{ nullptr };
|
||||
std::unique_ptr<VRTexture> mMsaaResolveMirrorTexture[2]{ };
|
||||
std::unique_ptr<VRTexture> mMirrorTexture{ nullptr };
|
||||
|
||||
|
|
|
@ -6,22 +6,6 @@
|
|||
# OpenXR_INCLUDE_DIR, where to find openxr.h
|
||||
# OpenXR_VERSION, the version of the found library
|
||||
#
|
||||
# This module accepts the following env variables
|
||||
# OPENXR_ROOT
|
||||
# This module responds to the the flag:
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2003-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
|
||||
if(WIN32)
|
||||
|
|
Loading…
Reference in a new issue