Open GL ES ->模型矩阵、视图矩阵、投影矩阵等变换矩阵数学推导以及方法接口说明

发布于:2025-03-29 ⋅ 阅读:(28) ⋅ 点赞:(0)

Open GL ES 变换矩阵详解

一、坐标空间变换流程

局部空间 ->Model Matrix(模型矩阵)-> 世界空间
世界空间->View Matrix(视图矩阵)->观察空间
观察空间 ->Projection Matrix(投影矩阵)->裁剪空间
裁剪空间 ->ViewPort Transform(视口变换)>屏幕空间

二、变换矩阵及计算

1. 模型矩阵Model Matrix

  • 方法: Matrix.rotateM(), Matrix.translateM(), Matrix.scaleM()
  • 公式:
  • 位移、缩放计算过程
[ Scale_x    0        0      Translation_x ]   [ x ]   [ Scale_x·x + Translation_x ]
[ 0       Scale_y     0      Translation_y ] × [ y ] = [ Scale_y·y + Translation_y ]
[ 0          0     Scale_z   Translation_z ]   [ z ]   [ Scale_z·z + Translation_z ]
[ 0          0        0            1       ]   [ 1 ]   [            1             ]
  • 旋转计算过程
[ cos(θ)  -sin(θ)   0    0 ]   [ x ]   [ x·cos(θ) - y·sin(θ) ]
[ sin(θ)   cos(θ)   0    0 ] × [ y ] = [ x·sin(θ) + y·cos(θ) ]
[   0        0      1    0 ]   [ z ]   [          z          ]
[   0        0      0    1 ]   [ 1 ]   [          1          ]

