OpenGL

五、OpenGL基础变换与矩阵栈

2020-02-23  本文已影响0人  收纳箱

1. 基础变换

1.1 平移

平移

1.2 旋转

旋转

1.3 缩放

缩放

1.4 组合变换

平移和旋转

先旋转再平移 先平移再旋转

对比上面2个变换,我们可以发现:在组合变换中,变换的顺序是不可以随意修改的。

//先旋转再平移
                     ┏ cosθ   sinθ  0 ┓┏ 1    0    0 ┓
[X, Y, 1] = [x, y, 1]┃ -sinθ  cosθ  0 ┃┃ 0    1    0 ┃
                     ┗ 0      0     1 ┛┗ dx   dy   1 ┛

//先平移再旋转
                     ┏ 1    0    0 ┓┏ cosθ   sinθ  0 ┓
[X, Y, 1] = [x, y, 1]┃ 0    1    0 ┃┃ -sinθ  cosθ  0 ┃
                     ┗ dx   dy   1 ┛┗ 0      0     1 ┛

这个的问题本质原因是矩阵的乘法不满足交换律

1.5 代码示例

效果
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
//红色
GLfloat vRed[] = {1.0,0.0,0,1};

void RenderScene(void)
{
    //清除屏幕、深度缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //1.建立基于时间变化的动画
    static CStopWatch rotTimer;
    //当前时间 * 60s
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
    //2.矩阵变量
    /*
     mView: 平移
     mModel: 旋转
     mModelView: 模型视图
     mModelViewProjection: 模型视图投影MVP
     */
    M3DMatrix44f mView, mModel, mModelView, mModelViewProjection;

    //mModel旋转矩阵,绕y轴旋转yRot度
    m3dRotationMatrix44(mModel, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);

    //mView平移矩阵,沿z轴移动-2.5
    m3dTranslationMatrix44(mView, 0.0f, 0.0f, -2.5f);
    
    //mModelview = mView * mModel
    m3dMatrixMultiply44(mModelview, mView, mModel);
    
    //mModelViewProjection = ProjectionMatrix * mView * mModel
     m3dMatrixMultiply44(mModelViewProjection,
                         viewFrustum.GetProjectionMatrix(),
                         mModelview);
  
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, 
                                 mModelViewProjection, 
                                 vBlack);
    torusBatch.Draw();

    glutSwapBuffers();
    glutPostRedisplay();
}

2. 矩阵栈

我们在矩阵储存时可能用到以下实例:

GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLFrame             cameraFrame;
GLFrame             objectFrame;

其中,cameraFrame用于存储观察者矩阵,objectFrame用于存储模型矩阵。projectionMatrix只用于存储投影矩阵,我们操作最多的是modelViewMatrix

objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
//GLFrame中默认的朝向是z轴的负方向,即(0.0, 0.0, -1.0)
//向前走-15.0,即(0.0, 0.0, -1.0 * -15.0) = (0.0, 0.0, 15.0)
cameraFrame.MoveForward(-15.0f);
//压栈
modelViewMatrix.PushMatrix();
//获取观察者矩阵
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//栈顶矩阵乘以传入矩阵,相乘的结果简存储在栈顶
modelViewMatrix.MultMatrix(mCamera);
//获取模型矩阵
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
//由于先乘的观察者矩阵,现在再乘以模型矩阵
//栈顶 = M_view * M_model
modelViewMatrix.MultMatrix(mObjectFrame);
...
//由于初始化时传入了,modelViewMatrix和projectionMatrix的引用
//transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//下面的代码会计算projectionMatrix * modelViewMatrix
//结合上面的代码,等价于M_projection * M_view * M_model
transformPipeline.GetModelViewProjectionMatrix()
...
//出栈
modelViewMatrix.PopMatrix();

2.1 优化矩阵栈操作

不同的实现方式

之前我们用cameraFrameobjectFrame来记录相机和模型的变化,用到了两个对象。但我们可以固定一个对象,变化另一个对象。

例如,之前的做法需要观察者向后退,同时物体旋转,把变化作用到了两个物体上,所以用到了两个矩阵分别记录两个物体的变化,最后再使用矩阵相乘把两个变化合并起来。

如果固定一个物体,那么根据相对运动,就是把之前两个物体的变化,相对地作用到另一个物体上,就可以少用一个矩阵了。

下面我们看看代码如何实现:

2.1 矩阵栈过程

矩阵栈过程

上面就是矩阵栈的操作过程,其中:

这个操作类似于iOSCore Graphiccontext的保存与恢复。

//保存
void CGContextSaveGState(CGContextRef c);
//恢复
void CGContextRestoreGState(CGContextRef c);
上一篇下一篇

猜你喜欢

热点阅读