美文网首页OpenGL
OpenGL 之3D数学

OpenGL 之3D数学

作者: MonKey_Money | 来源:发表于2020-07-16 10:21 被阅读0次

3D数学和图像图形的关系

对于学习OpenGL 有一个误区,就是大家认为如果不能精通那些3D图形数学知识,会让我们寸步难⾏,其实不不然。就像我们不需要懂得任何关于汽⻋车结构和内燃机方⾯面的 知识也能每天开车。但是,我们最好能对汽车有足够的了解,以便我们意识到什么时候需要更换机油、定期加油、汽车常规保养工作。
同样要成为一名可靠和有能力的OpenGL程序员,⾄少需要理解这些基础知识,才知 能作什么?以及那些工具适合我们要做的⼯工作。
初学者,经过一段时间的实践,就会渐理解矩阵和向量。并且培养出一种更为直观的能⼒,能够在实践中充分利用所学的内容。

在开发过程我们涉及到的图形变换,就会涉及到矩阵/向量的计算.例如大家在使用 CAnimation 实现仿射变换,就使用了了OpenGL渲染技术.

向量

在数学中,向量(也称为欧几里得向量、几何向量、矢量),指具有大小(magnitude)和方向的量。它可以形象化地表示为带箭头的线段。箭头所指:代表向量的方向;线段长度:代表向量的大小。
在 3D 笛卡尔坐标系, 基本上. 一个顶点 就是XYZ 坐标空间上的一个位置. 而在空间中给定的一个位置 恰恰是由一个单独的 XYZ 定义的. 而这这样的 XYZ 就是向量;


image.png

单位向量

单位向量是指模等于1的向量。由于是非[零向量],单位向量具有确定的方向。单位向量有无数个。
如果一个向量为X,Y,Z,则X²+Y²+Z² = 1,说明(x,y,z)为单位向量.
如果向量X²+Y²+Z² != 1 则这个向量不是单位向量,我们把它缩放到1这个过程叫做标准化,将一个向量进行标准化就是将它缩为1也叫做单位化向量
(x,y,z)经过单位化向量后就是(x/√x²+y²+z²,y/√x²+y²+z²,z/√x²+y²+z²)

OpenGL中的向量

math3D中有2个数据类型能够表示一个3维或者4维向量

3维向量

typedef float   M3DVector3f[3];     //(x,y,z)x,y,z各数据类型为float
typedef double  M3DVector3d[3]; //(x,y,z)x,y,z各数据类型为double

4维向量

typedef float   M3DVector4f[4];  //(x,y,z,w)x,y,z各数据类型为float
typedef double  M3DVector4d[4];     //(x,y,z,w)x,y,z各数据类型为double

在典型情况下,w坐标设为1.0。x,y,z值通过除以w,来进⾏行行缩放。而除以1.0则本质上不改 变x,y,z值。

    gltMakeSphere(sphereBatch, 3.0, 10, 20);
    M3DVector3f verctor3f = {1,0,1};
    M3DVector4f verctor4f = {1,0,0,1};
    M3DVector3f  verctor3f3[3] = {
        1,0,0,
        0,1,0,
        0,0,1
    };

向量点乘

2个单元向量 之间进⾏点乘运算将得到一个标量(不是三维向量量,是一个标量量).它表示两个向量之间的夹角的余弦值[-1,1];
如果向量不是单位向量,我们可以通过单位化向量。
单位向量1(x1,y1,z1)点乘单位向量2(x2,y2,z2)等于x1x2+y1y2+z1*z2

image.png
如图单位向量v1点乘单位向量v2等于angle的余弦值.

math3d关于点乘的api

inline double m3dDotProduct3(const M3DVector3d u, const M3DVector3d v)
    { return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; }

结果是u和v都是单位向量,得到是u和v夹角的余弦值.

inline double m3dGetAngleBetweenVectors3(const M3DVector3d u, const M3DVector3d v)
    {
    double dTemp = m3dDotProduct3(u, v);
    return acos(dTemp);
    }

结果是U和V的夹角。

向量叉乘

