美文网首页
OpenGL-04-入门级案例2:绘制通过键位移动的正方形

OpenGL-04-入门级案例2:绘制通过键位移动的正方形

作者: 宇宙那么大丶 | 来源:发表于2020-07-10 18:37 被阅读0次

    与上篇中的绘制三角形的主要区别:修改了图元链接方式、增加了键位控制

    void setupRC() //函数中修改一行代码
    
    //修改图元链接方式GL_TRIANGLE_FAN
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
         
    
    int main(int argc,char *argv[]) //函数中新增两行代码
     
    //针对MAC OS X,为了更加安全,设置当前工作目录
    gltSetWorkingDirectory(argv[0]);
    
    //添加新的特殊函数
    glutSpecialFunc(SpecialKeys);
    

    坐标更新方法

    运行可以发现:每次点击键位进行移动的时候,都会走一次RenderScene方法
    此外还需要考虑超出边界的问题,增加限制条件

    一个非常形象的正方形
    #include "GLShaderManager.h"
    #include "GLTools.h"
    #include <GLUT/GLUT.h>
    
    //定义一个着色管理器
    GLShaderManager shaderManager;
    //简单的批次容器,是GLTools的一个简单的容器类
    GLBatch triangleBatch;
    
    //设置顶点到X/Y轴距离 = 正方形边长的一半
    GLfloat blockSize = 0.1f;
    
    //正方形的4个点坐标
    GLfloat vVerts[] = {
            -blockSize,-blockSize,0.0f,//A点
            blockSize,-blockSize,0.0f,//B点
            blockSize,blockSize,0.0f,//C点
            -blockSize,blockSize,0.0f//D点
    };
    
    void changeSize(int w,int h)
    {
        glViewport(0, 0, w, h);
    }
    
    //渲染方法,每次更新界面(或者图形进行移动就会触发)
    void RenderScene(void)
    {
    
        //1、清除一个或一组特定缓存区
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
         
        //2、设置颜色
        GLfloat vColor[] = {1.0,1.0,0.0,1.0f};
        
        //3、传递到存储着色器中
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vColor);
        
        //4、提交着色器
        triangleBatch.Draw();
        
        //5、将后台缓冲区进行渲染,渲染结束后交换给前台
        glutSwapBuffers();
        
       
        
    }
    
    
    void setupRC()
    {
        
        //1、设置背景颜色
        glClearColor(0.98f, 0.4f, 0.7f, 1);
        
        //2、初始化渲染管理器
        shaderManager.InitializeStockShaders();
        
        //3、顶点已经声明在公共
        
        //4、修改图元链接方式GL_TRIANGLE_FAN
        triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
        triangleBatch.CopyVertexData3f(vVerts);
        triangleBatch.End();
        
    }
    
    
    void SpecialKeys (int key, int x,int y)
    {
        //每次移动的距离
        GLfloat stepSize = 0.05f;
        
        //拿到左上角顶点D的坐标
        GLfloat squX = vVerts[9];
        GLfloat squY = vVerts[10];
        
        if (key == GLUT_KEY_UP) {
            //向上移动,Y+size
            squY += stepSize;
        }
        
        if (key == GLUT_KEY_DOWN) {
            squY -= stepSize;
        }
        
        if (key == GLUT_KEY_RIGHT) {
            squX += stepSize;
        }
        
        if (key == GLUT_KEY_LEFT) {
            squX -= stepSize;
        }
        
        //===考虑到边界问题===
        if (squX < -1.0f) {
            squX = -1.0f;
        }
        
        if ((squX + blockSize *2) > 1.0f) {
            squX = 1.0f - blockSize*2;
        }
        
        if (squY > 1.0f) {
            squY = 1.0f;
        }
        
        if ((squY - blockSize *2) < -1.0f) {
            squY = -1.0f + blockSize *2;
        }
        
        //然后更新ABCD四个顶点
        //此时是根据D点的计算,A的Y比D的Y小 = DY-边长(边长 = blockSize*2)
        vVerts[0] = squX;
        vVerts[1] = squY - blockSize*2;
        
        vVerts[3] = squX + blockSize*2;
        vVerts[4] = squY - blockSize*2;
        
        vVerts[6] = squX + blockSize*2;
        vVerts[7] = squY;
        
        vVerts[9] = squX;
        vVerts[10] = squY;
        
        //更新数据,触发重新渲染
        triangleBatch.CopyVertexData3f(vVerts);
        glutPostRedisplay();
        
    }
    int main(int argc,char *argv[])
    {
        //针对MAC OS X,为了更加安全,设置当前工作目录
        gltSetWorkingDirectory(argv[0]);
        
        //准备工作
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
        glutInitWindowSize(800, 600);
        glutCreateWindow("Square");
        glutReshapeFunc(changeSize);
        glutDisplayFunc(RenderScene);
        //添加新的特殊函数
        glutSpecialFunc(SpecialKeys);
        
        
        GLenum status = glewInit();
        if (GLEW_OK != status) {
            printf("GLEW Error:%s\n",glewGetErrorString(status));
            return 1;
        }
        
     
        setupRC();
        glutMainLoop();
     
        return  0;
        
    }
    
     
    
    

    矩阵方式

    思考:如果一个图形有100个顶点,那坐标更新要写100次吗?
    我们可以用矩阵方式修改代码进行简单实现。
    并且在上述代码基础上,增加边移动边旋转效果(矩阵相乘)

    我们先声明两个需要用到的参数,然后只需要修改如下2个方法就可以了。

    //矩阵方法
    //记录在X轴方向上偏移的距离
    GLfloat xPos = 0.0f;
    //记录在Y轴方向上偏移的距离
    GLfloat yPos = 0.0f;
    
    void RenderScene2(void)
    {
    
        //1、清除一个或一组特定缓存区
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
         
        //2、设置颜色
        GLfloat vColor[] = {1.0,1.0,0.0,1.0f};
        
        //设置矩阵  平移+旋转+最终
        M3DMatrix44f mTransfrom,mRotation,mFinal;
        
        //平移
        m3dTranslationMatrix44(mTransfrom, xPos, yPos, 0.0f);
        
        //旋转  (每次平移旋转5度)
        static float yRot = 0.0f;
        yRot += 5.0f;
        m3dRotationMatrix44(mRotation, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
        
        //矩阵相乘拿到mFinal
        m3dMatrixMultiply44(mFinal, mTransfrom, mRotation);
        
        //3、使用着色器:GLT_SHADER_IDENTITY不够用,换成平面着色器(是一个固定着色器)
        shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinal,vColor);
        
        //4、进行绘制
        triangleBatch.Draw();
        
        //5、将后台缓冲区进行渲染,渲染结束后交换给前台
        glutSwapBuffers();
        
       
        
    }
    
    void SpecialKeys2 (int key, int x,int y)
    {
        //每次移动的距离
        GLfloat stepSize = 0.05f;
        
        
        if (key == GLUT_KEY_UP) {
            //向上移动,Y+size
            yPos += stepSize;
        }
        
        if (key == GLUT_KEY_DOWN) {
            yPos -= stepSize;
        }
        
        if (key == GLUT_KEY_RIGHT) {
            xPos += stepSize;
        }
        
        if (key == GLUT_KEY_LEFT) {
            xPos -= stepSize;
        }
        
        //===考虑到边界问题,碰撞检测===
        //此处xPos yPos可以看成中心点
        if (xPos < (-1.0f + blockSize)) {
            
            xPos = -1.0f + blockSize;
        }
        
        if (xPos > (1.0f - blockSize)) {
            xPos = 1.0f - blockSize;
        }
        
        if (yPos < (-1.0f + blockSize)) {
            yPos = -1.0f + blockSize;
        }
        
        if (yPos > (1.0f - blockSize)) {
            yPos = 1.0f - blockSize;
        }
        
        //触发重新渲染
        glutPostRedisplay();
        
    }
    
    

    相关文章

      网友评论

          本文标题:OpenGL-04-入门级案例2:绘制通过键位移动的正方形

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