4x4 矩阵预乘和后乘

2024-02-07

我有以下功能:

void Matrix::Scale(const float xScale, const float yScale, const float zScale)
{
    Matrix scaleMatrix;
    scaleMatrix.m_data[M11] = xScale;
    scaleMatrix.m_data[M22] = yScale;
    scaleMatrix.m_data[M33] = zScale;
    *this *= scaleMatrix;
}

void Matrix::Translate(const float xTranslation, const float yTranslation, const float zTranslation)
{
    Matrix translationMatrix;
    translationMatrix.m_data[M14] = xTranslation;
    translationMatrix.m_data[M24] = yTranslation;
    translationMatrix.m_data[M34] = zTranslation;
    *this *= translationMatrix;
}

我不确定这两个函数的最后一行。我应该进行预乘法还是后乘法(即我现在正在做的事情)。它对这个类的使用有什么影响?我正在使用 OpenGL 的类,因此任何与该类的相似之处可能都会有用。

Edit:

我的着色器代码如下所示:

void main()
{
    gl_Position = vec4(v_xy, 0.0, 1.0) * v_ModelMatrix * v_ViewMatrix * v_ProjectionMatrix;
    f_uv = v_uv;
}

我的矩阵乘法函数如下所示:

// Row 1
result[M11] = lhs[M11] * rhs[M11]   +   lhs[M12] * rhs[M21]   +   lhs[M13] * rhs[M31]   +   lhs[M14] * rhs[M41];    // Column 1
result[M12] = lhs[M11] * rhs[M12]   +   lhs[M12] * rhs[M22]   +   lhs[M13] * rhs[M32]   +   lhs[M14] * rhs[M42];    // Column 2
result[M13] = lhs[M11] * rhs[M13]   +   lhs[M12] * rhs[M23]   +   lhs[M13] * rhs[M33]   +   lhs[M14] * rhs[M43];    // Column 3
result[M14] = lhs[M11] * rhs[M14]   +   lhs[M12] * rhs[M24]   +   lhs[M13] * rhs[M34]   +   lhs[M14] * rhs[M44];    // Column 4

// Row 2
result[M21] = lhs[M21] * rhs[M11]   +   lhs[M22] * rhs[M21]   +   lhs[M23] * rhs[M31]   +   lhs[M24] * rhs[M41];    // Column 1
result[M22] = lhs[M21] * rhs[M12]   +   lhs[M22] * rhs[M22]   +   lhs[M23] * rhs[M32]   +   lhs[M24] * rhs[M42];    // Column 2
result[M23] = lhs[M21] * rhs[M13]   +   lhs[M22] * rhs[M23]   +   lhs[M23] * rhs[M33]   +   lhs[M24] * rhs[M43];    // Column 3
result[M24] = lhs[M21] * rhs[M14]   +   lhs[M22] * rhs[M24]   +   lhs[M23] * rhs[M34]   +   lhs[M24] * rhs[M44];    // Column 4

// Row 3
result[M31] = lhs[M31] * rhs[M11]   +   lhs[M32] * rhs[M21]   +   lhs[M33] * rhs[M31]   +   lhs[M34] * rhs[M41];    // Column 1
result[M32] = lhs[M31] * rhs[M12]   +   lhs[M32] * rhs[M22]   +   lhs[M33] * rhs[M32]   +   lhs[M34] * rhs[M42];    // Column 2
result[M33] = lhs[M31] * rhs[M13]   +   lhs[M32] * rhs[M23]   +   lhs[M33] * rhs[M33]   +   lhs[M34] * rhs[M43];    // Column 3
result[M34] = lhs[M31] * rhs[M14]   +   lhs[M32] * rhs[M24]   +   lhs[M33] * rhs[M34]   +   lhs[M34] * rhs[M44];    // Column 4