两个向量叉乘就可以得到另外一个向量,新的向量会与原来2个向量定义的平面垂直。(叉乘不要求两个向量为单位向量)
新的向量与原来两个向量垂直,我们可以得到两个方向的新向量,显然得到两个向量是不对的,在这里要用右手法则判断


image.png

math3d关于叉乘的api

inline void m3dCrossProduct3(M3DVector3d result, const M3DVector3d u, const M3DVector3d v)
    {
    result[0] = u[1]*v[2] - v[1]*u[2];
    result[1] = -u[0]*v[2] + v[0]*u[2];
    result[2] = u[0]*v[1] - v[0]*u[1];
    }

result为u叉乘v的结果

矩阵

在空间有一个点.使⽤ xyz 描述它的位置. 此时让其围绕任意位置旋转一定⻆角度
后. 我们需要知道这个点的新的位置. 此时需要通过矩阵进行计算;矩阵只有一行或者一列都是合理的. 只有一⾏或者一列数字可以称为向量. 也可以称为矩阵;

math3d的定义矩阵

typedef float   M3DMatrix33f[9];    
typedef double  M3DMatrix33d[9];

两种定义方式只是精度不同,都为三维矩阵

typedef float M3DMatrix44f[16];     
typedef double M3DMatrix44d[16];

精度不同的四维矩阵

在其他编程标准中,许多矩阵库定义一个矩阵使用二维数组,OpenGL的约定里,更多倾向使用一维数组,这样做的原因是: OpenGL 使用的是 Column-Major(以列为主)矩阵排序的约定

image.png

单位矩阵

    GLfloat m[] = {
        1,0,0,0, //x轴
        0,1,0,0,//y轴
        0,0,1,0, //Z轴
        0,0,0,1 //Translation
        
    };
    M3DMatrix44f  matrix44f = {
        1,0,0,0, //x轴
        0,1,0,0,//y轴
        0,0,1,0, //Z轴
        0,0,0,1 //Translation
    };

单元矩阵初始化

void m3dLoadIdentity33(M3DMatrix33f m);
void m3dLoadIdentity33(M3DMatrix33d m);
void m3dLoadIdentity44(M3DMatrix44f m);
void m3dLoadIdentity44(M3DMatrix44d m);

将⼀个 向量乘以单元矩阵 ,就相当于一个向量乘以1. 不会发生任何改变。


UnitMatrix.png

单元矩阵[线性代数]

在线性代数学的维度,为了了便于书写. 所以坐标计算. 都是从左往右顺序,进⾏算. 如下列公式
变换后顶点向量量 = V_local * M_model * M_view * M_pro
变换后顶点向量量 = 顶点 ✖ 模型矩阵 ✖ 观察矩阵 ✖ 投影矩阵;


image.png

单元矩阵[OpenGL]角度

变换顶点向量量 = M_pro * M_view * M_model * V_local
变换顶点向量量 = 投影矩阵 ✖ 视图变换矩阵 ✖ 模型矩阵 ✖ 顶点


image.png

矩阵不是不满足交换律吗?为什么单元矩阵在线性代数和OpenGL不同呢

A*B = Bᵀ*Aᵀ 
A = (1,2,3,4)
B = {
1,2,0,0,
2,3,0,1
0,0,1,1,
0,0,1,1
}
A*B  = {
5,8,7,9
}
Bᵀ = {
1,2,0,0
2,3,0,0,
0,0,1,1
0,1,1,1
}
Aᵀ = {
1,
2,
3,
4
},
 Bᵀ*Aᵀ = {
5,
8,
7,
9
}

A 到Aᵀ就是从行矩阵转化成列矩阵的过程,这个过程叫矩阵的转置
所以在openGL中运用的是列矩阵。
顶点着色器中的运用


image.png

矩阵在OpenGL里的变化

变换 解释
视图变换 指定观察者
模型变化 在场景中移动物体
模型视图 描述视图/模型变换的⼆二元性(2种看到模型转 换的⽅方式)
投影 改变视景体⼤大⼩小和设置它的投影⽅方式
视口 伪变化,对窗⼝口上最终输出进⾏行行缩放

视图变换

