由于移动端接下来我们需要深入了解学习和使用OpenGL ES,前期我们需要了解基础OpenGL基本用法, 后续进行原理探讨.
下面推荐几个OpenGL学习的书籍/网站
红宝书
[蓝宝书/超级宝典,自行百度网盘下载]
http://www.opengl-tutorial.org/
(推荐)
https://learnopengl-cn.github.io/
(个人理解)
红宝书在前半部分, 没有例子, 只有原理精炼. 没有清晰 OpenGL 概念的初学者看几遍都看不懂的. 亲身经历是浪费了大量阅读时间, 收获甚微. 不过, 红宝书包含很多高级的内容 (在第 7 章以后), 这部分是蓝宝书所没有的.
蓝宝书有清楚的例子, 有深入浅出的解释, 对 Rendering Pipeline 的解释足以支撑你深入学习和阅读其他书籍. 个人认为蓝宝书之于 OpenGL 犹如 C++ Primer 之于 C++.
下面开始配置环境, 配置环境的目的在于后面每次练习/项目都会基于这次的配置基础工程展开, 因此配置完毕后把基础代码保存一份,以防每次需要重新配置.
配置完成demo
一、需导入库
- CLTools
- glew
- libGLTools.a
(可以在配置完成demo下载后找到libGLTools.a和 include文件夹即是我们需要的)
二、开始配置
- Command+Shift+N
-
添加OpenGl.framework 和 GLUT.framework 两个系统库
-
拖入include文件夹和libGLTools.a
-
配置搜索路径("$(SRCROOT)/工程名/include") 注意: 根据自己实际文件配置相对路径.即从根目录找到include文件夹的路径
-
由于只需要创建一个窗口来使用基础OpenGL绘制. 因此直接在Main函数操作即可, 删除多余文件 AppDelegate.h 、 AppDelegate.m 、 main.m 、ViewController.h 、 ViewController.m ;
-
创建 main.cpp文件,文件名写main
三、测试环境是否搭建成功
可直接拷贝以下代码替换至main.cpp中
#include
#include "GLShaderManager.h"
#include "GLTools.h"
#include
//简单的批次容器,是GLTools的一个简单的容器类
GLBatch triangleBatch;
//着色管理器
GLShaderManager shaderManager;
//blockSize : 边长的1/2
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.0f;
GLfloat yPos = 0.0f;
//窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w,int h)
{
glViewport(0,0, w, h);
}
//为程序作一次性的设置
void SetupRC()
{
//设置背影颜色
glClearColor(0.0f,0.0f,1.0f,1.0f);
//初始化着色管理器
shaderManager.InitializeStockShaders();
//设置三角形,其中数组vVert包含所有3个顶点的x,y,笛卡尔坐标对。
// GLfloat vVerts[] = {
//
// -0.5f,0.0f,0.0f,
//
// 0.5f,0.0f,0.0f,
//
// 0.0f,0.5f,0.0f,
//
// };
//批次处理
// begin方法第一个参数是指用不同的模式来绘图,第二个参数是指有几个顶点
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
//开始渲染
void RenderScene(void)
{
//清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//设置一组浮点数来表示红色
GLfloat vGreen[] = {0.0f,1.0f,0.0f,1.0f};
// GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
//传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
// shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vGreen);
// x,y,z,w(缩放因子默认1.0)
M3DMatrix44f mTransformMatrix,mFinalTransform,mRotationMatix;
m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);
static float ZRot = 0.0f;
m3dRotationMatrix44(mRotationMatix, m3dDegToRad(ZRot), 0.0f, 0.0f, 1.0f);
ZRot += 5.0f;
//矩阵相乘
m3dMatrixMultiply44(mFinalTransform, mTransformMatrix, mRotationMatix);
//平面着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vGreen);
//提交着色器
triangleBatch.Draw();
//将在后台缓冲区进行渲染,然后在结束时交换到前台
glutSwapBuffers();
}
void SpecialKeys(int key,int x, int y)
{
/* 键盘上下左右移动绘制的正方形 第一种方法
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[10];
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;
}
//更新顶点之前 检测是否到边界 到了则限制在显示范围内
if (blockX < -1.0f) {
blockX = -1.0f;
}
if (blockX > 1.0f - blockSize * 2) {
blockX = 1.0f - blockSize * 2;
}
if (blockY < -1.0f + blockSize * 2) {
blockY = -1.0f + blockSize * 2;
}
if (blockY > 1.0f) {
blockY = 1.0f;
}
//更新其他顶点的位置
//A点
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize * 2;
//B点
vVerts[3] = blockX + blockSize * 2;
vVerts[4] = blockY - blockSize * 2;
//C点
vVerts[6] = blockX + blockSize * 2;
vVerts[7] = blockY;
//D点
vVerts[9] = blockX;
vVerts[10] = blockY;
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
*/
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.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();
}
int main(int argc,char* argv[])
{
//设置当前工作目录,针对MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT库
glutInit(&argc, argv);
/*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小,标题窗口
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
SetupRC();
glutMainLoop();
return 0;
}
-
运行
-
如果你跟我一样是Xcode10.0或者以上版本 应该跟我一样, 一片黑. 不着急 ,最小化窗口 再打开. 或者把窗口拉大一点. 就看到结果了. 按下键盘上下左右试试?
这个问题是因为Xcode升级10.0以后不调用ChanggeSize方法, 暂时不影响我们继续研究OpenGL和OpenGL ES.
OK 配置完成 记得保存一份配置完成代码 SetupRC和 RenderScene方法中是绘制的具体过程 以后替换为自己的即可.