0%

MAC搭建GLFW3和GLEW、GLAD的OpenGL环境

GLFW是什么?

GLFW是一个开源的多平台库,用于桌面上的OpenGL、OpenGL ES和Vulkan开发。它提供了一个简单的API,用于创建窗口、上下文和表面,接收输入和事件。和GLFW类似功能的几个库是GLUT、SDL、SFML和GLFW。我使用的是GLFW,大多数库的配置方法和GLFW差不多。

GLEW是什么?

GLEW是一个跨平台C++扩展库,基于OpenGL图形接口。GLEW能自动识别你的平台上所支持的全部OpenGL高级扩展函数。只要包含一个glew.h头文件,你就能使用gl、glu、wgl、glx的全部函数。GLEW支持目前流行的各种操作系统(包括Windows、Linux、Mac OSX、FreeBSD、Irix 和 Solaris)。

安装GLFW 和 GLEW

1
2
brew install glfw3
brew install glew

安装完成之后,在/opt/homebrew/Cellar路径下可以看见glew和glfw。

GLAD是什么?

GLAD是一个开源库,帮助开发者确定OpenGL函数位置。

安装GLAD

打开GLAD网站https://glad.dav1d.de/,选择3.3以上Core配置,直接Generate下载即可。

下载完成后解压会得到include和src文件夹,include文件夹中有glad和KRH两个文件夹,src中只有一个glad.c文件。

将include下的文件夹,包括glad和KRH都拷贝到/usr/local/include路径下,方便后期配置。

在Xcode配置glew、glfw和glad的路径

在Xcode中配置好glew和glfw、glad的路径

新建项目

新建MAC命令行项目,然后到 build Setting -> Header Search Path 和 Library Search Path 添加相应的配置。

配置Header Search Path:
$(glew_header) 、$(glfw_header)、$(glad_header)

配置Library Search Path:
$(inherited) $(glew_lib) $(glfw_lib)

增加Build Phases配置:
添加glfw和glew的库的时候需要对应的路径

1
2
/opt/homebrew/Cellar/glew/2.2.0_1/lib
/opt/homebrew/Cellar/glfw/3.3.6/lib

删除原来的main文件,新建C++的main文件,并创建相应的header文件。如果使用到了GLAD,还需要将glad.c源文件拖到项目中。
测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>


// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// Shaders
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";

// The MAIN function, from here we start the application and run the game loop
int main()
{
std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);

// Set the required callback functions
glfwSetKeyCallback(window, key_callback);

// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit();

// Define the viewport dimensions
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);


// Build and compile our shader program
// Vertex shader
GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Check for compile time errors
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment shader
GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for compile time errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Link shaders
GLint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);


// Set up vertex data (and buffer(s)) and attribute pointers
//GLfloat vertices[] = {
// // First triangle
// 0.5f, 0.5f, // Top Right
// 0.5f, -0.5f, // Bottom Right
// -0.5f, 0.5f, // Top Left
// // Second triangle
// 0.5f, -0.5f, // Bottom Right
// -0.5f, -0.5f, // Bottom Left
// -0.5f, 0.5f // Top Left
//};
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, // Top Right
0.5f, -0.5f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f // Top Left
};
GLuint indices[] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
GLuint VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind

glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs), remember: do NOT unbind the EBO, keep it bound to this VAO


// Uncommenting this call will result in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

// Game loop
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();

// Render
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// Draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
//glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

// Swap the screen buffers
glfwSwapBuffers(window);
}
// Properly de-allocate all resources once they've outlived their purpose
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return 0;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}

如果出现下图所示的效果,则环境配置成功

遇到的错误

提示dyld: Library not loaded: /opt/homebrew/opt/glfw/lib/libglfw.3.dylib,详细错误信息如下:

1
2
3
4
5
dyld: Library not loaded: /opt/homebrew/opt/glfw/lib/libglfw.3.dylib
  Referenced from: /Users/tingyue/Library/Developer/Xcode/DerivedData/测试opengl-cveeuitmqxwjawbhmdcvrxupnsvp/Build/Products/Debug/测试opengl
  Reason: no suitable image found.  Did find:
/opt/homebrew/opt/glfw/lib/libglfw.3.dylib: code signature in (/opt/homebrew/opt/glfw/lib/libglfw.3.dylib) not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?)
/opt/homebrew/Cellar/glfw/3.3.6/lib/libglfw.3.3.dylib: code signature in (/opt/homebrew/Cellar/glfw/3.3.6/lib/libglfw.3.3.dylib) not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?)

解决办法:
找到项目的Signing&Capabilities选项,然后勾选Disable Library Validation选项,重新运行起来就可以了。

Demo下载

下载Demo工程

参考链接

Mac下Xcode+OpenGL环境搭建
创建窗口