视图变换是应用到场景中的第一种变换, 它⽤来确定场景中的有利位置,在默认情况下, 透视投影中位于原点(0,0,0),并沿着 z 轴负方向进行观察 (向显示器内部”看过去”).当观察者点位于原点(0,0,0) 时,就像在透视投影中一样
视图变换将观察者放在你希望的任何位置.并允许在任何方向上观察场景, 确定视图变换就像 在场景中放置观察者并让它指向某一个方向;
从大局上考虑, 在应用任何其他模型变换之前, 必须先应用视图变换. 这样做是因为, 对于 视觉坐标系⽽言, 视图变换移动了当前的工作的坐标系; 后续的变化都会基于新调整的坐标系进⾏.

模型变换

模型变换: ⽤于操纵模型与其中某特定变换. 这些变换将对象移动到需要的位置. 通过旋转,缩放,平移.


image.png
image.png

模型变换不符合交换律

image.png

两种看待模型变换

image.png

math3d中模型变换

模型平移变换

 void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z)

m:设置平移后的矩阵
X:X轴方向上平移的距离
Y:Y轴方向上平移的距离
Z:Z轴方向上平移的距离


image.png

模型旋转变换

void m3dRotationMatrix44(M3DMatrix44d m, double angle, double x, double y, double z);

m:设置旋转后的矩阵
angle:设置旋转的角度
X:如果为1,沿X轴旋转 ,如果为0,X轴不旋转
Y:如果为1,沿Y轴旋转,如果为0,Y轴不旋转
Z:如果为1,沿Z轴旋转, 如果为0,Z轴不旋转


image.png

模型缩放变换

 void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale)

m:设置旋转后的矩阵
xScale:x轴的坐标缩放xScale,如果为-1,x轴翻转
yScale:y轴的坐标缩放yScale,如果为-1,y轴翻转
Z xScale:z轴的坐标缩放zScale,如果为-1,z轴翻转


image.png

模型综合变换

void m3dMatrixMultiply44(M3DMatrix44d product, const M3DMatrix44d a, const M3DMatrix44d b);

product:两种模型变化后的结果
a:先按照a矩阵变化
b:后按照b矩阵变化.

** 其实我们经过打断点再手动计算可知,是bxa,,为什么呢?原因是OpenGL默认是列矩阵,我们手动设置的值还是按照数学规律设置的,因为转置,所以相等**

投影变换

image.png

相关文章

  • OpenGL笔记十:OpenGL ES初探

    前言 期待您移步上篇:OpenGL笔记九:3D数学小记 OpenGL ES OpenGL ES允许应⽤程序利⽤底层...

  • OpenGL 之3D数学

    3D数学和图像图形的关系 对于学习OpenGL 有一个误区,就是大家认为如果不能精通那些3D图形数学知识,会让我们...

  • OpenGL之3D数学

    向量 向量是既有大小又有方向的量。 零向量与单位向量 模等于0的向量为零向量,模等于1的向量叫做单位向量。注意零向...

  • 02总结--010--OpenGL 基础变换:向量和矩阵的深入理

    在正式进入本章节内容之前,先来正视几个观念。 1. 3D 数学在OpenGL中充当什么角色? 对于学习OpenGL...

  • OpenGL学习之3D数学

    一:向量的记法 通常使⽤下标法来引⽤向量量的某个分量⽐比如,a1 = 1;a2 = 2 ; a3 = 3实际开发中...

  • OpenGL向量、矩阵应用

    一、3D数学 3D数学.在图像图形开发中的充当了什么⻆色?对于学习OpenGL 有一个误区,就是大家认为如果不能精...

  • OpenGL 3D数学

    1.标量与向量相乘 k * [x, y, z] = [x, y, z] * k = [kx, ky, kz] 2....

  • OpenGL中的向量和矩阵

    OpenGL坐标变化时经常用到矩阵来计算变化后点的位置,为了更好的理解3D数学在OpenGL中的作用,本文将简单地...

  • OpenGL 3D数学篇

    1

  • OpenGL ES Android 第一课

    官网镇楼OpenGL 简介 openGL 与 OpenGL ES 区别 OpenGL 跨平台的高性能3D渲染AP...

网友评论

    本文标题:OpenGL 之3D数学

    本文链接:https://www.haomeiwen.com/subject/iyouhktx.html