美文网首页
3、OpenGL初探之OpenGL初探之绘制可用键盘移动的三角形

3、OpenGL初探之OpenGL初探之绘制可用键盘移动的三角形

作者: 溪浣双鲤 | 来源:发表于2019-08-16 00:52 被阅读0次
前言:前一部分了解了OpenGL环境搭建和基本API之后,我们先来做一个小小的练习,使用固定管线来绘制一个可移动的三角形,同时详细解释一下一些常用方法的含义

一、搭建OpenGL在Mac下的环境


搭建Xcode环境,这里不再做过多赘述了

传送门:https://www.jianshu.com/p/05555148d567

二、实战开始


(注:完整代码在文章的最后面)
1、首先来到main函数中进行环境初始化和一些函数的注册

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("Triangle");
        
    glutReshapeFunc(ChangeSize);
    
    glutDisplayFunc(RenderScene);
    
    glutSpecialFunc(SpecialKeys);
    
    GLenum err = glewInit();
    
    if(GLEW_OK != err) {
        
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        
        return 1;
        
    }
    
    SetupRC();
    
    glutMainLoop();
    
    return 0;
}

下面来一一分析对应函数和方法的意思,

gltSetWorkingDirectory(argv[0]) : 是”GLTools“用来设置当前工作目录的函数,实际上在windows中是不必要的,因为工作目录默认就是与程序的可执行程序的目录相同。但是在Mac OSX环境中,这个程序将当前工作文件夹改为应用程序捆绑包中的"/Resource"文件夹.'GLUT'的优先设定会自动设定为这个,这样写也是为了更加安全。

glutInit(&argc, argv): 初始化GLUT库,这个函数只是传入命令参数并且初始化glut库

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL): 设置显示模式。其中GLUT_DOUBLE 指的是初始化双缓冲窗口显示模式,GLUT_RGBA RGBA颜色显示模式,GLUT_DEPTH 初始化深度测试显示模式,可以用于开启深度测试,GLUT_STENCIL 初始化模板缓冲区

glutInitWindowSize(800,600) 初始化一个GLUT窗口并设置窗口大小
glutCreateWindow("Triangle") 设置窗口的标题

glutReshapeFunc(ChangeSize) 注册绑定重塑函数,当窗口第一次创建或者窗口大小发生变化,需要界面重绘时,系统会自动调用这个已经注册过的自定义函数ChangeSize
glutDisplayFunc(RenderScene) 注册绑定显示函数,当屏幕发生渲染或者你使用代码强制渲染,需要界面重绘的时候,系统会自动调用这个已经注册绑定过的自定义函数RenderSize

glutSpecialFunc(SpecialKeys); 当你使用特殊键位的时候比如键盘的上下左右键的时候,就会走到这个方法里,在这个函数中做特殊键位区分的时候,这些特殊键位都有对应的枚举值比如上(GLUT_KEY_UP) 下(GLUT_KEY_DOWN)左(GLUT_KEY_LEFT)右(GLUT_KEY_RIGHT),我找了一些,这个简单了解一下就行了

#define GLUT_KEY_F1         1
#define GLUT_KEY_F2         2
#define GLUT_KEY_F3         3
#define GLUT_KEY_F4         4
#define GLUT_KEY_F5         5
#define GLUT_KEY_F6         6
#define GLUT_KEY_F7         7
#define GLUT_KEY_F8         8
#define GLUT_KEY_F9         9
#define GLUT_KEY_F10            10
#define GLUT_KEY_F11            11
#define GLUT_KEY_F12            12
/* directional keys */
#define GLUT_KEY_LEFT           100
#define GLUT_KEY_UP         101
#define GLUT_KEY_RIGHT          102
#define GLUT_KEY_DOWN           103
#define GLUT_KEY_PAGE_UP        104
#define GLUT_KEY_PAGE_DOWN      105
#define GLUT_KEY_HOME           106
#define GLUT_KEY_END            107
#define GLUT_KEY_INSERT         108

GLenum err = glewInit(); 初始化一个GLEW库,确保OpenGL API对程序完全可用,在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题

SetupRC() 自定方法,设置我们的渲染环境

glutMainLoop() 运行循环,类似OC的Runloop,函数在调用之后,在主窗口被关闭之前都不会返回,一个应用程序只需要调用一次,这个函数负责处理我们所有的消息,直到我们关闭程序为止。

2、接着引入固定管线着色器和OpenGL一些基本库文件

#include "GLShaderManager.h"

#include "GLTools.h"

#include <glut/glut.h>


GLShaderManager.h 这个移入了GLTool着色器管理器类shader manager,没有着色器,我们就不能再OpenGL核心框架进行着色,着色器管理器不仅允许我们创建并管理着色器,还提供了一组”存储着色器“,他们能够进行一些基本的渲染操作。

