美文网首页
4.OpenGL向量、矩阵应用、基础变化

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

作者: bytebytebyte | 来源:发表于2020-11-28 09:28 被阅读0次

    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;
    }
    

    相关文章

      网友评论

          本文标题:4.OpenGL向量、矩阵应用、基础变化

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