Sirius' blog Sirius' blog
首页
  • 学习笔记

    • 《C++》
    • 《MATLAB》
    • 《Python》
  • 学习笔记

    • 《Git》
    • 《CMake》
  • 技术文档
  • 博客搭建
  • 学习
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Sirius0v0

怕什么真理无穷,进一寸有一寸的欢喜
首页
  • 学习笔记

    • 《C++》
    • 《MATLAB》
    • 《Python》
  • 学习笔记

    • 《Git》
    • 《CMake》
  • 技术文档
  • 博客搭建
  • 学习
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • OpenGL简介与安装配置
  • OpenGL绘制图形
  • OpenGL中的缩放旋转与平移
    • 坐标系的旋转(Rotate)
    • 坐标系的平移(Translate)
    • 坐标的缩放(Scale)
    • 轴角法:实现绕任意轴旋转
    • SRT(缩放、旋转、平移)顺序
    • OpenGL中不同的空间以及转换矩阵
      • 对象空间到世界空间(Local to World)[M]
      • 世界空间到视角空间(World to View)[V]
      • 视角空间到剪裁空间(View to Clip)[P]
      • NDC to Window
      • 投影变换的实现
  • 《OpenGL》学习笔记
Sirius0v0
2023-08-26
目录

OpenGL中的缩放旋转与平移

# OpenGL中的缩放旋转与平移

本章需要熟知线性代数中的旋转矩阵的知识。

# 坐标系的旋转(Rotate)

对于一个绝对矢量,在坐标系1下的坐标为pos1=(x1,y1)pos_1 = (x_1,y_1)pos1​=(x1​,y1​),在坐标系2下的坐标为pos2=(x2,y2)pos_2 = (x_2,y_2)pos2​=(x2​,y2​),已知坐标系1到坐标系2的旋转矩阵为L12L_{12}L12​,则有关系式:

pos2=L12∗pos1pos_2 = L_{12}*pos_1pos2​=L12​∗pos1​

该公式表示的是绝对矢量在不同坐标系下的坐标变换关系。

# 坐标系的平移(Translate)

通常采用扩维的方法表示坐标系的平移。对于旋转矩阵如下:

[abcd]\begin{bmatrix} a&b\\ c&d\\ \end{bmatrix}[ac​bd​]

如果在xxx与yyy分量平移uuu和vvv,则有附加平移的旋转矩阵:

[abucdv001]\begin{bmatrix} a&b&u\\ c&d&v\\ 0&0&1 \end{bmatrix}⎣⎢⎡​ac0​bd0​uv1​⎦⎥⎤​

此时原坐标(x,y,z)(x,y,z)(x,y,z)需要扩为(x,y,z,w)(x,y,z,w)(x,y,z,w)。

glm::mat4 glm::translate(glm::vec3 translation);

绝对矢量不随坐标系移动,因而平移项起作用,此时w=1

相对矢量无所谓平移,此时w=0。因此可以通过设置w的值来表示是否有平移。

auto world_pos = glm::vec3(l2w*glm::vec4(local_pos,1));
auto world_vel = glm::vec3(l2w*glm::vec4(local_vel,0));

# 坐标的缩放(Scale)

利用矩阵中对角元素对各个分量进行缩放。

glm::mat4 glm::scale(glm::vec3 scales);

# 轴角法:实现绕任意轴旋转

