mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-04 19:45:33 +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/vrsession.hpp
|
||||
mwvr/vrsession.cpp
|
||||
mwvr/vrtexture.hpp
|
||||
mwvr/vrtexture.cpp
|
||||
mwvr/vrframebuffer.hpp
|
||||
mwvr/vrframebuffer.cpp
|
||||
mwvr/vrtypes.hpp
|
||||
mwvr/vrtypes.cpp
|
||||
mwvr/vrview.hpp
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#ifdef USE_OPENXR
|
||||
#include "mwvr/vrinputmanager.hpp"
|
||||
#include "mwvr/vrviewer.hpp"
|
||||
#include "mwvr/vrgui.hpp"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
|
|
|
@ -111,26 +111,11 @@ namespace MWVR
|
|||
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
|
||||
OpenXRManager::CleanupOperation::operator()(
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -51,6 +41,7 @@ namespace MWVR
|
|||
|
||||
~OpenXRManager();
|
||||
|
||||
/// Manager has been initialized.
|
||||
bool realized();
|
||||
|
||||
//! Forward call to xrWaitFrame()
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "openxrswapchain.hpp"
|
||||
#include "openxrswapchainimpl.hpp"
|
||||
#include "vrtexture.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||
|
@ -445,13 +444,11 @@ namespace MWVR
|
|||
switch (newState)
|
||||
{
|
||||
case XR_SESSION_STATE_READY:
|
||||
//case XR_SESSION_STATE_IDLE:
|
||||
{
|
||||
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
|
||||
beginInfo.primaryViewConfigurationType = mViewConfigType;
|
||||
CHECK_XRCMD(xrBeginSession(mSession, &beginInfo));
|
||||
mSessionRunning = true;
|
||||
//waitFrame();
|
||||
break;
|
||||
}
|
||||
case XR_SESSION_STATE_STOPPING:
|
||||
|
|
|
@ -33,19 +33,14 @@ namespace MWVR {
|
|||
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);
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchain::acquiredImage() const
|
||||
{
|
||||
return impl().acquiredImage();
|
||||
return impl().acquiredDepthTexture();
|
||||
}
|
||||
|
||||
int OpenXRSwapchain::width() const
|
||||
|
@ -68,7 +63,7 @@ namespace MWVR {
|
|||
return impl().isAcquired();
|
||||
}
|
||||
|
||||
VRTexture* OpenXRSwapchain::renderBuffer() const
|
||||
VRFramebuffer* OpenXRSwapchain::renderBuffer() const
|
||||
{
|
||||
return impl().renderBuffer();
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
#define OPENXR_SWAPCHAIN_HPP
|
||||
|
||||
#include "openxrmanager.hpp"
|
||||
#include "vrtexture.hpp"
|
||||
|
||||
struct XrSwapchainSubImage;
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
class OpenXRSwapchainImpl;
|
||||
class VRFramebuffer;
|
||||
|
||||
/// \brief Creation and management of openxr swapchains
|
||||
class OpenXRSwapchain
|
||||
|
@ -20,29 +20,40 @@ namespace MWVR
|
|||
public:
|
||||
//! Prepare for render (set FBO)
|
||||
void beginFrame(osg::GraphicsContext* gc);
|
||||
|
||||
//! Finalize render
|
||||
void endFrame(osg::GraphicsContext* gc);
|
||||
//! Prepare for render
|
||||
void acquire(osg::GraphicsContext* gc);
|
||||
//! Finalize render
|
||||
void release(osg::GraphicsContext* gc);
|
||||
//! Currently acquired image
|
||||
uint32_t acquiredImage() const;
|
||||
|
||||
//! Currently acquired color texture
|
||||
uint32_t acquiredColorTexture() const;
|
||||
|
||||
//! Currently acquired depth texture
|
||||
uint32_t acquiredDepthTexture() const;
|
||||
|
||||
//! Whether subchain is currently acquired (true) or released (false)
|
||||
bool isAcquired() const;
|
||||
|
||||
//! Width of the view surface
|
||||
int width() const;
|
||||
|
||||
//! Height of the view surface
|
||||
int height() const;
|
||||
|
||||
//! Samples of the view surface
|
||||
int samples() const;
|
||||
|
||||
//! Get the current texture
|
||||
VRTexture* renderBuffer() const;
|
||||
VRFramebuffer* renderBuffer() const;
|
||||
|
||||
//! Get the private implementation
|
||||
OpenXRSwapchainImpl& impl() { return *mPrivate; }
|
||||
|
||||
//! Get the private implementation
|
||||
const OpenXRSwapchainImpl& impl() const { return *mPrivate; }
|
||||
|
||||
protected:
|
||||
OpenXRSwapchain(const OpenXRSwapchain&) = delete;
|
||||
void operator=(const OpenXRSwapchain&) = delete;
|
||||
private:
|
||||
std::unique_ptr<OpenXRSwapchainImpl> mPrivate;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "openxrswapchainimpl.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
#include "vrframebuffer.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
|
@ -47,9 +48,8 @@ namespace MWVR {
|
|||
|
||||
// Find supported depth swapchain format.
|
||||
constexpr int64_t RequestedDepthSwapchainFormats[] = {
|
||||
GL_DEPTH_COMPONENT32F,
|
||||
GL_DEPTH_COMPONENT24,
|
||||
GL_DEPTH_COMPONENT16,
|
||||
GL_DEPTH_COMPONENT32F,
|
||||
};
|
||||
|
||||
swapchainFormatIt =
|
||||
|
@ -108,7 +108,7 @@ namespace MWVR {
|
|||
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, 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.imageRect.offset = { 0, 0 };
|
||||
|
@ -121,18 +121,22 @@ namespace MWVR {
|
|||
CHECK_XRCMD(xrDestroySwapchain(mSwapchain));
|
||||
}
|
||||
|
||||
VRTexture* OpenXRSwapchainImpl::renderBuffer() const
|
||||
VRFramebuffer* OpenXRSwapchainImpl::renderBuffer() const
|
||||
{
|
||||
if (isAcquired())
|
||||
return mRenderBuffers[mAcquiredImageIndex].get();
|
||||
throw std::logic_error("Swapbuffer not acquired before use");
|
||||
checkAcquired();
|
||||
return mRenderBuffers[mAcquiredImageIndex].get();
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::acquiredImage() const
|
||||
uint32_t OpenXRSwapchainImpl::acquiredColorTexture() const
|
||||
{
|
||||
if (isAcquired())
|
||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
||||
throw std::logic_error("Swapbuffer not acquired before use");
|
||||
checkAcquired();
|
||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::acquiredDepthTexture() const
|
||||
{
|
||||
checkAcquired();
|
||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
||||
}
|
||||
|
||||
bool OpenXRSwapchainImpl::isAcquired() const
|
||||
|
@ -142,14 +146,17 @@ namespace MWVR {
|
|||
|
||||
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
|
||||
{
|
||||
if (isAcquired())
|
||||
throw std::logic_error("Trying to acquire already acquired swapchain");
|
||||
acquire(gc);
|
||||
renderBuffer()->beginFrame(gc);
|
||||
renderBuffer()->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
}
|
||||
|
||||
int swapCount = 0;
|
||||
|
||||
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc)
|
||||
{
|
||||
checkAcquired();
|
||||
release(gc);
|
||||
}
|
||||
|
||||
|
@ -180,4 +187,9 @@ namespace MWVR {
|
|||
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &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 endFrame(osg::GraphicsContext* gc);
|
||||
void acquire(osg::GraphicsContext* gc);
|
||||
void release(osg::GraphicsContext* gc);
|
||||
|
||||
VRTexture* renderBuffer() const;
|
||||
|
||||
uint32_t acquiredImage() const;
|
||||
VRFramebuffer* renderBuffer() const;
|
||||
uint32_t acquiredColorTexture() const;
|
||||
uint32_t acquiredDepthTexture() const;
|
||||
|
||||
bool isAcquired() const;
|
||||
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
||||
|
@ -31,6 +29,15 @@ namespace MWVR
|
|||
int height() const { return mHeight; };
|
||||
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 mDepthSwapchain = XR_NULL_HANDLE;
|
||||
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
|
||||
|
@ -42,7 +49,7 @@ namespace MWVR
|
|||
int64_t mSwapchainColorFormat = -1;
|
||||
int64_t mSwapchainDepthFormat = -1;
|
||||
uint32_t mFBO = 0;
|
||||
std::vector<std::unique_ptr<VRTexture> > mRenderBuffers{};
|
||||
std::vector<std::unique_ptr<VRFramebuffer> > mRenderBuffers{};
|
||||
int mRenderBuffer{ 0 };
|
||||
uint32_t mAcquiredImageIndex{ 0 };
|
||||
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 "../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()
|
||||
{
|
||||
if (swingType >= 0)
|
||||
if (velocity >= minVelocity)
|
||||
if (swingType != ESM::Weapon::AT_Thrust || thrustVelocity >= 0.f)
|
||||
if (mSwingType >= 0)
|
||||
if (mVelocity >= mMinVelocity)
|
||||
if (mSwingType != ESM::Weapon::AT_Thrust || mThrustVelocity >= 0.f)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -85,20 +68,20 @@ namespace MWVR {
|
|||
void StateMachine::transition(
|
||||
SwingState newState)
|
||||
{
|
||||
Log(Debug::Verbose) << "Transition:" << stateToString(state) << "->" << stateToString(newState);
|
||||
maxSwingVelocity = 0.f;
|
||||
timeSinceEnteredState = 0.f;
|
||||
movementSinceEnteredState = 0.f;
|
||||
state = newState;
|
||||
Log(Debug::Verbose) << "Transition:" << stateToString(mState) << "->" << stateToString(newState);
|
||||
mMaxSwingVelocity = 0.f;
|
||||
mTimeSinceEnteredState = 0.f;
|
||||
mMovementSinceEnteredState = 0.f;
|
||||
mState = newState;
|
||||
}
|
||||
|
||||
void StateMachine::reset()
|
||||
{
|
||||
maxSwingVelocity = 0.f;
|
||||
timeSinceEnteredState = 0.f;
|
||||
velocity = 0.f;
|
||||
previousPosition = osg::Vec3(0.f, 0.f, 0.f);
|
||||
state = SwingState_Ready;
|
||||
mMaxSwingVelocity = 0.f;
|
||||
mTimeSinceEnteredState = 0.f;
|
||||
mVelocity = 0.f;
|
||||
mPreviousPosition = osg::Vec3(0.f, 0.f, 0.f);
|
||||
mState = SwingState_Ready;
|
||||
}
|
||||
|
||||
static bool isMeleeWeapon(int type)
|
||||
|
@ -151,7 +134,7 @@ namespace MWVR {
|
|||
if (!enabled)
|
||||
return;
|
||||
|
||||
timeSinceEnteredState += dt;
|
||||
mTimeSinceEnteredState += dt;
|
||||
|
||||
|
||||
// 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.
|
||||
// Theoretically, the player's hand really could be at 0,0,0
|
||||
// but that's a super rare case so whatever.
|
||||
if (previousPosition == osg::Vec3(0.f, 0.f, 0.f))
|
||||
previousPosition = handPose.position;
|
||||
if (mPreviousPosition == osg::Vec3(0.f, 0.f, 0.f))
|
||||
mPreviousPosition = handPose.position;
|
||||
|
||||
osg::Vec3 movement = handPose.position - previousPosition;
|
||||
movementSinceEnteredState += movement.length();
|
||||
previousPosition = handPose.position;
|
||||
osg::Vec3 movement = handPose.position - mPreviousPosition;
|
||||
mMovementSinceEnteredState += movement.length();
|
||||
mPreviousPosition = handPose.position;
|
||||
osg::Vec3 swingVector = movement / dt;
|
||||
osg::Vec3 swingDirection = swingVector;
|
||||
swingDirection.normalize();
|
||||
|
@ -193,24 +176,24 @@ namespace MWVR {
|
|||
// Compute swing velocities
|
||||
|
||||
// Thrust follows the orientation of the weapon. Negative thrust = no attack.
|
||||
thrustVelocity = swingVector * thrustDirection;
|
||||
velocity = swingVector.length();
|
||||
mThrustVelocity = swingVector * thrustDirection;
|
||||
mVelocity = swingVector.length();
|
||||
|
||||
|
||||
if (isSideSwingValidForWeapon(weaponType))
|
||||
{
|
||||
// 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);
|
||||
slashChopVelocity = velocity * planeComponent;
|
||||
sideVelocity = -1000.f;
|
||||
mSlashChopVelocity = mVelocity * planeComponent;
|
||||
mSideVelocity = -1000.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If side swing is not valid for the weapon, count slash/chop only along in
|
||||
// the direction of the weapon's edge.
|
||||
slashChopVelocity = std::abs(swingVector * slashChopDirection);
|
||||
sideVelocity = std::abs(swingVector * sideDirection);
|
||||
mSlashChopVelocity = std::abs(swingVector * slashChopDirection);
|
||||
mSideVelocity = std::abs(swingVector * sideDirection);
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,34 +203,34 @@ namespace MWVR {
|
|||
// Pick swing type based on greatest current velocity
|
||||
// Note i use abs() of thrust velocity to prevent accidentally triggering
|
||||
// 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
|
||||
// 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
|
||||
{
|
||||
// First check if the weapon is pointing upwards. In which case slash is not
|
||||
// applicable, and the attack must be a chop.
|
||||
if (orientationVerticality > 0.707)
|
||||
swingType = ESM::Weapon::AT_Chop;
|
||||
mSwingType = ESM::Weapon::AT_Chop;
|
||||
else
|
||||
{
|
||||
// Next check if the swing is more horizontal or vertical. A slash
|
||||
// would be more horizontal.
|
||||
if (swingVerticality > 0.707)
|
||||
swingType = ESM::Weapon::AT_Chop;
|
||||
mSwingType = ESM::Weapon::AT_Chop;
|
||||
else
|
||||
swingType = ESM::Weapon::AT_Slash;
|
||||
mSwingType = ESM::Weapon::AT_Slash;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state)
|
||||
switch (mState)
|
||||
{
|
||||
case SwingState_Cooldown:
|
||||
return update_cooldownState();
|
||||
|
@ -260,13 +243,13 @@ namespace MWVR {
|
|||
case SwingState_Launch:
|
||||
return update_launchState();
|
||||
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()
|
||||
{
|
||||
if (timeSinceEnteredState >= minimumPeriod)
|
||||
if (mTimeSinceEnteredState >= mMinimumPeriod)
|
||||
transition_cooldownToReady();
|
||||
}
|
||||
|
||||
|
@ -291,19 +274,19 @@ namespace MWVR {
|
|||
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
|
||||
std::string sound = "Weapon Swish";
|
||||
if (strength < 0.5f)
|
||||
sndMgr->playSound3D(ptr, sound, 1.0f, 0.8f); //Weak attack
|
||||
if (strength < 1.0f)
|
||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f); //Medium attack
|
||||
if (mStrength < 0.5f)
|
||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
||||
if (mStrength < 1.0f)
|
||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
||||
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()
|
||||
{
|
||||
if (movementSinceEnteredState > minimumPeriod)
|
||||
if (mMovementSinceEnteredState > mMinimumPeriod)
|
||||
transition_launchToSwing();
|
||||
if (!canSwing())
|
||||
return transition_launchToReady();
|
||||
|
@ -326,26 +309,26 @@ namespace MWVR {
|
|||
|
||||
void StateMachine::update_swingState()
|
||||
{
|
||||
maxSwingVelocity = std::max(velocity, maxSwingVelocity);
|
||||
strength = std::min(1.f, (maxSwingVelocity - minVelocity) / maxVelocity);
|
||||
mMaxSwingVelocity = std::max(mVelocity, mMaxSwingVelocity);
|
||||
mStrength = std::min(1.f, (mMaxSwingVelocity - mMinVelocity) / mMaxVelocity);
|
||||
|
||||
// When velocity falls below minimum, transition to register the miss
|
||||
if (!canSwing())
|
||||
return transition_swingingToImpact();
|
||||
// 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();
|
||||
}
|
||||
|
||||
void StateMachine::transition_swingingToImpact()
|
||||
{
|
||||
ptr.getClass().hit(ptr, strength, swingType, false);
|
||||
mPtr.getClass().hit(mPtr, mStrength, mSwingType, false);
|
||||
transition(SwingState_Impact);
|
||||
}
|
||||
|
||||
void StateMachine::update_impactState()
|
||||
{
|
||||
if (velocity < minVelocity)
|
||||
if (mVelocity < mMinVelocity)
|
||||
return transition_impactToCooldown();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
namespace MWVR {
|
||||
namespace RealisticCombat {
|
||||
|
||||
/// Enum describing the current state of the MWVR::RealisticCombat::StateMachine
|
||||
enum SwingState
|
||||
{
|
||||
SwingState_Ready,
|
||||
|
@ -21,35 +23,38 @@ namespace MWVR {
|
|||
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
|
||||
{
|
||||
// TODO: These should be configurable
|
||||
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 };
|
||||
|
||||
public:
|
||||
StateMachine(MWWorld::Ptr ptr);
|
||||
void update(float dt, bool enabled);
|
||||
MWWorld::Ptr ptr() { return mPtr; }
|
||||
|
||||
protected:
|
||||
bool canSwing();
|
||||
|
||||
void playSwish();
|
||||
|
@ -57,7 +62,6 @@ namespace MWVR {
|
|||
|
||||
void transition(SwingState newState);
|
||||
|
||||
void update(float dt, bool enabled);
|
||||
|
||||
void update_cooldownState();
|
||||
void transition_cooldownToReady();
|
||||
|
@ -74,6 +78,31 @@ namespace MWVR {
|
|||
|
||||
void update_impactState();
|
||||
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);
|
||||
bool isMale = ref->mBase->isMale();
|
||||
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;
|
||||
// TODO: Player height should be configurable
|
||||
// For now i'm just using my own
|
||||
float sizeFactor = 1.85f / charHeight;
|
||||
float realHeight = Settings::Manager::getFloat("real height", "VR");
|
||||
float sizeFactor = charHeight / realHeight;
|
||||
Environment::get().getSession()->setPlayerScale(sizeFactor);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace MWVR
|
|||
class FingerController;
|
||||
class ForearmController;
|
||||
|
||||
/// Subclassing NpcAnimation to override behaviours not compatible with VR
|
||||
/// Subclassing NpcAnimation to implement VR related behaviour
|
||||
class VRAnimation : public MWRender::NpcAnimation
|
||||
{
|
||||
protected:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "vrtexture.hpp"
|
||||
#include "vrframebuffer.hpp"
|
||||
|
||||
#include <osg/Texture2D>
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
|||
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)
|
||||
, mWidth(width)
|
||||
, mHeight(height)
|
||||
|
@ -72,12 +72,12 @@ namespace MWVR
|
|||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
VRTexture::~VRTexture()
|
||||
VRFramebuffer::~VRFramebuffer()
|
||||
{
|
||||
destroy(nullptr);
|
||||
}
|
||||
|
||||
void VRTexture::destroy(osg::State* state)
|
||||
void VRFramebuffer::destroy(osg::State* state)
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ namespace MWVR
|
|||
gl->glDeleteFramebuffers(1, &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";
|
||||
|
||||
if (mDepthBuffer)
|
||||
|
@ -100,30 +100,17 @@ namespace MWVR
|
|||
if (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* 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)
|
||||
{
|
||||
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)
|
||||
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);
|
||||
|
@ -131,17 +118,4 @@ namespace MWVR
|
|||
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
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
|
||||
{
|
||||
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:
|
||||
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);
|
||||
~VRTexture();
|
||||
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);
|
||||
~VRFramebuffer();
|
||||
|
||||
void destroy(osg::State* state);
|
||||
|
||||
|
@ -22,15 +25,13 @@ namespace MWVR
|
|||
auto height() const { return mHeight; }
|
||||
auto msaaSamples() const { return mSamples; }
|
||||
|
||||
void beginFrame(osg::GraphicsContext* gc);
|
||||
void endFrame(osg::GraphicsContext* gc, uint32_t blitTarget);
|
||||
void bindFramebuffer(osg::GraphicsContext* gc, uint32_t target);
|
||||
|
||||
uint32_t fbo(void) const { return mFBO; }
|
||||
uint32_t colorBuffer(void) const { return mColorBuffer; }
|
||||
|
||||
//! 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, int target);
|
||||
|
||||
private:
|
||||
// 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 mBlitFBO = 0;
|
||||
uint32_t mDepthBuffer = 0;
|
||||
bool mOwnDepthBuffer = false;
|
||||
uint32_t mColorBuffer = 0;
|
||||
bool mOwnColorBuffer = false;
|
||||
uint32_t mSamples = 0;
|
||||
uint32_t mTextureTarget = 0;
|
||||
};
|
|
@ -327,8 +327,7 @@ namespace MWVR
|
|||
if (mLayerName == "Notification")
|
||||
{
|
||||
// The latest widget for notification is always the top one
|
||||
// So we just have to stretch the rectangle to the bottom
|
||||
// TODO: This might get deprecated with this new system?
|
||||
// So i just stretch the rectangle to the bottom.
|
||||
mRealRect.bottom = 1.f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,10 +48,11 @@ namespace MWVR
|
|||
Fixed
|
||||
};
|
||||
|
||||
/// Configuration of a VRGUILayer
|
||||
struct LayerConfig
|
||||
{
|
||||
int priority; //!< Higher priority shows over lower priority windows.
|
||||
bool sideBySide; //!< Resize layer window to occupy full quad
|
||||
int priority; //!< Higher priority shows over lower priority windows by moving higher priority layers slightly closer to the player.
|
||||
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::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.
|
||||
|
@ -66,6 +67,11 @@ namespace MWVR
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -77,20 +83,19 @@ namespace MWVR
|
|||
VRGUIManager* parent);
|
||||
~VRGUILayer();
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
friend class VRGUIManager;
|
||||
osg::Camera* camera();
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> menuTexture();
|
||||
|
||||
void setAngle(float angle);
|
||||
void updateTracking(const Pose& headPose = {});
|
||||
void updatePose();
|
||||
void updateRect();
|
||||
void update();
|
||||
|
||||
void insertWidget(MWGui::Layout* widget);
|
||||
void removeWidget(MWGui::Layout* widget);
|
||||
int widgetCount() { return mWidgets.size(); }
|
||||
|
||||
bool operator<(const VRGUILayer& rhs) const { return mConfig.priority < rhs.mConfig.priority; }
|
||||
|
||||
public:
|
||||
|
@ -108,6 +113,7 @@ namespace MWVR
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -116,6 +122,11 @@ namespace MWVR
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -124,29 +135,33 @@ namespace MWVR
|
|||
|
||||
~VRGUIManager(void);
|
||||
|
||||
/// Set visibility of the layer this layout is on
|
||||
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 insertWidget(MWGui::Layout* widget);
|
||||
|
||||
/// Remove the given layer quad
|
||||
void removeLayer(const std::string& name);
|
||||
|
||||
void removeWidget(MWGui::Layout* widget);
|
||||
|
||||
/// Update layer quads based on player camera
|
||||
void updateTracking(void);
|
||||
|
||||
/// Update layer quads based on the given camera
|
||||
void updateTracking(osg::Camera* camera);
|
||||
|
||||
/// Check current pointer target and update focus layer
|
||||
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; };
|
||||
|
||||
private:
|
||||
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 };
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#include "vrinputmanager.hpp"
|
||||
|
||||
#include "vrviewer.hpp"
|
||||
#include "vrgui.hpp"
|
||||
#include "vranimation.hpp"
|
||||
#include "openxrinput.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
#include "openxrmanager.hpp"
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
#include "openxraction.hpp"
|
||||
#include "realisticcombat.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
|
@ -139,15 +142,16 @@ namespace MWVR
|
|||
channel->setEnabled(true);
|
||||
}
|
||||
|
||||
// TODO: Configurable haptics: on/off + max intensity
|
||||
void VRInputManager::applyHapticsLeftHand(float intensity)
|
||||
{
|
||||
mXRInput->applyHaptics(TrackedLimb::LEFT_HAND, intensity);
|
||||
if (mHapticsEnabled)
|
||||
mXRInput->applyHaptics(TrackedLimb::LEFT_HAND, intensity);
|
||||
}
|
||||
|
||||
void VRInputManager::applyHapticsRightHand(float intensity)
|
||||
{
|
||||
mXRInput->applyHaptics(TrackedLimb::RIGHT_HAND, intensity);
|
||||
if (mHapticsEnabled)
|
||||
mXRInput->applyHaptics(TrackedLimb::RIGHT_HAND, intensity);
|
||||
}
|
||||
|
||||
void VRInputManager::requestRecenter()
|
||||
|
@ -176,6 +180,7 @@ namespace MWVR
|
|||
controllerBindingsFile,
|
||||
grab)
|
||||
, mXRInput(nullptr)
|
||||
, mHapticsEnabled{Settings::Manager::getBool("haptics enabled", "VR")}
|
||||
{
|
||||
std::vector<SuggestedBindings> suggestedBindings;
|
||||
// Set up default bindings for the oculus
|
||||
|
@ -337,7 +342,7 @@ namespace MWVR
|
|||
|
||||
auto& player = world->getPlayer();
|
||||
auto playerPtr = world->getPlayerPtr();
|
||||
if (!mRealisticCombat || mRealisticCombat->ptr != playerPtr)
|
||||
if (!mRealisticCombat || mRealisticCombat->ptr() != playerPtr)
|
||||
mRealisticCombat.reset(new RealisticCombat::StateMachine(playerPtr));
|
||||
bool enabled = !guiMode && player.getDrawState() == MWMechanics::DrawState_Weapon && !player.isDisabled();
|
||||
mRealisticCombat->update(dt, enabled);
|
||||
|
@ -360,7 +365,7 @@ namespace MWVR
|
|||
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();
|
||||
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||
|
||||
|
||||
// OpenMW does not currently provide any way to directly request skipping a video.
|
||||
|
@ -425,7 +430,7 @@ namespace MWVR
|
|||
mActionManager->screenshot();
|
||||
break;
|
||||
case A_Recenter:
|
||||
xrGUIManager->updateTracking();
|
||||
vrGuiManager->updateTracking();
|
||||
requestRecenter();
|
||||
break;
|
||||
case A_MenuSelect:
|
||||
|
@ -601,7 +606,7 @@ namespace MWVR
|
|||
mActionManager->setAttemptJump(true);
|
||||
break;
|
||||
case A_Recenter:
|
||||
xrGUIManager->updateTracking();
|
||||
vrGuiManager->updateTracking();
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
requestRecenter();
|
||||
break;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef VR_INPUT_MANAGER_HPP
|
||||
#define VR_INPUT_MANAGER_HPP
|
||||
|
||||
#include "vrviewer.hpp"
|
||||
#include "realisticcombat.hpp"
|
||||
#include "vrtypes.hpp"
|
||||
|
||||
#include "../mwinput/inputmanagerimp.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
@ -15,8 +15,11 @@ namespace MWVR
|
|||
{
|
||||
struct OpenXRInput;
|
||||
|
||||
/// As far as I can tell, SDL does not support VR controllers.
|
||||
/// So I subclass the input manager and insert VR controls.
|
||||
namespace RealisticCombat {
|
||||
class StateMachine;
|
||||
}
|
||||
|
||||
/// Extension of the input manager to include VR inputs
|
||||
class VRInputManager : public MWInput::InputManager
|
||||
{
|
||||
public:
|
||||
|
@ -72,6 +75,7 @@ namespace MWVR
|
|||
osg::Vec3 mHeadOffset{ 0,0,0 };
|
||||
bool mShouldRecenter{ true };
|
||||
bool mActivationIndication{ false };
|
||||
bool mHapticsEnabled{ true };
|
||||
float mYaw{ 0.f };
|
||||
|
||||
float mVrAngles[3]{ 0.f,0.f,0.f };
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
|
@ -37,7 +38,24 @@
|
|||
namespace MWVR
|
||||
{
|
||||
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()
|
||||
|
@ -177,13 +195,10 @@ namespace MWVR
|
|||
}
|
||||
|
||||
|
||||
// TODO: Invokation should depend on earliest render rather than necessarily phase.
|
||||
// Specifically. Without shadows this is fine because nothing is being rendered
|
||||
// during cull or earlier.
|
||||
// Thought: Add an Shadowmapping phase and invoke it from the shadow code
|
||||
// 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)
|
||||
// TODO: Invokation could depend on earliest actual render rather than necessarily any specific phase.
|
||||
// For example, shadows do some draw calls during cull an as such phase should be "Cull" or earlier with shadows enabled.
|
||||
// But may be "Draw" without shadows.
|
||||
if (phase == mXrSyncPhase && getFrame(phase)->mShouldRender)
|
||||
doFrameSync();
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace MWVR
|
|||
private:
|
||||
std::mutex mMutex{};
|
||||
std::condition_variable mCondition{};
|
||||
FramePhase mXrSyncPhase{ FramePhase::Cull };
|
||||
|
||||
long long mFrames{ 0 };
|
||||
long long mLastRenderedFrame{ 0 };
|
||||
|
|
|
@ -57,7 +57,8 @@ namespace MWVR {
|
|||
|
||||
void VRView::prerenderCallback(osg::RenderInfo& renderInfo)
|
||||
{
|
||||
if (mSwapchain)
|
||||
|
||||
if (Environment::get().getManager()->xrSessionRunning())
|
||||
{
|
||||
mSwapchain->beginFrame(renderInfo.getState()->getGraphicsContext());
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "openxrmanagerimpl.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
#include "vrsession.hpp"
|
||||
#include "vrframebuffer.hpp"
|
||||
#include "vrview.hpp"
|
||||
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
|
@ -14,16 +16,25 @@ namespace MWVR
|
|||
"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(
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer)
|
||||
: mRealizeOperation(new RealizeOperation())
|
||||
, mViewer(viewer)
|
||||
: mViewer(viewer)
|
||||
, mPreDraw(new PredrawCallback(this))
|
||||
, mPostDraw(new PostdrawCallback(this))
|
||||
, mConfigured(false)
|
||||
{
|
||||
mViewer->setRealizeOperation(mRealizeOperation);
|
||||
//this->setName("OpenXRRoot");
|
||||
mViewer->setRealizeOperation(new RealizeOperation());
|
||||
}
|
||||
|
||||
VRViewer::~VRViewer(void)
|
||||
|
@ -51,8 +62,7 @@ namespace MWVR
|
|||
mainCamera->setInitialDrawCallback(new VRView::InitialDrawCallback());
|
||||
|
||||
auto* xr = Environment::get().getManager();
|
||||
if (!xr->realized())
|
||||
xr->realize(context);
|
||||
xr->realize(context);
|
||||
|
||||
// Run through initial events to start session
|
||||
// For the rest of runtime this is handled by vrsession
|
||||
|
@ -70,6 +80,9 @@ namespace MWVR
|
|||
// Configure eyes, their cameras, and their enslavement.
|
||||
osg::Vec4 clearColor = mainCamera->getClearColor();
|
||||
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++)
|
||||
{
|
||||
|
@ -86,14 +99,15 @@ namespace MWVR
|
|||
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));
|
||||
if (mirror)
|
||||
mMsaaResolveMirrorTexture[i].reset(new VRFramebuffer(context->getState(),
|
||||
view->swapchain().width(),
|
||||
view->swapchain().height(),
|
||||
0));
|
||||
}
|
||||
|
||||
|
||||
mMirrorTexture.reset(new VRTexture(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
||||
if (mirror)
|
||||
mMirrorTexture.reset(new VRFramebuffer(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||
|
||||
mMainCameraGC = mainCamera->getGraphicsContext();
|
||||
|
@ -124,6 +138,9 @@ namespace MWVR
|
|||
|
||||
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
||||
{
|
||||
if (!mMirrorTexture)
|
||||
return;
|
||||
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
|
@ -131,12 +148,14 @@ namespace MWVR
|
|||
int mirrorWidth = screenWidth / 2;
|
||||
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++)
|
||||
{
|
||||
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());
|
||||
mMirrorTexture->beginFrame(gc);
|
||||
mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
// Mirror the index when rendering to the mirror texture to allow cross eye mirror textures.
|
||||
unsigned mirrorIndex = sViewNames.size() - 1 - i;
|
||||
resolveTexture.blit(gc, mirrorIndex * mirrorWidth, 0, (mirrorIndex + 1) * mirrorWidth, screenHeight);
|
||||
|
@ -155,16 +174,14 @@ namespace MWVR
|
|||
}
|
||||
|
||||
void
|
||||
VRViewer::RealizeOperation::operator()(
|
||||
RealizeOperation::operator()(
|
||||
osg::GraphicsContext* gc)
|
||||
{
|
||||
OpenXRManager::RealizeOperation::operator()(gc);
|
||||
|
||||
Environment::get().getViewer()->realize(gc);
|
||||
return Environment::get().getViewer()->realize(gc);
|
||||
}
|
||||
|
||||
bool
|
||||
VRViewer::RealizeOperation::realized()
|
||||
RealizeOperation::realized()
|
||||
{
|
||||
return Environment::get().getViewer()->realized();
|
||||
}
|
||||
|
|
|
@ -4,16 +4,20 @@
|
|||
#include <memory>
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Camera>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include "openxrmanager.hpp"
|
||||
#include "vrgui.hpp"
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
class VRFramebuffer;
|
||||
class VRView;
|
||||
|
||||
/// \brief Manages stereo rendering and mirror texturing.
|
||||
///
|
||||
/// Manipulates the osgViewer by disabling main camera rendering, and instead rendering to
|
||||
|
@ -21,16 +25,6 @@ namespace MWVR
|
|||
class VRViewer
|
||||
{
|
||||
public:
|
||||
class RealizeOperation : public OpenXRManager::RealizeOperation
|
||||
{
|
||||
public:
|
||||
RealizeOperation() {};
|
||||
void operator()(osg::GraphicsContext* gc) override;
|
||||
bool realized() override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class SwapBuffersCallback : public osg::GraphicsContext::SwapCallback
|
||||
{
|
||||
public:
|
||||
|
@ -90,15 +84,14 @@ namespace MWVR
|
|||
void disableMainCamera(void);
|
||||
|
||||
private:
|
||||
osg::ref_ptr<OpenXRManager::RealizeOperation> mRealizeOperation = nullptr;
|
||||
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
||||
std::map<std::string, osg::ref_ptr<VRView> > mViews{};
|
||||
std::map<std::string, osg::ref_ptr<osg::Camera> > mCameras{};
|
||||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||
std::unique_ptr<VRTexture> mMsaaResolveMirrorTexture[2]{ };
|
||||
std::unique_ptr<VRTexture> mMirrorTexture{ nullptr };
|
||||
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture[2]{ };
|
||||
std::unique_ptr<VRFramebuffer> mMirrorTexture{ nullptr };
|
||||
|
||||
std::mutex mMutex;
|
||||
|
||||
|
|
Loading…
Reference in a new issue