// Row 4
result[M41] = lhs[M41] * rhs[M11]   +   lhs[M42] * rhs[M21]   +   lhs[M43] * rhs[M31]   +   lhs[M44] * rhs[M41];    // Column 1
result[M42] = lhs[M41] * rhs[M12]   +   lhs[M42] * rhs[M22]   +   lhs[M43] * rhs[M32]   +   lhs[M44] * rhs[M42];    // Column 2
result[M43] = lhs[M41] * rhs[M13]   +   lhs[M42] * rhs[M23]   +   lhs[M43] * rhs[M33]   +   lhs[M44] * rhs[M43];    // Column 3
result[M44] = lhs[M41] * rhs[M14]   +   lhs[M42] * rhs[M24]   +   lhs[M43] * rhs[M34]   +   lhs[M44] * rhs[M44];    // Column 4

我的印象是,如果你对矩阵进行后乘(即viewMatrix = transform * viewMatrix;)那么你的着色器代码需要以与我当前相反的顺序应用 MVP?

Edit2:

上的汇总表http://scratchapixel.com/lessons/3d-basic-lessons/lesson-4-geometry/conventions-again-row-major-vs-column-major-vector/ http://scratchapixel.com/lessons/3d-basic-lessons/lesson-4-geometry/conventions-again-row-major-vs-column-major-vector/让我感到困惑的是,因为我正在使用 OpenGL 的后乘法(指示列优先),但我的矩阵在内存中以行优先布局?


您似乎在这里混合了两个问题,我猜这就是 scrapapixel 上的网页试图解释的内容。从您所引用的页面上的信息来看,事情似乎很清楚,但是很难将此类内容牢记在心。你有理论(你用笔和纸在数学中做什么)和你的实现(C++)。这是两个不同的问题。

数学:您可以使用两种符号,即列专业或行专业。正如 GraphicsMuncher 在此网页上提到的,对于行主向量,在纸上,您需要编写向量矩阵乘法 vM,其中 v 是行向量 (1x4),M 是您的 4x4 矩阵,为什么,因为您只能在数学上写[1x4]*[4x4],而不是相反。同样,如果您使用列,则向量需要垂直书写,或以符号 [4x1](4 行,1 列)的形式书写。因此,与矩阵的乘法只能写成:[4x4][4x1]。矩阵放在向量:Mv 前面。第一个表示法称为后乘法,第二个 (Mv) 称为前乘法(矩阵在前面)。 现在,正如 GraphicsMuncher 所提到的,如果您需要变换向量(或点),那么当您将它们写在纸上时,您需要注意乘法的顺序。如果你想用矩阵 T 平移一些东西,然后用 R 旋转,然后用 S 缩放,那么在列主要世界中,你需要写 v' = S * R * T * v。在行主要世界中你需要写成 v' = v * T * R * S。

这是为了理论。

计算机:当你决定用 C++ 实现这个时,就到了关键的时刻。这样做的好处是 C++ 不会强加给你任何事情。您可以按照您想要的方式将矩阵系数的值映射到内存中,并且可以编写代码以按照您想要的方式执行与另一个矩阵的矩阵乘法。同样,如何访问向量矩阵乘法的系数完全取决于您。

您需要清楚地区分如何在内存中映射系数,以及从数学角度来看需要使用哪些约定来表示向量。这是两个独立的问题。例如,在您的情况下,您可能将矩阵类声明为包含 16 个连续浮点数的数组。没关系。其中系数 m14、m24、m34 表示矩阵的平移部分(Tx、Ty、Tz),因此您假设您的“约定”是行优先,即使您被告知使用 OpenGL 矩阵约定(据说是列)主要的。在这里,您的困惑来自于这样一个事实:内存中系数的映射与您自己制作的“列主”矩阵的心理表示不同。你编码“行”,但据说你使用(从数学角度来看)“列”,因此你很难理解你做的事情是对还是错。

重要的是要将矩阵视为由三个轴和平移定义的坐标系的表示。将这些数据存储在内存中的位置和方式完全取决于您。假设代表坐标系三个轴的三个向量分别命名为AX(x,y,z)、AY(x,y,z)、AZ(x,y,z),平移向量记为(Tx ,Ty,Tz),那么从数学上来说,如果你使用你拥有的列向量(我猜乳胶不支持):

    AXx AYx AZx Tx 
M = AXy AYy AZy Ty
    AXz AYz AZz Tz
     0   0   0  1 

坐标系的轴是垂直书写的。现在,如果您使用行优先:

    AXx AXy AXz 0 
