1 glm::mat4矩阵插值
在glm中我们可以使用glm::slerp方法对四元数glm::quat进行插值,比如
glm::quat result_quat = glm::slerp(start_quat, end_quat, t);
其中start_quat为源四元数,end_quat为目标四元数,t为插值系数。
但是glm::mat4是一个变换矩阵,那么既包括旋转,同时也包含位移和缩放信息,在glm中目前没有提供一个现成的函数进行glm::mat4的插值。
我封装了两个函数,在插值过的过程中只对旋转和位移进行插值。
方法一:
static glm::mat4 slerp_matrix2(const glm::mat4& start, const glm::mat4& end, float t) {
// 方法2
glm::quat start_quat = glm::quat_cast(start);
glm::quat end_quat = glm::quat_cast(end);
glm::quat result_quat = glm::slerp(start_quat, end_quat, t);
glm::mat4 result_mat = glm::mat4_cast(result_quat);
result_mat[3] = start[3] * (1 - t) + end[3] * t;
return result_mat;
}
方法二:
static glm::mat4 slerp_matrix1(const glm::mat4& start, const glm::mat4& end, float t) {
// 方法1
// 提取起始矩阵的旋转部分
glm::mat3 start_matrix(
start[0][0], start[0][1], start[0][2],
start[1][0], start[1][1], start[1][2],
start[2][0], start[2][1], start[2][2]
);
glm::quat start_quat = glm::quat_cast(start_matrix);
// 提取结束矩阵的旋转部分
glm::mat3 end_matrix(
end[0][0], end[0][1], end[0][2],
end[1][0], end[1][1], end[1][2],
end[2][0], end[2][1], end[2][2]
);
glm::quat end_quat = glm::quat_cast(end_matrix);
// 插值四元数
glm::quat result_quat = glm::slerp(start_quat, end_quat, t);
// 将插值后的四元数转换回旋转矩阵
glm::mat3 result_rotation = glm::mat3_cast(result_quat);
// 构造最终的插值矩阵
glm::mat4 result_mat = glm::mat4(1.0f);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
result_mat[i][j] = result_rotation[i][j];
}
}
// 应用平移插值
glm::vec3 start_translation = glm::vec3(start[3]);
glm::vec3 end_translation = glm::vec3(end[3]);
glm::vec3 result_translation = glm::mix(start_translation, end_translation, t);
result_mat[3] = glm::vec4(result_translation, 1.0f);
return result_mat;
}
上述两个方法的实现思路差不多,旋转部分插值使用四元数,位移部分插值按插值系数进行插值就行,然后再将旋转部分和位移部分进行整合,形成最后的变换矩阵。
上述例子的测试代码如下:
#include <iostream>
#include "glm/glm.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"
static glm::mat4 slerp_matrix1(const glm::mat4& start, const glm::mat4& end, float t) {
// 方法1
// 提取起始矩阵的旋转部分
glm::mat3 start_matrix(
start[0][0], start[0][1], start[0][2],
start[1][0], start[1][1], start[1][2],
start[2][0], start[2][1], start[2][2]
);
glm::quat start_quat = glm::quat_cast(start_matrix);
// 提取结束矩阵的旋转部分
glm::mat3 end_matrix(
end[0][0], end[0][1], end[0][2],
end[1][0], end[1][1], end[1][2],
end[2][0], end[2][1], end[2][2]
);
glm::quat end_quat = glm::quat_cast(end_matrix);
// 插值四元数
glm::quat result_quat = glm::slerp(start_quat, end_quat, t);
// 将插值后的四元数转换回旋转矩阵
glm::mat3 result_rotation = glm::mat3_cast(result_quat);
// 构造最终的插值矩阵
glm::mat4 result_mat = glm::mat4(1.0f);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
result_mat[i][j] = result_rotation[i][j];
}
}
// 应用平移插值
glm::vec3 start_translation = glm::vec3(start[3]);
glm::vec3 end_translation = glm::vec3(end[3]);
glm::vec3 result_translation = glm::mix(start_translation, end_translation, t);
result_mat[3] = glm::vec4(result_translation, 1.0f);
return result_mat;
}
static glm::mat4 slerp_matrix2(const glm::mat4& start, const glm::mat4& end, float t) {
// 方法2
glm::quat start_quat = glm::quat_cast(start);
glm::quat end_quat = glm::quat_cast(end);
glm::quat result_quat = glm::slerp(start_quat, end_quat, t);
glm::mat4 result_mat = glm::mat4_cast(result_quat);
result_mat[3] = start[3] * (1 - t) + end[3] * t;
return result_mat;
}
int main() {
glm::mat4 start_matrix(1.0);
glm::mat4 end_matrix = glm::mat4(
0.0, -1.0, 0.0, 0.0,
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
5.0, 6.0, 7.0, 1.0);
glm::mat4 interpolation_matrix_1 = slerp_matrix1(start_matrix, end_matrix, 0.7);
glm::mat4 interpolation_matrix_2 = slerp_matrix2(start_matrix, end_matrix, 0.7);
bool compare = (interpolation_matrix_1 == interpolation_matrix_2);
return 0;
}
在示例代码中,使用方法一和方法二对同一个输入矩阵按相同系数进行插值,然后比较两个方法的插值结果是否一致。
参考链接
本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:glm – 使用glm对两个glm::mat4变换矩阵进行插值
原文链接:https://www.stubbornhuang.com/3054/
发布于:2024年07月24日 21:24:40
修改于:2024年07月24日 21:24:40
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论
50