抱歉,本文写的很乱,建议跳过代码部分。
#include <cstdio>
#include <cstdlib> #include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
using namespace std; #include <shader.hpp>
#include <shader.cpp> static const GLfloat g_vertex_buffer_data[] = {
-1.0f,-1.0f,-1.0f, // triangle 1 : begin
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, // triangle 1 : end
1.0f, 1.0f,-1.0f, // triangle 2 : begin
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f,-1.0f, // triangle 2 : end
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f
}; //每个顶点一个颜色
static const GLfloat g_color_buffer_data[] = {
0.583f, 0.771f, 0.014f,
0.609f, 0.115f, 0.436f,
0.327f, 0.483f, 0.844f,
0.822f, 0.569f, 0.201f,
0.435f, 0.602f, 0.223f,
0.310f, 0.747f, 0.185f,
0.597f, 0.770f, 0.761f,
0.559f, 0.436f, 0.730f,
0.359f, 0.583f, 0.152f,
0.483f, 0.596f, 0.789f,
0.559f, 0.861f, 0.639f,
0.195f, 0.548f, 0.859f,
0.014f, 0.184f, 0.576f,
0.771f, 0.328f, 0.970f,
0.406f, 0.615f, 0.116f,
0.676f, 0.977f, 0.133f,
0.971f, 0.572f, 0.833f,
0.140f, 0.616f, 0.489f,
0.997f, 0.513f, 0.064f,
0.945f, 0.719f, 0.592f,
0.543f, 0.021f, 0.978f,
0.279f, 0.317f, 0.505f,
0.167f, 0.620f, 0.077f,
0.347f, 0.857f, 0.137f,
0.055f, 0.953f, 0.042f,
0.714f, 0.505f, 0.345f,
0.783f, 0.290f, 0.734f,
0.722f, 0.645f, 0.174f,
0.302f, 0.455f, 0.848f,
0.225f, 0.587f, 0.040f,
0.517f, 0.713f, 0.338f,
0.053f, 0.959f, 0.120f,
0.393f, 0.621f, 0.362f,
0.673f, 0.211f, 0.457f,
0.820f, 0.883f, 0.371f,
0.982f, 0.099f, 0.879f
}; int main() {
if(!glfwInit()) {
fprintf(stderr, "Failed To init OpenGL\n");
} // We want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
// To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL // Open a window and create its OpenGL context
// (In the accompanying source code, this variable is global)
GLFWwindow* window;
window = glfwCreateWindow(, , "Tutorial 01", NULL, NULL);
if( window == NULL ){
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.\n" );
glfwTerminate();
return -;
}
glfwMakeContextCurrent(window); // Initialize GLEW
glewExperimental = true; // Needed in core profile //z-buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEFT); if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -;
} //背景颜色
glClearColor(0.0f, 0.0f, 0.4f, 0.0f); //shader
GLuint programID = LoadShaders( "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/vertex.shader", "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/fragment.shader" ); GLuint VertexArrayID;
glGenVertexArrays(, &VertexArrayID);
glBindVertexArray(VertexArrayID); //vertex buffer
GLuint vertexbuffer;
glGenBuffers(, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); //color buffer
GLuint colorbuffer;
glGenBuffers(, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); mat4 Projection = perspective(radians(70.0f), (float)/, 0.1f, .f); mat4 View = lookAt(vec3(, , -), vec3(,,), vec3(,,)); mat4 Model = mat4(1.0f); //模型到投影转换
mat4 mvp = Projection * View * Model; GLuint MatrixID = glGetUniformLocation(programID, "mvp"); while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)) {
//每次开始时清空画布
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //使用shader
glUseProgram(programID); //把变换矩阵送进shader
glUniformMatrix4fv(MatrixID, , GL_FALSE, &mvp[][]); //画三角形
glEnableVertexAttribArray();
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, , (void*)); //三角形颜色
glEnableVertexAttribArray();
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, , (void*)); //draw call
glDrawArrays(GL_TRIANGLES, , * ); glDisableVertexAttribArray();
glDisableVertexAttribArray(); glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return ;
}
Code
首先是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
shader.hpp
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std; #include <stdlib.h>
#include <string.h> #include <GL/glew.h> #include "shader.hpp" GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ // Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); // Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open()){
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
}else{
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
getchar();
return ;
} // Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
} GLint Result = GL_FALSE;
int InfoLogLength; // Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, , &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID); // Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[]);
printf("%s\n", &VertexShaderErrorMessage[]);
} // Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, , &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID); // Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[]);
printf("%s\n", &FragmentShaderErrorMessage[]);
} // Link the program
printf("Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID); // Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > ){
std::vector<char> ProgramErrorMessage(InfoLogLength+);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[]);
printf("%s\n", &ProgramErrorMessage[]);
} glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID); glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID); return ProgramID;
}
shader.cpp
别忘了#include <shader.hpp> 并把 shader.cpp 添加到项目的Compile Sources里
g_vertex_buffer_data 和 g_color_buffer_data 储存正方形的顶点位置信息和颜色信息
main 函数里:
if(!glfwInit()) {
fprintf(stderr, "Failed To init OpenGL\n");
} // We want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
// To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL // Open a window and create its OpenGL context
// (In the accompanying source code, this variable is global)
GLFWwindow* window;
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL Window", NULL, NULL);
if( window == NULL ){
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.\n" );
glfwTerminate();
return -;
}
glfwMakeContextCurrent(window); // Initialize GLEW
glewExperimental = true; // Needed in core profile if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -;
}
init 操作
启用z-buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
我感觉注释说的够清楚了。。。直接看代码吧
//背景颜色
glClearColor(0.0f, 0.0f, 0.4f, 0.0f); //载入并编译shader
GLuint programID = LoadShaders( "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/vertex.shader", "/Users/jeff/IDEProjects/xcode_projects/openGL/openGL/fragment.shader" ); //VAO
//加速存储效率,储存VBO
//Veretx Array Object
GLuint VertexArrayID;
//创建
glGenVertexArrays(, &VertexArrayID);
//绑定
glBindVertexArray(VertexArrayID); //以下创建两个VBO
//Vertex Buffer Object
//用于将数据储存到显存中 //第一个VBO
//储存顶点数据
GLuint vertexbuffer;
//创建
glGenBuffers(, &vertexbuffer);
//绑定
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
//储存数据
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); //第二个VBO
//储存颜色信息
//操作原理同上
GLuint colorbuffer;
glGenBuffers(, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); //创建坐标变换矩阵
//本地 -> 世界 -> 视口 -> 齐次剪裁空间 空间变换流程
// Model View Projection 对应需要的矩阵
//透视变换
mat4 Projection = perspective(radians(70.0f), (float)WIDTH / HEIGHT, 0.1f, .f);
//视口变换
mat4 View = lookAt(vec3(, , ), vec3(,,), vec3(,,));
//本地变换
mat4 Model = mat4(1.0f); //集成本地到齐次剪裁空间的转换
mat4 MVP = Projection * View * Model; //从shader中取出mvp (不是上面的MVP,特地用大小写区分了)
//方便等会传入数据
GLuint MatrixID = glGetUniformLocation(programID, "mvp"); while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)) {
//每次开始时清空画布
//同时清空z-buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //使用shader
glUseProgram(programID); //把变换矩阵送进shader
glUniformMatrix4fv(MatrixID, , GL_FALSE, &MVP[][]); //把顶点信息送入shader
//数字0对应vertex shader中的 location = 0
glEnableVertexAttribArray();
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, , (void*)); //把三角形颜色送入shader
//数字0对应vertex shader中的 location = 1
glEnableVertexAttribArray();
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, , (void*)); //draw call
glDrawArrays(GL_TRIANGLES, , * ); //一定要在draw call之后关闭
glDisableVertexAttribArray();
glDisableVertexAttribArray(); //切换前后缓存,将渲染好的显示出来
glfwSwapBuffers(window);
glfwPollEvents();
}
main
vertex shader:
#version core
layout(location = ) in vec3 vertexPosition_modelspace;
layout(location = ) in vec3 vertexColor; uniform mat4 mvp;
out vec3 fragmentColor; void main() {
gl_Position = mvp * vec4(vertexPosition_modelspace, );
fragmentColor = vertexColor;
}
fragment shader:
#version core out vec3 color;
in vec3 fragmentColor; void main() {
color = fragmentColor;
}
至于这两个shader干嘛的。。。我先学习学习