M = AYx AYy AYz 0
    AZx AZy AZz 0
     Tx  Ty  Tz 1

坐标系的轴是水平书写的。因此,现在涉及计算机世界的问题是如何将这些系数存储在内存中。你也可以这样做:

float m[16] = { AXx, AXy, AXz, 0, AYx, AYy, AYz, 0, AZx, AZy, AZz, 0, Tx, Ty, Tz, 1}; 

它会告诉您您使用哪种约定吗?不,你还可以写:

float m[16] = { AXx, AXy, AXz, Tx, AYx, AYy, AYz, Ty, AZx, AZy, AZz, Tz, 0, 0, 0, 1}; 

or

float m[16] = { AXx, AYx, AZx, Tx, AXy, AYy, AZy, Ty, AXz, AYz, AZz, Tz, 0, 0, 0, 1};

再说一次,这并没有给你一个具体的指示,告诉你你使用的是哪种“数学”约定。您只是以不同的方式将 16 个系数存储在内存中,只要您知道这种方式是什么就完全没问题,以便您以后可以适当地访问它们。现在请记住,无论您使用行还是列数学符号,向量乘以矩阵都应该给出相同的向量。因此,真正重要的是,将向量的 (x,y,z) 坐标乘以矩阵中的正确系数,这需要了解“您”如何决定将矩阵系数存储在内存中:

