• 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

  • 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

glm – 使用glm对两个glm::mat4变换矩阵进行插值

3D数学基础 发布于2024-07-24 阅读 1,586次 0次评论 0次点赞 本文共3472个字,阅读需要9分钟。

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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
Assimp的aiMatrix4x4与glm的mat4相互转换
3D数学基础
下一篇
Blender - 如何安装插件
Blender
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号