数据科学与计算机学院 徐海洋
本学习基于 LearnOpenGL (旧版)。
基本环境:
- MacBook Pro (15-inch, 2016)
- macOS High Sierra (版本10.13.3)
- Inter HD Graphics 530 1536 MB
- Xcode (Version 9.2)
使用 GLUT 的方法:
- 在 Xcode 项目配置里的 Build Phases 中添加库 OpenGL.framework 和 GLUT.framework 。
- 在源文件中引入头文件 GLUT.h 。
⚠️:在 Xcode 中警告使用的 glut 函数在 macOS 10.9 开始被弃用。
解决办法为:在 Xcode 项目配置里的 General 中修改部署目标为 10.8 或以下版本。
⚠️:系统默认的 OpenGL 的实现版本为 2.1 。
查看 OpenGL 版本等信息的办法为:
std::cout <<"OpenGL Vendor: " <std::endl;
std::cout <<"OpenGL Renderer: " <std::endl;
std::cout <<"OpenGL Version: " <std::endl;
在学习中要求使用 OpenGL 版本为 3.3 及以上。
首先,在 Apple 的开发者网站 OpenGL for macOS 中查看设备的 OpenGL 版本支持。(本设备支持 4.1 版本)
接下来,采用 GLEW 和 GLFW 的解决方案,一个较好的实践为:
- 安装 GLEW:从其 GitHub 中下载 zip 解压后进入根目录。
$ make
$ sudo make install
$ make clean
⚠️:在本机实践中需要先在 auto 文件夹中 make 一下。
- 安装 GLFW:首先在 CMake 官网 中下载 dmg 文件并安装;接着在 GLFW 的 GitHub 仓库中下载 zip 并解压;最后使用 CMake 编译源文件。
⚠️:在本机实践中先 configure 后勾选 BUILD_SHARED_LIBS 来创建库,再 configure 一次后点击 Generate 并确认完成。
- 配置 Xcode 项目: 同样地,先在 Build Phases 中添加库 libGLEW.2.1.0.dylib 和 libglfw.3.3.dylib 。不同的是,在 Build Settings 中分别设置 Always Search User Paths 为 Yes , Header Search Paths 为 /usr/local/include 和 Library Search Paths 为 /usr/local/lib 。
完成配置后,在源文件中依次引入头文件 glew.h 和 glfw3.h 并添加代码段:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
⚠️:确认安装最新的 glfw 版本并完成上述代码配置,因为在 3.2 版本下本机实践出现了 first responder error 。
最后,根据教程中绘制三角形的方法(着色器、VBO 和 VAO),成功在本机上使用 OpenGL 4.1 复现 。
⚠️:可能出现创建的窗口红色闪烁问题,在本机实践中利用清除颜色可以解决。
⚠️:可能出现其他绘制方法没有显示的问题,建议使用教程方法解决。
⚠️:教程中的 glfwGetFramebufferSize 函数可能无法使用,利用文中的可选方案解决。
⚠️:教程参考代码。
复现代码如下:
#include
#define GLEW_STATIC
#include
#include
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGLab", nullptr, nullptr);
if (window == nullptr) {
std::cout <<"Failed to create GLFW window" <<std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cout <<"Failed to initialize GLEW" <<std::endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
char* vertexShaderSource = "#version 330 core\n\nlayout (location = 0) in vec3 position;\n\nvoid main()\n{\n\tgl_Position = vec4(position.x, position.y, position.z, 1.0);\n}";
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
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" <std::endl;
}
char* fragmentShaderSource = "#version 330 core\n\nout vec4 color;\n\nvoid main()\n{\n\tcolor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n}";
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout <<"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" <std::endl;
}
GLuint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout <<"ERROR::SHADER::PROGRAM::LINK_FAILED\n" <std::endl;
}
glUseProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
std::cout <<"OpenGL Vendor: " <std::endl;
std::cout <<"OpenGL Renderer: " <std::endl;
std::cout <<"OpenGL Version: " <std::endl;
std::cout <<"GLFW library version: " <std::endl;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}