Vector3 vecMatMult (Vector3 v,
    float AXx, float AXy, float AXz, float Tx,
    float AYx, float AYy, float AYz, float Ty,
    float AZz, float AZy, float AZz, float Tz) {
    return Vector3(
        v.x * AXx + v.y * AYx + v.z * AZx + Tx,
        v.x * AXy + v.y * AYy + v.z * AZy + Ty,
        v.x * AXz + v.y * AYz + v.z * AZz + Tz
}

编辑:上面的代码是错误的,现在修复它。

我编写这个函数是为了强调这样一个事实:无论您使用哪种约定,向量 * 矩阵乘法的结果都只是向量的输入坐标与坐标系的轴坐标 AX、AY 和 AZ 之间的乘法和加法(无论您使用的符号,无论您如何将它们存储在内存中)。

如果您使用:

float m[16] = { AXx, AXy, AXz, 0, AYx, AYy, AYz, 0, AZx, AZy, AZz, 0, Tx, Ty, Tz, 1};

您需要致电:

vecMatMult(v, m[0], m[1], m[2], m[12], m[4], m[5], m[6], m[13], ...

如果您使用:

float m[16] = { AXx, AYx, AZx, Tx, AXy, AYy, AZy, Ty, AXz, AYz, AZz, Tz, 0, 0, 0, 1};

您需要致电:

vecMatMult(v, m[0], m[4], m[8], m[3], m[1], m[5], m[9], m[10], ...

这是否告诉您您使用哪种约定?不需要。当您进行 vec * mat 乘法时,您只需要在正确的位置调用正确的系数即可。这就是它的全部内容,尽管看起来可能令人不安。

现在,当涉及到 mat * mat 乘法时,情况略有不同。您可以假设矩阵相乘的顺序不同。所以 R * S * T 与 T * S * R 不同。顺序确实很重要。现在,如果您使用“行专业”,那么从数学上讲,您需要编写(使用您的符号):

mt11 = ml11 * mr11 + ml12 * mr21 + m13 * m31 + ml14 * mr41

其中 ml 是左手矩阵,mr 是右手矩阵:mt = ml * mr。但请注意,我没有使用方括号 [] 作为访问索引,因为我不想建议我们访问存储在此处的一维数组中的元素。我们只是在讨论矩阵的系数。如果您想用 C++ 编写此代码,那么这完全取决于您如何将系数存储在内存中,如上所述。

希望能帮助到你。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4x4 矩阵预乘和后乘 的相关文章

  • 用于代数简化和求解的 C# 库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 网络上有很多代数求解器和简化器 例如 algebra com 上不错的代数求解器和简化器 然而 我正在
  • 为什么 int8_t 和用户通过 cin 输入显示奇怪的结果[重复]

    这个问题在这里已经有答案了 一小段代码让我发疯 但希望你能阻止我跳出窗外 看这里 include
  • 复制 std::function 的成本有多高?

    While std function是可移动的 但在某些情况下不可能或不方便 复制它会受到重大处罚吗 它是否可能取决于捕获变量的大小 如果它是使用 lambda 表达式创建的 它依赖于实现吗 std function通常被实现为值语义 小缓
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • qdbusxml2cpp 未知类型

    在使用 qdbusxml2cpp 程序将以下 xml 转换为 Qt 类时 我收到此错误 qdbusxml2cpp c ObjectManager a ObjectManager ObjectManager cpp xml object ma
  • 为什么调用非 const 成员函数而不是 const 成员函数?

    为了我的目的 我尝试包装一些类似于 Qt 共享数据指针的东西 经过测试 我发现当应该调用 const 函数时 会选择它的非 const 版本 我正在使用 C 0x 选项进行编译 这是一个最小的代码 struct Data int x con
  • 具有交替类型的可变参数模板参数包

    我想知道是否可以使用参数包捕获交替参数模式 例如 template
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • C# 中的合并运算符?

    我想我记得看到过类似的东西 三元运算符 http msdn microsoft com en us library ty67wk28 28VS 80 29 aspx在 C 中 它只有两部分 如果变量值不为空 则返回变量值 如果为空 则返回默
  • 外键与独立关系 - Entity Framework 5 有改进吗?

    我读过了several http www ladislavmrnka com 2011 05 foreign key vs independent associations in ef 4 文章和问题 https stackoverflow
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • 如何设置 log4net 每天将我的文件记录到不同的文件夹中?

    我想将每天的所有日志保存在名为 YYYYMMdd 的文件夹中 log4net 应该根据系统日期时间处理创建新文件夹 我如何设置它 我想将一天中的所有日志保存到 n 个 1MB 的文件中 我不想重写旧文件 但想真正拥有一天中的所有日志 我该如
  • C++ 函数重载类似转换

    我收到一个错误 指出两个重载具有相似的转换 我尝试了太多的事情 但没有任何帮助 这是那段代码 CString GetInput int numberOfInput BOOL clearBuffer FALSE UINT timeout IN
  • 无法接收 UDP Windows RT

    我正在为 Windows 8 RT 编写一个 Windows Store Metro Modern RT 应用程序 需要在端口 49030 上接收 UDP 数据包 但我似乎无法接收任何数据包 我已按照使用教程进行操作DatagramSock
  • WebSocket安全连接自签名证书

    目标是一个与用户电脑上安装的 C 应用程序交换信息的 Web 应用程序 客户端应用程序是 websocket 服务器 浏览器是 websocket 客户端 最后 用户浏览器中的 websocket 客户端通过 Angular 持久创建 并且
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看

随机推荐

  • 保护 Linux Web 服务器的公共访问

    我想设置一个便宜的 Linux 机器作为 Web 服务器来托管各种 Web 技术 我想到了 PHP 和 Java EE 但我将来也想尝试使用 Ruby 或 Python 我相当精通设置 Tomcat 在 Linux 上运行以提供 Java
  • UILineBreakMode 与 NSLineBreakMode

    我看到一些 UIStringDrawing 方法已更新为使用 NSLineBreakMode 而不是 iOS 6 0 中的 UILineBreakMode E g CGSize sizeWithFont UIFont font constr
  • 原型继承最佳实践?

    我刚刚接触 JavaScript 并试图了解原型继承 似乎有多种方法可以达到相同的效果 所以我想看看是否有任何最佳实践或理由以一种方式做事而不是另一种方式 这就是我要说的 Method 1 function Rabbit this name
  • 2页出现死锁

    我正在解决在生产环境中看到的一些死锁 我对此很陌生 但有些事情对我来说似乎很奇怪 所以我有下面的死锁图 死锁的右侧是更新 如下所示 UPDATE order sub line SET sub line status 300 WHERE or
  • 从 C# 调用方中的非托管 DLL 捕获标准输出

    我有一个 C 应用程序通过一些 C CLI 编组代码调用本机 C DLL C gt C CLI gt C 无 CLR 我希望 DLL 在运行时将字符串更新发送回调用应用程序 目前 非托管 DLL 将输出写入 stdout 本质上我需要在 U
  • AngularJs 将 HTML 中每个 ng-repeat 的实例传递给指令

    我认为这应该很简单 但我错过了一些东西 我怎样才能通过flowObj in my ng repeat下面是我的指令 我想将它传递给我的指令 然后单击 使用它FlowObj 然后应用一些逻辑 我尝试在我的指令中使用注释代码 scope tes
  • Ruby:为什么我不能创建新文件?

    我正在尝试创建一个 json 文件并写入它 我的代码如下所示 def save as json object f File new file json f puts object to json w f close end save as
  • android-support-v4 删除未使用的类

    实际上 我正在尝试将应用程序的 apk 缩小到尽可能小的大小 我目前导入了 android support v4 jar 文件 我的问题是 如何从此 jar 文件中删除未使用的类 经过一番搜索后没有找到任何信息 如果 ProGuard 是解
  • 如何使用 Salt 创建 SHA256 哈希?

    我目前正在开发一个 Visual Studio C Windows 窗体项目 但是 我对 SHA256 salted 的工作原理感到困惑 我在网上找到了一些例子 但无法理解如何调用这个函数 我想在连接到数据库 Microsoft Acces
  • 如何在 ag-grid 表的页脚中启用或显示总行数

    我正在使用 Ag Grid 表 我想在表的页脚中显示总行 我如何通过使用 2 个表来实现它 第 1 个表用于实际数据 第 2 个表用于总计行 它与普通的不可滚动表格一起工作正常 但如果它是固定或可滚动表格 则顶部表格会滚动 但底部表格会粘在
  • 在 HashMap 或 LinkedList 中将嵌套类设为静态的原因是什么? [复制]

    这个问题在这里已经有答案了 在大多数情况下 我看到嵌套类是static 让我们举个例子Entry上课于HashMap static class Entry
  • Protractor browser.wait 不等待

    我假设 browser wait 应该是一个阻塞调用 但它没有按我的预期工作 这是我的样本 describe browser wait function beforeEach function browser wait function c
  • 问题:使用 Windows 7,运行我的应用程序时出现未经授权的访问异常

    我的应用程序引发未经授权的访问错误 运行我的应用程序时 我尝试访问以下位置的目录 Application UserAppDataPath 问题 它说我无权访问 Application UserAppDataPath 目录 有没有办法在我的应
  • pyqtgraph:同步不同图中轴的缩放

    我想同步几个 pyqtgraph 图的 X 轴 当用户通过鼠标交互重新缩放 X 轴时 例如 鼠标在 x 轴上时滚动滚轮 我想将相同的更改分配给所有其他绘图 那么我该怎么做呢 我从下面的基本示例中导出了最小化代码 我是否必须覆盖viewRan
  • 在 html 表 中将单行加粗 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我使用以下
  • 来自 iOS 的 Instagram 签名 API 调用

    对 Instagram 帖子方法进行签名 API 调用以关注用户 点赞用户的图像等 用户每小时的关注次数限制为 20 次 但如果我们进行签名 API 调用 那么用户每小时可以进行 60 次关注 但我的问题是如何进行签名 API 调用 我尝试
  • 限制 Apigility 中的结果

    我使用 Apigility 创建了一个代码连接 API 现在我正在使用标准创建存根 在我的PostResource有一种方法叫做fetchAll params array 我为该方法创建了代码 以便它返回一组可分页的结果 var Hydra
  • 在 MySQL 中查找同一个表中的重复项

    我有一个包含两列的表 艺术家 release id 我可以运行什么查询来显示重复记录 例如我的桌子是 ArtistX 45677 ArtistY 378798 ArtistX 45677 ArtistZ 123456 ArtistY 888
  • 显示ajax、Jquery返回的响应的html代码

    我有一个 jquery AJAX 函数 它检索一些 HTML 标记并将其显示在页面上 我还想显示返回的 HTML 的 html 代码 我四处寻找解决方案 但没有找到任何解决方案 有人可以帮忙吗 非常感谢 post get news php
  • 4x4 矩阵预乘和后乘

    我有以下功能 void Matrix Scale const float xScale const float yScale const float zScale Matrix scaleMatrix scaleMatrix m data