[C++]学习《DirectX12 3D 游戏开发实战》 第三天 变换

DirectXMath库提供的变换函数
#include <windows.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
#include <iomanip> // 为将数字精确到小数点后两位


using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;

ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v)
{
    XMFLOAT4 dest;
    XMStoreFloat4(&dest, v);

    os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ", " << dest.w << ")";
    return os;
}

ostream& XM_CALLCONV operator << (ostream& os, FXMMATRIX m)
{
    for (int i = 0; i < 4; ++i)
    {
        os << setprecision(2) << XMVectorGetX(m.r[i]) << "\t";
        os << XMVectorGetY(m.r[i]) << "\t";
        os << setprecision(2) << XMVectorGetZ(m.r[i]) << "\t";
        os << XMVectorGetW(m.r[i]);
        os << endl;
    }
    return os;
}

int main() {
    if (!XMVerifyCPUSupport())
    {
        cout << "directx math not supported" << endl;
        return 0;
    }

    //(x,y,z,0) 表示向量
    //(x,y,z,1) 表示点
    XMVECTOR a = XMVectorSet(0.5f, 2.0f, 1.0f, 0.0f);// 例3.2里的缩放比例
    XMVECTOR b3_2max = XMVectorSet(-4.0f, -4.0f, 0.0f, 1.0f); // 例3.2里的最小点坐标
    XMVECTOR c = XMVectorSet(12.0f, -10.0f, 0.0f, 1.0f); // 例3.4里的移动点
    XMVECTOR c3_4min = XMVectorSet(-8.0f, 2.0f, 0.0f, 1.0f); // 例3.4里的最小点坐标
 
    float k = (-30.0 / 180 ) * XM_PI;// 例3.3里的角度改弧度

    //缩放
    XMMATRIX S1 = XMMatrixScaling(0.5f, 2.0f, 1.0f);// 生成沿 x 轴、y 轴和 z 轴缩放的矩阵。 例3.2里的缩放矩阵
    XMMATRIX S2 = XMMatrixScalingFromVector(a);// 从 3D 向量生成缩放矩阵。

    //旋转
    XMMATRIX Rx = XMMatrixRotationX(k);// 生成绕 x 轴旋转的矩阵。输入绕 x 轴旋转的角度(以弧度为单位)。 在顺着面向原点的旋转轴观察时,角度是按顺时针方向测量的。
    XMMATRIX Ry = XMMatrixRotationY(k);// 生成绕 y 轴旋转的矩阵。输入绕 y 轴旋转的角度(以弧度为单位)。 在顺着面向原点的旋转轴观察时,角度是按顺时针方向测量的。
    XMMATRIX Rz = XMMatrixRotationZ(k);// 生成绕 z 轴旋转的矩阵。输入绕 z 轴旋转的角度(以弧度为单位)。 在顺着面向原点的旋转轴观察时,角度是按顺时针方向测量的。
    XMMATRIX Rn = XMMatrixRotationAxis(XMVectorSplatOne(), k);// 生成围绕任意轴旋转的矩阵。

    //平移
    XMMATRIX T1 = XMMatrixTranslation(12.0f, -10.0f, 0.0f);// 从指定的偏移量生成转换矩阵。 例3.4里的平移矩阵
    XMMATRIX T2 = XMMatrixTranslationFromVector(c);// 从向量生成转换矩阵。

    //向量与矩阵的乘积
    XMVECTOR x = XMVector3TransformCoord(c3_4min, T1);// 书上:计算向量与矩阵的乘积aA, 此函数针对点的变换,即总是默认a的w=1。 官方:按给定矩阵转换 3D 向量,将结果投影回 w = 1。
    XMVECTOR y = XMVector3TransformNormal(b3_2max,S1);// 书上:计算向量与矩阵的乘积aA, 此函数针对向量的变换,即总是默认a的w=0。 官方:按给定矩阵转换 3D 矢量法线。
    //对于最后的两个函数来说,用户不必显式设置w分量,因为在执行XMVector3TransformCoord时,默认w=1,而当执行XMVector3TransformNormal时,默认w=0.


    cout << "例3.2中的缩放矩阵 S1 = "                << endl << S1 << endl;
    cout << "3D向量中的分量构建的缩放矩阵 S2 = "      << endl << S2 << endl;
    cout << "绕x轴“逆时针”旋转30度的矩阵 Rx = "       << endl << Rx << endl;
    cout << "绕y轴“逆时针”旋转30度的矩阵 Ry = "       << endl << Ry << endl;
    cout << "绕z轴“逆时针”旋转30度的矩阵 Rz = "       << endl << Rz << endl;
    cout << "绕任意轴“逆时针”旋转30度的矩阵 Rn = "    << endl << Rn << endl;
    cout << "例3.4里的平移矩阵 T1 = "                << endl << T1 << endl;
    cout << "3D向量中的分量构建的平移矩阵 T2 = "      << endl << T2 << endl;
    cout << "例3.4中进行平移变换后的向量 x = "        << endl << x  << endl;
    cout << "例3.2中进行缩放变换后的向量 y = "        << endl << y  << endl;

}