轴角法即给定一根轴线nnn和绕这个轴的旋转角度α\alphaα,求旋转矩阵。它实际上是罗德里格斯旋转公式(Rodrigues' Rotation Formula) (opens new window),其形式如下:

罗德里格斯旋转公式

R(n,α)=cos(α)I+(1−cos(α))nnT+sin(α)NR(n,\alpha)=cos(\alpha)I+(1-cos(\alpha))nn^T+sin(\alpha)NR(n,α)=cos(α)I+(1−cos(α))nnT+sin(α)N

其中,NNN为轴nnn的叉乘矩阵表示。

来自 维基百科-罗德里格斯旋转公式(Rodrigues' Rotation Formula) (opens new window)

在glm中可以通过函数实现轴角法的旋转:

glm::mat4 glm::rotate(float rad, glm::vec3 axis);

# SRT(缩放、旋转、平移)顺序

一般缩放必须先于旋转,旋转必须先于平移,因此应用顺序必须为:缩放、旋转、平移。SRT

glm::mat4 l2w = 
    glm::translate(glm::vec3(0.0f,0.5f,0.0f))
    * glm::rotate(glm::radians(45.0f),glm::vec3(0.0f,0.0f,1.0f))
    * glm::scale(glm::vec3(2.0f,1.0f,1.0f));

# OpenGL中不同的空间以及转换矩阵

# 对象空间到世界空间(Local to World)[M]

对象空间中,模型本身为坐标原点;世界空间以世界中心为原点。

正如茶杯在对象空间原点,在桌子(世界空间)的左上角一样。

# 世界空间到视角空间(World to View)[V]

视角空间以观察点为原点。

正如我从桌子正前方观察桌子和茶杯。

# 视角空间到剪裁空间(View to Clip)[P]

经过投影矩阵的变换(经此变换,从右手系变为了左手系),让看的物体更加真实,符合透视规则。然后将屏幕以外的东西剔除剪裁。

为防止剪裁后屏幕非正方形而将物体压扁,需要在投影矩阵中“预判一下”,提前利用宽高比进行压缩。

# NDC to Window

剪裁空间经过光栅化到窗口空间。此时将-1~1的浮点数坐标,转换为0~1920或1080的像素坐标系。

# 投影变换的实现

为了符合透视原理,也就是“近大远小”,为了让计算机能够渲染出这样的效果,我们需要一个定量的公式。假设zzz为物体距离眼睛的距离,从眼睛看向屏幕,前方为z正值,此时可以根据距离大小,将物体缩小1/z1/z1/z倍,即:

[x′y′]=[x/zy/z]\begin{bmatrix} x'\\ y'\\ \end{bmatrix}=\begin{bmatrix} x/z\\ y/z\\ \end{bmatrix}[x′y′​]=[x/zy/z​]

由于非线性,不容易用矩阵表示。

升维大法!!:利用矩阵变换将zzz分量搬运到www分量,然后规定从4维转回到3维矢量时,要额外除以他们的分量www,这样就可以实现,过程如下:

[1000010000000010][xyz1]=[xy0z]\begin{bmatrix} 1&0&0&0\\ 0&1&0&0\\ 0&0&0&0\\ 0&0&1&0\\ \end{bmatrix}\begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix}=\begin{bmatrix} x\\ y\\ 0\\ z\\ \end{bmatrix}⎣⎢⎢⎢⎡​1000​0100​0001​0000​⎦⎥⎥⎥⎤​⎣⎢⎢⎢⎡​xyz1​⎦⎥⎥⎥⎤​=⎣⎢⎢⎢⎡​xy0z​⎦⎥⎥⎥⎤​

当降维时,所有分量除以www,则有:

[x/z,y/z,0/z]T\left[ x/z,y/z,0/z \right]^T[x/z,y/z,0/z]T

代码实现:

// 对于绝对矢量
glm::vec4 tmp4d_pos = v2c * glm::vec4(pos,1);
glm::vec3 new_pos = glm::vec3(
    tmp4d_pos.x / tmp4d_pos.w,
    tmp4d_pos.y / tmp4d_pos.w,
    tmp4d_pos.z / tmp4d_pos.w
);
编辑 (opens new window)
#OpenGL#Cpp
上次更新: 2023/08/27, 00:31:08
OpenGL绘制图形

← OpenGL绘制图形

最近更新
01
ipopt优化库配置及使用
07-21
02
ubuntu离线安装包的方法
07-21
03
其它控件的使用
03-05
更多文章>
Theme by Vdoing | Copyright © 2020-2024 Sirius0v0 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式