vrapi_getSkeleton;

This commit is contained in:
bjorn 2020-08-12 15:47:10 -06:00
parent 438f7ef0d6
commit 1b5e7b2203
3 changed files with 126 additions and 18 deletions

View File

@ -499,18 +499,17 @@ static int l_lovrHeadsetGetAxis(lua_State* L) {
static int l_lovrHeadsetGetSkeleton(lua_State* L) {
Device device = luax_optdevice(L, 1);
float poses[MAX_HEADSET_BONES * 8];
uint32_t poseCount = MAX_HEADSET_BONES;
float poses[HAND_JOINT_COUNT * 8];
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getSkeleton(device, poses, &poseCount)) {
if (driver->getSkeleton(device, poses)) {
if (!lua_istable(L, 2)) {
lua_createtable(L, poseCount, 0);
lua_createtable(L, HAND_JOINT_COUNT, 0);
} else {
lua_settop(L, 2);
}
for (uint32_t i = 0; i < poseCount; i++) {
lua_createtable(L, 7, 0);
for (uint32_t i = 0; i < HAND_JOINT_COUNT; i++) {
lua_createtable(L, 8, 0);
float angle, ax, ay, az;
float* pose = poses + i * 8;

View File

@ -4,7 +4,7 @@
#pragma once
#define MAX_HEADSET_BONES 32
#define HAND_JOINT_COUNT 26
struct Model;
struct ModelData;
@ -77,6 +77,35 @@ typedef enum {
MAX_AXES
} DeviceAxis;
typedef enum {
JOINT_PALM,
JOINT_WRIST,
JOINT_THUMB_METACARPAL,
JOINT_THUMB_PROXIMAL,
JOINT_THUMB_DISTAL,
JOINT_THUMB_TIP,
JOINT_INDEX_METACARPAL,
JOINT_INDEX_PROXIMAL,
JOINT_INDEX_INTERMEDIATE,
JOINT_INDEX_DISTAL,
JOINT_INDEX_TIP,
JOINT_MIDDLE_METACARPAL,
JOINT_MIDDLE_PROXIMAL,
JOINT_MIDDLE_INTERMEDIATE,
JOINT_MIDDLE_DISTAL,
JOINT_MIDDLE_TIP,
JOINT_RING_METACARPAL,
JOINT_RING_PROXIMAL,
JOINT_RING_INTERMEDIATE,
JOINT_RING_DISTAL,
JOINT_RING_TIP,
JOINT_PINKY_METACARPAL,
JOINT_PINKY_PROXIMAL,
JOINT_PINKY_INTERMEDIATE,
JOINT_PINKY_DISTAL,
JOINT_PINKY_TIP
} HandJoint;
// Notes:
// - getDisplayFrequency may return 0.f if the information is unavailable.
// - For isDown, changed can be set to false if change information is unavailable or inconvenient.
@ -106,7 +135,7 @@ typedef struct HeadsetInterface {
bool (*isDown)(Device device, DeviceButton button, bool* down, bool* changed);
bool (*isTouched)(Device device, DeviceButton button, bool* touched);
bool (*getAxis)(Device device, DeviceAxis axis, float* value);
bool (*getSkeleton)(Device device, float* poses, uint32_t* poseCount);
bool (*getSkeleton)(Device device, float* poses);
bool (*vibrate)(Device device, float strength, float duration, float frequency);
struct ModelData* (*newModelData)(Device device, bool animated);
bool (*animate)(Device device, struct Model* model);

View File

@ -47,6 +47,7 @@ static struct {
Canvas* canvases[4];
ovrTracking tracking[3];
ovrHandPose handPose[2];
ovrHandSkeleton skeleton[2];
ovrInputCapabilityHeader hands[2];
ovrInputStateTrackedRemote input[2];
uint32_t changedButtons[2];
@ -323,6 +324,75 @@ static bool vrapi_getAxis(Device device, DeviceAxis axis, float* value) {
return false;
}
static bool vrapi_getSkeleton(Device device, float* poses) {
if (device != DEVICE_HAND_LEFT && device != DEVICE_HAND_RIGHT) {
return false;
}
uint32_t index = device - DEVICE_HAND_LEFT;
ovrHandPose* handPose = &state.handPose[index];
ovrHandSkeleton* skeleton = &state.skeleton[index];
if (state.hands[index].Type != ovrControllerType_Hand || skeleton->Header.Version == 0 || handPose->HandConfidence != ovrConfidence_HIGH) {
return false;
}
float LOVR_ALIGN(16) globalPoses[ovrHandBone_Max * 8];
for (uint32_t i = 0; i < ovrHandBone_Max; i++) {
float* pose = &globalPoses[i * 8];
if (skeleton->BoneParentIndices[i] >= 0) {
memcpy(pose, &globalPoses[skeleton->BoneParentIndices[i] * 8], 8 * sizeof(float));
} else {
memcpy(pose + 0, &handPose->RootPose.Position.x, 3 * sizeof(float));
memcpy(pose + 4, &handPose->RootPose.Orientation.x, 4 * sizeof(float));
}
float LOVR_ALIGN(16) translation[4];
memcpy(translation, &skeleton->BonePoses[i].Position.x, 3 * sizeof(float));
quat_rotate(pose + 4, translation);
vec3_add(pose + 0, translation);
quat_mul(pose + 4, &handPose->BoneRotations[i].x);
}
// We try our best, okay?
static const uint32_t boneMap[HAND_JOINT_COUNT] = {
[JOINT_WRIST] = ovrHandBone_WristRoot,
[JOINT_THUMB_METACARPAL] = ovrHandBone_Thumb0,
[JOINT_THUMB_PROXIMAL] = ovrHandBone_Thumb2,
[JOINT_THUMB_DISTAL] = ovrHandBone_Thumb3,
[JOINT_THUMB_TIP] = ovrHandBone_ThumbTip,
[JOINT_INDEX_METACARPAL] = ovrHandBone_WristRoot,
[JOINT_INDEX_PROXIMAL] = ovrHandBone_Index1,
[JOINT_INDEX_INTERMEDIATE] = ovrHandBone_Index2,
[JOINT_INDEX_DISTAL] = ovrHandBone_Index3,
[JOINT_INDEX_TIP] = ovrHandBone_IndexTip,
[JOINT_MIDDLE_METACARPAL] = ovrHandBone_WristRoot,
[JOINT_MIDDLE_PROXIMAL] = ovrHandBone_Middle1,
[JOINT_MIDDLE_INTERMEDIATE] = ovrHandBone_Middle2,
[JOINT_MIDDLE_DISTAL] = ovrHandBone_Middle3,
[JOINT_MIDDLE_TIP] = ovrHandBone_MiddleTip,
[JOINT_RING_METACARPAL] = ovrHandBone_WristRoot,
[JOINT_RING_PROXIMAL] = ovrHandBone_Ring1,
[JOINT_RING_INTERMEDIATE] = ovrHandBone_Ring2,
[JOINT_RING_DISTAL] = ovrHandBone_Ring3,
[JOINT_RING_TIP] = ovrHandBone_RingTip,
[JOINT_PINKY_METACARPAL] = ovrHandBone_Pinky0,
[JOINT_PINKY_PROXIMAL] = ovrHandBone_Pinky1,
[JOINT_PINKY_INTERMEDIATE] = ovrHandBone_Pinky2,
[JOINT_PINKY_DISTAL] = ovrHandBone_Pinky3,
[JOINT_PINKY_TIP] = ovrHandBone_PinkyTip
};
for (uint32_t i = 1; i < HAND_JOINT_COUNT; i++) {
memcpy(&poses[i * 8], &globalPoses[boneMap[i] * 8], 8 * sizeof(float));
}
memcpy(poses + 0, &handPose->RootPose.Position.x, 3 * sizeof(float));
memcpy(poses + 4, &handPose->RootPose.Orientation.x, 4 * sizeof(float));
return true;
}
static bool vrapi_vibrate(Device device, float strength, float duration, float frequency) {
if (device != DEVICE_HAND_LEFT && device != DEVICE_HAND_RIGHT) {
return false;
@ -343,18 +413,18 @@ static struct ModelData* vrapi_newModelData(Device device, bool animated) {
return NULL;
}
ovrHandSkeleton skeleton;
skeleton.Header.Version = ovrHandVersion_1;
ovrHandedness hand = device == DEVICE_HAND_LEFT ? VRAPI_HAND_LEFT : VRAPI_HAND_RIGHT;
if (vrapi_GetHandSkeleton(state.session, hand, &skeleton.Header) != ovrSuccess) {
if (state.skeleton[device - DEVICE_HAND_LEFT].Header.Version == 0) {
return NULL;
}
ovrHandSkeleton* skeleton = &state.skeleton[device - DEVICE_HAND_LEFT];
ovrHandMesh* mesh = malloc(sizeof(ovrHandMesh));
float* inverseBindMatrices = malloc(ovrHandBone_MaxSkinnable * 16 * sizeof(float));
lovrAssert(mesh && inverseBindMatrices, "Out of memory");
mesh->Header.Version = ovrHandVersion_1;
ovrHandedness hand = device == DEVICE_HAND_LEFT ? VRAPI_HAND_LEFT : VRAPI_HAND_RIGHT;
if (vrapi_GetHandMesh(state.session, hand, &mesh->Header) != ovrSuccess) {
free(mesh);
return NULL;
@ -437,8 +507,8 @@ static struct ModelData* vrapi_newModelData(Device device, bool animated) {
model->skins[0].jointCount = model->jointCount;
model->skins[0].inverseBindMatrices = inverseBindMatrices;
for (uint32_t i = 0; i < model->jointCount; i++) {
ovrVector3f* position = &skeleton.BonePoses[i].Position;
ovrQuatf* orientation = &skeleton.BonePoses[i].Orientation;
ovrVector3f* position = &skeleton->BonePoses[i].Position;
ovrQuatf* orientation = &skeleton->BonePoses[i].Orientation;
model->nodes[i] = (ModelNode) {
.transform.properties.translation = { position->x, position->y, position->z },
@ -457,8 +527,8 @@ static struct ModelData* vrapi_newModelData(Device device, bool animated) {
// Get the global transform of the bone by multiplying by the parent's global transform
// This relies on the bones being ordered in hierarchical order
ovrMatrix4f parentTransform = ovrMatrix4f_CreateIdentity();
if (skeleton.BoneParentIndices[i] >= 0) {
parentTransform = globalTransforms[skeleton.BoneParentIndices[i]];
if (skeleton->BoneParentIndices[i] >= 0) {
parentTransform = globalTransforms[skeleton->BoneParentIndices[i]];
}
globalTransforms[i] = ovrMatrix4f_Multiply(&parentTransform, &localPose);
@ -472,8 +542,8 @@ static struct ModelData* vrapi_newModelData(Device device, bool animated) {
// This is somewhat slow, we use the fact that bones are sorted to reduce the work a bit.
model->nodes[i].childCount = 0;
model->nodes[i].children = children;
for (uint32_t j = i + 1; j < model->jointCount && j < skeleton.NumBones; j++) {
if ((uint32_t) skeleton.BoneParentIndices[j] == i) {
for (uint32_t j = i + 1; j < model->jointCount && j < skeleton->NumBones; j++) {
if ((uint32_t) skeleton->BoneParentIndices[j] == i) {
model->nodes[i].children[model->nodes[i].childCount++] = j;
children++;
}
@ -689,6 +759,15 @@ static void vrapi_update(float dt) {
}
case ovrControllerType_Hand:
// Cache hand skeleton
if (state.skeleton[i].Header.Version == 0) {
state.skeleton[i].Header.Version = ovrHandVersion_1;
ovrHandedness hand = i == 0 ? VRAPI_HAND_LEFT : VRAPI_HAND_RIGHT;
if (vrapi_GetHandSkeleton(state.session, hand, &state.skeleton[i].Header) != ovrSuccess) {
state.skeleton[i].Header.Version = 0;
}
}
state.handPose[i].Header.Version = ovrHandVersion_1;
vrapi_GetHandPose(state.session, header->DeviceID, state.displayTime, &state.handPose[i].Header);
break;
@ -720,6 +799,7 @@ HeadsetInterface lovrHeadsetVrApiDriver = {
.isDown = vrapi_isDown,
.isTouched = vrapi_isTouched,
.getAxis = vrapi_getAxis,
.getSkeleton = vrapi_getSkeleton,
.vibrate = vrapi_vibrate,
.newModelData = vrapi_newModelData,
.animate = vrapi_animate,