运行结果:

个人总结笔记
1.1 线性变换 (linear transformation)

\tau(u+v)=\tau(u)+\tau(v)

\tau(ku)=k\tau(u)

u和v是任意3D向量,k为标量。

1.1.1 缩放 (scaling)

S(x,y,z)=(s_{x}x,s_{y}y,s_{z}z)

缩放矩阵 (scaling matrix):

S=\begin{bmatrix} s_{x} & 0 & 0\\ 0&s_{y} &0 \\ 0&0 & s_{z} \end{bmatrix}

对应逆矩阵:

S^{-1}=\begin{bmatrix} \frac{1}{s_{x}} & 0 & 0\\ 0&\frac{1}{s_{y}} &0 \\ 0& 0 & \frac{1}{s_{z}} \end{bmatrix}

1.1.2 旋转 (rotation)

绕x轴旋转:

R_{x}=\begin{bmatrix} 1& 0& 0& 0\\ 0& cos\Theta & sin\Theta & 0\\ 0& - sin\Theta& cos\Theta& 0\\ 0 & 0 & 0& 1 \end{bmatrix}

绕y轴旋转:

R_{y}=\begin{bmatrix} cos\Theta& 0& - sin\Theta& 0\\ 0& 1 & 0 & 0\\ sin\Theta& 0& cos\Theta& 0\\ 0 & 0 & 0& 1 \end{bmatrix}

绕z轴旋转:

R_{z}=\begin{bmatrix} cos\Theta & sin\Theta & 0& 0\\ -sin\Theta & cos\Theta & 0 & 0\\ 0& 0 & 1 &0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

绕任意轴旋转:

R_{n}=\begin{bmatrix} c+(1-c)x^2 & (1-c)xy+sz &(1-c)xz-sy \\ (1-c)xy-sz& c+(1-c)y^2& (1-c)yz+sz\\ (1-c)xz+sy& (1-c)yz-sx& c+(1-c)z^2 \end{bmatrix}

其中c=cos\Thetas=sin\Theta

1.2 仿射变换 (affine transformation)

一个线性变换 + 一个平移变换

\alpha (u)=\tau(u)+b

b为平移向量。

矩阵表示:

