本文參考https://learnopengl.com/Getting-started/Creating-a-window
GLFW
GLFW是一個由c寫成的庫,為OpenGL提供基本渲染的的一個實現(xiàn)類庫
Building GLFW
GLFW 的lib庫不一定在每一臺電腦都可以使用蚂夕,所以需要在使用者自己的電腦上編譯GLFW源文件胳喷,以生成lib庫 喂链,這樣是比較靠譜的司草。
下載地址
CMake
CMake是一個工具哥倔,可以使用預(yù)定義的CMake腳本從一組源代碼文件中生成用戶選擇的項目/解決方案文件(例如Visual Studio,Code :: Blocks唯沮,Eclipse)。這使我們可以從GLFW的源代碼包生成一個Visual Studio 2012項目文件堪遂,我們可以使用它來編譯生成GLFW庫介蛉。
下載地址
CMake安裝好后 , 我們將選擇已下載的GLFW源文件包的根文件夾溶褪,然后在GLFW源文件包里面創(chuàng)建一個build文件夾币旧,然后將build輸出目錄選擇這個目錄,具體看如下圖
一旦設(shè)置了源文件夾和目標(biāo)文件夾猿妈,點擊Configure按鈕吹菱,CMake就可以讀取所需的設(shè)置和源代碼巍虫。然后,我們必須為項目選擇生成器鳍刷,并且由于我們使用的是Visual Studio 2017占遥,因此我們將選擇“Visual Studio 17” 。然后CMake將顯示可能的構(gòu)建選項來配置結(jié)果庫输瓜。這個時候不用管瓦胎,再次點擊`Configure就可以存儲設(shè)置完成 ,然后接著我們可以點擊Generate尤揣,生成的項目文件會在你的build文件夾中生成搔啊。
Compilation
在build文件夾中,可以找到一個名為GLFW.sln的文件北戏,并且我們用Visual Studio 2017打開它负芋。
我們可以點擊Build Solution按鈕,然后會在build / src / Debug生成的編譯庫glfw3.lib (注意最欠,我們使用的是版本3)示罗。
GLFW源代碼目錄中,你會看到由一個Include目錄芝硬,然后里面是GLFW的一些庫文件蚜点,這個Include庫文件以及之前說過的glfw3.lib 是我們所需要的。
Glad
在完成準(zhǔn)備工作之前拌阴,由于OpenGL是一個標(biāo)準(zhǔn)/規(guī)范绍绘,因此驅(qū)動程序制造商必須將該規(guī)范實施到特定圖形卡支持的驅(qū)動程序。由于OpenGL驅(qū)動程序有許多不同的版本迟赃,其大部分功能的位置在編譯時并不知道陪拘,需要在運行時查詢。然后開發(fā)人員的任務(wù)是檢索他/她所需功能的位置并將它們存儲在函數(shù)指針中以備后用纤壁。檢索這些位置是特定于操作系統(tǒng)的左刽,在Windows中它看起來像這樣:
//定義函數(shù)的原型
typedef void(* GL_GENBUFFERS)(GLsizei,GLuint *);
//找到函數(shù)并將其分配給函數(shù)指針
GL_GENBUFFERS glGenBuffers =(GL_GENBUFFERS)wglGetProcAddress(“glGenBuffers”);
//現(xiàn)在可以調(diào)用正常的函數(shù)
無符號整型緩沖區(qū);
glGenBuffers(1酌媒,&buffer);
正如你所看到的欠痴,代碼看起來很復(fù)雜,對于你可能需要的尚未聲明的每個函數(shù)來說秒咨,這是一個麻煩的過程喇辽。值得慶幸的是,這里還有一些專門處理這類事務(wù)的類庫Glad
設(shè)置GLAD
GLAD是一個 開源的庫雨席, 下載地址菩咨,可以管理我們所討論的所有繁瑣工作。 GLAD與大多數(shù)常見的開源庫有略微不同的配置設(shè)置。 GLAD使用Web服務(wù)抽米,我們可以告訴GLAD我們要定義哪個版本的OpenGL特占,并根據(jù)該版本加載所有相關(guān)的OpenGL函數(shù)。所以一般我們不用關(guān)心這個源代碼缨硝,只需要使用由這個開源庫提供的Web服務(wù)即可
我們打開 Web服務(wù) (點擊這個鏈接)摩钙,將會打開一個網(wǎng)頁,在網(wǎng)頁中做如下操作:
確保語言設(shè)置為C ++查辩,
并在API部分中選擇至少3.3的OpenGL版本(這是我們將用于這些教程的內(nèi)容;更高版本也可以)胖笛。
確保配置文件設(shè)置為Core,
保證Generate a loader被勾選宜岛。忽略擴展(至少在目前為止我們先這么做)长踊,
然后單擊generate以生成庫文件。
然后你可以看到GLAD應(yīng)該已經(jīng)為您提供了一個zip文件萍倡,其中包含兩個包含文件夾glad and KHR和一個glad.c文件身弊。這幾個東西是我們需要的。
準(zhǔn)備
1.在你的工作目錄新建一個目錄Opengl
2.在Opengl里面新建兩個文件夾Includes和Libs
3.將前文提到的GLFW的Include文件里的glfw目錄和glad ,KHR 均拷貝到Includes目錄下
4.將前文提到的GLFW的glfw3.lib拷貝到Libs目錄下
5.glad.c將會拷貝到vs工程列敲,這個后面交代
微信截圖_20180419205046.png
Our first project
現(xiàn)在讓我們打開Visual Studio并創(chuàng)建一個新項目阱佛。如果給出多個選項并選擇空項目,請選擇Visual C ++(不要忘記給項目一個合適的名稱)戴而。我們現(xiàn)在有一個工作空間來創(chuàng)建我們的第一個OpenGL應(yīng)用程序凑术!
我們將glad.c拷貝到工程目錄源代碼目錄,同時新建一個Main.cpp文件所意,并粘貼如下內(nèi)容
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader program
// ------------------------------------
// vertex shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char 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
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile 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
int 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 configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
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(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
// uncomment this call to draw in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glDrawArrays(GL_TRIANGLES, 0, 3);
// glBindVertexArray(0); // no need to unbind it every time
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
Linking
在跑起來之前淮逊,還有一些東西需要設(shè)置
通過轉(zhuǎn)到項目屬性(在解決方案資源管理器中右鍵單擊項目名稱),我們可以添加這些目錄(其中VS應(yīng)該搜索庫/包含文件)扶踊,然后轉(zhuǎn)到“VC ++目錄”泄鹏,如圖中所示下面(請注意圖中加粗的部分),用于配置類庫和引用:
然后是鏈接器輸入配置秧耗,如下
之后备籽,你build工程,就可以看到一個三角形分井,如下圖
本文是一個簡化版本胶台,詳細版本,請參見https://learnopengl.com/Getting-started/Creating-a-window
Have Fun杂抽。
其他后續(xù)問題
今天發(fā)現(xiàn)opengl開源庫有很多版本,比如glut韩脏,freeGlut等等缩麸,相應(yīng)的配置方式可以參考各自的官方鏈接,如有需要赡矢,后期補上這方面的配置說明