渲染独立骨骼
Rendering independent bones
我正在尝试根据给定的位置在 3D space 中渲染一只手的模型
来自 XR_EXT_hand_tracking 扩展的 XrHandJointLocationEXT
数组。
我同时使用 GTLF hand models from Valve,它们的骨骼数量正确
匹配 XrHandJointEXT 枚举中 OpenXR 规范定义的关节。
我的渲染如下:
每一帧我都通过乘以当前变换来独立更新每个关节
与从 GLTF 模型中检索到的逆绑定矩阵。 XrPosef
是相对于 3D space 中心的。我正在使用 cglm 来处理所有矩阵计算。
for (size_t i = 0; i < XR_HAND_JOINT_COUNT_EXT; ++i) {
const XrHandJointLocationEXT *joint = &locations->jointLocations[i];
const XrPosef *pose = &joint->pose;
glm_mat4_identity(model->bones[i]);
vec3 position;
wxrc_xr_vector3f_to_cglm(&pose->position, position);
glm_translate(model->bones[i], position);
versor orientation;
wxrc_xr_quaternion_to_cglm(&pose->orientation, orientation);
glm_quat_rotate(model->bones[i], orientation, model->bones[i]);
glm_mat4_mul(model->bones[i], model->inv_bind[i], model->bones[i]);
}
然后 bones
数组与 view-proj
一起上传到顶点着色器
矩阵,为 HMD 的每个 eye
计算。
#version 320 es"
uniform mat4 vp;
uniform mat4 bones[26];
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tex_coord;
layout (location = 2) in uvec4 joint;
layout (location = 3) in vec4 weight;
out vec2 vert_tex_coord;
void main() {
mat4 skin =
bones[joint.x] * weight.x +
bones[joint.y] * weight.y +
bones[joint.z] * weight.z +
bones[joint.w] * weight.w;
gl_Position = vp * skin * vec4(pos, 1.0);
vert_tex_coord = tex_coord;
}
计算方法是否正确?我得到了不错但“有问题”的结果。如你看到的
在下面的截图中,我在手的顶部渲染了两个独立的关节
模型,你可以看到拇指上有一个小故障。
计算骨骼变换时是否应该考虑父骨骼?
终于找到了我的问题的答案:GTLF 模型的关节顺序与顺序 XrHandJointEXT 不匹配,导致正确的变换应用于错误的关节。
在我的例子中,我的模型将 Wrist
节点定义为第一个节点,将 Palm
节点定义为最后一个节点,其中 OpenXR 将 XR_HAND_JOINT_PALM_EXT
定义为第一个节点,并且XR_HAND_JOINT_WRIST_EXT
作为第二个。
这是更新函数的代码
bool
wxrc_hand_model_update(struct wxrc_hand_model *model,
const XrHandJointLocationEXT *locations)
{
/*
* OpenXR defines joint 0 as XR_HAND_JOINT_PALM_EXT, but the valve hand
* model defines Palm as the last joint
* TODO: handle this dynamically for other models
*/
static const size_t convert[26] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0
};
for (size_t i = 0; i < XR_HAND_JOINT_COUNT_EXT; ++i) {
const XrHandJointLocationEXT *joint = &locations[convert[i]];
const XrPosef *pose = &joint->pose;
mat4 transform = GLM_MAT4_IDENTITY_INIT;
vec3 position;
wxrc_xr_vector3f_to_cglm(&pose->position, position);
glm_translate(transform, position);
versor orientation;
wxrc_xr_quaternion_to_cglm(&pose->orientation, orientation);
glm_quat_rotate(transform, orientation, transform);
glm_mat4_mul(transform, model->inv_bind[i], model->bones[i]);
}
return true;
}
我正在尝试根据给定的位置在 3D space 中渲染一只手的模型
来自 XR_EXT_hand_tracking 扩展的 XrHandJointLocationEXT
数组。
我同时使用 GTLF hand models from Valve,它们的骨骼数量正确
匹配 XrHandJointEXT 枚举中 OpenXR 规范定义的关节。
我的渲染如下:
每一帧我都通过乘以当前变换来独立更新每个关节
与从 GLTF 模型中检索到的逆绑定矩阵。 XrPosef
是相对于 3D space 中心的。我正在使用 cglm 来处理所有矩阵计算。
for (size_t i = 0; i < XR_HAND_JOINT_COUNT_EXT; ++i) {
const XrHandJointLocationEXT *joint = &locations->jointLocations[i];
const XrPosef *pose = &joint->pose;
glm_mat4_identity(model->bones[i]);
vec3 position;
wxrc_xr_vector3f_to_cglm(&pose->position, position);
glm_translate(model->bones[i], position);
versor orientation;
wxrc_xr_quaternion_to_cglm(&pose->orientation, orientation);
glm_quat_rotate(model->bones[i], orientation, model->bones[i]);
glm_mat4_mul(model->bones[i], model->inv_bind[i], model->bones[i]);
}
然后 bones
数组与 view-proj
一起上传到顶点着色器
矩阵,为 HMD 的每个 eye
计算。
#version 320 es"
uniform mat4 vp;
uniform mat4 bones[26];
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tex_coord;
layout (location = 2) in uvec4 joint;
layout (location = 3) in vec4 weight;
out vec2 vert_tex_coord;
void main() {
mat4 skin =
bones[joint.x] * weight.x +
bones[joint.y] * weight.y +
bones[joint.z] * weight.z +
bones[joint.w] * weight.w;
gl_Position = vp * skin * vec4(pos, 1.0);
vert_tex_coord = tex_coord;
}
计算方法是否正确?我得到了不错但“有问题”的结果。如你看到的 在下面的截图中,我在手的顶部渲染了两个独立的关节 模型,你可以看到拇指上有一个小故障。
计算骨骼变换时是否应该考虑父骨骼?
终于找到了我的问题的答案:GTLF 模型的关节顺序与顺序 XrHandJointEXT 不匹配,导致正确的变换应用于错误的关节。
在我的例子中,我的模型将 Wrist
节点定义为第一个节点,将 Palm
节点定义为最后一个节点,其中 OpenXR 将 XR_HAND_JOINT_PALM_EXT
定义为第一个节点,并且XR_HAND_JOINT_WRIST_EXT
作为第二个。
这是更新函数的代码
bool
wxrc_hand_model_update(struct wxrc_hand_model *model,
const XrHandJointLocationEXT *locations)
{
/*
* OpenXR defines joint 0 as XR_HAND_JOINT_PALM_EXT, but the valve hand
* model defines Palm as the last joint
* TODO: handle this dynamically for other models
*/
static const size_t convert[26] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0
};
for (size_t i = 0; i < XR_HAND_JOINT_COUNT_EXT; ++i) {
const XrHandJointLocationEXT *joint = &locations[convert[i]];
const XrPosef *pose = &joint->pose;
mat4 transform = GLM_MAT4_IDENTITY_INIT;
vec3 position;
wxrc_xr_vector3f_to_cglm(&pose->position, position);
glm_translate(transform, position);
versor orientation;
wxrc_xr_quaternion_to_cglm(&pose->orientation, orientation);
glm_quat_rotate(transform, orientation, transform);
glm_mat4_mul(transform, model->inv_bind[i], model->bones[i]);
}
return true;
}