Hello OpenGL--002:会移动的三角形

所要实现的效果图:


会移动的三角形.GIF

想要实现这种效果我们分为两步,1、绘制出一个三角形, 2、让三角形动起来。

一、三角形的绘制

首先导入头文件:

#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>

定义一个着色管理器及一个简单的批次容器:

GLShaderManager shaderManager;
/** GLTools的一个简单的容器类 */
GLBatch triangleBatch;

main函数中初始化GLUT库,以及注册相应的函数:

int main(int argc,char *argv[])
{
    //初始化glut
    glutInit(&argc, argv);
    //初始化绘制的模式
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH|GLUT_STENCIL);
    //初始化窗口大小
    glutInitWindowSize(500, 500);
    //创建窗口及设置窗口名称
    glutCreateWindow("会移动的三角形");
    //注册重塑函数 窗口大小发生变化时会调用该函数
    glutReshapeFunc(changeSize);
    //注册显示函数
    glutDisplayFunc(RenderScene);
     //初始化一个GLEW库,确保OpenGL API对程序完全可用。
    GLenum status = glewInit();
    if (GLEW_OK != status) {
        printf("error: %s\n", glewGetErrorString(status));
        return 1;
    }
    //设置渲染环境
    setupRC();
    glutMainLoop();
    
    return  0;
    
}
  • GLUT_DOUBLE 双缓存窗口,屏幕显示调用glutSwapBuffers() ,绘图指令实际是在离屏缓存区执行的,然后迅速转换成窗口视图,这种方式经常用来生成动画效果。既然存在双缓存窗口必然也存在单缓存窗口GLUT_SINGLE ,屏幕显示调用glFlush(),将图像直接在当前显示缓存中进行渲染,会存在图形跳动/闪烁问题。
  • GLUT_RGBA 颜色模式。
  • GLUT_DEPTH 深度测试,标志将一个深度缓存区分配为显示的一部分,我们能够执行深度测试。
  • GLUT_STENCIL 确保我们也会有一个可用的模板缓存区。
void changeSize(int w, int h){

    glViewport(0, 0, w, h);
}

其函数原型为 glViewport(GLint x,GLint y,GLsizei width,GLsizei height)x,y 以像素为单位,指定了窗口的左下角位置。,height表示视口矩形的宽度和高度,根据窗口的实时变化重绘窗口,通常x,y 都是为0。

设置渲染环境setupRC()

void setupRC()
{
    //设置窗口的背景色
    glClearColor(0.98f, 0.40f, 0.7f, 1);    
    //初始化固定着色器
    shaderManager.InitializeStockShaders();    
    //定义三角形的顶点坐标。
    GLfloat vVerts[] = {
        0.0f,0.2f,0.0f,//这三个值分别代表了坐标系中x,y,z值
        -0.2f,0.0f,0.0f,
        0.2f,0.0f,0.0f
    };
    triangleBatch.Begin(GL_TRIANGLES, 3);
    //拷贝顶点数据
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}

显示函数RenderScene()

void RenderScene(void)
{
    //1.清除一个或者多个指定的缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
     //2.设置一组浮点数来表示红色 
    GLfloat vRed[] = {1.0,1.00,0.0,0.5f};
    //传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    //提交着色器
    triangleBatch.Draw();
    //在开始的设置openGL 窗口的时候,我们指定要一个双缓冲区的渲染环境。这就意味着将在后台缓冲区进行渲染,渲染结束后交换给前台。这种方式可以防止观察者看到可能伴随着动画帧与动画帧之间的闪烁的渲染过程。缓冲区交换平台将以平台特定的方式进行。
    //将后台缓冲区进行渲染,然后结束后交换给前台
    glutSwapBuffers();
//    glFlush();
}

运行就可以绘制出我们想要的三角形了:


三角形的绘制.png
二、用键位控制三角形的移动

首先看一下,三角形平移的坐标变换:

平移坐标变换.png

由此可知移动三角形我们只需将顶点数组数据,进行坐标平移变换,重新渲染视图即可实现,三角形的平移。
定义一个三角形移动的函数void SpecialKeys(int key, int x, int y) 在main函数中注册该函数:

glutSpecialFunc(SpecialKeys);

通过移动顶点坐标实现,三角形的移动:

