向量

向量相乘

  • 点乘:
向量点乘公式 点乘坐标运算
  • 叉乘:叉乘示意 叉乘坐标运算

注意,叉乘的方向取决于坐标系是左手系还是右手系.

常见软件使用坐标系如下:

  • OpenGL : 右手系
  • DirectX: 左手系
  • Unreal : 左手系
  • Unity : 左手系
  • glm : 右手系

矩阵

矩阵乘法

矩阵乘法运算 矩阵乘法运算(三维示意)

值得注意的是,在矩阵乘法中,乘法交换律是不满足的.
又由于各种平台对一维向量的表示不同(行向量还是列向量),所以在矩阵乘法中顺序尤为重要.

比如MVP矩阵,在OpenGL中使用的是列向量,所以MVP矩阵的乘法顺序是P * V * M * v.
而在DirectX中使用的是行向量,所以MVP矩阵的乘法顺序是v * M * v * P .

以下是常见软件向量表示方法:

  • OpenGL : 列向量
  • Unity : 列向量
  • DirectX: 行向量
  • glm : 列向量

矩阵与向量相乘

矩阵与向量相乘运算

我们的模型顶点一般是一个三维向量,我们可以利用举证对这个向量进行变换,比如平移,旋转,缩放等操作.

缩放矩阵

缩放矩阵 注意,第四个缩放向量仍然是1,因为在3D空间中缩放w分量是无意义的.w分量另有其他用途,在后文中会说明.

位移矩阵

位移矩阵 这里如果没有w分量我们是不能位移向量的

旋转矩阵

旋转矩阵 旋转矩阵只能绕x,y,z轴旋转,且必须依次旋转,这就导致了万向锁,当然可以使用一个可以绕任意轴旋转的矩阵,但这样就需要更多的计算量(如下图所示).常用的方法是四元数. 绕任意轴旋转矩阵

矩阵结合

在结合最终的变换矩阵时,我们需要注意矩阵的乘法顺序.

  1. 缩放
  2. 旋转
  3. 位移

glm

glm是一个开源的数学库,可以帮助我们更方便的进行矩阵运算.

我们需要的GLM的大多数功能都可以从下面这3个头文件中找到:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

使用以下代码创建变换矩阵:

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
glm::mat4 trans(1.0f);//初始化为单位矩阵,否则后面步骤无效
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));

vec = trans * vec;

应用到shader

在glsl中,我们也有mat4类型,可以更改我们的VertexShader如下:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 transform;

void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}

接下来要做的事情就简单了,就是在程序中想gpu塞入一个uniform变量,我们对此已经轻车熟路了.只是需要使用到的函数不太一样.

unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

这里glUniformMatrix4fv的参数如下:

  • 第一个参数是uniform变量的位置
  • 第二个参数是矩阵的数量
  • 第三个参数是是否进行转置
  • 第四个参数是矩阵的指针

我们只要已经按要求设置好了我们的trans变量,就可以得到我们想要的效果了.
这里实现了一个旋转速度不断加快的效果:
旋转效果

总结

在学习本节之后,我们终于可以准备迈入3D世界了,在下一节中,我们将学习一些让人十分激动的效果.