OpenGL学习笔记: mac下OpenGL环境搭建
Posted 计算机科学家的世界
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL学习笔记: mac下OpenGL环境搭建相关的知识,希望对你有一定的参考价值。
1,OpenGL是什么
OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
2,OpenGL能做什么
OpenGL能用来开发跨平台的渲染引擎,在android、OSX、ios、Windows、PS等平台均可使用 OpenGL(ES)。
3,OpenGL不能做什么
OpenGL不能做物理模拟,OpenGL不能做网络通信,一句话,除了渲染以外的事情,OpenGL都做不了,OpenGL只是一个3D渲染API接口标准。
4,OpenGL VS DirectX
OpenGL和DirectX 相比有以下几点不同:
- OpenGL只能做渲染,DirectX除了渲染以外还能做许多其它的,比如,DirectX 里面包含d3dxmath可以用来做3D数学运算;DirectX里面包含的外部设备接口模块可以用来接受外部设备的输入。
- OpenGL只是一个定义了一些接口的标准,只要实现了这些接口,那么就算是实现了OpenGL,相反的,DirectX则只有微软自己实现的那一份代码,所有人都使用微软给出的那份代码。
- OpenGL能跨平台,几乎所有的平台都支持OpenGL,从移动设备到PC产品再到主机平台,都支持OpenGL,而DirectX则只有微软自己的XBox和Windows支持。
- 速度方面,DirectX完爆OpenGL,对同一硬件而言,DirectX是OpenGL 渲染速度的两倍多。
5,MAC OpenGL环境搭建
我在MAC上使用OpenGL时,使用了如下一些工具和库:Mac Ports、glfw、glew、XCode。
- MacPorts是MAC 平台用来安装第三方库的软件,与 Linux上的apt-install有点像,大家可以从https://www.macports.org/下载
- glfw,OpenGL的扩展程序,因为OpenGL只是一个渲染接口,如果要在具体平台上写OpenGL渲染代码,就要使用 qlfw等库将OpenGL 和本地窗口等环境联系起来,安装glfw只需要使用mac ports即可(sudo port install glfw)。
- glew,与 glfw类似,使用sudo port install glew安装。
- XCode,MAC平台开发唯一的神器,别告诉我在mac你还在用Eclipse写C++。
6,Demo代码
在这里,我只给出一个demo代码,即使用Gourand着色画一个正方形,代码主要包含以下几部分。
/*
* File: Shader.h
* author: 张雄
* date: 2016_02_21
* purpose: 用于定义OpenGL shader操作的接口
*/
#ifndef __ZX_NXENGINE_SHADER_H__
#define __ZX_NXENGINE_SHADER_H__
#include "../common/NXCore.h"
namespace NX
class Shader
public:
/*
* <函数功能>
* 构造函数
*
* <函数参数>
* szFilePath: 要使用的shader代码的路径,需要保证的是,仅使用szFilePath,在
* 程序中即可找到shader文件。
* uShaerType: 要使用的shader 代码的shader类型,此类型有GL_VERTEX_SHADER等
* 与OpenGL中使用的值完全相同。
*/
Shader(const char* szFilePath, GLenum uShaderType);
virtual ~Shader();
public:
/*
* <函数功能>
* 编译shader,shader文件和类型由构造函数给出
*/
virtual std::string Compile();
public:
operator GLuint()
return m_uShaderId;
private:
std::string ReadShaderSource();
private:
GLuint m_uShaderId;
GLenum m_uShaderType;
std::string m_strShaderSourceFilePath;
;
#endif
#include <fstream>
#include <string>
#include "NXShader.h"
#include "NXLog.h"
NX::Shader::Shader(const char* szFilePath, GLenum uShaderType)
m_strShaderSourceFilePath = (szFilePath);
m_uShaderId = 0;
m_uShaderType = uShaderType;
NX::Shader::~Shader()
if(m_uShaderId != 0)
glDeleteShader(m_uShaderId);
m_uShaderId = 0;
m_uShaderType = 0;
std::string NX::Shader::Compile()
std::string strErr(256 + 1, 0);
m_uShaderId = glCreateShader(m_uShaderType);
const std::string strShaderSrc = ReadShaderSource();
if(strShaderSrc.empty())
sprintf((char*)strErr.c_str(), "shader file [%s] not exist or is empty", m_strShaderSourceFilePath.c_str());
glb_GetLog().log("%s", strErr.c_str());
return strErr;
const char * szShaderSrc = strShaderSrc.c_str();
glShaderSource(m_uShaderId, 1, &szShaderSrc, NULL);
glCompileShader(m_uShaderId);
glGetShaderInfoLog(m_uShaderId, (GLuint)strErr.length(), NULL, &(strErr[0]));
glb_GetLog().log("compile shader [%s] with compile msg [%s]", m_strShaderSourceFilePath.c_str(),
(strErr[0] == 0 ? "Compile succeed" : strErr.c_str()));
return strErr;
std::string NX::Shader::ReadShaderSource()
std::ifstream in(m_strShaderSourceFilePath);
std::string line;
std::string strShaderSrc;
while(std::getline(in, line))
line += "\\r\\n";
strShaderSrc += line;
in.close();
return strShaderSrc;;
/*
* File: Application.h
* author: 张雄
* date: 2016_02_21
* purpose: 用于定义OpenGL应用程序接口,注意,此接口使用了glfw和glew,需要先安装此工具库,
* 在mac上可使用macports安装,具体操作请google macports,Linux系统使用apt-get,
* windows系统请直接下载库和头文件(自己编译估计有点坑)
*/
#ifndef __ZX_NXENGINE_APPLICATION_H__
#define __ZX_NXENGINE_APPLICATION_H__
#include "../common/NXcore.h"
namespace NX
class Application
public:
Application();
virtual ~Application();
public:
/*
* <函数功能>
* 使用glfw和glew库初始化OpenGL环境,注意,此函数应该是构造函数之后调用的第一个类函数,
* 在调用此函数并且成功之前,不得调用其它OpenGL函数。其它类如果继承此类,则需要首先调用
* 此类的Init函数,再执行子类的Init代码。
*
* <函数参数>
* vCmdLine: 命令行字符串数组,与C的main函数类似
* iCmdCount: 命令行字符串个数
* iWidth: OpenGL使用的窗口的宽(以像素为单位)
* iHeight: OpenGL使用的窗口的高(以像素为单位)
* <返回值>
* true: 初始化成功,在init之后,即可调用其它OpenGL函数
* false: 初始化失败
*/
virtual bool Init(__in const char* vCmdLine[], __in const int iCmdCount,
__in const int iWidth, __in const int iHeight);
/*
* <函数功能>
* 游戏中的Tick函数。
*
* <函数参数>
* iTime: 时间,以秒为单位
*/
virtual void Tick(const double DeltaTime);
/*
* <函数功能>
* 游戏中的Render函数,主要完成游戏中的渲染
*
*/
virtual void Render();
/*
* <函数功能>
* 游戏中的主循环,其它类若要继承此类,最好不要重载Run函数,以免不必要的麻烦
*
*/
virtual void Run();
public:
/*
* <函数功能>
* 错误处理函数
*
* <函数参数>
* 与glfw中错误处理回调函数的参数完全相同。
*/
virtual void OnError(int error, const char* description);
/*
* <函数功能>
* 错误处理函数
*
* <函数参数>
* 与glfw中键盘事件回调函数的参数意义完全相同
*/
virtual void OnKeyEvent(int key, int scancode, int action, int mods);
;
#endif
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "NXApplication.h"
#include "../math/NXMath.h"
#include "../common/NXLog.h"
static NX::Application* g_pThis = NULL;
static GLFWwindow* g_window = NULL;
static void error_callback(int error, const char* description);
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
NX::Application::Application()
g_pThis = NULL;
g_window = NULL;
NX::Application::~Application()
g_pThis = NULL;
g_window = NULL;
bool NX::Application::Init(const char* vCmdLine[], const int iCmdCount, const int iWidth, const int iHeight)
g_pThis = this;
NX::InitNXMath();
if (!glfwInit())
fprintf(stderr, "Failed initialize GLFW.");
exit(EXIT_FAILURE);
return false;
glfwSetErrorCallback(error_callback);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(iWidth, iHeight, "OpenGL", NULL, NULL);
if(!window)
std::fprintf(stderr, "Failed to create GLFW window.");
glfwTerminate();
exit(EXIT_FAILURE);
return false;
g_window = window;
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glb_GetLog().logToConsole("OpenGL version supported by this platform (%s)", glGetString(GL_VERSION));
glb_GetLog().log("OpenGL version supported by this platform (%s)", glGetString(GL_VENDOR));
glewExperimental = GL_TRUE;
glewInit();
return true;
void NX::Application::Tick(const double DeltaTime)
static double iTotalTime = 0;
iTotalTime += DeltaTime;
static char Title[32];
static int iFrameCount = 0;
++iFrameCount;
if(iTotalTime >= 1.0)
sprintf(Title, "fps: %.2f", (iFrameCount / iTotalTime));
iFrameCount = 0;
iTotalTime = 0;
glfwSetWindowTitle(g_window, Title);
void NX::Application::Render()
static const GLfloat green[] = 0.0f, 0.25f, 0.0f, 1.0f ;
glClearBufferfv(GL_COLOR, 0, green);
void NX::Application::OnError(int error, const char* description)
std::fputs(description, stderr);
void NX::Application::OnKeyEvent(int key, int scancode, int action, int mods)
if(g_window == NULL)
return;
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(g_window, GL_TRUE);
void NX::Application::Run()
static double PreTime = glfwGetTime();
static double NowTime = glfwGetTime();
while(!glfwWindowShouldClose(g_window))
NowTime = glfwGetTime();
Tick(NowTime - PreTime);
Render();
glFlush();
glfwSwapBuffers(g_window);
glfwPollEvents();
PreTime = NowTime;
static void error_callback(int error, const char* description)
if(!g_pThis)
return;
g_pThis->OnError(error, description);
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
if(!g_window)
return;
g_pThis->OnKeyEvent(key, scancode, action, mods);
#ifndef __ZX_OPENGL_APPLICATION_CHAP1_1_H__
#define __ZX_OPENGL_APPLICATION_CHAP1_1_H__
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../engine/render/NXApplication.h"
#include "../engine/common/NXLog.h"
#include "../engine/render/NXProgram.h"
class AppChap1_1: public NX::Application
public:
typedef struct vertex
GLfloat x;
GLfloat y;
GLfloat r;
GLfloat g;
GLfloat b;
GLfloat a;
vertex;
public:
AppChap1_1();
virtual ~AppChap1_1();
public:
virtual bool Init(const char* vCmdLine[], const int iCmdCount, const int iWidth, const int iHeight);
virtual void Tick(const double DeltaTime);
virtual void Render();
virtual void OnKeyEvent(int key, int scancode, int action, int mods);
private:
GLuint m_uVBO1;
GLuint m_uVBO2;
GLuint m_uVAO1;
GLuint m_uVAO2;
GLuint m_UsedVBO;
GLuint m_UsedVAO;
NX::Program* m_pg;
;
#endif
#include <iostream>
#include "AppChap1_1.h"
#include "NXShader.h"
AppChap1_1::AppChap1_1()
m_uVAO1 = 0;
m_uVAO2 = 0;
m_uVBO1 = 0;
m_uVBO2 = 0;
m_UsedVBO = 0;
AppChap1_1::~AppChap1_1()
bool AppChap1_1::Init(const char* vCmdLine[], const int iCmdCount, const int iWidth, const int iHeight)
if(!NX::Application::Init(vCmdLine, iCmdCount, iWidth, iHeight))
return false;
//vao1
glGenVertexArrays(1, &m_uVAO1);
glBindVertexArray(m_uVAO1);
//vbo1
glGenBuffers(1, &m_uVBO1);
glBindBuffer(GL_ARRAY_BUFFER, m_uVBO1);
vertex v[4] =
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f
;
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//vao2
glGenVertexArrays(1, &m_uVAO2);
glBindVertexArray(m_uVAO2);
//vbo2
glGenBuffers(1, &m_uVBO2);
glBindBuffer(GL_ARRAY_BUFFER, m_uVBO2);
vertex v[4] =
-0.8f, 0.8f, 0.0f, 1.0f, 1.0f, 1.0f,
0.8f, 0.8f, 1.0f, 0.0f, 1.0f, 1.0f,
-0.8f, -0.8f, 1.0f, 1.0f, 0.0f, 1.0f,
0.8f, -0.8f, 0.0f, 0.0f, 0.0f, 1.0f
;
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_UsedVAO = m_uVAO1;
m_UsedVBO = m_uVBO1;
//program
m_pg = new NX::Program();
m_pg->AddShader("./redbook/Chap1/VS1_1.glsl", GL_VERTEX_SHADER);
m_pg->AddShader("./redbook/Chap1/FS1_1.glsl", GL_FRAGMENT_SHADER);
m_pg->LinkProgram();
m_pg->UseProgram();
return true;
void AppChap1_1::Tick(const double DeltaTime)
void AppChap1_1::Render()
m_pg->UseProgram();
glClearColor(0.0f, 0.25f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(m_UsedVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_UsedVBO);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)8);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//glViewport(100, 100, 400, 100);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
void AppChap1_1::OnKeyEvent(int key, int scancode, int action, int mods)
Application::OnKeyEvent(key, scancode, action, mods);
if(action == GLFW_PRESS)
return;
std::cout << "change buffer..." << std::endl;
if(m_UsedVBO == m_uVBO1)
m_UsedVBO = m_uVBO2;
else
m_UsedVBO = m_uVBO1;
if(m_UsedVAO == m_uVAO1)
m_UsedVAO = m_uVAO2;
else
m_UsedVAO = m_uVAO1;
#include <iostream>
#include <memory>
#include "NXShader.h"
#include "NXLog.h"
#include "NXVector.h"
#include "NXMatrix.h"
#include "DemoHeader.h"
int main(int argc, const char* argv[])
NX::glb_GetLog().logToConsole("begin main");
std::auto_ptr<NX::Application> app(new AppChap1_1());
if(!app->Init(argv, argc, 800, 800))
std::cout << "failed init application..." << std::endl;
return 1;
NX::glb_GetLog().logToConsole("begin application");
app->Run();
NX::glb_GetLog().logToConsole("end main");
return 0;
#version 410 core
in vec4 Color;
out vec4 vFinalColor;
void main(void)
vFinalColor = Color;
#version 330 core
layout(location = 0) in vec2 vPosition;
layout(location = 1) in vec4 vColor;
out vec4 Color;
void main()
gl_Position = vec4(vPosition, -0.5f, 1.0f);
Color = vColor;
我整个开发环境如下所示:(从后面给的Git上下载代码可直接打开的哦)
程序的结果如下:
按下键盘上任何键后(ESC则会退出渲染程序),变换成如下:
在学习OpenGL的时候,我自己封装了一些基本的类,比如 Program、shader、Texture等,这些代码我放在GitHub上,其中包含我上面列出的代码,第一个程序比较简单,我也不愿意花更多时间去讲一些东西,大家只需要从Git下过来编译即可得到相同的结果,至于 OpenGL的后序学习和我编写的代码,我将会慢慢发出来,代码部分会发至Git,有兴趣的欢迎评阅。
以上是关于OpenGL学习笔记: mac下OpenGL环境搭建的主要内容,如果未能解决你的问题,请参考以下文章
openGL 学习之路一 在mac电脑上搭建opengl环境