You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
7.7 KiB
C++
207 lines
7.7 KiB
C++
#ifndef MISC_STEREO_H
|
|
#define MISC_STEREO_H
|
|
|
|
#include <osg/Matrix>
|
|
#include <osg/Vec3>
|
|
#include <osg/Camera>
|
|
#include <osg/StateSet>
|
|
|
|
#include <memory>
|
|
|
|
#include <components/sceneutil/mwshadowtechnique.hpp>
|
|
|
|
// Some cursed headers like to define these
|
|
#if defined(near) || defined(far)
|
|
#undef near
|
|
#undef far
|
|
#endif
|
|
|
|
namespace osgViewer
|
|
{
|
|
class Viewer;
|
|
}
|
|
|
|
namespace Misc
|
|
{
|
|
//! Represents the relative pose in space of some object
|
|
struct Pose
|
|
{
|
|
//! Position in space
|
|
osg::Vec3 position{ 0,0,0 };
|
|
//! Orientation in space.
|
|
osg::Quat orientation{ 0,0,0,1 };
|
|
|
|
//! Add one pose to another
|
|
Pose operator+(const Pose& rhs);
|
|
const Pose& operator+=(const Pose& rhs);
|
|
|
|
//! Scale a pose (does not affect orientation)
|
|
Pose operator*(float scalar);
|
|
const Pose& operator*=(float scalar);
|
|
Pose operator/(float scalar);
|
|
const Pose& operator/=(float scalar);
|
|
|
|
bool operator==(const Pose& rhs) const;
|
|
|
|
osg::Matrix viewMatrix(bool useGLConventions);
|
|
};
|
|
|
|
//! Fov that defines all 4 angles from center
|
|
struct FieldOfView {
|
|
float angleLeft{ 0.f };
|
|
float angleRight{ 0.f };
|
|
float angleUp{ 0.f };
|
|
float angleDown{ 0.f };
|
|
|
|
bool operator==(const FieldOfView& rhs) const;
|
|
|
|
//! Generate a perspective matrix from this fov
|
|
osg::Matrix perspectiveMatrix(float near, float far) const;
|
|
};
|
|
|
|
//! Represents an eye including both pose and fov.
|
|
struct View
|
|
{
|
|
Pose pose;
|
|
FieldOfView fov;
|
|
bool operator==(const View& rhs) const;
|
|
};
|
|
|
|
//! Represent two eyes. The eyes are in relative terms, and are assumed to lie on the horizon plane.
|
|
struct StereoView
|
|
{
|
|
struct UpdateViewCallback
|
|
{
|
|
//! Called during the update traversal of every frame to source updated stereo values.
|
|
virtual void updateView(View& left, View& right) = 0;
|
|
};
|
|
|
|
//! Default implementation of UpdateViewCallback that just provides some hardcoded values for debugging purposes
|
|
struct DefaultUpdateViewCallback : public UpdateViewCallback
|
|
{
|
|
void updateView(View& left, View& right) override;
|
|
};
|
|
|
|
enum class Technique
|
|
{
|
|
None = 0, //!< Stereo disabled (do nothing).
|
|
BruteForce, //!< Two slave cameras culling and drawing everything.
|
|
GeometryShader_IndexedViewports, //!< Frustum camera culls and draws stereo into indexed viewports using an automatically generated geometry shader.
|
|
};
|
|
|
|
//! A draw callback that adds stereo information to the operator.
|
|
//! The stereo information is an enum describing which of the views the callback concerns.
|
|
//! With some stereo methods, there is only one callback, in which case the enum will be 'Both'.
|
|
//!
|
|
//! A typical use case of this callback is to prevent firing callbacks twice and correctly identifying the last/first callback.
|
|
struct StereoDrawCallback : public osg::Camera::DrawCallback
|
|
{
|
|
public:
|
|
enum class View
|
|
{
|
|
Both, Left, Right
|
|
};
|
|
public:
|
|
StereoDrawCallback()
|
|
{}
|
|
|
|
void operator()(osg::RenderInfo& info) const override;
|
|
|
|
virtual void operator()(osg::RenderInfo& info, View view) const = 0;
|
|
|
|
private:
|
|
};
|
|
|
|
static StereoView& instance();
|
|
|
|
//! Adds two cameras in stereo to the mainCamera.
|
|
//! All nodes matching the mask are rendered in stereo using brute force via two camera transforms, the rest are rendered in stereo via a geometry shader.
|
|
//! \param noShaderMask mask in all nodes that do not use shaders and must be rendered brute force.
|
|
//! \param sceneMask must equal MWRender::VisMask::Mask_Scene. Necessary while VisMask is still not in components/
|
|
//! \note the masks apply only to the GeometryShader_IndexdViewports technique and can be 0 for the BruteForce technique.
|
|
StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask);
|
|
|
|
//! Updates uniforms with the view and projection matrices of each stereo view, and replaces the camera's view and projection matrix
|
|
//! with a view and projection that closely envelopes the frustums of the two eyes.
|
|
void update();
|
|
void updateStateset(osg::StateSet* stateset);
|
|
|
|
void initializeStereo(osgViewer::Viewer* viewer, Technique technique);
|
|
//! Initialized scene. Call when the "scene root" node has been created
|
|
void initializeScene();
|
|
|
|
void setStereoTechnique(Technique technique);
|
|
|
|
//! Callback that updates stereo configuration during the update pass
|
|
void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb);
|
|
|
|
//! Set the cull callback on the appropriate camera object
|
|
void setCullCallback(osg::ref_ptr<osg::NodeCallback> cb);
|
|
|
|
//! Apply the cullmask to the appropriate camera objects
|
|
void setCullMask(osg::Node::NodeMask cullMask);
|
|
|
|
//! Get the last applied cullmask.
|
|
osg::Node::NodeMask getCullMask();
|
|
|
|
|
|
osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const;
|
|
osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const;
|
|
|
|
osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const;
|
|
osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const;
|
|
|
|
private:
|
|
void setupBruteForceTechnique();
|
|
void setupGeometryShaderIndexedViewportTechnique();
|
|
void removeBruteForceTechnique();
|
|
void removeGeometryShaderIndexedViewportTechnique();
|
|
void disableStereo();
|
|
void enableStereo();
|
|
|
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
|
osg::ref_ptr<osg::Camera> mMainCamera;
|
|
osg::ref_ptr<osg::Group> mRoot;
|
|
osg::ref_ptr<osg::Group> mScene;
|
|
osg::ref_ptr<osg::Group> mStereoRoot;
|
|
osg::ref_ptr<osg::Callback> mUpdateCallback;
|
|
Technique mTechnique;
|
|
|
|
// Keeps state relevant to doing stereo via the geometry shader
|
|
osg::ref_ptr<osg::Group> mStereoGeometryShaderRoot{ new osg::Group };
|
|
osg::Node::NodeMask mNoShaderMask;
|
|
osg::Node::NodeMask mSceneMask;
|
|
osg::Node::NodeMask mCullMask;
|
|
|
|
// Keeps state and cameras relevant to doing stereo via brute force
|
|
osg::ref_ptr<osg::Group> mStereoBruteForceRoot{ new osg::Group };
|
|
osg::ref_ptr<osg::Camera> mLeftCamera{ new osg::Camera };
|
|
osg::ref_ptr<osg::Camera> mRightCamera{ new osg::Camera };
|
|
|
|
using SharedShadowMapConfig = SceneUtil::MWShadowTechnique::SharedShadowMapConfig;
|
|
osg::ref_ptr<SharedShadowMapConfig> mMasterConfig;
|
|
osg::ref_ptr<SharedShadowMapConfig> mSlaveConfig;
|
|
bool mSharedShadowMaps;
|
|
|
|
// Camera viewports
|
|
bool flipViewOrder{ true };
|
|
|
|
// Updates stereo configuration during the update pass
|
|
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback;
|
|
|
|
// OSG camera callbacks set using set*callback. StereoView manages that these are always set on the appropriate camera(s);
|
|
osg::ref_ptr<osg::NodeCallback> mCullCallback{ nullptr };
|
|
};
|
|
|
|
//! Overrides all stereo-related states/uniforms to disable stereo for the scene rendered by camera
|
|
void disableStereoForCamera(osg::Camera* camera);
|
|
|
|
//! Overrides all stereo-related states/uniforms to enable stereo for the scene rendered by camera
|
|
void enableStereoForCamera(osg::Camera* camera, bool horizontalSplit);
|
|
|
|
//! Reads settings to determine stereo technique
|
|
StereoView::Technique getStereoTechnique(void);
|
|
}
|
|
|
|
#endif
|