mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-04 22:45:35 +00:00
Comments etc
This commit is contained in:
parent
91de6392ca
commit
45656f1d06
24 changed files with 319 additions and 282 deletions
|
@ -152,8 +152,8 @@ if(BUILD_VR_OPENXR)
|
||||||
mwvr/vrinput.cpp
|
mwvr/vrinput.cpp
|
||||||
mwvr/vrsession.hpp
|
mwvr/vrsession.hpp
|
||||||
mwvr/vrsession.cpp
|
mwvr/vrsession.cpp
|
||||||
mwvr/vrtexture.hpp
|
mwvr/vrframebuffer.hpp
|
||||||
mwvr/vrtexture.cpp
|
mwvr/vrframebuffer.cpp
|
||||||
mwvr/vrtypes.hpp
|
mwvr/vrtypes.hpp
|
||||||
mwvr/vrtypes.cpp
|
mwvr/vrtypes.cpp
|
||||||
mwvr/vrview.hpp
|
mwvr/vrview.hpp
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
#include "mwvr/vrinputmanager.hpp"
|
#include "mwvr/vrinputmanager.hpp"
|
||||||
#include "mwvr/vrviewer.hpp"
|
#include "mwvr/vrviewer.hpp"
|
||||||
|
#include "mwvr/vrgui.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
|
@ -111,26 +111,11 @@ namespace MWVR
|
||||||
return impl().getRecommendedSwapchainConfig();
|
return impl().getRecommendedSwapchainConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
OpenXRManager::RealizeOperation::operator()(
|
|
||||||
osg::GraphicsContext* gc)
|
|
||||||
{
|
|
||||||
auto* xr = Environment::get().getManager();
|
|
||||||
xr->realize(gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
OpenXRManager::RealizeOperation::realized()
|
|
||||||
{
|
|
||||||
auto* xr = Environment::get().getManager();
|
|
||||||
return xr->realized();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenXRManager::CleanupOperation::operator()(
|
OpenXRManager::CleanupOperation::operator()(
|
||||||
osg::GraphicsContext* gc)
|
osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
|
// TODO: Use this to make proper cleanup such as cleaning up VRFramebuffers.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,16 +26,6 @@ namespace MWVR
|
||||||
class OpenXRManager : public osg::Referenced
|
class OpenXRManager : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class RealizeOperation : public osg::GraphicsOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RealizeOperation() : osg::GraphicsOperation("OpenXRRealizeOperation", false) {};
|
|
||||||
void operator()(osg::GraphicsContext* gc) override;
|
|
||||||
virtual bool realized();
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
class CleanupOperation : public osg::GraphicsOperation
|
class CleanupOperation : public osg::GraphicsOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -51,6 +41,7 @@ namespace MWVR
|
||||||
|
|
||||||
~OpenXRManager();
|
~OpenXRManager();
|
||||||
|
|
||||||
|
/// Manager has been initialized.
|
||||||
bool realized();
|
bool realized();
|
||||||
|
|
||||||
//! Forward call to xrWaitFrame()
|
//! Forward call to xrWaitFrame()
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "openxrswapchain.hpp"
|
#include "openxrswapchain.hpp"
|
||||||
#include "openxrswapchainimpl.hpp"
|
#include "openxrswapchainimpl.hpp"
|
||||||
#include "vrtexture.hpp"
|
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||||
|
@ -445,13 +444,11 @@ namespace MWVR
|
||||||
switch (newState)
|
switch (newState)
|
||||||
{
|
{
|
||||||
case XR_SESSION_STATE_READY:
|
case XR_SESSION_STATE_READY:
|
||||||
//case XR_SESSION_STATE_IDLE:
|
|
||||||
{
|
{
|
||||||
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
|
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
|
||||||
beginInfo.primaryViewConfigurationType = mViewConfigType;
|
beginInfo.primaryViewConfigurationType = mViewConfigType;
|
||||||
CHECK_XRCMD(xrBeginSession(mSession, &beginInfo));
|
CHECK_XRCMD(xrBeginSession(mSession, &beginInfo));
|
||||||
mSessionRunning = true;
|
mSessionRunning = true;
|
||||||
//waitFrame();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case XR_SESSION_STATE_STOPPING:
|
case XR_SESSION_STATE_STOPPING:
|
||||||
|
|
|
@ -33,19 +33,14 @@ namespace MWVR {
|
||||||
return impl().endFrame(gc);
|
return impl().endFrame(gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenXRSwapchain::acquire(osg::GraphicsContext* gc)
|
uint32_t OpenXRSwapchain::acquiredColorTexture() const
|
||||||
{
|
{
|
||||||
return impl().acquire(gc);
|
return impl().acquiredColorTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenXRSwapchain::release(osg::GraphicsContext* gc)
|
uint32_t OpenXRSwapchain::acquiredDepthTexture() const
|
||||||
{
|
{
|
||||||
return impl().release(gc);
|
return impl().acquiredDepthTexture();
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t OpenXRSwapchain::acquiredImage() const
|
|
||||||
{
|
|
||||||
return impl().acquiredImage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpenXRSwapchain::width() const
|
int OpenXRSwapchain::width() const
|
||||||
|
@ -68,7 +63,7 @@ namespace MWVR {
|
||||||
return impl().isAcquired();
|
return impl().isAcquired();
|
||||||
}
|
}
|
||||||
|
|
||||||
VRTexture* OpenXRSwapchain::renderBuffer() const
|
VRFramebuffer* OpenXRSwapchain::renderBuffer() const
|
||||||
{
|
{
|
||||||
return impl().renderBuffer();
|
return impl().renderBuffer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
#define OPENXR_SWAPCHAIN_HPP
|
#define OPENXR_SWAPCHAIN_HPP
|
||||||
|
|
||||||
#include "openxrmanager.hpp"
|
#include "openxrmanager.hpp"
|
||||||
#include "vrtexture.hpp"
|
|
||||||
|
|
||||||
struct XrSwapchainSubImage;
|
struct XrSwapchainSubImage;
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
class OpenXRSwapchainImpl;
|
class OpenXRSwapchainImpl;
|
||||||
|
class VRFramebuffer;
|
||||||
|
|
||||||
/// \brief Creation and management of openxr swapchains
|
/// \brief Creation and management of openxr swapchains
|
||||||
class OpenXRSwapchain
|
class OpenXRSwapchain
|
||||||
|
@ -20,29 +20,40 @@ namespace MWVR
|
||||||
public:
|
public:
|
||||||
//! Prepare for render (set FBO)
|
//! Prepare for render (set FBO)
|
||||||
void beginFrame(osg::GraphicsContext* gc);
|
void beginFrame(osg::GraphicsContext* gc);
|
||||||
|
|
||||||
//! Finalize render
|
//! Finalize render
|
||||||
void endFrame(osg::GraphicsContext* gc);
|
void endFrame(osg::GraphicsContext* gc);
|
||||||
//! Prepare for render
|
|
||||||
void acquire(osg::GraphicsContext* gc);
|
//! Currently acquired color texture
|
||||||
//! Finalize render
|
uint32_t acquiredColorTexture() const;
|
||||||
void release(osg::GraphicsContext* gc);
|
|
||||||
//! Currently acquired image
|
//! Currently acquired depth texture
|
||||||
uint32_t acquiredImage() const;
|
uint32_t acquiredDepthTexture() const;
|
||||||
|
|
||||||
//! Whether subchain is currently acquired (true) or released (false)
|
//! Whether subchain is currently acquired (true) or released (false)
|
||||||
bool isAcquired() const;
|
bool isAcquired() const;
|
||||||
|
|
||||||
//! Width of the view surface
|
//! Width of the view surface
|
||||||
int width() const;
|
int width() const;
|
||||||
|
|
||||||
//! Height of the view surface
|
//! Height of the view surface
|
||||||
int height() const;
|
int height() const;
|
||||||
|
|
||||||
//! Samples of the view surface
|
//! Samples of the view surface
|
||||||
int samples() const;
|
int samples() const;
|
||||||
|
|
||||||
//! Get the current texture
|
//! Get the current texture
|
||||||
VRTexture* renderBuffer() const;
|
VRFramebuffer* renderBuffer() const;
|
||||||
|
|
||||||
//! Get the private implementation
|
//! Get the private implementation
|
||||||
OpenXRSwapchainImpl& impl() { return *mPrivate; }
|
OpenXRSwapchainImpl& impl() { return *mPrivate; }
|
||||||
|
|
||||||
//! Get the private implementation
|
//! Get the private implementation
|
||||||
const OpenXRSwapchainImpl& impl() const { return *mPrivate; }
|
const OpenXRSwapchainImpl& impl() const { return *mPrivate; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenXRSwapchain(const OpenXRSwapchain&) = delete;
|
||||||
|
void operator=(const OpenXRSwapchain&) = delete;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<OpenXRSwapchainImpl> mPrivate;
|
std::unique_ptr<OpenXRSwapchainImpl> mPrivate;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "openxrswapchainimpl.hpp"
|
#include "openxrswapchainimpl.hpp"
|
||||||
#include "vrenvironment.hpp"
|
#include "vrenvironment.hpp"
|
||||||
|
#include "vrframebuffer.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
@ -47,9 +48,8 @@ namespace MWVR {
|
||||||
|
|
||||||
// Find supported depth swapchain format.
|
// Find supported depth swapchain format.
|
||||||
constexpr int64_t RequestedDepthSwapchainFormats[] = {
|
constexpr int64_t RequestedDepthSwapchainFormats[] = {
|
||||||
GL_DEPTH_COMPONENT32F,
|
|
||||||
GL_DEPTH_COMPONENT24,
|
GL_DEPTH_COMPONENT24,
|
||||||
GL_DEPTH_COMPONENT16,
|
GL_DEPTH_COMPONENT32F,
|
||||||
};
|
};
|
||||||
|
|
||||||
swapchainFormatIt =
|
swapchainFormatIt =
|
||||||
|
@ -108,7 +108,7 @@ namespace MWVR {
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mDepthSwapchainImageBuffers.data())));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mDepthSwapchainImageBuffers.data())));
|
||||||
|
|
||||||
for (unsigned i = 0; i < imageCount; i++)
|
for (unsigned i = 0; i < imageCount; i++)
|
||||||
mRenderBuffers.emplace_back(new VRTexture(state, mWidth, mHeight, mSamples, mSwapchainImageBuffers[i].image, mDepthSwapchainImageBuffers[i].image));
|
mRenderBuffers.emplace_back(new VRFramebuffer(state, mWidth, mHeight, mSamples, mSwapchainImageBuffers[i].image, mDepthSwapchainImageBuffers[i].image));
|
||||||
|
|
||||||
mSubImage.swapchain = mSwapchain;
|
mSubImage.swapchain = mSwapchain;
|
||||||
mSubImage.imageRect.offset = { 0, 0 };
|
mSubImage.imageRect.offset = { 0, 0 };
|
||||||
|
@ -121,18 +121,22 @@ namespace MWVR {
|
||||||
CHECK_XRCMD(xrDestroySwapchain(mSwapchain));
|
CHECK_XRCMD(xrDestroySwapchain(mSwapchain));
|
||||||
}
|
}
|
||||||
|
|
||||||
VRTexture* OpenXRSwapchainImpl::renderBuffer() const
|
VRFramebuffer* OpenXRSwapchainImpl::renderBuffer() const
|
||||||
{
|
{
|
||||||
if (isAcquired())
|
checkAcquired();
|
||||||
return mRenderBuffers[mAcquiredImageIndex].get();
|
return mRenderBuffers[mAcquiredImageIndex].get();
|
||||||
throw std::logic_error("Swapbuffer not acquired before use");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t OpenXRSwapchainImpl::acquiredImage() const
|
uint32_t OpenXRSwapchainImpl::acquiredColorTexture() const
|
||||||
{
|
{
|
||||||
if (isAcquired())
|
checkAcquired();
|
||||||
|
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t OpenXRSwapchainImpl::acquiredDepthTexture() const
|
||||||
|
{
|
||||||
|
checkAcquired();
|
||||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
||||||
throw std::logic_error("Swapbuffer not acquired before use");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenXRSwapchainImpl::isAcquired() const
|
bool OpenXRSwapchainImpl::isAcquired() const
|
||||||
|
@ -142,14 +146,17 @@ namespace MWVR {
|
||||||
|
|
||||||
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
|
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
|
if (isAcquired())
|
||||||
|
throw std::logic_error("Trying to acquire already acquired swapchain");
|
||||||
acquire(gc);
|
acquire(gc);
|
||||||
renderBuffer()->beginFrame(gc);
|
renderBuffer()->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int swapCount = 0;
|
int swapCount = 0;
|
||||||
|
|
||||||
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc)
|
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
|
checkAcquired();
|
||||||
release(gc);
|
release(gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,4 +187,9 @@ namespace MWVR {
|
||||||
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
||||||
CHECK_XRCMD(xrReleaseSwapchainImage(mDepthSwapchain, &releaseInfo));
|
CHECK_XRCMD(xrReleaseSwapchainImage(mDepthSwapchain, &releaseInfo));
|
||||||
}
|
}
|
||||||
|
void OpenXRSwapchainImpl::checkAcquired() const
|
||||||
|
{
|
||||||
|
if (!isAcquired())
|
||||||
|
throw std::logic_error("Swapchain must be acquired before use. Call between OpenXRSwapchain::beginFrame() and OpenXRSwapchain::endFrame()");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,10 @@ namespace MWVR
|
||||||
|
|
||||||
void beginFrame(osg::GraphicsContext* gc);
|
void beginFrame(osg::GraphicsContext* gc);
|
||||||
void endFrame(osg::GraphicsContext* gc);
|
void endFrame(osg::GraphicsContext* gc);
|
||||||
void acquire(osg::GraphicsContext* gc);
|
|
||||||
void release(osg::GraphicsContext* gc);
|
|
||||||
|
|
||||||
VRTexture* renderBuffer() const;
|
VRFramebuffer* renderBuffer() const;
|
||||||
|
uint32_t acquiredColorTexture() const;
|
||||||
uint32_t acquiredImage() const;
|
uint32_t acquiredDepthTexture() const;
|
||||||
|
|
||||||
bool isAcquired() const;
|
bool isAcquired() const;
|
||||||
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
||||||
|
@ -31,6 +29,15 @@ namespace MWVR
|
||||||
int height() const { return mHeight; };
|
int height() const { return mHeight; };
|
||||||
int samples() const { return mSamples; };
|
int samples() const { return mSamples; };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenXRSwapchainImpl(const OpenXRSwapchainImpl&) = delete;
|
||||||
|
void operator=(const OpenXRSwapchainImpl&) = delete;
|
||||||
|
|
||||||
|
void acquire(osg::GraphicsContext* gc);
|
||||||
|
void release(osg::GraphicsContext* gc);
|
||||||
|
void checkAcquired() const;
|
||||||
|
|
||||||
|
private:
|
||||||
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
||||||
XrSwapchain mDepthSwapchain = XR_NULL_HANDLE;
|
XrSwapchain mDepthSwapchain = XR_NULL_HANDLE;
|
||||||
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
|
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
|
||||||
|
@ -42,7 +49,7 @@ namespace MWVR
|
||||||
int64_t mSwapchainColorFormat = -1;
|
int64_t mSwapchainColorFormat = -1;
|
||||||
int64_t mSwapchainDepthFormat = -1;
|
int64_t mSwapchainDepthFormat = -1;
|
||||||
uint32_t mFBO = 0;
|
uint32_t mFBO = 0;
|
||||||
std::vector<std::unique_ptr<VRTexture> > mRenderBuffers{};
|
std::vector<std::unique_ptr<VRFramebuffer> > mRenderBuffers{};
|
||||||
int mRenderBuffer{ 0 };
|
int mRenderBuffer{ 0 };
|
||||||
uint32_t mAcquiredImageIndex{ 0 };
|
uint32_t mAcquiredImageIndex{ 0 };
|
||||||
bool mIsAcquired{ false };
|
bool mIsAcquired{ false };
|
||||||
|
|
|
@ -1,27 +1,3 @@
|
||||||
/////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// State machine for "realistic" combat in openmw vr
|
|
||||||
//
|
|
||||||
// Initial state: Ready.
|
|
||||||
//
|
|
||||||
// State Ready: Ready to initiate a new attack.
|
|
||||||
// State Launch: Player has begun swinging his weapon.
|
|
||||||
// State Swing: Currently swinging weapon.
|
|
||||||
// State Impact: Contact made, weapon still swinging.
|
|
||||||
// State Cooldown: Swing completed, wait a minimum period before next.
|
|
||||||
//
|
|
||||||
// Transition rules:
|
|
||||||
// Ready -> Launch: When the minimum velocity of swing is achieved.
|
|
||||||
// Launch -> Ready: When the minimum velocity of swing is lost before minimum distance was swung.
|
|
||||||
// Launch -> Swing: When minimum distance is swung.
|
|
||||||
// - Play Swish sound
|
|
||||||
// Swing -> Impact: When minimum velocity is lost, or when a hit is detected.
|
|
||||||
// - Register hit based on max velocity observed in swing state
|
|
||||||
// Impact -> Cooldown: When velocity returns below minimum.
|
|
||||||
// Cooldown -> Ready: When the minimum period has passed since entering Cooldown state
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "realisticcombat.hpp"
|
#include "realisticcombat.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -70,13 +46,20 @@ namespace MWVR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StateMachine::StateMachine(MWWorld::Ptr ptr) : ptr(ptr) {}
|
StateMachine::StateMachine(MWWorld::Ptr ptr)
|
||||||
|
: mPtr(ptr)
|
||||||
|
, mMinVelocity(Settings::Manager::getFloat("realistic combat minimum swing velocity", "VR"))
|
||||||
|
, mMaxVelocity(Settings::Manager::getFloat("realistic combat maximum swing velocity", "VR"))
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "realistic combat minimum swing velocity: " << mMinVelocity;
|
||||||
|
Log(Debug::Verbose) << "realistic combat maximum swing velocity: " << mMaxVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
bool StateMachine::canSwing()
|
bool StateMachine::canSwing()
|
||||||
{
|
{
|
||||||
if (swingType >= 0)
|
if (mSwingType >= 0)
|
||||||
if (velocity >= minVelocity)
|
if (mVelocity >= mMinVelocity)
|
||||||
if (swingType != ESM::Weapon::AT_Thrust || thrustVelocity >= 0.f)
|
if (mSwingType != ESM::Weapon::AT_Thrust || mThrustVelocity >= 0.f)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -85,20 +68,20 @@ namespace MWVR {
|
||||||
void StateMachine::transition(
|
void StateMachine::transition(
|
||||||
SwingState newState)
|
SwingState newState)
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << "Transition:" << stateToString(state) << "->" << stateToString(newState);
|
Log(Debug::Verbose) << "Transition:" << stateToString(mState) << "->" << stateToString(newState);
|
||||||
maxSwingVelocity = 0.f;
|
mMaxSwingVelocity = 0.f;
|
||||||
timeSinceEnteredState = 0.f;
|
mTimeSinceEnteredState = 0.f;
|
||||||
movementSinceEnteredState = 0.f;
|
mMovementSinceEnteredState = 0.f;
|
||||||
state = newState;
|
mState = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::reset()
|
void StateMachine::reset()
|
||||||
{
|
{
|
||||||
maxSwingVelocity = 0.f;
|
mMaxSwingVelocity = 0.f;
|
||||||
timeSinceEnteredState = 0.f;
|
mTimeSinceEnteredState = 0.f;
|
||||||
velocity = 0.f;
|
mVelocity = 0.f;
|
||||||
previousPosition = osg::Vec3(0.f, 0.f, 0.f);
|
mPreviousPosition = osg::Vec3(0.f, 0.f, 0.f);
|
||||||
state = SwingState_Ready;
|
mState = SwingState_Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isMeleeWeapon(int type)
|
static bool isMeleeWeapon(int type)
|
||||||
|
@ -151,7 +134,7 @@ namespace MWVR {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timeSinceEnteredState += dt;
|
mTimeSinceEnteredState += dt;
|
||||||
|
|
||||||
|
|
||||||
// First determine direction of different swing types
|
// First determine direction of different swing types
|
||||||
|
@ -180,12 +163,12 @@ namespace MWVR {
|
||||||
// So i reset position when tracking is re-acquired to avoid a superspeed strike.
|
// So i reset position when tracking is re-acquired to avoid a superspeed strike.
|
||||||
// Theoretically, the player's hand really could be at 0,0,0
|
// Theoretically, the player's hand really could be at 0,0,0
|
||||||
// but that's a super rare case so whatever.
|
// but that's a super rare case so whatever.
|
||||||
if (previousPosition == osg::Vec3(0.f, 0.f, 0.f))
|
if (mPreviousPosition == osg::Vec3(0.f, 0.f, 0.f))
|
||||||
previousPosition = handPose.position;
|
mPreviousPosition = handPose.position;
|
||||||
|
|
||||||
osg::Vec3 movement = handPose.position - previousPosition;
|
osg::Vec3 movement = handPose.position - mPreviousPosition;
|
||||||
movementSinceEnteredState += movement.length();
|
mMovementSinceEnteredState += movement.length();
|
||||||
previousPosition = handPose.position;
|
mPreviousPosition = handPose.position;
|
||||||
osg::Vec3 swingVector = movement / dt;
|
osg::Vec3 swingVector = movement / dt;
|
||||||
osg::Vec3 swingDirection = swingVector;
|
osg::Vec3 swingDirection = swingVector;
|
||||||
swingDirection.normalize();
|
swingDirection.normalize();
|
||||||
|
@ -193,24 +176,24 @@ namespace MWVR {
|
||||||
// Compute swing velocities
|
// Compute swing velocities
|
||||||
|
|
||||||
// Thrust follows the orientation of the weapon. Negative thrust = no attack.
|
// Thrust follows the orientation of the weapon. Negative thrust = no attack.
|
||||||
thrustVelocity = swingVector * thrustDirection;
|
mThrustVelocity = swingVector * thrustDirection;
|
||||||
velocity = swingVector.length();
|
mVelocity = swingVector.length();
|
||||||
|
|
||||||
|
|
||||||
if (isSideSwingValidForWeapon(weaponType))
|
if (isSideSwingValidForWeapon(weaponType))
|
||||||
{
|
{
|
||||||
// Compute velocity in the plane normal to the thrust direction.
|
// Compute velocity in the plane normal to the thrust direction.
|
||||||
float thrustComponent = std::abs(thrustVelocity / velocity);
|
float thrustComponent = std::abs(mThrustVelocity / mVelocity);
|
||||||
float planeComponent = std::sqrt(1 - thrustComponent * thrustComponent);
|
float planeComponent = std::sqrt(1 - thrustComponent * thrustComponent);
|
||||||
slashChopVelocity = velocity * planeComponent;
|
mSlashChopVelocity = mVelocity * planeComponent;
|
||||||
sideVelocity = -1000.f;
|
mSideVelocity = -1000.f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If side swing is not valid for the weapon, count slash/chop only along in
|
// If side swing is not valid for the weapon, count slash/chop only along in
|
||||||
// the direction of the weapon's edge.
|
// the direction of the weapon's edge.
|
||||||
slashChopVelocity = std::abs(swingVector * slashChopDirection);
|
mSlashChopVelocity = std::abs(swingVector * slashChopDirection);
|
||||||
sideVelocity = std::abs(swingVector * sideDirection);
|
mSideVelocity = std::abs(swingVector * sideDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,34 +203,34 @@ namespace MWVR {
|
||||||
// Pick swing type based on greatest current velocity
|
// Pick swing type based on greatest current velocity
|
||||||
// Note i use abs() of thrust velocity to prevent accidentally triggering
|
// Note i use abs() of thrust velocity to prevent accidentally triggering
|
||||||
// chop/slash when player is withdrawing the weapon.
|
// chop/slash when player is withdrawing the weapon.
|
||||||
if (sideVelocity > std::abs(thrustVelocity) && sideVelocity > slashChopVelocity)
|
if (mSideVelocity > std::abs(mThrustVelocity) && mSideVelocity > mSlashChopVelocity)
|
||||||
{
|
{
|
||||||
// Player is swinging with the "blunt" side of a weapon that
|
// Player is swinging with the "blunt" side of a weapon that
|
||||||
// cannot be used that way.
|
// cannot be used that way.
|
||||||
swingType = -1;
|
mSwingType = -1;
|
||||||
}
|
}
|
||||||
else if (std::abs(thrustVelocity) > slashChopVelocity)
|
else if (std::abs(mThrustVelocity) > mSlashChopVelocity)
|
||||||
{
|
{
|
||||||
swingType = ESM::Weapon::AT_Thrust;
|
mSwingType = ESM::Weapon::AT_Thrust;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// First check if the weapon is pointing upwards. In which case slash is not
|
// First check if the weapon is pointing upwards. In which case slash is not
|
||||||
// applicable, and the attack must be a chop.
|
// applicable, and the attack must be a chop.
|
||||||
if (orientationVerticality > 0.707)
|
if (orientationVerticality > 0.707)
|
||||||
swingType = ESM::Weapon::AT_Chop;
|
mSwingType = ESM::Weapon::AT_Chop;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Next check if the swing is more horizontal or vertical. A slash
|
// Next check if the swing is more horizontal or vertical. A slash
|
||||||
// would be more horizontal.
|
// would be more horizontal.
|
||||||
if (swingVerticality > 0.707)
|
if (swingVerticality > 0.707)
|
||||||
swingType = ESM::Weapon::AT_Chop;
|
mSwingType = ESM::Weapon::AT_Chop;
|
||||||
else
|
else
|
||||||
swingType = ESM::Weapon::AT_Slash;
|
mSwingType = ESM::Weapon::AT_Slash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state)
|
switch (mState)
|
||||||
{
|
{
|
||||||
case SwingState_Cooldown:
|
case SwingState_Cooldown:
|
||||||
return update_cooldownState();
|
return update_cooldownState();
|
||||||
|
@ -260,13 +243,13 @@ namespace MWVR {
|
||||||
case SwingState_Launch:
|
case SwingState_Launch:
|
||||||
return update_launchState();
|
return update_launchState();
|
||||||
default:
|
default:
|
||||||
throw std::logic_error(std::string("You forgot to implement state ") + stateToString(state) + " ya dingus");
|
throw std::logic_error(std::string("You forgot to implement state ") + stateToString(mState) + " ya dingus");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::update_cooldownState()
|
void StateMachine::update_cooldownState()
|
||||||
{
|
{
|
||||||
if (timeSinceEnteredState >= minimumPeriod)
|
if (mTimeSinceEnteredState >= mMinimumPeriod)
|
||||||
transition_cooldownToReady();
|
transition_cooldownToReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,19 +274,19 @@ namespace MWVR {
|
||||||
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
||||||
std::string sound = "Weapon Swish";
|
std::string sound = "Weapon Swish";
|
||||||
if (strength < 0.5f)
|
if (mStrength < 0.5f)
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 0.8f); //Weak attack
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
||||||
if (strength < 1.0f)
|
if (mStrength < 1.0f)
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f); //Medium attack
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
||||||
else
|
else
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.2f); //Strong attack
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
|
||||||
|
|
||||||
Log(Debug::Verbose) << "Swing: " << swingTypeToString(swingType);
|
Log(Debug::Verbose) << "Swing: " << swingTypeToString(mSwingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::update_launchState()
|
void StateMachine::update_launchState()
|
||||||
{
|
{
|
||||||
if (movementSinceEnteredState > minimumPeriod)
|
if (mMovementSinceEnteredState > mMinimumPeriod)
|
||||||
transition_launchToSwing();
|
transition_launchToSwing();
|
||||||
if (!canSwing())
|
if (!canSwing())
|
||||||
return transition_launchToReady();
|
return transition_launchToReady();
|
||||||
|
@ -326,26 +309,26 @@ namespace MWVR {
|
||||||
|
|
||||||
void StateMachine::update_swingState()
|
void StateMachine::update_swingState()
|
||||||
{
|
{
|
||||||
maxSwingVelocity = std::max(velocity, maxSwingVelocity);
|
mMaxSwingVelocity = std::max(mVelocity, mMaxSwingVelocity);
|
||||||
strength = std::min(1.f, (maxSwingVelocity - minVelocity) / maxVelocity);
|
mStrength = std::min(1.f, (mMaxSwingVelocity - mMinVelocity) / mMaxVelocity);
|
||||||
|
|
||||||
// When velocity falls below minimum, transition to register the miss
|
// When velocity falls below minimum, transition to register the miss
|
||||||
if (!canSwing())
|
if (!canSwing())
|
||||||
return transition_swingingToImpact();
|
return transition_swingingToImpact();
|
||||||
// Call hit with simulated=true to check for hit without actually causing an impact
|
// Call hit with simulated=true to check for hit without actually causing an impact
|
||||||
if (ptr.getClass().hit(ptr, strength, swingType, true))
|
if (mPtr.getClass().hit(mPtr, mStrength, mSwingType, true))
|
||||||
return transition_swingingToImpact();
|
return transition_swingingToImpact();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::transition_swingingToImpact()
|
void StateMachine::transition_swingingToImpact()
|
||||||
{
|
{
|
||||||
ptr.getClass().hit(ptr, strength, swingType, false);
|
mPtr.getClass().hit(mPtr, mStrength, mSwingType, false);
|
||||||
transition(SwingState_Impact);
|
transition(SwingState_Impact);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::update_impactState()
|
void StateMachine::update_impactState()
|
||||||
{
|
{
|
||||||
if (velocity < minVelocity)
|
if (mVelocity < mMinVelocity)
|
||||||
return transition_impactToCooldown();
|
return transition_impactToCooldown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
namespace MWVR {
|
namespace MWVR {
|
||||||
namespace RealisticCombat {
|
namespace RealisticCombat {
|
||||||
|
|
||||||
|
/// Enum describing the current state of the MWVR::RealisticCombat::StateMachine
|
||||||
enum SwingState
|
enum SwingState
|
||||||
{
|
{
|
||||||
SwingState_Ready,
|
SwingState_Ready,
|
||||||
|
@ -21,35 +23,38 @@ namespace MWVR {
|
||||||
SwingState_Cooldown,
|
SwingState_Cooldown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// \brief State machine for "realistic" combat in openmw vr
|
||||||
|
///
|
||||||
|
/// \sa SwingState
|
||||||
|
///
|
||||||
|
/// Initial state: Ready.
|
||||||
|
///
|
||||||
|
/// State Ready: Ready to initiate a new attack.
|
||||||
|
/// State Launch: Player has begun swinging his weapon.
|
||||||
|
/// State Swing: Currently swinging weapon.
|
||||||
|
/// State Impact: Contact made, weapon still swinging.
|
||||||
|
/// State Cooldown: Swing completed, wait a minimum period before next.
|
||||||
|
///
|
||||||
|
/// Transition rules:
|
||||||
|
/// Ready -> Launch: When the minimum velocity of swing is achieved.
|
||||||
|
/// Launch -> Ready: When the minimum velocity of swing is lost before minimum distance was swung.
|
||||||
|
/// Launch -> Swing: When minimum distance is swung.
|
||||||
|
/// - Play Swish sound
|
||||||
|
/// Swing -> Impact: When minimum velocity is lost, or when a hit is detected.
|
||||||
|
/// - Register hit based on max velocity observed in swing state
|
||||||
|
/// Impact -> Cooldown: When velocity returns below minimum.
|
||||||
|
/// Cooldown -> Ready: When the minimum period has passed since entering Cooldown state
|
||||||
|
///
|
||||||
|
///
|
||||||
struct StateMachine
|
struct StateMachine
|
||||||
{
|
{
|
||||||
// TODO: These should be configurable
|
public:
|
||||||
const float minVelocity = 1.f;
|
|
||||||
const float maxVelocity = 4.f;
|
|
||||||
|
|
||||||
float velocity = 0.f;
|
|
||||||
float maxSwingVelocity = 0.f;
|
|
||||||
|
|
||||||
SwingState state = SwingState_Ready;
|
|
||||||
MWWorld::Ptr ptr = MWWorld::Ptr();
|
|
||||||
int swingType = -1;
|
|
||||||
float strength = 0.f;
|
|
||||||
|
|
||||||
float thrustVelocity{ 0.f };
|
|
||||||
float slashChopVelocity{ 0.f };
|
|
||||||
float sideVelocity{ 0.f };
|
|
||||||
|
|
||||||
float minimumPeriod{ .25f };
|
|
||||||
|
|
||||||
float timeSinceEnteredState = { 0.f };
|
|
||||||
float movementSinceEnteredState = { 0.f };
|
|
||||||
|
|
||||||
bool mEnabled = false;
|
|
||||||
|
|
||||||
osg::Vec3 previousPosition{ 0.f,0.f,0.f };
|
|
||||||
|
|
||||||
StateMachine(MWWorld::Ptr ptr);
|
StateMachine(MWWorld::Ptr ptr);
|
||||||
|
void update(float dt, bool enabled);
|
||||||
|
MWWorld::Ptr ptr() { return mPtr; }
|
||||||
|
|
||||||
|
protected:
|
||||||
bool canSwing();
|
bool canSwing();
|
||||||
|
|
||||||
void playSwish();
|
void playSwish();
|
||||||
|
@ -57,7 +62,6 @@ namespace MWVR {
|
||||||
|
|
||||||
void transition(SwingState newState);
|
void transition(SwingState newState);
|
||||||
|
|
||||||
void update(float dt, bool enabled);
|
|
||||||
|
|
||||||
void update_cooldownState();
|
void update_cooldownState();
|
||||||
void transition_cooldownToReady();
|
void transition_cooldownToReady();
|
||||||
|
@ -74,6 +78,31 @@ namespace MWVR {
|
||||||
|
|
||||||
void update_impactState();
|
void update_impactState();
|
||||||
void transition_impactToCooldown();
|
void transition_impactToCooldown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MWWorld::Ptr mPtr;
|
||||||
|
const float mMinVelocity;
|
||||||
|
const float mMaxVelocity;
|
||||||
|
|
||||||
|
float mVelocity = 0.f;
|
||||||
|
float mMaxSwingVelocity = 0.f;
|
||||||
|
|
||||||
|
SwingState mState = SwingState_Ready;
|
||||||
|
int mSwingType = -1;
|
||||||
|
float mStrength = 0.f;
|
||||||
|
|
||||||
|
float mThrustVelocity{ 0.f };
|
||||||
|
float mSlashChopVelocity{ 0.f };
|
||||||
|
float mSideVelocity{ 0.f };
|
||||||
|
|
||||||
|
float mMinimumPeriod{ .25f };
|
||||||
|
|
||||||
|
float mTimeSinceEnteredState = { 0.f };
|
||||||
|
float mMovementSinceEnteredState = { 0.f };
|
||||||
|
|
||||||
|
bool mEnabled = false;
|
||||||
|
|
||||||
|
osg::Vec3 mPreviousPosition{ 0.f,0.f,0.f };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,11 +459,10 @@ namespace MWVR
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
||||||
bool isMale = ref->mBase->isMale();
|
bool isMale = ref->mBase->isMale();
|
||||||
float charHeightFactor = isMale ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale;
|
float charHeightFactor = isMale ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale;
|
||||||
float charHeightBase = 1.8f;
|
float charHeightBase = 1.8f; // Is this ~ the right value?
|
||||||
float charHeight = charHeightBase * charHeightFactor;
|
float charHeight = charHeightBase * charHeightFactor;
|
||||||
// TODO: Player height should be configurable
|
float realHeight = Settings::Manager::getFloat("real height", "VR");
|
||||||
// For now i'm just using my own
|
float sizeFactor = charHeight / realHeight;
|
||||||
float sizeFactor = 1.85f / charHeight;
|
|
||||||
Environment::get().getSession()->setPlayerScale(sizeFactor);
|
Environment::get().getSession()->setPlayerScale(sizeFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MWVR
|
||||||
class FingerController;
|
class FingerController;
|
||||||
class ForearmController;
|
class ForearmController;
|
||||||
|
|
||||||
/// Subclassing NpcAnimation to override behaviours not compatible with VR
|
/// Subclassing NpcAnimation to implement VR related behaviour
|
||||||
class VRAnimation : public MWRender::NpcAnimation
|
class VRAnimation : public MWRender::NpcAnimation
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "vrtexture.hpp"
|
#include "vrframebuffer.hpp"
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
|
|
||||||
VRTexture::VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer, uint32_t depthBuffer)
|
VRFramebuffer::VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer, uint32_t depthBuffer)
|
||||||
: mState(state)
|
: mState(state)
|
||||||
, mWidth(width)
|
, mWidth(width)
|
||||||
, mHeight(height)
|
, mHeight(height)
|
||||||
|
@ -72,12 +72,12 @@ namespace MWVR
|
||||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VRTexture::~VRTexture()
|
VRFramebuffer::~VRFramebuffer()
|
||||||
{
|
{
|
||||||
destroy(nullptr);
|
destroy(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRTexture::destroy(osg::State* state)
|
void VRFramebuffer::destroy(osg::State* state)
|
||||||
{
|
{
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ namespace MWVR
|
||||||
gl->glDeleteFramebuffers(1, &mFBO);
|
gl->glDeleteFramebuffers(1, &mFBO);
|
||||||
}
|
}
|
||||||
else if (mFBO)
|
else if (mFBO)
|
||||||
// Without access to opengl methods, i'll just let the FBOs leak.
|
// Without access to glDeleteFramebuffers, i'll have to leak FBOs.
|
||||||
Log(Debug::Warning) << "destroy() called without a State. Leaking FBO";
|
Log(Debug::Warning) << "destroy() called without a State. Leaking FBO";
|
||||||
|
|
||||||
if (mDepthBuffer)
|
if (mDepthBuffer)
|
||||||
|
@ -100,30 +100,17 @@ namespace MWVR
|
||||||
if (mColorBuffer)
|
if (mColorBuffer)
|
||||||
glDeleteTextures(1, &mColorBuffer);
|
glDeleteTextures(1, &mColorBuffer);
|
||||||
|
|
||||||
mFBO = mDepthBuffer = mColorBuffer;
|
mFBO = mDepthBuffer = mColorBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRTexture::beginFrame(osg::GraphicsContext* gc)
|
void VRFramebuffer::bindFramebuffer(osg::GraphicsContext* gc, uint32_t target)
|
||||||
{
|
{
|
||||||
auto state = gc->getState();
|
auto state = gc->getState();
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
|
gl->glBindFramebuffer(target, mFBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRTexture::endFrame(osg::GraphicsContext* gc, uint32_t blitTarget)
|
void VRFramebuffer::blit(osg::GraphicsContext* gc, int x, int y, int w, int h)
|
||||||
{
|
|
||||||
auto* state = gc->getState();
|
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
|
||||||
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, mBlitFBO);
|
|
||||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, mFBO);
|
|
||||||
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, blitTarget, 0);
|
|
||||||
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
||||||
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
|
|
||||||
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
|
||||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VRTexture::blit(osg::GraphicsContext* gc, int x, int y, int w, int h)
|
|
||||||
{
|
{
|
||||||
auto* state = gc->getState();
|
auto* state = gc->getState();
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||||
|
@ -131,17 +118,4 @@ namespace MWVR
|
||||||
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRTexture::blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int blitTarget)
|
|
||||||
{
|
|
||||||
auto* state = gc->getState();
|
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
|
||||||
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, mBlitFBO);
|
|
||||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, mFBO);
|
|
||||||
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, blitTarget, 0);
|
|
||||||
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
||||||
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
|
|
||||||
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
|
||||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -10,11 +10,14 @@
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
class VRTexture : public osg::Referenced
|
/// \brief Manages an opengl framebuffer
|
||||||
|
///
|
||||||
|
/// Intended for managing the vr swapchain, but is also use to manage the mirror texture as a convenience.
|
||||||
|
class VRFramebuffer : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer = 0, uint32_t depthBuffer = 0);
|
VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer = 0, uint32_t depthBuffer = 0);
|
||||||
~VRTexture();
|
~VRFramebuffer();
|
||||||
|
|
||||||
void destroy(osg::State* state);
|
void destroy(osg::State* state);
|
||||||
|
|
||||||
|
@ -22,15 +25,13 @@ namespace MWVR
|
||||||
auto height() const { return mHeight; }
|
auto height() const { return mHeight; }
|
||||||
auto msaaSamples() const { return mSamples; }
|
auto msaaSamples() const { return mSamples; }
|
||||||
|
|
||||||
void beginFrame(osg::GraphicsContext* gc);
|
void bindFramebuffer(osg::GraphicsContext* gc, uint32_t target);
|
||||||
void endFrame(osg::GraphicsContext* gc, uint32_t blitTarget);
|
|
||||||
|
|
||||||
uint32_t fbo(void) const { return mFBO; }
|
uint32_t fbo(void) const { return mFBO; }
|
||||||
uint32_t colorBuffer(void) const { return mColorBuffer; }
|
uint32_t colorBuffer(void) const { return mColorBuffer; }
|
||||||
|
|
||||||
//! Blit to region in currently bound draw fbo
|
//! Blit to region in currently bound draw fbo
|
||||||
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h);
|
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h);
|
||||||
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int target);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Set aside a weak pointer to the constructor state to use when freeing FBOs, if no state is given to destroy()
|
// Set aside a weak pointer to the constructor state to use when freeing FBOs, if no state is given to destroy()
|
||||||
|
@ -44,7 +45,9 @@ namespace MWVR
|
||||||
uint32_t mFBO = 0;
|
uint32_t mFBO = 0;
|
||||||
uint32_t mBlitFBO = 0;
|
uint32_t mBlitFBO = 0;
|
||||||
uint32_t mDepthBuffer = 0;
|
uint32_t mDepthBuffer = 0;
|
||||||
|
bool mOwnDepthBuffer = false;
|
||||||
uint32_t mColorBuffer = 0;
|
uint32_t mColorBuffer = 0;
|
||||||
|
bool mOwnColorBuffer = false;
|
||||||
uint32_t mSamples = 0;
|
uint32_t mSamples = 0;
|
||||||
uint32_t mTextureTarget = 0;
|
uint32_t mTextureTarget = 0;
|
||||||
};
|
};
|
|
@ -327,8 +327,7 @@ namespace MWVR
|
||||||
if (mLayerName == "Notification")
|
if (mLayerName == "Notification")
|
||||||
{
|
{
|
||||||
// The latest widget for notification is always the top one
|
// The latest widget for notification is always the top one
|
||||||
// So we just have to stretch the rectangle to the bottom
|
// So i just stretch the rectangle to the bottom.
|
||||||
// TODO: This might get deprecated with this new system?
|
|
||||||
mRealRect.bottom = 1.f;
|
mRealRect.bottom = 1.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,11 @@ namespace MWVR
|
||||||
Fixed
|
Fixed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Configuration of a VRGUILayer
|
||||||
struct LayerConfig
|
struct LayerConfig
|
||||||
{
|
{
|
||||||
int priority; //!< Higher priority shows over lower priority windows.
|
int priority; //!< Higher priority shows over lower priority windows by moving higher priority layers slightly closer to the player.
|
||||||
bool sideBySide; //!< Resize layer window to occupy full quad
|
bool sideBySide; //!< All layers with this config will show up side by side in a partial circle around the player, and will all be resized to a predefined size.
|
||||||
osg::Vec4 backgroundColor; //!< Background color of layer
|
osg::Vec4 backgroundColor; //!< Background color of layer
|
||||||
osg::Vec3 offset; //!< Offset from tracked node in meters
|
osg::Vec3 offset; //!< Offset from tracked node in meters
|
||||||
osg::Vec2 center; //!< Model space centerpoint of menu geometry. All menu geometries have model space lengths of 1 in each dimension. Use this to affect how geometries grow with changing size.
|
osg::Vec2 center; //!< Model space centerpoint of menu geometry. All menu geometries have model space lengths of 1 in each dimension. Use this to affect how geometries grow with changing size.
|
||||||
|
@ -66,6 +67,11 @@ namespace MWVR
|
||||||
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief A single VR GUI Quad.
|
||||||
|
///
|
||||||
|
/// In VR menus are shown as quads within the game world.
|
||||||
|
/// The behaviour of that quad is defined by the MWVR::LayerConfig struct
|
||||||
|
/// Each instance of VRGUILayer is used to show one MYGUI layer.
|
||||||
class VRGUILayer
|
class VRGUILayer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -77,20 +83,19 @@ namespace MWVR
|
||||||
VRGUIManager* parent);
|
VRGUIManager* parent);
|
||||||
~VRGUILayer();
|
~VRGUILayer();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class VRGUIManager;
|
||||||
osg::Camera* camera();
|
osg::Camera* camera();
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> menuTexture();
|
osg::ref_ptr<osg::Texture2D> menuTexture();
|
||||||
|
|
||||||
void setAngle(float angle);
|
void setAngle(float angle);
|
||||||
void updateTracking(const Pose& headPose = {});
|
void updateTracking(const Pose& headPose = {});
|
||||||
void updatePose();
|
void updatePose();
|
||||||
void updateRect();
|
void updateRect();
|
||||||
void update();
|
|
||||||
|
|
||||||
void insertWidget(MWGui::Layout* widget);
|
void insertWidget(MWGui::Layout* widget);
|
||||||
void removeWidget(MWGui::Layout* widget);
|
void removeWidget(MWGui::Layout* widget);
|
||||||
int widgetCount() { return mWidgets.size(); }
|
int widgetCount() { return mWidgets.size(); }
|
||||||
|
|
||||||
bool operator<(const VRGUILayer& rhs) const { return mConfig.priority < rhs.mConfig.priority; }
|
bool operator<(const VRGUILayer& rhs) const { return mConfig.priority < rhs.mConfig.priority; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -108,6 +113,7 @@ namespace MWVR
|
||||||
osg::Quat mRotation{ 0,0,0,1 };
|
osg::Quat mRotation{ 0,0,0,1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief osg user data used to refer back to VRGUILayer objects when intersecting with the scene graph.
|
||||||
class VRGUILayerUserData : public osg::Referenced
|
class VRGUILayerUserData : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -116,6 +122,11 @@ namespace MWVR
|
||||||
std::weak_ptr<VRGUILayer> mLayer;
|
std::weak_ptr<VRGUILayer> mLayer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Manager of VRGUILayer objects.
|
||||||
|
///
|
||||||
|
/// Constructs and destructs VRGUILayer objects in response to MWGui::Layout::setVisible calls.
|
||||||
|
/// Layers can also be made visible directly by calling insertLayer() directly, e.g. to show
|
||||||
|
/// the video player.
|
||||||
class VRGUIManager
|
class VRGUIManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -124,29 +135,33 @@ namespace MWVR
|
||||||
|
|
||||||
~VRGUIManager(void);
|
~VRGUIManager(void);
|
||||||
|
|
||||||
|
/// Set visibility of the layer this layout is on
|
||||||
void setVisible(MWGui::Layout*, bool visible);
|
void setVisible(MWGui::Layout*, bool visible);
|
||||||
|
|
||||||
void updateSideBySideLayers();
|
/// Insert the given layer quad if it isn't already
|
||||||
|
|
||||||
void insertLayer(const std::string& name);
|
void insertLayer(const std::string& name);
|
||||||
|
|
||||||
void insertWidget(MWGui::Layout* widget);
|
/// Remove the given layer quad
|
||||||
|
|
||||||
void removeLayer(const std::string& name);
|
void removeLayer(const std::string& name);
|
||||||
|
|
||||||
void removeWidget(MWGui::Layout* widget);
|
/// Update layer quads based on player camera
|
||||||
|
|
||||||
void updateTracking(void);
|
void updateTracking(void);
|
||||||
|
|
||||||
|
/// Update layer quads based on the given camera
|
||||||
void updateTracking(osg::Camera* camera);
|
void updateTracking(osg::Camera* camera);
|
||||||
|
|
||||||
|
/// Check current pointer target and update focus layer
|
||||||
bool updateFocus();
|
bool updateFocus();
|
||||||
|
|
||||||
void setFocusLayer(VRGUILayer* layer);
|
/// Gui cursor coordinates to use to simulate a mouse press/move if the player is currently pointing at a vr gui layer
|
||||||
|
|
||||||
osg::Vec2i guiCursor() { return mGuiCursor; };
|
osg::Vec2i guiCursor() { return mGuiCursor; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void computeGuiCursor(osg::Vec3 hitPoint);
|
void computeGuiCursor(osg::Vec3 hitPoint);
|
||||||
|
void updateSideBySideLayers();
|
||||||
|
void insertWidget(MWGui::Layout* widget);
|
||||||
|
void removeWidget(MWGui::Layout* widget);
|
||||||
|
void setFocusLayer(VRGUILayer* layer);
|
||||||
|
|
||||||
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#include "vrinputmanager.hpp"
|
#include "vrinputmanager.hpp"
|
||||||
|
|
||||||
|
#include "vrviewer.hpp"
|
||||||
|
#include "vrgui.hpp"
|
||||||
#include "vranimation.hpp"
|
#include "vranimation.hpp"
|
||||||
#include "openxrinput.hpp"
|
#include "openxrinput.hpp"
|
||||||
#include "vrenvironment.hpp"
|
#include "vrenvironment.hpp"
|
||||||
#include "openxrmanager.hpp"
|
#include "openxrmanager.hpp"
|
||||||
#include "openxrmanagerimpl.hpp"
|
#include "openxrmanagerimpl.hpp"
|
||||||
#include "openxraction.hpp"
|
#include "openxraction.hpp"
|
||||||
|
#include "realisticcombat.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
@ -139,14 +142,15 @@ namespace MWVR
|
||||||
channel->setEnabled(true);
|
channel->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Configurable haptics: on/off + max intensity
|
|
||||||
void VRInputManager::applyHapticsLeftHand(float intensity)
|
void VRInputManager::applyHapticsLeftHand(float intensity)
|
||||||
{
|
{
|
||||||
|
if (mHapticsEnabled)
|
||||||
mXRInput->applyHaptics(TrackedLimb::LEFT_HAND, intensity);
|
mXRInput->applyHaptics(TrackedLimb::LEFT_HAND, intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRInputManager::applyHapticsRightHand(float intensity)
|
void VRInputManager::applyHapticsRightHand(float intensity)
|
||||||
{
|
{
|
||||||
|
if (mHapticsEnabled)
|
||||||
mXRInput->applyHaptics(TrackedLimb::RIGHT_HAND, intensity);
|
mXRInput->applyHaptics(TrackedLimb::RIGHT_HAND, intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +180,7 @@ namespace MWVR
|
||||||
controllerBindingsFile,
|
controllerBindingsFile,
|
||||||
grab)
|
grab)
|
||||||
, mXRInput(nullptr)
|
, mXRInput(nullptr)
|
||||||
|
, mHapticsEnabled{Settings::Manager::getBool("haptics enabled", "VR")}
|
||||||
{
|
{
|
||||||
std::vector<SuggestedBindings> suggestedBindings;
|
std::vector<SuggestedBindings> suggestedBindings;
|
||||||
// Set up default bindings for the oculus
|
// Set up default bindings for the oculus
|
||||||
|
@ -337,7 +342,7 @@ namespace MWVR
|
||||||
|
|
||||||
auto& player = world->getPlayer();
|
auto& player = world->getPlayer();
|
||||||
auto playerPtr = world->getPlayerPtr();
|
auto playerPtr = world->getPlayerPtr();
|
||||||
if (!mRealisticCombat || mRealisticCombat->ptr != playerPtr)
|
if (!mRealisticCombat || mRealisticCombat->ptr() != playerPtr)
|
||||||
mRealisticCombat.reset(new RealisticCombat::StateMachine(playerPtr));
|
mRealisticCombat.reset(new RealisticCombat::StateMachine(playerPtr));
|
||||||
bool enabled = !guiMode && player.getDrawState() == MWMechanics::DrawState_Weapon && !player.isDisabled();
|
bool enabled = !guiMode && player.getDrawState() == MWMechanics::DrawState_Weapon && !player.isDisabled();
|
||||||
mRealisticCombat->update(dt, enabled);
|
mRealisticCombat->update(dt, enabled);
|
||||||
|
@ -360,7 +365,7 @@ namespace MWVR
|
||||||
void VRInputManager::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");
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
auto* xrGUIManager = Environment::get().getGUIManager();
|
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||||
|
|
||||||
|
|
||||||
// OpenMW does not currently provide any way to directly request skipping a video.
|
// OpenMW does not currently provide any way to directly request skipping a video.
|
||||||
|
@ -425,7 +430,7 @@ namespace MWVR
|
||||||
mActionManager->screenshot();
|
mActionManager->screenshot();
|
||||||
break;
|
break;
|
||||||
case A_Recenter:
|
case A_Recenter:
|
||||||
xrGUIManager->updateTracking();
|
vrGuiManager->updateTracking();
|
||||||
requestRecenter();
|
requestRecenter();
|
||||||
break;
|
break;
|
||||||
case A_MenuSelect:
|
case A_MenuSelect:
|
||||||
|
@ -601,7 +606,7 @@ namespace MWVR
|
||||||
mActionManager->setAttemptJump(true);
|
mActionManager->setAttemptJump(true);
|
||||||
break;
|
break;
|
||||||
case A_Recenter:
|
case A_Recenter:
|
||||||
xrGUIManager->updateTracking();
|
vrGuiManager->updateTracking();
|
||||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
requestRecenter();
|
requestRecenter();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef VR_INPUT_MANAGER_HPP
|
#ifndef VR_INPUT_MANAGER_HPP
|
||||||
#define VR_INPUT_MANAGER_HPP
|
#define VR_INPUT_MANAGER_HPP
|
||||||
|
|
||||||
#include "vrviewer.hpp"
|
#include "vrtypes.hpp"
|
||||||
#include "realisticcombat.hpp"
|
|
||||||
#include "../mwinput/inputmanagerimp.hpp"
|
#include "../mwinput/inputmanagerimp.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -15,8 +15,11 @@ namespace MWVR
|
||||||
{
|
{
|
||||||
struct OpenXRInput;
|
struct OpenXRInput;
|
||||||
|
|
||||||
/// As far as I can tell, SDL does not support VR controllers.
|
namespace RealisticCombat {
|
||||||
/// So I subclass the input manager and insert VR controls.
|
class StateMachine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extension of the input manager to include VR inputs
|
||||||
class VRInputManager : public MWInput::InputManager
|
class VRInputManager : public MWInput::InputManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -72,6 +75,7 @@ namespace MWVR
|
||||||
osg::Vec3 mHeadOffset{ 0,0,0 };
|
osg::Vec3 mHeadOffset{ 0,0,0 };
|
||||||
bool mShouldRecenter{ true };
|
bool mShouldRecenter{ true };
|
||||||
bool mActivationIndication{ false };
|
bool mActivationIndication{ false };
|
||||||
|
bool mHapticsEnabled{ true };
|
||||||
float mYaw{ 0.f };
|
float mYaw{ 0.f };
|
||||||
|
|
||||||
float mVrAngles[3]{ 0.f,0.f,0.f };
|
float mVrAngles[3]{ 0.f,0.f,0.f };
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
@ -37,7 +38,24 @@
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
VRSession::VRSession()
|
VRSession::VRSession()
|
||||||
|
: mXrSyncPhase{FramePhase::Cull}
|
||||||
{
|
{
|
||||||
|
auto syncPhase = Settings::Manager::getString("openxr sync phase", "VR");
|
||||||
|
syncPhase = Misc::StringUtils::lowerCase(syncPhase);
|
||||||
|
if (syncPhase == "update")
|
||||||
|
mXrSyncPhase = FramePhase::Update;
|
||||||
|
else if (syncPhase == "cull")
|
||||||
|
mXrSyncPhase = FramePhase::Cull;
|
||||||
|
else if (syncPhase == "draw")
|
||||||
|
mXrSyncPhase = FramePhase::Draw;
|
||||||
|
else if (syncPhase == "swap")
|
||||||
|
mXrSyncPhase = FramePhase::Swap;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "Invalid openxr sync phase " << syncPhase << ", defaulting to cull";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log(Debug::Verbose) << "Using openxr sync phase " << syncPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
VRSession::~VRSession()
|
VRSession::~VRSession()
|
||||||
|
@ -177,13 +195,10 @@ namespace MWVR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Invokation should depend on earliest render rather than necessarily phase.
|
// TODO: Invokation could depend on earliest actual render rather than necessarily any specific phase.
|
||||||
// Specifically. Without shadows this is fine because nothing is being rendered
|
// For example, shadows do some draw calls during cull an as such phase should be "Cull" or earlier with shadows enabled.
|
||||||
// during cull or earlier.
|
// But may be "Draw" without shadows.
|
||||||
// Thought: Add an Shadowmapping phase and invoke it from the shadow code
|
if (phase == mXrSyncPhase && getFrame(phase)->mShouldRender)
|
||||||
// But with shadows rendering occurs during cull and we must do frame sync before those calls.
|
|
||||||
// If you want to pay the FPS toll and play with shadows, change FramePhase::Draw to FramePhase::Cull or enjoy your eyes getting torn apart by jitters.
|
|
||||||
if (phase == FramePhase::Cull && getFrame(phase)->mShouldRender)
|
|
||||||
doFrameSync();
|
doFrameSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ namespace MWVR
|
||||||
private:
|
private:
|
||||||
std::mutex mMutex{};
|
std::mutex mMutex{};
|
||||||
std::condition_variable mCondition{};
|
std::condition_variable mCondition{};
|
||||||
|
FramePhase mXrSyncPhase{ FramePhase::Cull };
|
||||||
|
|
||||||
long long mFrames{ 0 };
|
long long mFrames{ 0 };
|
||||||
long long mLastRenderedFrame{ 0 };
|
long long mLastRenderedFrame{ 0 };
|
||||||
|
|
|
@ -57,7 +57,8 @@ namespace MWVR {
|
||||||
|
|
||||||
void VRView::prerenderCallback(osg::RenderInfo& renderInfo)
|
void VRView::prerenderCallback(osg::RenderInfo& renderInfo)
|
||||||
{
|
{
|
||||||
if (mSwapchain)
|
|
||||||
|
if (Environment::get().getManager()->xrSessionRunning())
|
||||||
{
|
{
|
||||||
mSwapchain->beginFrame(renderInfo.getState()->getGraphicsContext());
|
mSwapchain->beginFrame(renderInfo.getState()->getGraphicsContext());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "openxrmanagerimpl.hpp"
|
#include "openxrmanagerimpl.hpp"
|
||||||
#include "vrenvironment.hpp"
|
#include "vrenvironment.hpp"
|
||||||
#include "vrsession.hpp"
|
#include "vrsession.hpp"
|
||||||
|
#include "vrframebuffer.hpp"
|
||||||
|
#include "vrview.hpp"
|
||||||
|
|
||||||
#include "../mwrender/vismask.hpp"
|
#include "../mwrender/vismask.hpp"
|
||||||
|
|
||||||
|
@ -14,16 +16,25 @@ namespace MWVR
|
||||||
"RightEye"
|
"RightEye"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Callback to do construction with a graphics context
|
||||||
|
class RealizeOperation : public osg::GraphicsOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RealizeOperation() : osg::GraphicsOperation("VRRealizeOperation", false) {};
|
||||||
|
void operator()(osg::GraphicsContext* gc) override;
|
||||||
|
bool realized();
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
VRViewer::VRViewer(
|
VRViewer::VRViewer(
|
||||||
osg::ref_ptr<osgViewer::Viewer> viewer)
|
osg::ref_ptr<osgViewer::Viewer> viewer)
|
||||||
: mRealizeOperation(new RealizeOperation())
|
: mViewer(viewer)
|
||||||
, mViewer(viewer)
|
|
||||||
, mPreDraw(new PredrawCallback(this))
|
, mPreDraw(new PredrawCallback(this))
|
||||||
, mPostDraw(new PostdrawCallback(this))
|
, mPostDraw(new PostdrawCallback(this))
|
||||||
, mConfigured(false)
|
, mConfigured(false)
|
||||||
{
|
{
|
||||||
mViewer->setRealizeOperation(mRealizeOperation);
|
mViewer->setRealizeOperation(new RealizeOperation());
|
||||||
//this->setName("OpenXRRoot");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VRViewer::~VRViewer(void)
|
VRViewer::~VRViewer(void)
|
||||||
|
@ -51,7 +62,6 @@ namespace MWVR
|
||||||
mainCamera->setInitialDrawCallback(new VRView::InitialDrawCallback());
|
mainCamera->setInitialDrawCallback(new VRView::InitialDrawCallback());
|
||||||
|
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
if (!xr->realized())
|
|
||||||
xr->realize(context);
|
xr->realize(context);
|
||||||
|
|
||||||
// Run through initial events to start session
|
// Run through initial events to start session
|
||||||
|
@ -70,6 +80,9 @@ namespace MWVR
|
||||||
// Configure eyes, their cameras, and their enslavement.
|
// Configure eyes, their cameras, and their enslavement.
|
||||||
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");
|
||||||
|
// 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
|
||||||
|
|
||||||
for (unsigned i = 0; i < sViewNames.size(); i++)
|
for (unsigned i = 0; i < sViewNames.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -86,14 +99,15 @@ namespace MWVR
|
||||||
mViewer->addSlave(camera, true);
|
mViewer->addSlave(camera, true);
|
||||||
mViewer->getSlave(i)._updateSlaveCallback = new VRView::UpdateSlaveCallback(view, context);
|
mViewer->getSlave(i)._updateSlaveCallback = new VRView::UpdateSlaveCallback(view, context);
|
||||||
|
|
||||||
mMsaaResolveMirrorTexture[i].reset(new VRTexture(context->getState(),
|
if (mirror)
|
||||||
|
mMsaaResolveMirrorTexture[i].reset(new VRFramebuffer(context->getState(),
|
||||||
view->swapchain().width(),
|
view->swapchain().width(),
|
||||||
view->swapchain().height(),
|
view->swapchain().height(),
|
||||||
0));
|
0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mirror)
|
||||||
mMirrorTexture.reset(new VRTexture(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
mMirrorTexture.reset(new VRFramebuffer(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
||||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||||
|
|
||||||
mMainCameraGC = mainCamera->getGraphicsContext();
|
mMainCameraGC = mainCamera->getGraphicsContext();
|
||||||
|
@ -124,6 +138,9 @@ namespace MWVR
|
||||||
|
|
||||||
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
|
if (!mMirrorTexture)
|
||||||
|
return;
|
||||||
|
|
||||||
auto* state = gc->getState();
|
auto* state = gc->getState();
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||||
|
|
||||||
|
@ -131,12 +148,14 @@ namespace MWVR
|
||||||
int mirrorWidth = screenWidth / 2;
|
int mirrorWidth = screenWidth / 2;
|
||||||
int screenHeight = mCameras["MainCamera"]->getViewport()->height();
|
int screenHeight = mCameras["MainCamera"]->getViewport()->height();
|
||||||
|
|
||||||
|
// Since OpenXR does not include native support for mirror textures, we have to generate them ourselves
|
||||||
|
// which means resolving msaa twice. If this is a performance concern, add an option to disable the mirror texture.
|
||||||
for (unsigned i = 0; i < sViewNames.size(); i++)
|
for (unsigned i = 0; i < sViewNames.size(); i++)
|
||||||
{
|
{
|
||||||
auto& resolveTexture = *mMsaaResolveMirrorTexture[i];
|
auto& resolveTexture = *mMsaaResolveMirrorTexture[i];
|
||||||
resolveTexture.beginFrame(gc);
|
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->beginFrame(gc);
|
mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
// Mirror the index when rendering to the mirror texture to allow cross eye mirror textures.
|
// Mirror the index when rendering to the mirror texture to allow cross eye mirror textures.
|
||||||
unsigned mirrorIndex = sViewNames.size() - 1 - i;
|
unsigned 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);
|
||||||
|
@ -155,16 +174,14 @@ namespace MWVR
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VRViewer::RealizeOperation::operator()(
|
RealizeOperation::operator()(
|
||||||
osg::GraphicsContext* gc)
|
osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
OpenXRManager::RealizeOperation::operator()(gc);
|
return Environment::get().getViewer()->realize(gc);
|
||||||
|
|
||||||
Environment::get().getViewer()->realize(gc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VRViewer::RealizeOperation::realized()
|
RealizeOperation::realized()
|
||||||
{
|
{
|
||||||
return Environment::get().getViewer()->realized();
|
return Environment::get().getViewer()->realized();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,20 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
#include "openxrmanager.hpp"
|
#include "openxrmanager.hpp"
|
||||||
#include "vrgui.hpp"
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
|
class VRFramebuffer;
|
||||||
|
class VRView;
|
||||||
|
|
||||||
/// \brief Manages stereo rendering and mirror texturing.
|
/// \brief Manages stereo rendering and mirror texturing.
|
||||||
///
|
///
|
||||||
/// Manipulates the osgViewer by disabling main camera rendering, and instead rendering to
|
/// Manipulates the osgViewer by disabling main camera rendering, and instead rendering to
|
||||||
|
@ -21,16 +25,6 @@ namespace MWVR
|
||||||
class VRViewer
|
class VRViewer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class RealizeOperation : public OpenXRManager::RealizeOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RealizeOperation() {};
|
|
||||||
void operator()(osg::GraphicsContext* gc) override;
|
|
||||||
bool realized() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwapBuffersCallback : public osg::GraphicsContext::SwapCallback
|
class SwapBuffersCallback : public osg::GraphicsContext::SwapCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -90,15 +84,14 @@ namespace MWVR
|
||||||
void disableMainCamera(void);
|
void disableMainCamera(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<OpenXRManager::RealizeOperation> mRealizeOperation = nullptr;
|
|
||||||
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
||||||
std::map<std::string, osg::ref_ptr<VRView> > mViews{};
|
std::map<std::string, osg::ref_ptr<VRView> > mViews{};
|
||||||
std::map<std::string, osg::ref_ptr<osg::Camera> > mCameras{};
|
std::map<std::string, osg::ref_ptr<osg::Camera> > mCameras{};
|
||||||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||||
std::unique_ptr<VRTexture> mMsaaResolveMirrorTexture[2]{ };
|
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture[2]{ };
|
||||||
std::unique_ptr<VRTexture> mMirrorTexture{ nullptr };
|
std::unique_ptr<VRFramebuffer> mMirrorTexture{ nullptr };
|
||||||
|
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue