mirror of https://github.com/bjornbytes/lovr.git
vrapi_getSkeleton;
This commit is contained in:
parent
438f7ef0d6
commit
1b5e7b2203
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue