Skip to content

Commit

Permalink
Fixed Skybox rendering for OpenVR
Browse files Browse the repository at this point in the history
Rectangle2D supports a second set of normals.
Fixed world space corner calculation for head to eye matrices.
  • Loading branch information
Slamy committed Apr 29, 2021
1 parent 253e829 commit 6ac9fab
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 20 deletions.
18 changes: 15 additions & 3 deletions OgreMain/include/OgreCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,22 @@ namespace Ogre {
struct VrData
{
Matrix4 mHeadToEye[2];
Matrix4 mEyeToHead[2];
Matrix4 mProjectionMatrix[2];
//Matrix4 mLeftToRight;
Matrix4 mProjectionMatrixInverse[2];
Vector3 mLeftToRight;

// The corners are ordered as follows: top-right far, top-left far, bottom-left far, bottom-right far.
Vector3 mWorldSpaceFarCorners[2][4];

void set( const Matrix4 eyeToHead[2], const Matrix4 projectionMatrix[2] )
{
for( int i=0; i<2; ++i )
{
mHeadToEye[i] = eyeToHead[i];
mEyeToHead[i] = eyeToHead[i];
mProjectionMatrix[i] = projectionMatrix[i];
mHeadToEye[i] = mHeadToEye[i].inverseAffine();
mProjectionMatrixInverse[i] = projectionMatrix[i].inverse();
mHeadToEye[i] = mEyeToHead[i].inverseAffine();
}
mLeftToRight = (mHeadToEye[0] * eyeToHead[1]).getTrans();
}
Expand Down Expand Up @@ -244,6 +249,8 @@ namespace Ogre {
static void setDefaultSortMode( CameraSortMode sortMode ) { msDefaultSortMode = sortMode; }
static CameraSortMode getDefaultSortMode( void ) { return msDefaultSortMode; }

/// Recalculate Vr world space corners for Sky rendering
void updateVrWorldSpaceFarCorners();
protected:
// Internal functions for calcs
bool isViewOutOfDate(void) const;
Expand Down Expand Up @@ -700,6 +707,11 @@ namespace Ogre {
bool isVisible(const Vector3& vert, FrustumPlane* culledBy = 0) const;
/// @copydoc Frustum::getWorldSpaceCorners
const Vector3* getWorldSpaceCorners(void) const;
/** Gets the 4 far world space corners of the frustum.
@remarks
The corners are ordered as follows: top-right far, top-left far, bottom-left far, bottom-right far.
*/
const Vector3* getVrWorldSpaceFarCorners(size_t eyeIdx) const;
/// @copydoc Frustum::getFrustumPlane
const Plane& getFrustumPlane( unsigned short plane ) const;
/// @copydoc Frustum::projectSphere
Expand Down
5 changes: 3 additions & 2 deletions OgreMain/include/OgreRectangle2D2.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ namespace Ogre

bool mChanged;
uint32 mGeometryFlags;
Vector3 mNormals[NumCorners];

Vector3 mNormals[NumCorners*2];
Vector2 mPosition;
Vector2 mSize;

Expand All @@ -93,6 +92,8 @@ namespace Ogre

void setNormals( const Vector3 &upperLeft, const Vector3 &bottomLeft, //
const Vector3 &upperRight, const Vector3 &bottomRight );
void setStereoNormals( const Vector3 &upperLeft, const Vector3 &bottomLeft, //
const Vector3 &upperRight, const Vector3 &bottomRight );

void setHollowRectRadius( Real radius );
Real getHollowRectRadius( void ) const { return mNormals[0].x; }
Expand Down
10 changes: 10 additions & 0 deletions OgreMain/include/OgreSceneManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ namespace Ogre {
/// For VR optimization
RadialDensityMask *mRadialDensityMask;

bool mSkyStereo{false};

// Fog
FogMode mFogMode;
ColourValue mFogColour;
Expand Down Expand Up @@ -1178,6 +1180,14 @@ namespace Ogre {
void setRadialDensityMask( bool bEnabled, const float radius[3] );
RadialDensityMask* getRadialDensityMask(void) const { return mRadialDensityMask; }

/**
* Must be used before setSky. Activates instanced stereo mode for OpenVR applications
*/
void setSkyStereoMode (bool bEnabled)
{
mSkyStereo = bEnabled;
}

/** Gets the SceneNode at the root of the scene hierarchy.
@remarks
The entire scene is held as a hierarchy of nodes, which
Expand Down
72 changes: 72 additions & 0 deletions OgreMain/src/OgreCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,73 @@ namespace Ogre {
return getProjectionMatrixWithRSDepth();
}
//-----------------------------------------------------------------------
void Camera::updateVrWorldSpaceFarCorners()
{
if( !mVrData )
{
return;
}

updateView();
Matrix4 eyeToWorld = mViewMatrix.inverseAffine();

// Note: Even though we can dealing with general projection matrix here,
// but because it's incompatibly with infinite far plane, thus, we
// still need to working with projection parameters.

// Calc near plane corners

for( size_t eyeIdx=0u; eyeIdx<2u; ++eyeIdx )
{
Real nearLeft, nearRight, nearBottom, nearTop;

Matrix4 invProj = mVrData->mProjectionMatrixInverse[eyeIdx];

Vector4 topLeft( -1.0f, 1.0f, -1.0f, 1.0f );
Vector4 topRight( 1.0f, 1.0f, -1.0f, 1.0f );
Vector4 bottomRight( 1.0f, -1.0f, -1.0f, 1.0f );
Vector4 bottomLeft( -1.0f, -1.0f, -1.0f, 1.0f );

topLeft = invProj * topLeft;
topRight = invProj * topRight;
bottomLeft = invProj * bottomLeft;
bottomRight = invProj * bottomRight;

// Rotate the view according to the HeadToEye matrix from OpenVR.
// Important for asymmetrical frustums which are present for some
// Oculus headsets and Windows Mixed Reality
Matrix4 eyeToHead= mVrData->mEyeToHead[eyeIdx];
eyeToHead.setTrans(Vector3::ZERO);

topLeft = eyeToHead * topLeft;
topRight = eyeToHead * topRight;
bottomLeft = eyeToHead * bottomLeft;
bottomRight = eyeToHead * bottomRight;

Vector4 nearTopLeft = topLeft * mNearDist;
Vector4 nearTopRight = topRight * mNearDist;
Vector4 nearBottomLeft = bottomLeft * mNearDist;
Vector4 nearBottomRight = bottomRight * mNearDist;

// Treat infinite fardist as some arbitrary far value
Real farDist = (mFarDist == 0) ? 100000 : mFarDist;

// Calc far plane corners
Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
Vector4 farTopLeft = nearTopLeft * radio;
Vector4 farTopRight = nearTopRight * radio;
Vector4 farBottomLeft = nearBottomLeft * radio;
Vector4 farBottomRight = nearBottomRight * radio;

// far
mVrData->mWorldSpaceFarCorners[eyeIdx][0] = eyeToWorld.transformAffine(Vector3(farTopRight.x, farTopRight.y, -farDist));
mVrData->mWorldSpaceFarCorners[eyeIdx][1] = eyeToWorld.transformAffine(Vector3(farTopLeft.x, farTopLeft.y, -farDist));
mVrData->mWorldSpaceFarCorners[eyeIdx][2] = eyeToWorld.transformAffine(Vector3(farBottomLeft.x, farBottomLeft.y, -farDist));
mVrData->mWorldSpaceFarCorners[eyeIdx][3] = eyeToWorld.transformAffine(Vector3(farBottomRight.x, farBottomRight.y, -farDist));
}

}
//-----------------------------------------------------------------------
bool Camera::getAutoAspectRatio(void) const
{
return mAutoAspectRatio;
Expand Down Expand Up @@ -894,6 +961,11 @@ namespace Ogre {
}
}
//-----------------------------------------------------------------------
const Vector3* Camera::getVrWorldSpaceFarCorners(size_t eyeIdx) const
{
return mVrData ? mVrData->mWorldSpaceFarCorners[eyeIdx] : nullptr;
}
//-----------------------------------------------------------------------
const Plane& Camera::getFrustumPlane( unsigned short plane ) const
{
if (mCullFrustum)
Expand Down
4 changes: 2 additions & 2 deletions OgreMain/src/OgreFrustum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ namespace Ogre {
// Treat infinite fardist as some arbitrary far value
Real farDist = (mFarDist == 0) ? 100000 : mFarDist;

// Calc far palne corners
// Calc far plane corners
Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
Real farLeft = nearLeft * radio;
Real farRight = nearRight * radio;
Expand Down Expand Up @@ -940,7 +940,7 @@ namespace Ogre {
// Treat infinite fardist as some arbitrary far value
Real farDist = (customFarPlane == 0) ? 100000 : customFarPlane;

// Calc far palne corners
// Calc far plane corners
Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
Real farLeft = nearLeft * radio;
Real farRight = nearRight * radio;
Expand Down
20 changes: 16 additions & 4 deletions OgreMain/src/OgreRectangle2D2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ namespace Ogre
if( bHasNormals )
{
for( size_t j = 0u; j < 3u; ++j )
*vertexData++ = mNormals[0][j];
*vertexData++ = mNormals[0 + 4 * i][j];
}

// Top left
Expand All @@ -250,7 +250,7 @@ namespace Ogre
if( bHasNormals )
{
for( size_t j = 0u; j < 3u; ++j )
*vertexData++ = mNormals[1][j];
*vertexData++ = mNormals[1 + 4 * i][j];
}

// Bottom right
Expand All @@ -261,7 +261,7 @@ namespace Ogre
if( bHasNormals )
{
for( size_t j = 0u; j < 3u; ++j )
*vertexData++ = mNormals[2][j];
*vertexData++ = mNormals[2 + 4 * i][j];
}

if( isQuad() )
Expand All @@ -274,7 +274,7 @@ namespace Ogre
if( bHasNormals )
{
for( size_t j = 0u; j < 3u; ++j )
*vertexData++ = mNormals[3][j];
*vertexData++ = mNormals[3 + 4 * i][j];
}
}
}
Expand Down Expand Up @@ -302,6 +302,18 @@ namespace Ogre
mNormals[CornerUpperRight] = upperRight;
mChanged = true;
}

void Rectangle2D::setStereoNormals( const Vector3 &upperLeft, const Vector3 &bottomLeft,
const Vector3 &upperRight, const Vector3 &bottomRight )
{
OGRE_ASSERT_MEDIUM( getBufferType() != BT_IMMUTABLE || mVaoPerLod[0].empty() );
OGRE_ASSERT_MEDIUM( hasNormals() || mVaoPerLod[0].empty() );
mNormals[4 + CornerBottomLeft] = bottomLeft;
mNormals[4 + CornerUpperLeft] = upperLeft;
mNormals[4 + CornerBottomRight] = bottomRight;
mNormals[4 + CornerUpperRight] = upperRight;
mChanged = true;
}
//-----------------------------------------------------------------------------------
void Rectangle2D::setHollowRectRadius( Real radius )
{
Expand Down
55 changes: 46 additions & 9 deletions OgreMain/src/OgreSceneManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1005,8 +1005,13 @@ void SceneManager::setSky( bool bEnabled, SkyMethod skyMethod, TextureGpu *textu
&mEntityMemoryManager[SCENE_STATIC], this );
// We can't use BT_DYNAMIC_* because the scene may be rendered from multiple cameras
// in the same frame, and dynamic supports only one set of values per frame
mSky->initialize( BT_DEFAULT,
Rectangle2D::GeometryFlagQuad | Rectangle2D::GeometryFlagNormals );

uint32 skyGeometryFlags=Rectangle2D::GeometryFlagQuad | Rectangle2D::GeometryFlagNormals;

if (mSkyStereo)
skyGeometryFlags|=Rectangle2D::GeometryFlagStereo;

mSky->initialize( BT_DEFAULT,skyGeometryFlags);
mSky->setGeometry( -Ogre::Vector2::UNIT_SCALE, Ogre::Vector2( 2.0f ) );
mSky->setRenderQueueGroup( 212u ); // Render after most stuff
mSceneRoot[SCENE_STATIC]->attachObject( mSky );
Expand Down Expand Up @@ -1064,6 +1069,13 @@ void SceneManager::setSky( bool bEnabled, SkyMethod skyMethod, TextureGpu *textu
tu->setTexture( texture );

mSky->setMaterial( mSkyMaterial );

GpuProgramParametersSharedPtr vsParams = pass->getVertexProgramParameters();
vsParams->setNamedConstant( "ogreBaseVertex", (float)mSky->getVaos( VpNormal )
.back()
->getBaseVertexBuffer()
->_getFinalBufferStart() );

}
else
{
Expand Down Expand Up @@ -1381,18 +1393,43 @@ void SceneManager::_renderPhase02(Camera* camera, const Camera *lodCamera,

if( mSky && mIlluminationStage != IRS_RENDER_TO_TEXTURE )
{
const Vector3 *corners = camera->getWorldSpaceCorners();
const Vector3 *corners;
const Vector3 &cameraPos = camera->getDerivedPosition();

const Real invFarPlane = 1.0f / camera->getFarClipDistance();
Vector3 cameraDirs[4];
cameraDirs[0] = ( corners[5] - cameraPos ) * invFarPlane;
cameraDirs[1] = ( corners[6] - cameraPos ) * invFarPlane;
cameraDirs[2] = ( corners[4] - cameraPos ) * invFarPlane;
cameraDirs[3] = ( corners[7] - cameraPos ) * invFarPlane;

mSky->setNormals( cameraDirs[0], cameraDirs[1], cameraDirs[2], cameraDirs[3] );
if (!mSky->isStereo())
{
corners = camera->getWorldSpaceCorners();
cameraDirs[0] = ( corners[5] - cameraPos ) * invFarPlane;
cameraDirs[1] = ( corners[6] - cameraPos ) * invFarPlane;
cameraDirs[2] = ( corners[4] - cameraPos ) * invFarPlane;
cameraDirs[3] = ( corners[7] - cameraPos ) * invFarPlane;

mSky->setNormals( cameraDirs[0], cameraDirs[1], cameraDirs[2], cameraDirs[3] );
mSky->setStereoNormals( cameraDirs[0], cameraDirs[1], cameraDirs[2], cameraDirs[3] );
}
else
{
camera->updateVrWorldSpaceFarCorners();

corners = camera->getVrWorldSpaceFarCorners(0);
cameraDirs[0] = ( corners[1] - cameraPos ) * invFarPlane;
cameraDirs[1] = ( corners[2] - cameraPos ) * invFarPlane;
cameraDirs[2] = ( corners[0] - cameraPos ) * invFarPlane;
cameraDirs[3] = ( corners[3] - cameraPos ) * invFarPlane;
mSky->setNormals( cameraDirs[0], cameraDirs[1], cameraDirs[2], cameraDirs[3] );

corners = camera->getVrWorldSpaceFarCorners(1);
cameraDirs[0] = ( corners[1] - cameraPos ) * invFarPlane;
cameraDirs[1] = ( corners[2] - cameraPos ) * invFarPlane;
cameraDirs[2] = ( corners[0] - cameraPos ) * invFarPlane;
cameraDirs[3] = ( corners[3] - cameraPos ) * invFarPlane;
mSky->setStereoNormals( cameraDirs[0], cameraDirs[1], cameraDirs[2], cameraDirs[3] );
}

mSky->update();

}

if( mRadialDensityMask && mIlluminationStage != IRS_RENDER_TO_TEXTURE &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@
#define nullptr (0)
#endif
#endif

#ifdef __MINGW32__
// For compilation on Windows with MinGW a special header must be used
#include "openvr_mingw.hpp"
#else
#include "openvr.h"
#endif


#if __cplusplus <= 199711L
#ifdef OgreDemoNullptrDefined
#undef OgreDemoNullptrDefined
Expand Down
7 changes: 7 additions & 0 deletions Samples/2.0/Tutorials/Tutorial_OpenVR/Tutorial_OpenVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
#define nullptr (0)
#endif
#endif

#ifdef __MINGW32__
// For compilation on Windows with MinGW a special header must be used
#include "openvr_mingw.hpp"
#else
#include "openvr.h"
#endif

#if __cplusplus <= 199711L
#ifdef OgreDemoNullptrDefined
#undef OgreDemoNullptrDefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ namespace Demo
mCameraController = new CameraController( mGraphicsSystem, false );

TutorialGameState::createScene01();

sceneManager->setSkyStereoMode(true);
sceneManager->setSky(true, Ogre::SceneManager::SkyCubemap, "SaintPetersBasilica.dds",
Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
}
//-----------------------------------------------------------------------------------
void Tutorial_OpenVRGameState::update( float timeSinceLast )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#version ogre_glsl_ver_330
#extension GL_ARB_shader_viewport_layer_array : require

vulkan_layout( OGRE_POSITION ) in vec2 vertex;
vulkan_layout( OGRE_NORMAL ) in vec3 normal;

in int gl_InstanceID;

vulkan( layout( ogre_P0 ) uniform Params { )
uniform float ogreBaseVertex;
uniform vec2 rsDepthRange;
uniform mat4 worldViewProj;
vulkan( }; )
Expand All @@ -22,7 +26,13 @@ out block
void main()
{
gl_Position.xy = (worldViewProj * vec4( vertex.xy, 0, 1.0f )).xy;

// TODO Move the second instance aside. There must be a way to make this more clean. But how?
gl_Position.x += 3.5f*gl_InstanceID;

gl_Position.z = rsDepthRange.y;
gl_Position.w = 1.0f;
outVs.cameraDir.xyz = normal.xyz;

gl_ViewportIndex = (gl_VertexID - ogreBaseVertex) >= 2 ? 1 : 0;
}

0 comments on commit 6ac9fab

Please sign in to comment.