\alpha (u)=uA+b=[x,y,z]\begin{bmatrix} A_{11} & A_{12} &A_{13} \\ A_{21}&A_{22} &A_{23} \\ A_{31}& A_{32} & A_{33} \end{bmatrix}+[b_{x},b_{y},b_{z}]=[x',y',z']

A是一个线性变换的矩阵表示。

1.2.1 齐次坐标 (homogeneous coordinate)

(x,y,z,0) 表示向量;

(x,y,z,1) 表示点。

如果用w=1把坐标扩充为齐次坐标,那么就可以将上式更简洁地写作:

[x,y,z,1]\begin{bmatrix} A_{11} & A_{12} & A_{13} & 0\\ A_{21} & A_{22} & A_{23} & 0\\ A_{31} & A_{32} & A_{33} &0 \\ b_{x} & b_{y} & b_{z} & 1 \end{bmatrix}=[x',y',z',1]

1.2.2 平移 (translation)

平移矩阵 (translation matrix):

T=\begin{bmatrix} 1 & 0& 0&0 \\ 0& 1& 0 & 0\\ 0& 0 & 1 &0 \\ b _{x} &b _{y} &b _{z} & 1 \end{bmatrix}

对应逆矩阵:

T^{-1}=\begin{bmatrix} 1 & 0& 0 &0 \\ 0& 1& 0 & 0\\ 0& 0 & 1& 0\\ -b_x& -b_y &-b_z & 1 \end{bmatrix}

1.2.3 仿射变换矩阵的几何意义

刚体变换 (rigid body transformation) 本质是一种 保形 (shape preserving) 变换。

刚体变换用仿射变换来表示:

\alpha (x,y,z)=\tau (x,y,z)+b=x\tau (i)+y\tau (j)+z\tau (k)+b

\tau为描述物体旋转操作的旋转变换,b为定义物体平移操作的平移向量。

这种思路同样可以运用在缩放或 斜切 (skew) 变换上。

1.3 变换的复合 (composition of transformations)

C=SRT

S是缩放矩阵,R是旋转矩阵,T是平移矩阵。

1.4 坐标变换 (change of coordinate transformation)

不同标架间的坐标的转换。

//在本书上

标架 (frame) = 参考系 (frame of reference) = 空间 (space) = 坐标系 (coordinate system)

1.4.1 坐标变换的向量、点、矩阵表示

向量:(x',y',z')=xu_{B}+yv_{B}+zw_{B}

点   :(x',y',z')=xu_{B}+yv_{B}+zw_{B}+Q_{B}

从标架 A 变换到标架 B,u、v、w分别是指向标架 A 中 x轴,y轴,z轴 正方向上的单位向量。

如果使用齐次坐标,就可以用同一公式对点和向量进行处理:

(x',y',z',w)=xu_{B}+yv_{B}+zw_{B}+Q_{B}

如果 w=0,此式化简为 向量 的坐标变换公式;

如果 w=1,此式化简为 点 的坐标变换公式。

矩阵形式:

[x',y',z',w]=[x,y,z,w]\begin{bmatrix} u_{B}\\ v_{B}\\ w_{B}\\ Q_{B} \end{bmatrix}=[x,y,z,w]\begin{bmatrix} u_{x} &u_{y} &u_{z} &0 \\ v_{x} &v_{y} &v_{z} &0 \\ w_{x} &w_{y} &w_{z} &0 \\ Q_{x} &Q_{y} &Q_{z} &1 \end{bmatrix}

=xu_{B}+yv_{B}+zw_{B}+wQ_{B}

其中Q_B=(Q_x,Q_y,Q_z,1)u_B=(u_x,u_y,u_z,0)

v_B=(v_x,v_y,v_z,0)w_B=(w_x,w_y,w_z,0)

分别表示标架 A 中的原点和诸坐标轴相对于标架 B 的齐次坐标。

坐标变换矩阵 (change of coordinate matrix) 或 标架变换矩阵 (change of frame matrix):

标架 A 中的坐标 转换(或映射, map) 为标架 B 中坐标的 4×4 矩阵。

1.4.2 坐标变换矩阵结合律

标架:F、G、H

A:坐标从 F 转换到 G 的标架变换矩阵。

B:坐标由 G 转换至 H 的标架变换矩阵。

p_F:标架 F 中的一个向量

求此向量相对于标架 H 的坐标 p_H

        逐步计算:

                ​​​​​​​        (p_FA)B=p_H

        ​​​​​​​        ​​​​​​​        (p_G)B=p_H

由于满足结合律,我们可将(p_FA)B=p_H写作:

p_F(AB)=p_H

C=AB看作将坐标从标架 F 直接变换至标架 H 的标架变换矩阵,它将变换矩阵 A 和 B 结合为一个净矩阵——思路类似于函数的复合。

这种计算方法会对性能产生影响。

1.4.3 坐标变换矩阵逆矩阵

p_B=p_AM

p_BM^{-1}=p_A

M^{-1}为将坐标由标架 B 转换到标架 A 的变换矩阵。

1.5 变换矩阵与坐标变换矩阵

变换:缩放、旋转和平移。

坐标变换:令几何本身发生改变的变换。行向量:坐标变换矩阵。

几何变换:改变几何体的变换。行向量:令物体先旋转再平移的放射变换矩阵。

两者计算结果相同,差别在于解析变换的角度不同。

用坐标变换:令物体保持不变,多个坐标系之间进行转换更为直观的情景中,描述对象的参考系发生变化,物体的坐标随之改变。

几何变换法:使物体仅在一个坐标系中变换的情景中,表示物体的变换而不改变参考系。

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值