2. 视图矩阵View Matrix

  • 方法: Matrix.setLookAtM(float[] rm, int rmOffset, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
  • 参数说明:
    eyeX, eyeY, eyeZ: 相机位置坐标
    centerX, centerY, centerZ: 物体位置坐标
    upX, upY, upZ: 相机上方向向量(通常为(0,1,0)
  • 数学函数定义:
  • 向量归一化normalize:
normalize(v) = v / |v|
  • 其中|v|是向量v的长度(模):
|v| =(v.x² + v.y² + v.z²)
  • 向量叉积cross product:
cross(a, b) = [a.y·b.z - a.z·b.y, a.z·b.x - a.x·b.z, a.x·b.y - a.y·b.x]
  • 向量点积dot product:
dot(a, b) = a.x·b.x + a.y·b.y + a.z·b.z
  • 计算过程:
  • 计算前方向向量: Front = normalize(Center - Eye)
Front.x = (centerX - eyeX) / √[(centerX - eyeX)² + (centerY - eyeY)² + (centerZ - eyeZ)²]
Front.y = (centerY - eyeY) / √[(centerX - eyeX)² + (centerY - eyeY)² + (centerZ - eyeZ)²]
Front.z = (centerZ - eyeZ) / √[(centerX - eyeX)² + (centerY - eyeY)² + (centerZ - eyeZ)²]
  • 计算右方向向量: Right = normalize(cross(Front, Up))
Right.x = (Front.y·upZ - Front.z·upY) / √[(Front.y·upZ - Front.z·upY)² + (Front.z·upX - Front.x·upZ)² + (Front.x·upY - Front.y·upX)²]
Right.y = (Front.z·upX - Front.x·upZ) / √[(Front.y·upZ - Front.z·upY)² + (Front.z·upX - Front.x·upZ)² + (Front.x·upY - Front.y·upX)²]
Right.z = (Front.x·upY - Front.y·upX) / √[(Front.y·upZ - Front.z·upY)² + (Front.z·upX - Front.x·upZ)² + (Front.x·upY - Front.y·upX)²]
  • 重新计算上方向向量(确保正交): Up = cross(Right, Front)
Up.x = Right.y·Front.z - Right.z·Front.y
Up.y = Right.z·Front.x - Right.x·Front.z
Up.z = Right.x·Front.y - Right.y·Front.x

(此处Up已经是单位向量,因为RightFront都是单位向量且相互垂直)
公式:

[ Right_x   Right_y   Right_z   -dot(Right,Eye) ]   [ x ]   [ Right_x·x + Right_y·y + Right_z·z - dot(Right,Eye) ]
[ Up_x      Up_y      Up_z      -dot(Up,Eye)    ] × [ y ] = [ Up_x·x + Up_y·y + Up_z·z - dot(Up,Eye)          ]
[ -Front_x  -Front_y  -Front_z   dot(Front,Eye) ]   [ z ]   [ -Front_x·x - Front_y·y - Front_z·z + dot(Front,Eye) ]
[ 0         0         0          1              ]   [ 1 ]   [                       1                          ]

其中:

dot(Right,Eye) = Right.x·eyeX + Right.y·eyeY + Right.z·eyeZ
dot(Up,Eye) = Up.x·eyeX + Up.y·eyeY + Up.z·eyeZ
dot(Front,Eye) = Front.x·eyeX + Front.y·eyeY + Front.z·eyeZ

3. 投影矩阵Projection Matrix

3.1 正交投影

  • 方法: Matrix.orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
  • 参数说明:
    left, right: 近平面左右边界坐标
    bottom, top: 近平面下上边界坐标
    near, far: 近平面和远平面到相机的距离
  • 取值范围与建议:
    left < right, bottom < top, near < far
    nearfar通常为正值,但某些实现中可以为负值
    坐标范围取决于场景大小,常见如(-10,10,-10,10,1,100)
  • 公式:
[ 2/(right-left)      0                 0              -(right+left)/(right-left) ]   [ x ]   [ 2x/(right-left) - (right+left)/(right-left) ]
[ 0            2/(top-bottom)           0              -(top+bottom)/(top-bottom) ] × [ y ] = [ 2y/(top-bottom) - (top+bottom)/(top-bottom) ]
[ 0                   0           -2/(far-near)        -(far+near)/(far-near)     ]   [ z ]   [ -2z/(far-near) - (far+near)/(far-near)      ]
[ 0                   0                 0                        1                 ]   [ 1 ]   [                  1                          ]
  • 特点:
    • 保持物体原始比例,不会因距离而变形
    • 视锥体是长方体形状
    • 适合2D绘制和UI界面

3.2 透视投影

  • 方法: Matrix.frustumM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
  • 参数说明:
    left, right: 近平面左右边界坐标
    bottom, top: 近平面上下边界坐标
    near: 近平面距离,必须为正值
    far: 远平面距离,必须为正值且大于near
  • 取值范围与建议:
    left=-right, bottom=-top
    near不宜过小,通常0.1-1.0
    far通常10-1000,取决于场景大小
  • 公式:
[ 2*near/(right-left)  0                  (right+left)/(right-left)  0                    ]   [ x ]
[ 0                    2*near/(top-bottom) (top+bottom)/(top-bottom)  0                    ] × [ y ]
[ 0                    0                   -(far+near)/(far-near)     -2*far*near/(far-near) ]   [ z ]
[ 0                    0                   -1                         0                    ]   [ 1 ]
  • 结果:
[ 2*near*x/(right-left) + (right+left)*z/(right-left)                            ]
[ 2*near*y/(top-bottom) + (top+bottom)*z/(top-bottom)                            ]
[ -(far+near)*z/(far-near) - 2*far*near/(far-near)                               ]
[ -z                                                                              ]
  • 特点:
    • 模拟人眼视觉,远处物体显得更小
    • 适合大多数3D场景渲染

三、MVP矩阵组合计算

  • 方法: Matrix.multiplyMM()
  • 计算流程:
// 模型视图矩阵Model x View = 视图矩阵View × 模型矩阵Model
Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modelMatrix, 0)

// MVP矩阵 = 投影矩阵Projection × 模型视图矩阵Model View = Projection × View × Model
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0)

// 最终坐标变换
// [x', y', z', w'] = MVP × [x, y, z, 1]
  • 注意事项:
  • OpenGL中矩阵乘法是右结合的,从右到左计算
  • 变换顺序非常重要: 先模型变换,再视图变换,最后投影变换
  • 最终变换结果应用于顶点着色器的gl_Position