//由于在SpecialKeys函数和setupRC函数中都需要用到顶点数据 因此我们可以将其定义为全局变量
GLfloat triangleSize = 0.2f;
GLfloat vVerts[] = {
    0.0f,triangleSize,0.0f,
    -triangleSize,0.0f,0.0f,
    triangleSize,0.0f,0.0f,
};

void SpecialKeys(int key, int x, int y){
    //移动的步长
    GLfloat stepSize = 0.15;(该值为标量,左减右加 上加下减)
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[1];

    //控制键值实现坐标的左右移动
    if (key == GLUT_KEY_UP) blockY += stepSize;//当点击键盘上向上的箭头是 a'点的纵坐标增加stepSize
    if (key == GLUT_KEY_DOWN) blockY -= stepSize;
    if (key == GLUT_KEY_RIGHT) blockX += stepSize;
    if (key == GLUT_KEY_LEFT) blockX -= stepSize;

    //边界检测 防止移动出屏幕之外
    if (blockX > 1.0f-triangleSize) blockX = 1.0f-triangleSize;
    if (blockX < triangleSize-1.0f) blockX = triangleSize-1.0f;
    if (blockY > 1.0f) blockY = 1.0f;
    if (blockY < triangleSize-1.0f) blockY = triangleSize-1.0f;

    //顶点更新
    vVerts[0] = blockX;//移动后a‘点的横坐标
    vVerts[1] = blockY;//移动后a’点的纵坐标 

   //以a点为坐标原点 则b点的坐标为(- triangleSize,- triangleSize,0) c点的坐标为( triangleSize,- triangleSize,0),则根据上面移动坐标变换可以得出b‘ c'点的坐标
    vVerts[3] = blockX - triangleSize;
    vVerts[4] = blockY-triangleSize;

    vVerts[6] = blockX + triangleSize;
    vVerts[7] = blockY - triangleSize;

    triangleBatch.CopyVertexData3f(vVerts);
    //顶点坐标移动后 重新绘制三角形
    glutPostRedisplay();
    
}

运行即可得到,三角形如演示图一样的三角形的移动效果,但这样做存在着一个问题,三角形还好我们只需要移动三个点就好,但当遇到不规则的图形时,这样移动显然是不合适的。通过线性代数的知识我们知道,通过矩阵的方式,我们也可以实现坐标的平移变换。

//定义x轴y轴的偏移量
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;

//重写SpecialKeys函数
void SpecialKeys(int key, int x, int y){
    //移动的步长
    GLfloat stepSize = 0.2f;

    if (key == GLUT_KEY_UP) yPos += stepSize;
    if (key == GLUT_KEY_DOWN) yPos -= stepSize;
    if (key == GLUT_KEY_RIGHT) xPos += stepSize;
    if (key == GLUT_KEY_LEFT) xPos -= stepSize;

    //边界检测
    if (xPos > 1.0f-triangleSize) xPos = 1.0f-triangleSize;
    if (xPos < triangleSize-1.0f) xPos = triangleSize-1.0f;
    if (yPos > 1.0f-triangleSize) yPos = 1.0f-triangleSize;
    if (yPos < -1.0f) yPos = -1.0f;

    glutPostRedisplay();
}

//重写RenderScene函数
void RenderScene(void){
    //清空缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //设置颜色
    GLfloat color[] = {0.3, 0.4,0.8,1};
    //定义一个矩阵
    M3DMatrix44f mTransFromMatrix;
    /** 平移矩阵
     m3dTranslationMatrix44(<#float *m#>, <#float x#>, <#float y#>, <#float z#>)
     第一个参数 将用来装平移矩阵的矩阵
     第二个参数是x轴的偏移量
     第三个参数是y轴的偏移量
     第四个参数是z轴的偏移量
     */
    m3dTranslationMatrix44(mTransFromMatrix, xPos, yPos, 0.0f);
   //GLT_SHADER_IDENTITY是片元着色器 无法进行坐标的平移变换  
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransFromMatrix, color);
    
    triangleBatch.Draw();
    glutSwapBuffers();    
}

通过运行我们依旧能得到一个会移动的三角形,但通过矩阵的方式远比顶点坐标一个个移动的方式要简单的多。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350