GLTools.h GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数

GLUT/GLUT.h 在Mac 系统下,需要#include <glut/glut.h> ; 在windows和Linux上,我们使用freeglut的静态库版本并需要添加一个宏

3、重塑函数的实现,在窗口大小改变的时候,接受新的宽度和高度

void changeSize(int w,int h)
{
    glViewport(0, 0, w, h);
    
}

glViewPort这个函数就是设置视口,x,y 参数代表窗口中视图的左下角坐标,而宽度、高度是像素为表示,通常x,y 都是为0,调用glViewPort会调用重新渲染RenderScene

4、接着定义一个着色器管理变量和一个批次类,GLBatch是GLTools的一个简单的容器类

GLBatch triangleBatch;

GLShaderManager shaderManager;

5、接下来,我们需要设置渲染环境和顶点数据

void SetupRC()

{

    glClearColor(0.0f,0.0f,1.0f,1.0f);
    
    shaderManager.InitializeStockShaders();
        
    GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };
    
    
    triangleBatch.Begin(GL_TRIANGLES,3);
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    triangleBatch.End();
}

glClearColor 设置清屏颜色,设置到颜色缓冲区里面,是一个状态基,可以理解为窗口的背景色

shaderManager.InitializeStockShaders() 初始化一个着色器管理器

GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };
    定义一个一维数组,里面存储三角形的三个顶点的坐标,每个顶点有三个数(x,y,z)

其中
triangleBatch.Begin(GL_TRIANGLES,3); 第一个参数GL_TRIANGLES指的是选择三角形的连接方式,第二个参数3代表3个顶点

triangleBatch.CopyVertexData3f(vVerts);把顶点数据copy进去,然后triangleBatch.End();表示设置完成

这里拓展一下便于理解,如果是画四边形SetUpRC中的顶点坐标需要修改成

如果是要绘制四边形,需要修改顶点数组,然后修改连接方式如下

void SetupRC()

{    
    glClearColor(0.0f,0.0f,1.0f,1.0f);
    
    shaderManager.InitializeStockShaders();
    
    GLfloat vVerts[] = {
        
        -0.5f,-0.5f,0.0f,
        
        -0.5f,0.5f,0.0f,
        
        0.5f,0.5f,0.0f,
        
        0.5f,-0.5f,0.0f,
        
    };
    
    triangleBatch.Begin(GL_TRIANGLE_FAN,4);
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    triangleBatch.End();
    
}

对比一下,顶点数组变了,然后连接方式由GL_TRIANGLES变为GL_TRIANGLE_FAN,顶点个数由3个变为4个

 顶点数组的变化很明显,就不细说了
 连接方式和顶点个数变了
 //三角形的
 triangleBatch.Begin(GL_TRIANGLES,3);
 //四边形的
 triangleBatch.Begin(GL_TRIANGLE_FAN,4);

这里再拓展一下,OpenGL图元只有点、线、三角形,现在画点,线以及多边形都没问题了,圆形就需要通过这三个做处理一下了

6、接下来我们需要设置渲染

void RenderScene(void)

{   
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
        
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
        
    triangleBatch.Draw();
        
    glutSwapBuffers();
    
}

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) 每次渲染前需要清除特定缓冲区比如深度缓冲区,颜色缓冲区

shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed) 不同的着色器,参数都是不一样的,但是函数名都是这个,绘制简单的三角形,用单元着色器就行了,所以选GLT_SHADER_IDENTITY,并设置绘制颜色

triangleBatch.Draw() 开始颜色渲染

glutSwapBuffers() 交换缓冲区,把渲染的内容提交上去

执行一下,就能看到蓝色背景的windows下,有一个红色的三角形

1.png

7、开始设置移动,设置移动之前需要把顶点坐标设置为全局变量,这样好处理,把下面顶点数组放到全局

GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };

把这段坐标换成下面这段,然后把边长减小点,便于查看效果

//blockSize 边长
GLfloat blockSize = 0.1f;

//三角形的3个点坐标
GLfloat vVerts[] = {
        -blockSize,0.0f,0.0f,
        blockSize,0.0f,0.0f,
        0.0f,blockSize,0.0f,
};

然后开始实现SpecialKeys函数,这里拓展一下,顶点较少可以使用更新顶点坐标这种移动方式,顶点较多的复杂图形,可以使用矩阵进行移动

void SpecialKeys (int key , int x, int y){
    
    GLfloat stepSize = 0.1f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[1];
    
    if (key == GLUT_KEY_UP) blockY += stepSize;
    if (key == GLUT_KEY_DOWN) blockY -= stepSize;
    if (key == GLUT_KEY_LEFT) blockX -= stepSize;
    if (key == GLUT_KEY_RIGHT) blockX += stepSize;
    
    //更新点的坐标 ABC
    vVerts[0] = blockX;
    vVerts[1] = blockY;
    
    vVerts[3] = blockX + 2 * stepSize;
    vVerts[4] = blockY;
    
    vVerts[6] = blockX + stepSize;
    vVerts[7] = blockY + stepSize;
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    glutPostRedisplay();
}


