最近在学习OpenXR标准并研究在Android上实现,现在基本功能已经实现,简单总结下。
1. OpenXR是什么:
官方网址介绍的挺好的,就不赘余了。
https://www.khronos.org/OpenXR
官方spec地址如下:
https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html
1.1 OpenXR Loader介绍及NDK编译
…
1.2 OpenXR Runtime设计与实现
…
2. OpenXR接口介绍
为方便理解,我们结合OpenXR官方示例DemoHelloXR进行讲解。
2.1 HelloXR 运行效果图
首先附上Helloxr的运行效果
2.1 HelloXR 运行时序
HelloXR是基于NativeActivity框架实现的Android应用,关于NativeActivity的相关知识这里就不介绍了,HelloXR的时序图如下:
2.2 OpenXR接口及实现
我们现在HelloXR中一些比较主要的方法及其实现方案进行简要介绍
xrCreateInstance
定义
XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
在Android 平台调用xrCreateInstance来创建XrInstance时,需要开启XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME扩展,并将一个XrInstanceCreateInfoAndroidKHR对象赋值给createInfo.next,代码属下
XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid;
instanceCreateInfoAndroid = {
XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR};
//将JavaVm及activity赋值给instanceCreateInfoAndroid
//以传递给Runtime,Runtime会通过该JavaVM及activity获取一些必需的Java对象
//如surface和Choreographer
instanceCreateInfoAndroid.applicationVM = data->applicationVM;
instanceCreateInfoAndroid.applicationActivity = data->applicationActivity;
XrInstanceCreateInfo createInfo{
XR_TYPE_INSTANCE_CREATE_INFO};
createInfo.next = &instanceCreateInfoAndroid;
//extensions必须包含XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME
createInfo.enabledExtensionCount = (uint32_t)extensions.size();
createInfo.enabledExtensionNames = extensions.data();
xrCreateInstance(&createInfo, &m_instance);
Android平台,OpenXR在xrCreateInstance创建XrInstance时,会将JavaVM和activity传递给Runtime,Runtime接着会通过该JavaVM和activity获取显示控件surface及Vsync信号接受对象Choreographer及其他一些必需的java对象或属性。
x.x OpenXR 坐标系定义
OpenXR 坐标系定义三种坐标系:
-
XR_REFERENCE_SPACE_TYPE_VIEW:
view坐标系,坐标原点为HMD左眼或者有眼,z轴指与视线相反,y轴垂直向上,x水平向右。 -
XR_REFERENCE_SPACE_TYPE_LOCAL
世界坐标系 -
XR_REFERENCE_SPACE_TYPE_STAGE
暂时与XR_REFERENCE_SPACE_TYPE_LOCAL相同,可以认为就是XR_REFERENCE_SPACE_TYPE_LOCAL
x.x OpenXR xrLocateViews定义及转换公式
- xrLocateViews定义
//session,应用创建的XrSession
//viewLocateInfo,主要包含预测时间及应用的基础坐标系
//viewState,表示预测状态标志位, position,orientation是否有效
//viewCapacityInput:view 数量,一般为2,表示左右眼
//views,获取的左右眼位置和姿态信息
XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
XrSession session,
const XrViewLocateInfo* viewLocateInfo,
XrViewState* viewState,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrView* views);
首先,我们介绍下XrViewLocateInfo结构体:
//displayTime:预测时间
//space:应用所在的基础坐标系。
typedef struct XrViewLocateInfo {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrViewConfigurationType viewConfigurationType;
XrTime displayTime;
XrSpace space;
} XrViewLocateInfo;
在调用xrLocateViews之前,首先需要创建一个应用的基础坐标系,并设置其初始位置和姿态。
Helloxr应用的基础坐标系m_appSpace:
//m_appSpace的初始位置
referenceSpaceType=XR_REFERENCE_SPACE_TYPE_LOCAL
pose.orientaion = {
0,0,0,1}
pose.position= {
0,0,0}
为了计算方便,建议m_appSpace就取上边的值,不然计算公式还需要考虑basepace的影响,比较麻烦!!在以后的计算中,我们全部假设基础坐标就为m_appSpace
xrLocateViews返回的是XrView对象views,其定义为
//pose:获取的view(表示左眼或者右眼)的位置姿态
//fov:获取的view(表示左眼或者右眼)的fov
typedef struct XrView {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrPosef pose;
XrFovf fov;
} XrView;
计算公式为:
- xrLocateViews返回的是XrViewLocateInfo.space 到XR_REFERENCE_SPACE_TYPE_VIEW坐标系的转换关系,由于基础坐标系XrViewLocateInfo.space 为m_appSpace,类型为XR_REFERENCE_SPACE_TYPE_LOCAL ,xrLocateViews返回的就是XR_REFERENCE_SPACE_TYPE_LOCAL 坐标系到XR_REFERENCE_SPACE_TYPE_VIEW的转换关系(或者说,XR_REFERENCE_SPACE_TYPE_LOCAL 坐标系旋转多少角度和平移多少距离后与XR_REFERENCE_SPACE_TYPE_VIEW坐标系重合)
//i=0时,表示左眼
//i=1时,表示右眼
views[i].pose.orientation = head.orientaion*eye[i].orientation
views[i].pose.position = head.orientaion*eye[i].position+ head.position
- 如果基础坐标系XrViewLocateInfo.space 类型为XR_REFERENCE_SPACE_TYPE_VIEW,
返回的是eye的位置和姿态,由于假定了XrViewLocateInfo.space为m_appSpace,该公式不会走到
views[i].pose.orientation = eye[i].orientation
views[i].pose.position = eye[i].position
x.x OpenXR xrLocateSpace定义及转换公式
- xrLocateSpace定义
//space:物体所在空间的初始位置姿态
//baseSpace:基础坐标空间,helloxr是m_appSpace
//time:预测时间
//location:获取的结果
XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
XrSpace space,
XrSpace baseSpace,
XrTime time,
XrSpaceLocation* location);
在调用xrLocateSpace,首先需要传入两个坐标空间,基础坐标空间baseSpace和物体所在的空间space。
helloxr 的基础坐标空间baseSpace为m_appSpace={XR_REFERENCE_SPACE_TYPE_LOCAL,{0,0,0,},{0,0,0,1}}。
xrLocateSpace返回的是XrSpaceLocation 对象location,其定义
//locationFlags 为获取的pose的质量
//pose 为获取的pose
typedef struct XrSpaceLocation {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrSpaceLocationFlags locationFlags;
XrPosef pose;
} XrSpaceLocation;
计算公式为:
- 如果space为XR_REFERENCE_SPACE_TYPE_VIEW坐标空间
location.pose.orientation = head.orientaion*space.orientation
location.pose.position = head.orientation*space.postion+ head.position
- 如果space为XR_REFERENCE_SPACE_TYPE_LOCAL坐标空间
location.pose.orientation = space.orientation
location.pose.position = space.position
x.x OpenXR MVP 矩阵计算
- ProjectionMatrix矩阵计算:直接通过views[i].fov
公式:
ProjectionMatrix=mat4_cast(views[i].fov)
- ViewMatrix矩阵计算:
在计算ViewMatrix矩阵时,不能直接使用views[i].pose,需要取下逆1
公式:
ViewMatrix = mat4_cast(invert(views[i].pose))
- ModelMatrix矩阵计算:
公式:
ModelMatrix= mat4_cast(location.pose)