#include <GLFW/glfw3.h>
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
以上代码是绘制窗口,也是OpenGL最基础的代码
#include <GLFW/glfw3.h>
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
//glewInit();
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();
画三角形,开始画三角,结束画三角,中间就是三角形三个顶点的位置,还有三角形绘制的颜色
缓冲区:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
using namespace std;
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[6] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
shader是只运行在GPU上的程序
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
using namespace std;
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上 4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int program = glCreateProgram();//创建program
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[6] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
string vertexShader = "#version 330 core\n"//在这里定义顶点着色器的着色信息
"\n"
"layout(location = 0) in vec4 position;\n"
"void main(){\n"
" gl_Position = position;\n"
"}\n";
string fragmentShader = "#version 330 core\n"//在这里定义片段着色器的着色信息
"\n"
"layout(location = 0) out vec4 color;\n"
"void main(){\n"
" color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
将shader写进文件
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "fstream"
#include "string"
#include "sstream"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[6] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
glDrawArrays(GL_TRIANGLES, 0, 3);//画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
#shader vertex
#version 330 core
layout(location = 0) in vec4 position;
void main(){
gl_Position = position;
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
void main(){
color = vec4(1.0, 0.0, 0.0, 1.0);
}
绘制长方形:用两个三角形拼接,所有几何体,都可以用三角形来拼接
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "fstream"
#include "string"
#include "sstream"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, -0.5,
-0.5, 0.5,
0.5, 0.5
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
glDrawArrays(GL_TRIANGLES, 0, 6);//画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
改动1:
改动2:
改动3:
但是在改动1的情况下,我们重复记录了相同的顶点,这造成了内存浪费,所以也要在Slate编程一样的去记录引用缓冲
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
存放顶点然后用引用缓冲进行绘制
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "fstream"
#include "string"
#include "sstream"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
差错:
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static void GLCheckError() {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << endl;
}
}
GLClearError();
glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);//这里故意将GL_UNSIGNED_INT改成了GL_INT用于检查错误
GLCheckError();
报错编号为1280,转为16进制就为500,500对应的枚举值为无效枚举
#define ASSERT(x) if(!x) __debugbreak();
static bool GLLogCall() {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << endl;
return false;
}
return true;
}
ASSERT(GLLogCall());
将GLCheckError改成GLLogCall,调用改成ASSERT(GLLogCall());
GLClearError();
glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr);
ASSERT(GLLogCall());
再整体封装一遍:
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall())
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static bool GLLogCall() {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << endl;
return false;
}
return true;
}
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr));
再进行一次优化:
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
当前所有代码:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "fstream"
#include "string"
#include "sstream"
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);X
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
使用uniform去修改shader内值
#shader vertex
#version 330 core
layout(location = 0) in vec4 position;
void main(){
gl_Position = position;
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main(){
color = u_Color;
}
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
int location = glGetUniformLocation(shader, "u_Color");
glUniform4f(location, 0.2, 0.4, 0.3, 1);
拿到shader内的u_Color变量,然后去设置vec4 u_Color的值
制作矩形颜色闪烁效果:
float r = 0.2;
float increment = 0.01;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(location, r, 0.4, 0.3, 1);
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);X
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
让矩形旋转,将四个位置乘以旋转矩阵,然后再将位置与引用进行重新绑定
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
#define PI 3.1415
struct Pos {
float x;
float y;
};
Pos RotateMatrix(int Angle, float x, float y) {
float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);
Pos pos = Pos{ newX, newY };
return pos;
}
void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
for (int i = 0; i < 8; i += 2) {
float tempX = Positions[i];
float tempY = Positions[i + 1];
Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
//cout << tempX << " / " << tempY << endl;
}
glGenBuffers(1, &dataId);
glBindBuffer(GL_ARRAY_BUFFER, dataId);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
glGenBuffers(1, &id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
Angle++;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void outputVertex(float Positions[]) {
for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
cout << Positions[i] << " \ " << Positions[i + 1] << endl;
}
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(1);//屏幕刷新频率,此时为一帧刷新一次
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
int location = glGetUniformLocation(shader, "u_Color");
glUniform4f(location, 0.2, 0.4, 0.3, 1);
float r = 0.2;
float increment = 0.01;
int Angle = 0;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(location, r, 0.4, 0.3, 1);
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
UpdateValue(Positions, Angle, ibo, Indices, a);
outputVertex(Positions);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);X
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
vao比vbo理论上速度要快,官方推荐用vao,之前上面实现方法为vbo
第一步:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3
加上以上代码使用vao
第二步:
unsigned int vao;
glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
glBindVertexArray(vao);
第三步:
glBindVertexArray(vao);
在while循环内进行绑定
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
static bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
#define PI 3.1415
struct Pos {
float x;
float y;
};
Pos RotateMatrix(int Angle, float x, float y) {
float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);
Pos pos = Pos{ newX, newY };
return pos;
}
void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
for (int i = 0; i < 8; i += 2) {
float tempX = Positions[i];
float tempY = Positions[i + 1];
Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
//cout << tempX << " / " << tempY << endl;
}
Angle++;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void outputVertex(float Positions[]) {
for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
cout << Positions[i] << " \ " << Positions[i + 1] << endl;
}
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int vao;
glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
glBindVertexArray(vao);
unsigned int a;
glGenBuffers(1, &a);//第一个参数代表生成缓冲区的数量,第二个为指定对象来生成缓冲区
//当生成多个缓冲区时:
//unsigned int b[3];
//glGenBuffers(3, b);
//cout << a << endl;
//for (int i = 0; i < 3; i++) {
// cout << b[i] << endl;
//}
glBindBuffer(GL_ARRAY_BUFFER, a);//定义缓冲区类型
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
//第二个参数时代表一个顶点需要几个值,比如二维需要两个float才能组成一个顶点的位置,当然顶点不只是位置信息,第三个参数为描述顶点位置的属性
//第四个参数代表是否将属性进行归一化,这里我们不需要,第五个参数代表一个顶点所占的字节数,第六个参数代表字节偏移量
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
int location = glGetUniformLocation(shader, "u_Color");
glUniform4f(location, 0.2, 0.4, 0.3, 1);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);//使用刚创建的program
float r = 0.2;
float increment = 0.01;
int Angle = 0;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(location, 0.2, 0.4, 0.3, 1);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, a);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), Positions, GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glUseProgram(shader);//使用刚创建的program
glUniform4f(location, r, 0.4, 0.3, 1);
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
UpdateValue(Positions, Angle, ibo, Indices, a);
outputVertex(Positions);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);X
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
分类管理:
IndexBuffer:
#pragma once
class IndexBuffer {
private:
unsigned int m_RendererID;
unsigned int m_Count;
public:
IndexBuffer(const unsigned int* data, unsigned int count);
~IndexBuffer();
void Bind() const;
void UnBind() const;
inline unsigned int GetCount() const { return m_Count; }
};
#include "IndexBuffer.h"
#include "Renderer.h"
IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count) : m_Count(count) {
glGenBuffers(1, &m_RendererID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);
}
IndexBuffer::~IndexBuffer() {
glDeleteBuffers(1, &m_RendererID);
}
void IndexBuffer::Bind() const {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
}
void IndexBuffer::UnBind() const {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
VertexBuffer:
#pragma once
class VertexBuffer {
private:
unsigned int m_RendererID;
public:
VertexBuffer(const void* data, unsigned int size);
~VertexBuffer();
void Bind();
void UnBind();
};
#include "VertexBuffer.h"
#include "Renderer.h"
VertexBuffer::VertexBuffer(const void* data, unsigned int size) {
glGenBuffers(1, &m_RendererID);
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
VertexBuffer::~VertexBuffer() {
glDeleteBuffers(1, &m_RendererID);
}
void VertexBuffer::Bind() {
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
}
void VertexBuffer::UnBind() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
Renderer:
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
void GLClearError();
bool GLLogCall(const char* function, const char* file, int line);
#include "Renderer.h"
#include "iostream"
using namespace std;
void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
使用:很清晰能够看清使用更加舒服简化了
VertexBuffer vb(Positions, 8 * sizeof(float));
IndexBuffer ib(Indices, 8 * sizeof(unsigned int));
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(location, 0.2, 0.4, 0.3, 1);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);//定义缓冲区类型
glBindVertexArray(vao);
ib.Bind();
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), Positions,吧GL_STATIC_DRAW);//绑定完毕就要开始存放顶点数据了
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glUseProgram(shader);//使用刚创建的program
glUniform4f(location, r, 0.4, 0.3, 1);
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
//UpdateValue(Positions, Angle, ibo, Indices, a);
outputVertex(Positions);
/*glBegin(GL_TRIANGLES);
glVertex2f(-0.5, -0.5f);
glVertex2f(0.5, 0.5f);
glVertex2f(0.5, -0.5f);
glColor3f(1, 0, 0);
glEnd();*/
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/*glDrawArrays(GL_TRIANGLES, 0, 6);*///画好了三角形,但是苦于没有shader,所以不显示
//glColor3f(1.f, 0, 0);X
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
所有代码:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"
#include "Renderer.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "iostream"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
#define PI 3.1415
struct Pos {
float x;
float y;
};
Pos RotateMatrix(int Angle, float x, float y) {
float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);
Pos pos = Pos{ newX, newY };
return pos;
}
void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
for (int i = 0; i < 8; i += 2) {
float tempX = Positions[i];
float tempY = Positions[i + 1];
Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
//cout << tempX << " / " << tempY << endl;
}
Angle++;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void outputVertex(float Positions[]) {
for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
cout << Positions[i] << " \ " << Positions[i + 1] << endl;
}
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
{
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
unsigned int vao;
glGenVertexArrays(1, &vao);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
glBindVertexArray(vao);
VertexBuffer vb(Positions, 8 * sizeof(float));
glEnableVertexAttribArray(0);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
IndexBuffer ib(Indices, 8 * sizeof(unsigned int));
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
//glUseProgram(shader);//使用刚创建的program
int location = glGetUniformLocation(shader, "u_Color");
glUniform4f(location, 0.2, 0.4, 0.3, 1);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);//使用刚创建的program
float r = 0.2;
float increment = 0.01;
int Angle = 0;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(location, 0.2, 0.4, 0.3, 1);
glBindVertexArray(vao);
ib.Bind();
glUseProgram(shader);//使用刚创建的program
glUniform4f(location, r, 0.4, 0.3, 1);
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
//UpdateValue(Positions, Angle, ibo, Indices, a);
outputVertex(Positions);
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
}
glfwTerminate();
return 0;
}
因为自己也是初学者,我刚开始看视频没太理解vao与vbo,看了这篇文章讲的比较通透:
(73条消息) 详解Opengl中VBO和VAO_代码乐的博客-CSDN博客_vbo vao
将VertexArray封装成类:
IndexBuffer:
#pragma once
class IndexBuffer {
private:
unsigned int m_RendererID;
unsigned int m_Count;
public:
IndexBuffer(const unsigned int* data, unsigned int count);
~IndexBuffer();
void Bind() const;
void UnBind() const;
inline unsigned int GetCount() const { return m_Count; }
};
#include "IndexBuffer.h"
#include "Renderer.h"
IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count) : m_Count(count) {
glGenBuffers(1, &m_RendererID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);
}
IndexBuffer::~IndexBuffer() {
glDeleteBuffers(1, &m_RendererID);
}
void IndexBuffer::Bind() const {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
}
void IndexBuffer::UnBind() const {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Renderer:
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
void GLClearError();
bool GLLogCall(const char* function, const char* file, int line);
#include "Renderer.h"
#include "iostream"
using namespace std;
void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
VertexArray:
#pragma once
#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
class VertexArray {
private:
unsigned int m_RendererID;
public:
VertexArray();
~VertexArray();
void Bind() const;
void UnBind() const;
void AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout);
};
#include "VertexArray.h"
#include "VertexBufferLayout.h"
VertexArray::VertexArray() {
glGenVertexArrays(1, &m_RendererID);//第一个参数是要生成顶点数组的数量,第二个参数为生成的顶点数组
glBindVertexArray(m_RendererID);
}
VertexArray::~VertexArray() {
glDeleteVertexArrays(1, &m_RendererID);
}
void VertexArray::AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout) {
vb.Bind();
const auto& elements = layout.GetElement();
unsigned int offset = 0;
for (unsigned int i = 0; i < elements.size(); i++) {
const auto& element = elements[i];
glEnableVertexAttribArray(i);//启用第一组顶点属性数组,0代表数组下标为0
glVertexAttribPointer(i, element.count, element.type, element.normalized, layout.GetStride(), (const void*)offset);//设置顶点属性,第一个参数为从第几个属性开始取值,很明显从第一个数组0号位
offset += element.count * VertexBufferElements::GetSizeOfType(element.type);
}
}
void VertexArray::Bind() const {
glBindVertexArray(m_RendererID);
}
void VertexArray::UnBind() const {
glBindVertexArray(0);
}
VertexBuffer:
#pragma once
class VertexBuffer {
private:
unsigned int m_RendererID;
public:
VertexBuffer(const void* data, unsigned int size);
~VertexBuffer();
void Bind() const;
void UnBind();
};
#include "VertexBuffer.h"
#include "Renderer.h"
VertexBuffer::VertexBuffer(const void* data, unsigned int size) {
glGenBuffers(1, &m_RendererID);
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
VertexBuffer::~VertexBuffer() {
glDeleteBuffers(1, &m_RendererID);
}
void VertexBuffer::Bind() const {
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
}
void VertexBuffer::UnBind() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
VertexBufferLayout:
#pragma once
#include "vector"
#include "Renderer.h"
#include "GL/glew.h"
struct VertexBufferElements {
unsigned int type;
unsigned int count;
unsigned char normalized;
static unsigned int GetSizeOfType(unsigned int type) {
switch (type) {
case GL_FLOAT: return 4;
case GL_UNSIGNED_INT: return 4;
case GL_UNSIGNED_BYTE: return 1;
}
ASSERT(false);
return 0;
}
};
class VertexBufferLayout {
private:
std::vector<VertexBufferElements> m_Elements;
unsigned int m_Stride;
public:
VertexBufferLayout() : m_Stride(0) {};
template<typename T>
void Push(unsigned int count) {
static_assert(false);
}
template<>
void Push<float>(unsigned int count) {
m_Elements.push_back(VertexBufferElements{ GL_FLOAT, count, GL_FALSE });
m_Stride += count * VertexBufferElements::GetSizeOfType(GL_FLOAT);
}
template<>
void Push<unsigned int>(unsigned int count) {
m_Elements.push_back(VertexBufferElements{ GL_UNSIGNED_INT, count, GL_FALSE });
m_Stride += count * VertexBufferElements::GetSizeOfType(GL_UNSIGNED_INT);
}
template<>
void Push<unsigned char>(unsigned int count) {
m_Elements.push_back(VertexBufferElements{ GL_UNSIGNED_BYTE, count, GL_TRUE });
m_Stride += count * VertexBufferElements::GetSizeOfType(GL_UNSIGNED_BYTE);
}
inline std::vector<VertexBufferElements> GetElement() const { return m_Elements; }
inline unsigned int GetStride() const { return m_Stride; }
};
Application:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "math.h"
#include "fstream"
#include "string"
#include "sstream"
#include "Renderer.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "VertexArray.h"
#include "iostream"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
static ShaderProgramSource ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if(line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
#define PI 3.1415
struct Pos {
float x;
float y;
};
Pos RotateMatrix(int Angle, float x, float y) {
float newX = x * cos(Angle * PI / 180) - y * sin(Angle * PI / 180);
float newY = x * sin(Angle * PI / 180) + y * cos(Angle * PI / 180);
Pos pos = Pos{ newX, newY };
return pos;
}
void UpdateValue(float Positions[], int& Angle, unsigned int id, unsigned int Indices[], unsigned int dataId) {
for (int i = 0; i < 8; i += 2) {
float tempX = Positions[i];
float tempY = Positions[i + 1];
Positions[i] = RotateMatrix(Angle, tempX, tempY).x;
Positions[i + 1] = RotateMatrix(Angle, tempX, tempY).y;
//cout << tempX << " / " << tempY << endl;
}
Angle++;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void outputVertex(float Positions[]) {
for (int i = 0; i < sizeof(Positions) / sizeof(float); i += 2) {
cout << Positions[i] << " \ " << Positions[i + 1] << endl;
}
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//改变OPENGL的版本为3.3
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(0.5);//屏幕刷新频率,此时为一帧刷新一次
if (glewInit() != GLEW_OK) {
cout << "ERROR" << endl;
}
{
float Positions[12] = {
-0.5f, -0.5f,
0.5f, 0.5f,
0.5, -0.5f,
-0.5, 0.5,
};
unsigned int Indices[] = {
0, 1, 2,
0, 1, 3
};
VertexArray va;//这里把vao给声明好,并绑定好
VertexBuffer vb(Positions, 8 * sizeof(float));//这里把顶点缓冲的数据也准备好了
VertexBufferLayout layout;//声明顶点样式
layout.Push<float>(2);//定义顶点样式,例如一个值组成一个顶点,从第几个顶点开始读,这里传进去的是2,证明两个浮点值组成一个顶点
va.AddBuffer(vb, layout);//将layout数据进行处理并将vb进行绑定
IndexBuffer ib(Indices, 8 * sizeof(unsigned int));
ShaderProgramSource source = ParseShader("Shader.shader");
cout << "Fragment: " << endl;
cout << source.FragmentSource << endl;
cout << "Vertex: " << endl;
cout << source.VertexSource << endl;
string vertexShader = source.VertexSource;//在这里定义顶点着色器的着色信息
string fragmentShader = source.FragmentSource;//在这里定义片段着色器的着色信息
unsigned int shader = CreateShader(vertexShader, fragmentShader);//通过创建好的着色器创建program
glUseProgram(shader);//使用刚创建的program
int location = glGetUniformLocation(shader, "u_Color");
glUniform4f(location, 0.2, 0.4, 0.3, 1);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//定义缓冲区类型
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);//使用刚创建的program
float r = 0.2;
float increment = 0.01;
int Angle = 0;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader);//使用刚创建的program
glUniform4f(location, 0.2, 0.4, r, 1);
va.Bind();
ib.Bind();
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
//UpdateValue(Positions, Angle, ibo, Indices, a);
//outputVertex(Positions);
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
}
glfwTerminate();
return 0;
}
将shader再一次进行封装处理:
#pragma once
#include "string"
#include "unordered_map"
using namespace std;
struct ShaderProgramSource {
string VertexSource;
string FragmentSource;
};
class Shader {
public:
Shader(const string& filepath);
~Shader();
void Bind() const;
void UnBind() const;
//Set Uniforms
void SetUniform4f(const string& name, float v0, float v1, float v2, float v3);
private:
unsigned int m_RendererID;
string m_FilePath;
unordered_map<string, int> m_UniformLocationCache;
private:
unsigned int CompileShader(const string& source, unsigned int type);
int CreateShader(const string& vertexShader, const string& fragmentShader);
ShaderProgramSource ParseShader(const string& filepath);
int GetUniformLocation(const string& name);
};
#include "Shader.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "iostream"
#include "sstream"
#include "fstream"
Shader::Shader(const string& filepath) : m_FilePath(filepath), m_RendererID(0) {
//CompileShader();
ShaderProgramSource source = ParseShader(m_FilePath);
m_RendererID = CreateShader(source.VertexSource, source.FragmentSource);//通过创建好的着色器创建program
}
Shader::~Shader() {
glDeleteProgram(m_RendererID);
}
void Shader::Bind() const{
glUseProgram(m_RendererID);
}
void Shader::UnBind() const {
glUseProgram(0);
}
void Shader::SetUniform4f(const string& name, float v0, float v1, float v2, float v3) {
glUniform4f(GetUniformLocation(name), v0, v1, v2, v3);
}
int Shader::GetUniformLocation(const string& name) {
if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end()) return m_UniformLocationCache[name];
int location = glGetUniformLocation(m_RendererID, name.c_str());
if (location == -1) cout << "Warning: uniform '" << name << "' doesn't exist!" << endl;
return location;
}
int Shader::CreateShader(const string& vertexShader, const string& fragmentShader) {
//总结:1、创建program 2、编译shader(1、创建shader 2、编译shader 3、获取着色器资源 4、判断shader是否创建成功) 3、将着色器附着在program对象上
//4、与program建立链接 5、验证program 6、删除shader
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vertexShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
ShaderProgramSource Shader::ParseShader(const string& filepath) {
ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line)) {
if (line.find("#shader") != string::npos) {
if (line.find("vertex") != string::npos) {
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != string::npos) {
type = ShaderType::FRAGMENT;
}
}
else {
ss[(int)type] << line << "\n";
}
}
return ShaderProgramSource{ ss[0].str(), ss[1].str() };
}
unsigned int Shader::CompileShader(const string& source, unsigned int type) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));//alloca是在栈上分配空间,malloc是在堆上分配空间,当遇到char message[length],而这个length却不是常量的时候可以使用该方法
glGetShaderInfoLog(id, length, &length, message);
cout << "FAILED TO COMPILE SHADER !" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
将绘制进行封装:
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Shader.h"
#define ASSERT(x) if(!x) __debugbreak();
#define GLCALL(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
using namespace std;
void GLClearError();
bool GLLogCall(const char* function, const char* file, int line);
class Renderer {
public:
void GLDrawCall(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const;
void GLClear() const;
};
#include "Renderer.h"
#include "iostream"
using namespace std;
void GLClearError() {
while (glGetError() != GL_NO_ERROR);
}
bool GLLogCall(const char* function, const char* file, int line) {
while (GLenum Enum = glGetError()) {
cout << "OpenGL Error: ( " << Enum << " )" << " Function Name : " << function << " File : " << file << " Line : " << line << endl;
return false;
}
return true;
}
void Renderer::GLDrawCall(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const {
va.Bind();
ib.Bind();
shader.Bind();
GLCALL(glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr));
}
void Renderer::GLClear() const {
glClear(GL_COLOR_BUFFER_BIT);
}
Renderer renderer;
float r = 0.2;
float increment = 0.01;
int Angle = 0;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
renderer.GLClear();
//shader.Bind();//使用刚创建的program
renderer.GLDrawCall(va, ib, shader);
shader.SetUniform4f("u_Color", 0.2, 0.4, r, 1);
//va.Bind();
// ib.Bind();
if (r < 0) increment = 0.01;
else if (r > 1) increment = -0.01;
r += increment;
//UpdateValue(Positions, Angle, ibo, Indices, a);
//outputVertex(Positions);
GLCALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}