其中设置blockX和blockY只是找了第一个点作为移动坐标参照物,然后相对第一个点的坐标换算出剩余两个点的坐标,比如A(-0.1,0,0) B(0.1,0,0),换算成A(blockX,0,0)那此时的B就是(block + 2 * 0.1,0, 0), vVerts[0]这里面的下标0,代表一维数组中的第一个点的x坐标,只上下左右移动,只需要改三个点对应的x,y坐标就行了, 三个点想x和y的坐标对应的下标分别是0,1和3,4和6,7,这样思路就很清楚了。

triangleBatch.CopyVertexData3f(vVerts); 这个将顶点数组通过GLBatch帮助类,将顶点数据传输到存储着色器中

glutPostRedisplay()这个是手动触发渲染函数。

然后直接运行,就能够得到一个可以用键盘控制上下左右移动的三角形。

完整代码如下

//
//  main.cpp
//
//  Created by battleMage on 2019/8/11.
//  Copyright © 2019 battleMage. All rights reserved.
//

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

GLBatch triangleBatch;
GLShaderManager shaderManager;

//blockSize 边长
GLfloat blockSize = 0.1f;

//三角形的3个点坐标
GLfloat vVerts[] = {
    -blockSize,0.0f,0.0f,
    blockSize,0.0f,0.0f,
    0.0f, blockSize,0.0f,
};

void ChangeSize(int w,int h){
    glViewport(0,0, w, h);
}

void SpecialKeys (int key , int x, int y){
    
    GLfloat stepSize = 0.1f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[1];
    
    if (key == GLUT_KEY_UP) blockY += stepSize;
    if (key == GLUT_KEY_DOWN) blockY -= stepSize;
    if (key == GLUT_KEY_LEFT) blockX -= stepSize;
    if (key == GLUT_KEY_RIGHT) blockX += stepSize;
    
    //更新点的坐标 ABC
    vVerts[0] = blockX;
    vVerts[1] = blockY;
    
    vVerts[3] = blockX + 2 * stepSize;
    vVerts[4] = blockY;
    
    vVerts[6] = blockX + stepSize;
    vVerts[7] = blockY + stepSize;
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    glutPostRedisplay();
}

void SetupRC(){
    glClearColor(0.0f,0.0f,1.0f,1.0f);
    shaderManager.InitializeStockShaders();
    triangleBatch.Begin(GL_TRIANGLES,3);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}

void RenderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    triangleBatch.Draw();
    glutSwapBuffers();
}

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("Triangle");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    SetupRC();
    glutMainLoop();
    return 0;
}


效果如下:


1.png 2.png 3.png

溪浣双鲤的技术摸爬滚打之路

相关文章

  • 3、OpenGL初探之OpenGL初探之绘制可用键盘移动的三角形

    一、搭建OpenGL在Mac下的环境 搭建Xcode环境,这里不再做过多赘述了 传送门:https://www.j...

  • openGL

    OpenGl ES 初探 专业名词解释 OpenGL上下文[ context) 在应用程序调用任何OpenGL的指...

  • Android音视频之使用OpenGL ES绘制图片

    关于 OpenGL ES 的介绍,请先看上篇:Android 音视频之使用 OpenGL ES 绘制三角形。 1....

  • 基础知识

    OpenGL初识[https://www.jianshu.com/p/207f0a8e492f] OpenGL初探...

  • OpenGL笔记十一:GLKit初探

    前言 期待您移步上篇:OpenGL笔记十:OpenGL ES初探 GLKit 框架概述 GLKit 框架的设计⽬标...

  • OpenGL一:OpenGL简介

    Demo: 01-渲染三角形、02-正方形移动、03-绘制图形 一、OpenGL 简介 OpenGL发展至今,已经...

  • 二、OpenGL 2D绘制

    1、概述 下面我通过使用OpenGL绘制三角形,来解析OpenGL的绘制原理。 我们先来回顾下OpenGL的渲染管...

  • (一)OpenGL初探

    OpenGL初探 开篇介绍 这篇文章,主要讲的是以下几点: 图形API简介 图形API解决什么问题 OpenGL专...

  • OpenGL初探

    关于图形API OpenGL (Open Graphics Library) 是一个跨编程语言、跨平台的编程图形程...

  • OpenGL初探

    图形API简介 OpenGL (Open Graphics Library)是一个跨编程语言、跨平台的编程图形程序...

网友评论

      本文标题:3、OpenGL初探之OpenGL初探之绘制可用键盘移动的三角形

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