4.OpenGL向量、矩阵应用、基础变化

2020-11-28  本文已影响0人  bytebytebyte

1.OpenGL学习误区?
如果不能精通那些3D图形数学知识,会让我们寸步难行。其实不然,我们不懂汽车结构不是每天还在开车嘛,但是我们需要懂得如何保养车,所以我们最好对汽车有足够的了解。同理我们至少要理解矩阵和向量。

2.3D数学的用处?
是OpenGL、ARKit、Unity3D、游戏开发必须学习的一块。

3.M3DVector3f 表示一个三维向量
M3DVector4f 表示一个四维向量
单位向量:
(1,0,0)
单位矩阵:
(1,0,0,
0,1,0,
0,0,1)

1,2,3
pushMatrix();1,2,3

1,2,3
pushMatrix(4);1,2,3,4

1,2,3
popMatrix();1,2,3

点乘运算返回2个向量之间的夹角
叉乘运算返回1个新的向量,这个新的向量与原来的2个向量垂直。叉乘不满足交换律所以要注意先后顺序
A0 A1 A2 A3
[ A4 A5 A6 A7 ]
A8 A9 A10 A11
A12 A13 A14 A15
行矩阵

A0 A4 A8 A12
[A1 A5 A9 A13 ]
A2 A6 A10 A14
A3 A7 A11 A15
列矩阵

行矩阵转置后是列矩阵

5.1个4*4的矩阵如何在3D空间中表示一个位置和方向的?
列向量进行了特别的标注,矩阵的最后一行都为0,只有最后一个元素为1.

6.将1个向量乘以一个单位矩阵得到的结果还是原来的矩阵。
4 1 0 0 0 4
[ 5 ] [ 0 1 0 0 ] [ 5 ]
2 0 0 1 0 2
1 0 0 0 1 1

7.注意理解代码中的常用矩阵函数如压栈、出栈等。

1.图形移动-矩阵变换

#include "GLShaderManager.h"
#include "GLTools.h"
#include "math3d.h"

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLBatch squareBatch;
GLShaderManager shaderManager;


GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
    - blockSize, - blockSize, 0.0f,
      blockSize, - blockSize, 0.0f,
      blockSize,   blockSize, 0.0f,
    - blockSize,   blockSize, 0.0f
};

GLfloat xPos = 0;
GLfloat yPos = 0;

//为程序做一次性的设置
void setupRC() {
    //初始化
    glClearColor(0, 0, 1, 1);
    shaderManager.InitializeStockShaders();
    
    //加载三角形
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();
}

//计算移动距离和碰撞检测
void specialKeys(int key, int x, int y) {
    GLfloat stepSize = 0.025f;
    if (key == GLUT_KEY_UP) {
        yPos += stepSize;
    }
    if (key == GLUT_KEY_DOWN) {
        yPos -= stepSize;
    }
    if (key == GLUT_KEY_LEFT) {
        xPos -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT) {
        xPos += stepSize;
    }
    //碰撞检测 否则会出屏幕
    if (xPos < - 1 + blockSize) {
        xPos = -1 + blockSize;
    }
    if (xPos > 1 - blockSize) {
        xPos = 1 - blockSize;
    }
    if (yPos < - 1 + blockSize) {
        yPos = -1 + blockSize;
    }
    if (yPos > 1 - blockSize) {
        yPos = 1 - blockSize;
    }
    glutPostRedisplay();
}

//开始渲染
void renderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    GLfloat vRed[] = { 1, 0, 0, 1 };
    M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
    //平移 xPos, yPos
    m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0);
    //每次重绘时旋转5度
    static float yRot = 0;
    yRot += 5;
    m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0, 0, 1);
    
    //将平移旋转的结果合并到mFinalTransform中
    m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
    
    //将矩阵结果提交到固定着色器(平面着色器)中
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
    squareBatch.Draw();
    
    glutSwapBuffers();
}

//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
    glViewport(0, 0, w, h);
}

int main(int argc, char *argv[]) {
  
    gltSetWorkingDirectory(argv[0]);
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutCreateWindow("Move Block with Arrow Keys");
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        fprintf(stderr, "Error:%s\n",glewGetErrorString(err));
        return 1;
    }
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(renderScene);
    glutSpecialFunc(specialKeys);
    setupRC();
    glutMainLoop();
    
    return 0;
}

2.使用矩阵创建几何图形(objectFrame 和objectFrame+CameraFrame))

#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include "StopWatch.h"

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame; //观察者位置
GLFrame objectFrame; //世界坐标位置
GLFrustum viewFrustum; //视景体,用来构造投影矩阵
GLTriangleBatch triangle; //三角形批次类
GLTriangleBatch sphereBatch; //球
GLTriangleBatch torusBatch; //环
GLTriangleBatch cylinderBatch; //圆柱
GLTriangleBatch coneBatch; //锥
GLTriangleBatch diskBatch; //磁盘
GLGeometryTransform transformPipeline;
M3DMatrix44f shadowMatrix;
GLfloat vGreen[] = { 0, 1, 0, 1 };
GLfloat vBlack[] = { 0, 0, 0, 1 };
int nStep = 0;

