MacOS配置OpenGL环境攻略

说明

写这篇文章是给自己的踩坑过程做个笔记,免得以后重新配置会很麻烦,当然也帮助一下用Mac也在学新版本OpenGL的同学们。

导入已有的库

使用XCode创建OpenGL项目,然后在Link Binary With Libraries中添加

  • OpenGL.framework
  • GLUT.framework

配置glew,glut,glfw3,gltools

参考文章:- Mac下使用OpenGL——配置glew/glut/glfw3/gltools环境 作者写的很清楚了,亲测可以配置成功,我就不抄一遍了。但是第四步的sudo ldconfig是无法跑过的,那是Linux的命令,你可以忽略它。

配置SOIL

SOIL是简易OpenGL图像库(Simple OpenGL Image Library)的缩写,它支持大多数流行的图像格式,使用起来也很简单,你可以从他们的主页下载。像其它库一样,你必须自己生成.lib。但是我建议MacOS不要去SOIL的官网下载并自己编译,因为编译链接Xcode时会报错:Undefined symbols for architecture x86_64,Windows系统这样做倒是没什么问题。Github上有人对libSOIL做了修改,能让它在MacOS上安装的更好,所以我们采用以下方法。(项目地址https://github.com/smibarber/libSOIL
第一步:克隆到本地,终端输入

1
git clone https://github.com/smibarber/libSOIL.git

第二步:继续输入

1
make

第三步:输入

1
make install

如果报错就在开头加一个sudo

最后:将libSOIL.dylib,libSOIL.a,SOIL.h拖进你的项目即可。这些你可以在本地的/opt/local/lib/和/opt/local/include/SOIL/里找到。

## 代码测试 以下是用LearnOpenGL的代码跑出来的程序结果,中文网址LearnOpenGL-CN-纹理。程序已经修改调试好,如果环境没有问题,只需更改SOIL_load_image的图片路径就可以了。
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <iostream>

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

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

// Other Libs
#include <SOIL.h>

const GLchar *vertexShaderSource="#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"layout (location = 2) in vec2 texCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 1.0f);\n"
"ourColor = color;\n"
"TexCoord = texCoord;\n"
"}\n\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"out vec4 color;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"color = texture(ourTexture, TexCoord);\n"
"}\n\0";


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

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

// The MAIN function, from here we start the application and run the game loop
int main()
{
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

// 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 viewwidth, viewheight;
glfwGetFramebufferSize(window, &viewwidth, &viewheight);
glViewport(0, 0, viewwidth, viewheight);



​ // Build and compile our shader program
​ GLuint 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
​ GLuint 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
​ GLuint 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[] = {
​ // Positions // Colors // Texture Coords
​ 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Top Right
​ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right
​ -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Left
​ -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.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);

​ 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);

// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// TexCoord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);

glBindVertexArray(0); // Unbind VAO



​ // Load and create a texture
​ GLuint texture;
​ glGenTextures(1, &texture);
​ glBindTexture(GL_TEXTURE_2D, texture); // All upcoming GL_TEXTURE_2D operations now have effect on this texture object
​ // Set the texture wrapping parameters
​ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT (usually basic wrapping method)
​ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
​ // Set texture filtering parameters
​ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
​ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
​ // Load image, create texture and generate mipmaps
​ int width, height;
​ unsigned char* image = SOIL_load_image("/Users/ZhouMingzhe/X-Code/OpenGL/image/container.jpg", &width, &height, 0, SOIL_LOAD_RGB);
​ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
​ glGenerateMipmap(GL_TEXTURE_2D);
​ SOIL_free_image_data(image);
​ glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.



​ // 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);



​ // Bind Texture
​ glBindTexture(GL_TEXTURE_2D, texture);

​ // Activate shader
​ glUseProgram(shaderProgram);

​ // Draw container
​ glBindVertexArray(VAO);
​ 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);
}

配置glm

如果前面都配置好了,直接在终端brew install glm即可,根本不需要其他骚操作。之前按照stackoverflow上说吧glm文件夹拖进项目,添加header search path等等都没有用,然后我抱着侥幸心理敲了这个命令,程序就跑通了。不过我配置glm的过程中有点迷,感觉很玄学,如果有人配置失败,或者要帮我补充一下,请回复在评论区,谢谢。


评论