抱歉,本文写的很乱,建议跳过代码部分。
1 #include <cstdio> 2 #include <cstdlib> 3 4 #include <GL/glew.h> 5 6 #include <GLFW/glfw3.h> 7 8 #include <glm/glm.hpp> 9 #include <glm/gtc/matrix_transform.hpp> 10 using namespace glm; 11 using namespace std; 12 13 #include <shader.hpp> 14 #include <shader.cpp> 15 16 static const GLfloat g_vertex_buffer_data[] = { 17 -1.0f,-1.0f,-1.0f, // triangle 1 : begin 18 -1.0f,-1.0f, 1.0f, 19 -1.0f, 1.0f, 1.0f, // triangle 1 : end 20 1.0f, 1.0f,-1.0f, // triangle 2 : begin 21 -1.0f,-1.0f,-1.0f, 22 -1.0f, 1.0f,-1.0f, // triangle 2 : end 23 1.0f,-1.0f, 1.0f, 24 -1.0f,-1.0f,-1.0f, 25 1.0f,-1.0f,-1.0f, 26 1.0f, 1.0f,-1.0f, 27 1.0f,-1.0f,-1.0f, 28 -1.0f,-1.0f,-1.0f, 29 -1.0f,-1.0f,-1.0f, 30 -1.0f, 1.0f, 1.0f, 31 -1.0f, 1.0f,-1.0f, 32 1.0f,-1.0f, 1.0f, 33 -1.0f,-1.0f, 1.0f, 34 -1.0f,-1.0f,-1.0f, 35 -1.0f, 1.0f, 1.0f, 36 -1.0f,-1.0f, 1.0f, 37 1.0f,-1.0f, 1.0f, 38 1.0f, 1.0f, 1.0f, 39 1.0f,-1.0f,-1.0f, 40 1.0f, 1.0f,-1.0f, 41 1.0f,-1.0f,-1.0f, 42 1.0f, 1.0f, 1.0f, 43 1.0f,-1.0f, 1.0f, 44 1.0f, 1.0f, 1.0f, 45 1.0f, 1.0f,-1.0f, 46 -1.0f, 1.0f,-1.0f, 47 1.0f, 1.0f, 1.0f, 48 -1.0f, 1.0f,-1.0f, 49 -1.0f, 1.0f, 1.0f, 50 1.0f, 1.0f, 1.0f, 51 -1.0f, 1.0f, 1.0f, 52 1.0f,-1.0f, 1.0f 53 }; 54 55 //每个顶点一个颜色 56 static const GLfloat g_color_buffer_data[] = { 57 0.583f, 0.771f, 0.014f, 58 0.609f, 0.115f, 0.436f, 59 0.327f, 0.483f, 0.844f, 60 0.822f, 0.569f, 0.201f, 61 0.435f, 0.602f, 0.223f, 62 0.310f, 0.747f, 0.185f, 63 0.597f, 0.770f, 0.761f, 64 0.559f, 0.436f, 0.730f, 65 0.359f, 0.583f, 0.152f, 66 0.483f, 0.596f, 0.789f, 67 0.559f, 0.861f, 0.639f, 68 0.195f, 0.548f, 0.859f, 69 0.014f, 0.184f, 0.576f, 70 0.771f, 0.328f, 0.970f, 71 0.406f, 0.615f, 0.116f, 72 0.676f, 0.977f, 0.133f, 73 0.971f, 0.572f, 0.833f, 74 0.140f, 0.616f, 0.489f, 75 0.997f, 0.513f, 0.064f, 76 0.945f, 0.719f, 0.592f, 77 0.543f, 0.021f, 0.978f, 78 0.279f, 0.317f, 0.505f, 79 0.167f, 0.620f, 0.077f, 80 0.347f, 0.857f, 0.137f, 81 0.055f, 0.953f, 0.042f, 82 0.714f, 0.505f, 0.345f, 83 0.783f, 0.290f, 0.734f, 84 0.722f, 0.645f, 0.174f, 85 0.302f, 0.455f, 0.848f, 86 0.225f, 0.587f, 0.040f, 87 0.517f, 0.713f, 0.338f, 88 0.053f, 0.959f, 0.120f, 89 0.393f, 0.621f, 0.362f, 90 0.673f, 0.211f, 0.457f, 91 0.820f, 0.883f, 0.371f, 92 0.982f, 0.099f, 0.879f 93 }; 94 95 int main() { 96 if(!glfwInit()) { 97 fprintf(stderr, "Failed To init OpenGL "); 98 } 99 100 // We want OpenGL 3.3 101 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 102 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 103 // To make MacOS happy; should not be needed 104 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 105 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL 106 107 // Open a window and create its OpenGL context 108 // (In the accompanying source code, this variable is global) 109 GLFWwindow* window; 110 window = glfwCreateWindow(800, 600, "Tutorial 01", NULL, NULL); 111 if( window == NULL ){ 112 fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials. " ); 113 glfwTerminate(); 114 return -1; 115 } 116 glfwMakeContextCurrent(window); // Initialize GLEW 117 glewExperimental = true; // Needed in core profile 118 119 //z-buffer 120 glEnable(GL_DEPTH_TEST); 121 glDepthFunc(GL_LEFT); 122 123 if (glewInit() != GLEW_OK) { 124 fprintf(stderr, "Failed to initialize GLEW "); 125 return -1; 126 } 127 128 //背景颜色 129 glClearColor(0.0f, 0.0f, 0.4f, 0.0f); 130 131 //shader 132 GLuint programID = LoadShaders( "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/vertex.shader", "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/fragment.shader" ); 133 134 GLuint VertexArrayID; 135 glGenVertexArrays(1, &VertexArrayID); 136 glBindVertexArray(VertexArrayID); 137 138 //vertex buffer 139 GLuint vertexbuffer; 140 glGenBuffers(1, &vertexbuffer); 141 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 142 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); 143 144 //color buffer 145 GLuint colorbuffer; 146 glGenBuffers(1, &colorbuffer); 147 glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); 148 glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); 149 150 mat4 Projection = perspective(radians(70.0f), (float)4/3, 0.1f, 1000.f); 151 152 mat4 View = lookAt(vec3(3, 4, -5), vec3(0,0,0), vec3(0,1,0)); 153 154 mat4 Model = mat4(1.0f); 155 156 //模型到投影转换 157 mat4 mvp = Projection * View * Model; 158 159 GLuint MatrixID = glGetUniformLocation(programID, "mvp"); 160 161 while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)) { 162 //每次开始时清空画布 163 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 164 165 //使用shader 166 glUseProgram(programID); 167 168 //把变换矩阵送进shader 169 glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]); 170 171 //画三角形 172 glEnableVertexAttribArray(0); 173 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 174 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 175 176 //三角形颜色 177 glEnableVertexAttribArray(1); 178 glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); 179 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 180 181 //draw call 182 glDrawArrays(GL_TRIANGLES, 0, 12 * 3); 183 184 glDisableVertexAttribArray(0); 185 glDisableVertexAttribArray(1); 186 187 glfwSwapBuffers(window); 188 glfwPollEvents(); 189 } 190 glfwTerminate(); 191 return 0; 192 }
首先是OpenGL的文件
对于OS X的用户来说,只要安装了Xcode,OpenGL也就被安装了(因为OS X用的就是这个。。)
但是还需要其他几个库,用于处理平台相关的事情或者方便我们编程,他们分别是GLFW,GLEW,GLM
在OS X上,用brew可以很方便的安装以上几个库,安装后进入下一步。
一、配置项目文件
打开Xcode,创建项目。
在如所示的的地方配置以上3个库的头文件位置。如果不知道库安装在哪了,可以用brew info glew的方式找到安装路径
配置结果如下,Libraray Search Path 不用管,后面会说
现在可以在项目的代码中正确的调用各个库的头文件了,比如
#include <GLFW/glfw3.h>
但是这样是无法编译通过的,因为lib文件还没有被链接进来,编译器会找不到头文件里面函数的定义之类的。
所以需要链接所有必要的lib文件。
链接后应该如下
点击那个“加号”添加lib
其中,4个framework直接搜就可以找到。
另外两个lib分别在GLEW和GLFW的安装目录下,比如我的路径如下:
[brew安装路径]/glew/1.13.0/lib/libGLEW.a
另一个同理,在安装目录的lib文件夹下面找得到。
glm库不用添加lib
至此所有的OpenGL代码应该就可以正常编译了,不过我上面贴的那段不行,因为我没贴全。。。
二、OpenGL程序的基本结构
首先需要按照以下顺序include一些头文件,这是魔法。
#include <GL/glew.h>
#include <GLFW/glfw3.h>
以上是最主要的头文件了,当然我们还需要不少辅助的东西,全部的include如下
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
#include <cstdio>
#include <cstdlib>
using namespace std;
OpenGL 3.0以后使用了可编程渲染管线,我们需要自己编写shader并编译
这里有个现成的编译shader的函数,拿来用就好
#ifndef SHADER_HPP #define SHADER_HPP GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path); #endif
1 #include <stdio.h> 2 #include <string> 3 #include <vector> 4 #include <iostream> 5 #include <fstream> 6 #include <algorithm> 7 using namespace std; 8 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <GL/glew.h> 13 14 #include "shader.hpp" 15 16 GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ 17 18 // Create the shaders 19 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); 20 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); 21 22 // Read the Vertex Shader code from the file 23 std::string VertexShaderCode; 24 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); 25 if(VertexShaderStream.is_open()){ 26 std::string Line = ""; 27 while(getline(VertexShaderStream, Line)) 28 VertexShaderCode += " " + Line; 29 VertexShaderStream.close(); 30 }else{ 31 printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ ! ", vertex_file_path); 32 getchar(); 33 return 0; 34 } 35 36 // Read the Fragment Shader code from the file 37 std::string FragmentShaderCode; 38 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); 39 if(FragmentShaderStream.is_open()){ 40 std::string Line = ""; 41 while(getline(FragmentShaderStream, Line)) 42 FragmentShaderCode += " " + Line; 43 FragmentShaderStream.close(); 44 } 45 46 GLint Result = GL_FALSE; 47 int InfoLogLength; 48 49 50 // Compile Vertex Shader 51 printf("Compiling shader : %s ", vertex_file_path); 52 char const * VertexSourcePointer = VertexShaderCode.c_str(); 53 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); 54 glCompileShader(VertexShaderID); 55 56 // Check Vertex Shader 57 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); 58 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 59 if ( InfoLogLength > 0 ){ 60 std::vector<char> VertexShaderErrorMessage(InfoLogLength+1); 61 glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); 62 printf("%s ", &VertexShaderErrorMessage[0]); 63 } 64 65 66 67 // Compile Fragment Shader 68 printf("Compiling shader : %s ", fragment_file_path); 69 char const * FragmentSourcePointer = FragmentShaderCode.c_str(); 70 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); 71 glCompileShader(FragmentShaderID); 72 73 // Check Fragment Shader 74 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); 75 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 76 if ( InfoLogLength > 0 ){ 77 std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1); 78 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); 79 printf("%s ", &FragmentShaderErrorMessage[0]); 80 } 81 82 83 84 // Link the program 85 printf("Linking program "); 86 GLuint ProgramID = glCreateProgram(); 87 glAttachShader(ProgramID, VertexShaderID); 88 glAttachShader(ProgramID, FragmentShaderID); 89 glLinkProgram(ProgramID); 90 91 // Check the program 92 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); 93 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); 94 if ( InfoLogLength > 0 ){ 95 std::vector<char> ProgramErrorMessage(InfoLogLength+1); 96 glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); 97 printf("%s ", &ProgramErrorMessage[0]); 98 } 99 100 101 glDetachShader(ProgramID, VertexShaderID); 102 glDetachShader(ProgramID, FragmentShaderID); 103 104 glDeleteShader(VertexShaderID); 105 glDeleteShader(FragmentShaderID); 106 107 return ProgramID; 108 }
别忘了#include <shader.hpp> 并把 shader.cpp 添加到项目的Compile Sources里
g_vertex_buffer_data 和 g_color_buffer_data 储存正方形的顶点位置信息和颜色信息
main 函数里:
1 if(!glfwInit()) { 2 fprintf(stderr, "Failed To init OpenGL "); 3 } 4 5 // We want OpenGL 3.3 6 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 7 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 8 // To make MacOS happy; should not be needed 9 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 10 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL 11 12 // Open a window and create its OpenGL context 13 // (In the accompanying source code, this variable is global) 14 GLFWwindow* window; 15 window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL Window", NULL, NULL); 16 if( window == NULL ){ 17 fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials. " ); 18 glfwTerminate(); 19 return -1; 20 } 21 glfwMakeContextCurrent(window); // Initialize GLEW 22 glewExperimental = true; // Needed in core profile 23 24 if (glewInit() != GLEW_OK) { 25 fprintf(stderr, "Failed to initialize GLEW "); 26 return -1; 27 }
启用z-buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
我感觉注释说的够清楚了。。。直接看代码吧
1 //背景颜色 2 glClearColor(0.0f, 0.0f, 0.4f, 0.0f); 3 4 //载入并编译shader 5 GLuint programID = LoadShaders( "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/vertex.shader", "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/fragment.shader" ); 6 7 //VAO 8 //加速存储效率,储存VBO 9 //Veretx Array Object 10 GLuint VertexArrayID; 11 //创建 12 glGenVertexArrays(1, &VertexArrayID); 13 //绑定 14 glBindVertexArray(VertexArrayID); 15 16 //以下创建两个VBO 17 //Vertex Buffer Object 18 //用于将数据储存到显存中 19 20 //第一个VBO 21 //储存顶点数据 22 GLuint vertexbuffer; 23 //创建 24 glGenBuffers(1, &vertexbuffer); 25 //绑定 26 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 27 //储存数据 28 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); 29 30 //第二个VBO 31 //储存颜色信息 32 //操作原理同上 33 GLuint colorbuffer; 34 glGenBuffers(1, &colorbuffer); 35 glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); 36 glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); 37 38 //创建坐标变换矩阵 39 //本地 -> 世界 -> 视口 -> 齐次剪裁空间 空间变换流程 40 // Model View Projection 对应需要的矩阵 41 //透视变换 42 mat4 Projection = perspective(radians(70.0f), (float)WIDTH / HEIGHT, 0.1f, 1000.f); 43 //视口变换 44 mat4 View = lookAt(vec3(3, 4, 5), vec3(0,0,0), vec3(0,1,0)); 45 //本地变换 46 mat4 Model = mat4(1.0f); 47 48 //集成本地到齐次剪裁空间的转换 49 mat4 MVP = Projection * View * Model; 50 51 //从shader中取出mvp (不是上面的MVP,特地用大小写区分了) 52 //方便等会传入数据 53 GLuint MatrixID = glGetUniformLocation(programID, "mvp"); 54 55 while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)) { 56 //每次开始时清空画布 57 //同时清空z-buffer 58 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 59 60 //使用shader 61 glUseProgram(programID); 62 63 //把变换矩阵送进shader 64 glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 65 66 //把顶点信息送入shader 67 //数字0对应vertex shader中的 location = 0 68 glEnableVertexAttribArray(0); 69 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); 70 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 71 72 //把三角形颜色送入shader 73 //数字0对应vertex shader中的 location = 1 74 glEnableVertexAttribArray(1); 75 glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); 76 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 77 78 //draw call 79 glDrawArrays(GL_TRIANGLES, 0, 12 * 3); 80 81 //一定要在draw call之后关闭 82 glDisableVertexAttribArray(0); 83 glDisableVertexAttribArray(1); 84 85 //切换前后缓存,将渲染好的显示出来 86 glfwSwapBuffers(window); 87 glfwPollEvents(); 88 }
vertex shader:
1 #version 330 core 2 layout(location = 0) in vec3 vertexPosition_modelspace; 3 layout(location = 1) in vec3 vertexColor; 4 5 uniform mat4 mvp; 6 out vec3 fragmentColor; 7 8 void main() { 9 gl_Position = mvp * vec4(vertexPosition_modelspace, 1); 10 fragmentColor = vertexColor; 11 }
fragment shader:
1 #version 330 core 2 3 out vec3 color; 4 in vec3 fragmentColor; 5 6 void main() { 7 color = fragmentColor; 8 }
至于这两个shader干嘛的。。。我先学习学习