数据科学与计算机学院 徐海洋
本学习基于 LearnOpenGL (旧版)。
基本环境:
使用 GLUT 的方法:
⚠️:在 Xcode 中警告使用的 glut 函数在 macOS 10.9 开始被弃用。
解决办法为:在 Xcode 项目配置里的 General 中修改部署目标为 10.8 或以下版本。
⚠️:系统默认的 OpenGL 的实现版本为 2.1 。
查看 OpenGL 版本等信息的办法为:
// 在初始化及创建窗口后
std::cout << "OpenGL Vendor: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
在学习中要求使用 OpenGL 版本为 3.3 及以上。
首先,在 Apple 的开发者网站 OpenGL for macOS 中查看设备的 OpenGL 版本支持。(本设备支持 4.1 版本)
接下来,采用 GLEW 和 GLFW 的解决方案,一个较好的实践为:
$ make
$ sudo make install
$ make clean
⚠️:在本机实践中需要先在 auto 文件夹中 make 一下。
⚠️:在本机实践中先 configure 后勾选 BUILD_SHARED_LIBS 来创建库,再 configure 一次后点击 Generate 并确认完成。
完成配置后,在源文件中依次引入头文件 glew.h 和 glfw3.h 并添加代码段:
// 在 glfw 初始化后
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); // for Mac OS X
⚠️:确认安装最新的 glfw 版本并完成上述代码配置,因为在 3.2 版本下本机实践出现了 first responder error 。
最后,根据教程中绘制三角形的方法(着色器、VBO 和 VAO),成功在本机上使用 OpenGL 4.1 复现 。
⚠️:可能出现创建的窗口红色闪烁问题,在本机实践中利用清除颜色可以解决。
⚠️:可能出现其他绘制方法没有显示的问题,建议使用教程方法解决。
⚠️:教程中的 glfwGetFramebufferSize 函数可能无法使用,利用文中的可选方案解决。
⚠️:教程参考代码。
复现代码如下:
//
// main.cpp
// opengl
//
// Created by hay on 2018/3/6.
// Copyright © 2018年 hay. All rights reserved.
//
#include
// GLEW
#define GLEW_STATIC
#include
// GLFW
#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); // for Mac OS X
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); // glfwGetFramebufferSize doesnt work
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);
// Vertex Shader
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" << infoLog << std::endl;
}
// Fragment Shader
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" << infoLog << 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" << infoLog << 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: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "GLFW library version: " << glfwGetVersionString() << 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;
}