//必要初始化
void setupRC() {
    glClearColor(0.7, 0.7, 0.7, 1);
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    objectFrame.MoveForward(15);//将物体向屏幕外移动15
    //使用三角形批次类构造图形对象
    /*
     球 void gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
     sphereBatch 三角形批次类对象
     fRadius 球体半径
     iSlices 从球体底部堆叠到顶部的 三角形带数量;其实球体是一圈一圈三角形带组成的
     iStacks 围绕球体一圈排列的三角形对数 几层三角形带
     建议:一个对称性好的球体的片段数量是堆叠数量的2倍即iStacks =iSlices * 2
     */
    gltMakeSphere(sphereBatch, 3, 10, 20);
    
    /*
     环面
     void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
     majorRadius 外半径 minorRadius内半径 numMajor主半径三角形数量 numMinor小半径三角形数量
     */
    gltMakeTorus(torusBatch, 3, 0.75, 15, 15);
    
    //圆柱
    gltMakeCylinder(cylinderBatch, 2, 2, 3, 15, 3);
    
    //圆锥 一端半径为0,另一端半径可指定
    gltMakeCylinder(coneBatch, 2, 0, 3, 13, 5);
    
    //磁盘 100 100 的效果会是什么样子的呢
    gltMakeDisk(diskBatch, 1.5, 3, 100, 100);
    
    
}

void drawWriteFramedBatch(GLTriangleBatch *pBatch) {
    //绘制图形
    //1.平面着色器,绘制三角形
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    //传过来的参数对应不同的图形Batch
    pBatch->Draw();
    
    //画出黑色轮廓
    //2.开启多边形偏移
    glEnable(GL_POLYGON_OFFSET_LINE);
    //多边形模型(背面、线) 将多边形背面设为线框模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //开启多边形偏移(设置偏移数量)
    glPolygonOffset(-1, -1);
    glLineWidth(2.5);
    
    //3.开启混合功能(颜色混合&抗锯齿功能)
    glEnable(GL_BLEND);
    //开启处理线段抗锯齿功能
    glEnable(GL_LINE_SMOOTH);
    //设置颜色混合因子
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //4.平面着色器绘制线条
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    
    pBatch->Draw();
    
    //5.恢复多边形模式和深度测试
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);

}



//开始渲染
void renderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
//    modelViewMatrix.PushMatrix(objectFrame);
    //或
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    
    
    //判断目前绘制第几个图形
    switch (nStep) {
        case 0:
            drawWriteFramedBatch(&sphereBatch);
            break;
        case 1:
            drawWriteFramedBatch(&torusBatch);
            break;
        case 2:
            drawWriteFramedBatch(&cylinderBatch);
            break;
        case 3:
            drawWriteFramedBatch(&coneBatch);
            break;
        case 4:
            drawWriteFramedBatch(&diskBatch);
            break;
    }
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
    
}

//上下左右移动图形
void specialKeys(int key, int x, int y) {
    if (key == GLUT_KEY_UP) {
        //移动世界坐标系,而不是去移动物体,将世界坐标系在X方向移动-5
        objectFrame.RotateWorld(m3dDegToRad(-5), 1, 0, 0);
    }
    if (key == GLUT_KEY_DOWN) {
        objectFrame.RotateWorld(m3dDegToRad(5), 1, 0, 0);
    }
    if (key == GLUT_KEY_LEFT) {
        objectFrame.RotateWorld(m3dDegToRad(-5), 0, 1, 0);
    }
    if (key == GLUT_KEY_RIGHT) {
        objectFrame.RotateWorld(m3dDegToRad(5), 0, 1, 0);
    }
    glutPostRedisplay();
}

//点击空格切换渲染图形
void keyPressFunc(unsigned char key, int x, int y) {
    if (key == 32) {
        nStep ++;
        if (nStep > 4) {
            nStep = 0;
        }
    }
    switch (nStep) {
        case 0:
            glutSetWindowTitle("Sphere");
            break;
        case 1:
            glutSetWindowTitle("Torus");
            break;
        case 2:
            glutSetWindowTitle("Cylinder");
            break;
        case 3:
            glutSetWindowTitle("Cone");
            break;
        case 4:
            glutSetWindowTitle("Disk");
            break;
    }
    glutPostRedisplay();
}

//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
    //1.视口
    glViewport(0, 0, w, h);
    
    //2.透视投影
    viewFrustum.SetPerspective(35, float(w) / float(h), 1, 500);
    //矩阵堆栈加载透视投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //3.矩阵堆栈加载单元矩阵
    modelViewMatrix.LoadIdentity();
    //4.transformPipeline管理矩阵堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
}


int main(int argc, char *argv[]) {
    gltSetWorkingDirectory(argv[0]);
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Sphere");
    glutReshapeFunc(ChangeSize);
    glutKeyboardFunc(keyPressFunc);
    glutSpecialFunc(specialKeys);
    glutDisplayFunc(renderScene);
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
        return 1;
    }
    setupRC();
    glutMainLoop();
    
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读