mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
641 lines
27 KiB
C
641 lines
27 KiB
C
/************************************************************************************
|
|
|
|
|
|
|
|
Filename : VrApi_Helpers.h
|
|
|
|
Content : Pure, stateless, inlined helper functions, used to initialize
|
|
|
|
parameters to the VrApi.
|
|
|
|
Created : March 2, 2015
|
|
|
|
Authors : J.M.P. van Waveren
|
|
|
|
|
|
|
|
Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved.
|
|
|
|
|
|
|
|
*************************************************************************************/
|
|
|
|
#ifndef OVR_VrApi_Helpers_h
|
|
|
|
#define OVR_VrApi_Helpers_h
|
|
|
|
|
|
|
|
#include "math.h" // for cosf(), sinf(), tanf()
|
|
|
|
#include "string.h" // for memset()
|
|
|
|
#include "VrApi_Config.h"
|
|
|
|
#include "VrApi_Version.h"
|
|
|
|
#include "VrApi_Types.h"
|
|
|
|
|
|
|
|
#define VRAPI_PI 3.14159265358979323846f
|
|
|
|
#define VRAPI_ZNEAR 0.1f
|
|
|
|
|
|
|
|
#if defined( __GNUC__ )
|
|
|
|
# define VRAPI_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)
|
|
|
|
#else
|
|
|
|
# define VRAPI_UNUSED(a) (a)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
// Matrix helper functions.
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
|
|
// Use left-multiplication to accumulate transformations.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_Multiply( const ovrMatrix4f * a, const ovrMatrix4f * b )
|
|
|
|
{
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = a->M[0][0] * b->M[0][0] + a->M[0][1] * b->M[1][0] + a->M[0][2] * b->M[2][0] + a->M[0][3] * b->M[3][0];
|
|
|
|
out.M[1][0] = a->M[1][0] * b->M[0][0] + a->M[1][1] * b->M[1][0] + a->M[1][2] * b->M[2][0] + a->M[1][3] * b->M[3][0];
|
|
|
|
out.M[2][0] = a->M[2][0] * b->M[0][0] + a->M[2][1] * b->M[1][0] + a->M[2][2] * b->M[2][0] + a->M[2][3] * b->M[3][0];
|
|
|
|
out.M[3][0] = a->M[3][0] * b->M[0][0] + a->M[3][1] * b->M[1][0] + a->M[3][2] * b->M[2][0] + a->M[3][3] * b->M[3][0];
|
|
|
|
|
|
|
|
out.M[0][1] = a->M[0][0] * b->M[0][1] + a->M[0][1] * b->M[1][1] + a->M[0][2] * b->M[2][1] + a->M[0][3] * b->M[3][1];
|
|
|
|
out.M[1][1] = a->M[1][0] * b->M[0][1] + a->M[1][1] * b->M[1][1] + a->M[1][2] * b->M[2][1] + a->M[1][3] * b->M[3][1];
|
|
|
|
out.M[2][1] = a->M[2][0] * b->M[0][1] + a->M[2][1] * b->M[1][1] + a->M[2][2] * b->M[2][1] + a->M[2][3] * b->M[3][1];
|
|
|
|
out.M[3][1] = a->M[3][0] * b->M[0][1] + a->M[3][1] * b->M[1][1] + a->M[3][2] * b->M[2][1] + a->M[3][3] * b->M[3][1];
|
|
|
|
|
|
|
|
out.M[0][2] = a->M[0][0] * b->M[0][2] + a->M[0][1] * b->M[1][2] + a->M[0][2] * b->M[2][2] + a->M[0][3] * b->M[3][2];
|
|
|
|
out.M[1][2] = a->M[1][0] * b->M[0][2] + a->M[1][1] * b->M[1][2] + a->M[1][2] * b->M[2][2] + a->M[1][3] * b->M[3][2];
|
|
|
|
out.M[2][2] = a->M[2][0] * b->M[0][2] + a->M[2][1] * b->M[1][2] + a->M[2][2] * b->M[2][2] + a->M[2][3] * b->M[3][2];
|
|
|
|
out.M[3][2] = a->M[3][0] * b->M[0][2] + a->M[3][1] * b->M[1][2] + a->M[3][2] * b->M[2][2] + a->M[3][3] * b->M[3][2];
|
|
|
|
|
|
|
|
out.M[0][3] = a->M[0][0] * b->M[0][3] + a->M[0][1] * b->M[1][3] + a->M[0][2] * b->M[2][3] + a->M[0][3] * b->M[3][3];
|
|
|
|
out.M[1][3] = a->M[1][0] * b->M[0][3] + a->M[1][1] * b->M[1][3] + a->M[1][2] * b->M[2][3] + a->M[1][3] * b->M[3][3];
|
|
|
|
out.M[2][3] = a->M[2][0] * b->M[0][3] + a->M[2][1] * b->M[1][3] + a->M[2][2] * b->M[2][3] + a->M[2][3] * b->M[3][3];
|
|
|
|
out.M[3][3] = a->M[3][0] * b->M[0][3] + a->M[3][1] * b->M[1][3] + a->M[3][2] * b->M[2][3] + a->M[3][3] * b->M[3][3];
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the transpose of a 4x4 matrix.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_Transpose( const ovrMatrix4f * a )
|
|
|
|
{
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = a->M[0][0]; out.M[0][1] = a->M[1][0]; out.M[0][2] = a->M[2][0]; out.M[0][3] = a->M[3][0];
|
|
|
|
out.M[1][0] = a->M[0][1]; out.M[1][1] = a->M[1][1]; out.M[1][2] = a->M[2][1]; out.M[1][3] = a->M[3][1];
|
|
|
|
out.M[2][0] = a->M[0][2]; out.M[2][1] = a->M[1][2]; out.M[2][2] = a->M[2][2]; out.M[2][3] = a->M[3][2];
|
|
|
|
out.M[3][0] = a->M[0][3]; out.M[3][1] = a->M[1][3]; out.M[3][2] = a->M[2][3]; out.M[3][3] = a->M[3][3];
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a 3x3 minor of a 4x4 matrix.
|
|
|
|
static inline float ovrMatrix4f_Minor( const ovrMatrix4f * m, int r0, int r1, int r2, int c0, int c1, int c2 )
|
|
|
|
{
|
|
|
|
return m->M[r0][c0] * ( m->M[r1][c1] * m->M[r2][c2] - m->M[r2][c1] * m->M[r1][c2] ) -
|
|
|
|
m->M[r0][c1] * ( m->M[r1][c0] * m->M[r2][c2] - m->M[r2][c0] * m->M[r1][c2] ) +
|
|
|
|
m->M[r0][c2] * ( m->M[r1][c0] * m->M[r2][c1] - m->M[r2][c0] * m->M[r1][c1] );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the inverse of a 4x4 matrix.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_Inverse( const ovrMatrix4f * m )
|
|
|
|
{
|
|
|
|
const float rcpDet = 1.0f / ( m->M[0][0] * ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) -
|
|
|
|
m->M[0][1] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) +
|
|
|
|
m->M[0][2] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) -
|
|
|
|
m->M[0][3] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) );
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) * rcpDet;
|
|
|
|
out.M[0][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 1, 2, 3 ) * rcpDet;
|
|
|
|
out.M[0][2] = ovrMatrix4f_Minor( m, 0, 1, 3, 1, 2, 3 ) * rcpDet;
|
|
|
|
out.M[0][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 1, 2, 3 ) * rcpDet;
|
|
|
|
out.M[1][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) * rcpDet;
|
|
|
|
out.M[1][1] = ovrMatrix4f_Minor( m, 0, 2, 3, 0, 2, 3 ) * rcpDet;
|
|
|
|
out.M[1][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 2, 3 ) * rcpDet;
|
|
|
|
out.M[1][3] = ovrMatrix4f_Minor( m, 0, 1, 2, 0, 2, 3 ) * rcpDet;
|
|
|
|
out.M[2][0] = ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) * rcpDet;
|
|
|
|
out.M[2][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 3 ) * rcpDet;
|
|
|
|
out.M[2][2] = ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 3 ) * rcpDet;
|
|
|
|
out.M[2][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 3 ) * rcpDet;
|
|
|
|
out.M[3][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) * rcpDet;
|
|
|
|
out.M[3][1] = ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 2 ) * rcpDet;
|
|
|
|
out.M[3][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 2 ) * rcpDet;
|
|
|
|
out.M[3][3] = ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 2 ) * rcpDet;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a 4x4 identity matrix.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateIdentity()
|
|
|
|
{
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = 1.0f; out.M[0][1] = 0.0f; out.M[0][2] = 0.0f; out.M[0][3] = 0.0f;
|
|
|
|
out.M[1][0] = 0.0f; out.M[1][1] = 1.0f; out.M[1][2] = 0.0f; out.M[1][3] = 0.0f;
|
|
|
|
out.M[2][0] = 0.0f; out.M[2][1] = 0.0f; out.M[2][2] = 1.0f; out.M[2][3] = 0.0f;
|
|
|
|
out.M[3][0] = 0.0f; out.M[3][1] = 0.0f; out.M[3][2] = 0.0f; out.M[3][3] = 1.0f;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a 4x4 homogeneous translation matrix.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateTranslation( const float x, const float y, const float z )
|
|
|
|
{
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = 1.0f; out.M[0][1] = 0.0f; out.M[0][2] = 0.0f; out.M[0][3] = x;
|
|
|
|
out.M[1][0] = 0.0f; out.M[1][1] = 1.0f; out.M[1][2] = 0.0f; out.M[1][3] = y;
|
|
|
|
out.M[2][0] = 0.0f; out.M[2][1] = 0.0f; out.M[2][2] = 1.0f; out.M[2][3] = z;
|
|
|
|
out.M[3][0] = 0.0f; out.M[3][1] = 0.0f; out.M[3][2] = 0.0f; out.M[3][3] = 1.0f;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a 4x4 homogeneous rotation matrix.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateRotation( const float radiansX, const float radiansY, const float radiansZ )
|
|
|
|
{
|
|
|
|
const float sinX = sinf( radiansX );
|
|
|
|
const float cosX = cosf( radiansX );
|
|
|
|
const ovrMatrix4f rotationX =
|
|
|
|
{ {
|
|
|
|
{ 1, 0, 0, 0 },
|
|
|
|
{ 0, cosX, -sinX, 0 },
|
|
|
|
{ 0, sinX, cosX, 0 },
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
} };
|
|
|
|
const float sinY = sinf( radiansY );
|
|
|
|
const float cosY = cosf( radiansY );
|
|
|
|
const ovrMatrix4f rotationY =
|
|
|
|
{ {
|
|
|
|
{ cosY, 0, sinY, 0 },
|
|
|
|
{ 0, 1, 0, 0 },
|
|
|
|
{ -sinY, 0, cosY, 0 },
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
} };
|
|
|
|
const float sinZ = sinf( radiansZ );
|
|
|
|
const float cosZ = cosf( radiansZ );
|
|
|
|
const ovrMatrix4f rotationZ =
|
|
|
|
{ {
|
|
|
|
{ cosZ, -sinZ, 0, 0 },
|
|
|
|
{ sinZ, cosZ, 0, 0 },
|
|
|
|
{ 0, 0, 1, 0 },
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
} };
|
|
|
|
const ovrMatrix4f rotationXY = ovrMatrix4f_Multiply( &rotationY, &rotationX );
|
|
|
|
return ovrMatrix4f_Multiply( &rotationZ, &rotationXY );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a projection matrix based on the specified dimensions.
|
|
|
|
// The far plane is placed at infinity if farZ <= nearZ.
|
|
|
|
// An infinite projection matrix is preferred for rasterization because, except for
|
|
|
|
// things *right* up against the near plane, it always provides better precision:
|
|
|
|
// "Tightening the Precision of Perspective Rendering"
|
|
|
|
// Paul Upchurch, Mathieu Desbrun
|
|
|
|
// Journal of Graphics Tools, Volume 16, Issue 1, 2012
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateProjection( const float minX, const float maxX,
|
|
|
|
float const minY, const float maxY, const float nearZ, const float farZ )
|
|
|
|
{
|
|
|
|
const float width = maxX - minX;
|
|
|
|
const float height = maxY - minY;
|
|
|
|
const float offsetZ = nearZ; // set to zero for a [0,1] clip space
|
|
|
|
|
|
|
|
ovrMatrix4f out;
|
|
|
|
if ( farZ <= nearZ )
|
|
|
|
{
|
|
|
|
// place the far plane at infinity
|
|
|
|
out.M[0][0] = 2 * nearZ / width;
|
|
|
|
out.M[0][1] = 0;
|
|
|
|
out.M[0][2] = ( maxX + minX ) / width;
|
|
|
|
out.M[0][3] = 0;
|
|
|
|
|
|
|
|
out.M[1][0] = 0;
|
|
|
|
out.M[1][1] = 2 * nearZ / height;
|
|
|
|
out.M[1][2] = ( maxY + minY ) / height;
|
|
|
|
out.M[1][3] = 0;
|
|
|
|
|
|
|
|
out.M[2][0] = 0;
|
|
|
|
out.M[2][1] = 0;
|
|
|
|
out.M[2][2] = -1;
|
|
|
|
out.M[2][3] = -( nearZ + offsetZ );
|
|
|
|
|
|
|
|
out.M[3][0] = 0;
|
|
|
|
out.M[3][1] = 0;
|
|
|
|
out.M[3][2] = -1;
|
|
|
|
out.M[3][3] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// normal projection
|
|
|
|
out.M[0][0] = 2 * nearZ / width;
|
|
|
|
out.M[0][1] = 0;
|
|
|
|
out.M[0][2] = ( maxX + minX ) / width;
|
|
|
|
out.M[0][3] = 0;
|
|
|
|
|
|
|
|
out.M[1][0] = 0;
|
|
|
|
out.M[1][1] = 2 * nearZ / height;
|
|
|
|
out.M[1][2] = ( maxY + minY ) / height;
|
|
|
|
out.M[1][3] = 0;
|
|
|
|
|
|
|
|
out.M[2][0] = 0;
|
|
|
|
out.M[2][1] = 0;
|
|
|
|
out.M[2][2] = -( farZ + offsetZ ) / ( farZ - nearZ );
|
|
|
|
out.M[2][3] = -( farZ * ( nearZ + offsetZ ) ) / ( farZ - nearZ );
|
|
|
|
|
|
|
|
out.M[3][0] = 0;
|
|
|
|
out.M[3][1] = 0;
|
|
|
|
out.M[3][2] = -1;
|
|
|
|
out.M[3][3] = 0;
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a projection matrix based on the given FOV.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateProjectionFov( const float fovDegreesX, const float fovDegreesY,
|
|
|
|
const float offsetX, const float offsetY, const float nearZ, const float farZ )
|
|
|
|
{
|
|
|
|
const float halfWidth = nearZ * tanf( fovDegreesX * ( VRAPI_PI / 180.0f * 0.5f ) );
|
|
|
|
const float halfHeight = nearZ * tanf( fovDegreesY * ( VRAPI_PI / 180.0f * 0.5f ) );
|
|
|
|
|
|
|
|
const float minX = offsetX - halfWidth;
|
|
|
|
const float maxX = offsetX + halfWidth;
|
|
|
|
|
|
|
|
const float minY = offsetY - halfHeight;
|
|
|
|
const float maxY = offsetY + halfHeight;
|
|
|
|
|
|
|
|
return ovrMatrix4f_CreateProjection( minX, maxX, minY, maxY, nearZ, farZ );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the 4x4 rotation matrix for the given quaternion.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CreateFromQuaternion( const ovrQuatf * q )
|
|
|
|
{
|
|
|
|
const float ww = q->w * q->w;
|
|
|
|
const float xx = q->x * q->x;
|
|
|
|
const float yy = q->y * q->y;
|
|
|
|
const float zz = q->z * q->z;
|
|
|
|
|
|
|
|
ovrMatrix4f out;
|
|
|
|
out.M[0][0] = ww + xx - yy - zz;
|
|
|
|
out.M[0][1] = 2 * ( q->x * q->y - q->w * q->z );
|
|
|
|
out.M[0][2] = 2 * ( q->x * q->z + q->w * q->y );
|
|
|
|
out.M[0][3] = 0;
|
|
|
|
|
|
|
|
out.M[1][0] = 2 * ( q->x * q->y + q->w * q->z );
|
|
|
|
out.M[1][1] = ww - xx + yy - zz;
|
|
|
|
out.M[1][2] = 2 * ( q->y * q->z - q->w * q->x );
|
|
|
|
out.M[1][3] = 0;
|
|
|
|
|
|
|
|
out.M[2][0] = 2 * ( q->x * q->z - q->w * q->y );
|
|
|
|
out.M[2][1] = 2 * ( q->y * q->z + q->w * q->x );
|
|
|
|
out.M[2][2] = ww - xx - yy + zz;
|
|
|
|
out.M[2][3] = 0;
|
|
|
|
|
|
|
|
out.M[3][0] = 0;
|
|
|
|
out.M[3][1] = 0;
|
|
|
|
out.M[3][2] = 0;
|
|
|
|
out.M[3][3] = 1;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert a standard projection matrix into a TexCoordsFromTanAngles matrix for
|
|
|
|
// the primary time warp surface.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_TanAngleMatrixFromProjection( const ovrMatrix4f * projection )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
A projection matrix goes from a view point to NDC, or -1 to 1 space.
|
|
|
|
Scale and bias to convert that to a 0 to 1 space.
|
|
|
|
|
|
|
|
const ovrMatrix3f m =
|
|
|
|
{ {
|
|
|
|
{ projection->M[0][0], 0.0f, projection->M[0][2] },
|
|
|
|
{ 0.0f, projection->M[1][1], projection->M[1][2] },
|
|
|
|
{ 0.0f, 0.0f, -1.0f }
|
|
|
|
} };
|
|
|
|
// Note that there is no Y-flip because eye buffers have 0,0 = left-bottom.
|
|
|
|
const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5f, 0.5f );
|
|
|
|
const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5f, 0.5f );
|
|
|
|
const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &s, &m );
|
|
|
|
const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &t, &r0 );
|
|
|
|
return r1;
|
|
|
|
|
|
|
|
clipZ = ( z * projection[2][2] + projection[2][3] ) / ( projection[3][2] * z )
|
|
|
|
z = projection[2][3] / ( clipZ * projection[3][2] - projection[2][2] )
|
|
|
|
z = ( projection[2][3] / projection[3][2] ) / ( clipZ - projection[2][2] / projection[3][2] )
|
|
|
|
*/
|
|
|
|
const ovrMatrix4f tanAngleMatrix =
|
|
|
|
{ {
|
|
|
|
{ 0.5f * projection->M[0][0], 0.0f, 0.5f * projection->M[0][2] - 0.5f, 0.0f },
|
|
|
|
{ 0.0f, 0.5f * projection->M[1][1], 0.5f * projection->M[1][2] - 0.5f, 0.0f },
|
|
|
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
|
|
|
// Store the values to convert a clip-Z to a linear depth in the unused matrix elements.
|
|
|
|
{ projection->M[2][2], projection->M[2][3], projection->M[3][2], 1.0f }
|
|
|
|
} };
|
|
|
|
return tanAngleMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a simple quad defined as a -1 to 1 XY unit square is transformed to
|
|
|
|
// the camera view with the given modelView matrix, it can alternately be
|
|
|
|
// drawn as a time warp overlay image to take advantage of the full window
|
|
|
|
// resolution, which is usually higher than the eye buffer textures, and
|
|
|
|
// avoids resampling both into the eye buffer, and again to the screen.
|
|
|
|
// This is used for high quality movie screens and user interface planes.
|
|
|
|
//
|
|
|
|
// Note that this is NOT an MVP matrix -- the "projection" is handled
|
|
|
|
// by the distortion process.
|
|
|
|
//
|
|
|
|
// The exact composition of the overlay image and the base image is
|
|
|
|
// determined by the warp program, you may still need to draw the geometry
|
|
|
|
// into the eye buffer to punch a hole in the alpha channel to let the
|
|
|
|
// overlay/underlay show through.
|
|
|
|
//
|
|
|
|
// This utility functions converts a model-view matrix that would normally
|
|
|
|
// draw a -1 to 1 unit square to the view into a TexCoordsFromTanAngles matrix
|
|
|
|
// for an overlay surface.
|
|
|
|
//
|
|
|
|
// The resulting z value should be straight ahead distance to the plane.
|
|
|
|
// The x and y values will be pre-multiplied by z for projective texturing.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_TanAngleMatrixFromUnitSquare( const ovrMatrix4f * modelView )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
// Take the inverse of the view matrix because the view matrix transforms the unit square
|
|
|
|
// from world space into view space, while the matrix needed here is the one that transforms
|
|
|
|
// the unit square from view space to world space.
|
|
|
|
const ovrMatrix4f inv = ovrMatrix4f_Inverse( modelView );
|
|
|
|
// This matrix calculates the projection onto the (-1, 1) X and Y axes of the unit square,
|
|
|
|
// of the intersection of the vector (tanX, tanY, -1) with the plane described by the matrix
|
|
|
|
// that transforms the unit square into world space.
|
|
|
|
const ovrMatrix3f m =
|
|
|
|
{ {
|
|
|
|
{ inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0],
|
|
|
|
inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1],
|
|
|
|
inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] },
|
|
|
|
{ inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0],
|
|
|
|
inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1],
|
|
|
|
inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] },
|
|
|
|
{ - inv.M[2][0],
|
|
|
|
- inv.M[2][1],
|
|
|
|
- inv.M[2][2] }
|
|
|
|
} };
|
|
|
|
// Flip the Y because textures have 0,0 = left-top as opposed to left-bottom.
|
|
|
|
const ovrMatrix3f f = ovrMatrix3f_CreateScaling( 1.0f, -1.0f );
|
|
|
|
const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5f, 0.5f );
|
|
|
|
const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5f, 0.5f );
|
|
|
|
const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &f, &m );
|
|
|
|
const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &s, &r0 );
|
|
|
|
const ovrMatrix3f r2 = ovrMatrix3f_Multiply( &t, &r1 );
|
|
|
|
return r2;
|
|
|
|
*/
|
|
|
|
|
|
|
|
const ovrMatrix4f inv = ovrMatrix4f_Inverse( modelView );
|
|
|
|
|
|
|
|
ovrMatrix4f m;
|
|
|
|
m.M[0][0] = + 0.5f * ( inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0] ) - 0.5f * inv.M[2][0];
|
|
|
|
m.M[0][1] = + 0.5f * ( inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1] ) - 0.5f * inv.M[2][1];
|
|
|
|
m.M[0][2] = + 0.5f * ( inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] ) - 0.5f * inv.M[2][2];
|
|
|
|
m.M[0][3] = 0.0f;
|
|
|
|
|
|
|
|
m.M[1][0] = - 0.5f * ( inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0] ) - 0.5f * inv.M[2][0];
|
|
|
|
m.M[1][1] = - 0.5f * ( inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1] ) - 0.5f * inv.M[2][1];
|
|
|
|
m.M[1][2] = - 0.5f * ( inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] ) - 0.5f * inv.M[2][2];
|
|
|
|
m.M[1][3] = 0.0f;
|
|
|
|
|
|
|
|
m.M[2][0] = - inv.M[2][0];
|
|
|
|
m.M[2][1] = - inv.M[2][1];
|
|
|
|
m.M[2][2] = - inv.M[2][2];
|
|
|
|
m.M[2][3] = 0.0f;
|
|
|
|
|
|
|
|
m.M[3][0] = 0.0f;
|
|
|
|
m.M[3][1] = 0.0f;
|
|
|
|
m.M[3][2] = 0.0f;
|
|
|
|
m.M[3][3] = 1.0f;
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to calculate external velocity for smooth stick yaw turning.
|
|
|
|
// To reduce judder in FPS style experiences when the application framerate is
|
|
|
|
// lower than the vsync rate, the rotation from a joypad can be applied to the
|
|
|
|
// view space distorted eye vectors before applying the time warp.
|
|
|
|
static inline ovrMatrix4f ovrMatrix4f_CalculateExternalVelocity( const ovrMatrix4f * viewMatrix, const float yawRadiansPerSecond )
|
|
|
|
{
|
|
|
|
const float angle = yawRadiansPerSecond * ( -1.0f / 60.0f );
|
|
|
|
const float sinHalfAngle = sinf( angle * 0.5f );
|
|
|
|
const float cosHalfAngle = cosf( angle * 0.5f );
|
|
|
|
|
|
|
|
// Yaw is always going to be around the world Y axis
|
|
|
|
ovrQuatf quat;
|
|
|
|
quat.x = viewMatrix->M[0][1] * sinHalfAngle;
|
|
|
|
quat.y = viewMatrix->M[1][1] * sinHalfAngle;
|
|
|
|
quat.z = viewMatrix->M[2][1] * sinHalfAngle;
|
|
|
|
quat.w = cosHalfAngle;
|
|
|
|
return ovrMatrix4f_CreateFromQuaternion( &quat );
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
// Default initialization helper functions.
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
|
|
// Utility function to default initialize the ovrInitParms.
|
|
|
|
static inline ovrInitParms vrapi_DefaultInitParms( const ovrJava * java )
|
|
|
|
{
|
|
|
|
ovrInitParms parms;
|
|
|
|
memset( &parms, 0, sizeof( parms ) );
|
|
|
|
|
|
|
|
parms.Type = VRAPI_STRUCTURE_TYPE_INIT_PARMS;
|
|
|
|
parms.ProductVersion = VRAPI_PRODUCT_VERSION;
|
|
|
|
parms.MajorVersion = VRAPI_MAJOR_VERSION;
|
|
|
|
parms.MinorVersion = VRAPI_MINOR_VERSION;
|
|
|
|
parms.PatchVersion = VRAPI_PATCH_VERSION;
|
|
|
|
parms.GraphicsAPI = VRAPI_GRAPHICS_API_OPENGL_ES_2;
|
|
|
|
parms.Java = *java;
|
|
|
|
|
|
|
|
return parms;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to default initialize the ovrModeParms.
|
|
|
|
static inline ovrModeParms vrapi_DefaultModeParms( const ovrJava * java )
|
|
|
|
{
|
|
|
|
ovrModeParms parms;
|
|
|
|
memset( &parms, 0, sizeof( parms ) );
|
|
|
|
|
|
|
|
parms.Type = VRAPI_STRUCTURE_TYPE_MODE_PARMS;
|
|
|
|
parms.AllowPowerSave = true;
|
|
|
|
parms.ResetWindowFullscreen = true;
|
|
|
|
parms.Java = *java;
|
|
|
|
|
|
|
|
return parms;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to default initialize the ovrPerformanceParms.
|
|
|
|
static inline ovrPerformanceParms vrapi_DefaultPerformanceParms()
|
|
|
|
{
|
|
|
|
ovrPerformanceParms parms;
|
|
|
|
parms.CpuLevel = 2;
|
|
|
|
parms.GpuLevel = 2;
|
|
|
|
parms.MainThreadTid = 0;
|
|
|
|
parms.RenderThreadTid = 0;
|
|
|
|
return parms;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
VRAPI_FRAME_INIT_DEFAULT,
|
|
|
|
VRAPI_FRAME_INIT_BLACK,
|
|
|
|
VRAPI_FRAME_INIT_BLACK_FLUSH,
|
|
|
|
VRAPI_FRAME_INIT_BLACK_FINAL,
|
|
|
|
VRAPI_FRAME_INIT_LOADING_ICON,
|
|
|
|
VRAPI_FRAME_INIT_LOADING_ICON_FLUSH,
|
|
|
|
VRAPI_FRAME_INIT_MESSAGE,
|
|
|
|
VRAPI_FRAME_INIT_MESSAGE_FLUSH
|
|
|
|
} ovrFrameInit;
|
|
|
|
|
|
|
|
// Utility function to default initialize the ovrFrameParms.
|
|
|
|
static inline ovrFrameParms vrapi_DefaultFrameParms( const ovrJava * java, const ovrFrameInit init, const double currentTime,
|
|
|
|
ovrTextureSwapChain * textureSwapChain )
|
|
|
|
{
|
|
|
|
const ovrMatrix4f projectionMatrix = ovrMatrix4f_CreateProjectionFov( 90.0f, 90.0f, 0.0f, 0.0f, 0.1f, 0.0f );
|
|
|
|
const ovrMatrix4f texCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &projectionMatrix );
|
|
|
|
|
|
|
|
ovrFrameParms parms;
|
|
|
|
memset( &parms, 0, sizeof( parms ) );
|
|
|
|
|
|
|
|
parms.Type = VRAPI_STRUCTURE_TYPE_FRAME_PARMS;
|
|
|
|
for ( int layer = 0; layer < VRAPI_FRAME_LAYER_TYPE_MAX; layer++ )
|
|
|
|
{
|
|
|
|
parms.Layers[layer].ProgramParms[2] = 1.0f; // color scale
|
|
|
|
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
|
|
|
{
|
|
|
|
parms.Layers[layer].Textures[eye].TexCoordsFromTanAngles = texCoordsFromTanAngles;
|
|
|
|
parms.Layers[layer].Textures[eye].TextureRect.width = 1.0f;
|
|
|
|
parms.Layers[layer].Textures[eye].TextureRect.height = 1.0f;
|
|
|
|
parms.Layers[layer].Textures[eye].HeadPose.Pose.Orientation.w = 1.0f;
|
|
|
|
parms.Layers[layer].Textures[eye].HeadPose.TimeInSeconds = currentTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
parms.LayerCount = 1;
|
|
|
|
parms.MinimumVsyncs = 1;
|
|
|
|
parms.ExtraLatencyMode = VRAPI_EXTRA_LATENCY_MODE_OFF;
|
|
|
|
parms.ExternalVelocity.M[0][0] = 1.0f;
|
|
|
|
parms.ExternalVelocity.M[1][1] = 1.0f;
|
|
|
|
parms.ExternalVelocity.M[2][2] = 1.0f;
|
|
|
|
parms.ExternalVelocity.M[3][3] = 1.0f;
|
|
|
|
parms.PerformanceParms = vrapi_DefaultPerformanceParms();
|
|
|
|
parms.Java = *java;
|
|
|
|
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].DstBlend = VRAPI_FRAME_LAYER_BLEND_ZERO;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Flags = 0;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].SrcBlend = VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Flags = 0;
|
|
|
|
|
|
|
|
switch ( init )
|
|
|
|
{
|
|
|
|
case VRAPI_FRAME_INIT_DEFAULT:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VRAPI_FRAME_INIT_BLACK:
|
|
|
|
case VRAPI_FRAME_INIT_BLACK_FLUSH:
|
|
|
|
case VRAPI_FRAME_INIT_BLACK_FINAL:
|
|
|
|
{
|
|
|
|
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;
|
|
|
|
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
|
|
|
{
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VRAPI_FRAME_INIT_LOADING_ICON:
|
|
|
|
case VRAPI_FRAME_INIT_LOADING_ICON_FLUSH:
|
|
|
|
{
|
|
|
|
parms.LayerCount = 2;
|
|
|
|
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Flags = VRAPI_FRAME_LAYER_FLAG_SPIN;
|
|
|
|
parms.Layers[1].ProgramParms[0] = 1.0f; // rotation in radians per second
|
|
|
|
parms.Layers[1].ProgramParms[1] = 16.0f; // icon size factor smaller than fullscreen
|
|
|
|
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
|
|
|
{
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Textures[eye].ColorTextureSwapChain = ( textureSwapChain != NULL ) ? textureSwapChain : (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VRAPI_FRAME_INIT_MESSAGE:
|
|
|
|
case VRAPI_FRAME_INIT_MESSAGE_FLUSH:
|
|
|
|
{
|
|
|
|
parms.LayerCount = 2;
|
|
|
|
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;
|
|
|
|
parms.Layers[1].ProgramParms[0] = 0.0f; // rotation in radians per second
|
|
|
|
parms.Layers[1].ProgramParms[1] = 2.0f; // message size factor smaller than fullscreen
|
|
|
|
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
|
|
|
{
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;
|
|
|
|
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Textures[eye].ColorTextureSwapChain = ( textureSwapChain != NULL ) ? textureSwapChain : (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( init == VRAPI_FRAME_INIT_BLACK_FLUSH || init == VRAPI_FRAME_INIT_LOADING_ICON_FLUSH || init == VRAPI_FRAME_INIT_MESSAGE_FLUSH )
|
|
|
|
{
|
|
|
|
parms.Flags |= VRAPI_FRAME_FLAG_FLUSH;
|
|
|
|
}
|
|
|
|
if ( init == VRAPI_FRAME_INIT_BLACK_FINAL )
|
|
|
|
{
|
|
|
|
parms.Flags |= VRAPI_FRAME_FLAG_FLUSH | VRAPI_FRAME_FLAG_FINAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parms;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
// Head Model
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
|
|
// Utility function to default initialize the ovrHeadModelParms.
|
|
|
|
static inline ovrHeadModelParms vrapi_DefaultHeadModelParms()
|
|
|
|
{
|
|
|
|
ovrHeadModelParms parms;
|
|
|
|
memset( &parms, 0, sizeof( parms ) );
|
|
|
|
|
|
|
|
parms.InterpupillaryDistance = 0.0640f; // average interpupillary distance
|
|
|
|
parms.EyeHeight = 1.6750f; // average eye height above the ground when standing
|
|
|
|
parms.HeadModelDepth = 0.0805f;
|
|
|
|
parms.HeadModelHeight = 0.0750f;
|
|
|
|
|
|
|
|
return parms;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
// Eye view matrix helper functions.
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
|
|
// Apply the head-on-a-stick model if head tracking is not available.
|
|
|
|
static inline ovrTracking vrapi_ApplyHeadModel( const ovrHeadModelParms * headModelParms, const ovrTracking * tracking )
|
|
|
|
{
|
|
|
|
if ( ( tracking->Status & VRAPI_TRACKING_STATUS_POSITION_TRACKED ) == 0 )
|
|
|
|
{
|
|
|
|
// Calculate the head position based on the head orientation using a head-on-a-stick model.
|
|
|
|
const ovrHeadModelParms * p = headModelParms;
|
|
|
|
const ovrMatrix4f m = ovrMatrix4f_CreateFromQuaternion( &tracking->HeadPose.Pose.Orientation );
|
|
|
|
ovrTracking newTracking = *tracking;
|
|
|
|
newTracking.HeadPose.Pose.Position.x = m.M[0][1] * p->HeadModelHeight - m.M[0][2] * p->HeadModelDepth;
|
|
|
|
newTracking.HeadPose.Pose.Position.y = m.M[1][1] * p->HeadModelHeight - m.M[1][2] * p->HeadModelDepth - p->HeadModelHeight;
|
|
|
|
newTracking.HeadPose.Pose.Position.z = m.M[2][1] * p->HeadModelHeight - m.M[2][2] * p->HeadModelDepth;
|
|
|
|
return newTracking;
|
|
|
|
}
|
|
|
|
return *tracking;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to get the center eye transform.
|
|
|
|
// Pass in NULL for 'input' if there is no additional controller input.
|
|
|
|
static inline ovrMatrix4f vrapi_GetCenterEyeTransform( const ovrHeadModelParms * headModelParms,
|
|
|
|
const ovrTracking * tracking,
|
|
|
|
const ovrMatrix4f * input )
|
|
|
|
{
|
|
|
|
VRAPI_UNUSED( headModelParms );
|
|
|
|
|
|
|
|
// Controller input is expected to be applied relative to the head in neutral position, which means
|
|
|
|
// ovrTracking::HeadPose.Pose.Position should be relative to the center of the head in neutral position.
|
|
|
|
const ovrMatrix4f centerEyeRotation = ovrMatrix4f_CreateFromQuaternion( &tracking->HeadPose.Pose.Orientation );
|
|
|
|
const ovrVector3f centerEyeOffset = tracking->HeadPose.Pose.Position;
|
|
|
|
const ovrMatrix4f centerEyeTranslation = ovrMatrix4f_CreateTranslation( centerEyeOffset.x, centerEyeOffset.y, centerEyeOffset.z );
|
|
|
|
const ovrMatrix4f centerEyeTransform = ovrMatrix4f_Multiply( ¢erEyeTranslation, ¢erEyeRotation );
|
|
|
|
return ( input == NULL ) ? centerEyeTransform : ovrMatrix4f_Multiply( input, ¢erEyeTransform );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to get the center eye view matrix.
|
|
|
|
// Pass in NULL for 'input' if there is no additional controller input.
|
|
|
|
static inline ovrMatrix4f vrapi_GetCenterEyeViewMatrix( const ovrHeadModelParms * headModelParms,
|
|
|
|
const ovrTracking * tracking,
|
|
|
|
const ovrMatrix4f * input )
|
|
|
|
{
|
|
|
|
const ovrMatrix4f centerEyeTransform = vrapi_GetCenterEyeTransform( headModelParms, tracking, input );
|
|
|
|
return ovrMatrix4f_Inverse( ¢erEyeTransform );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility function to get the eye view matrix based on the center eye view matrix and the IPD.
|
|
|
|
static inline ovrMatrix4f vrapi_GetEyeViewMatrix( const ovrHeadModelParms * headModelParms,
|
|
|
|
const ovrMatrix4f * centerEyeViewMatrix,
|
|
|
|
const int eye )
|
|
|
|
{
|
|
|
|
const float eyeOffset = ( eye ? -0.5f : 0.5f ) * headModelParms->InterpupillaryDistance;
|
|
|
|
const ovrMatrix4f eyeOffsetMatrix = ovrMatrix4f_CreateTranslation( eyeOffset, 0.0f, 0.0f );
|
|
|
|
return ovrMatrix4f_Multiply( &eyeOffsetMatrix, centerEyeViewMatrix );
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // OVR_VrApi_Helpers_h
|
|
|