OpenGL VAO+VBO+EBO+GLSL练习
一、VAO,VBO,EBO之间的关系
废话不多说,直接上图
也就是说:
-
每个个VAO管理着数个VBO,同时可以拥有一个EBO(EBO,索引数据,可以没有,此时直接用顶点数据绘制)
-
每个VBO用来存放数组数据,这个数据可以由你自己定义顺序
在绑定了VAO之后,后面绑定的VBO和EBO归属到这个VAO中
// 创建VAO对象
glGenVertexArrays(1, &_array);
glBindVertexArray(_array);
// 绑定顶点缓冲对象
glGenBuffers(1, &_vertex);
glBindBuffer(GL_ARRAY_BUFFER, _vertex);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// 绑定颜色缓冲对象
glGenBuffers(1, &_color);
glBindBuffer(GL_ARRAY_BUFFER, _color);
glBufferData(GL_ARRAY_BUFFER, sizeof(color), color, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// 绑定法线缓冲对象
glGenBuffers(1, &_normal);
glBindBuffer(GL_ARRAY_BUFFER, _normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(normal), normal, GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
// 绑定索引缓冲对象
glGenBuffers(1, &_index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
// 解除绑定
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
你可以用
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
来指定VBO中数据的安排方式
同时用glEnableVertexAttribArray(2);
来告诉glsl传入数据的位置
例如对上面的VAO,顶点着色器这样写:
#version 440
uniform mat4 _model_view;
uniform mat4 _projection;
uniform vec4 _light0_position;
layout (location = 0) in vec3 v;
layout (location = 1) in vec4 c;
layout (location = 2) in vec3 n;
struct v2f{
vec4 c;
};
out v2f vert_out;
void main(){
vert_out.c = c;
gl_Position = _projection * _model_view * vec4(v,1);
}
通过 layout (location = 1) in vec4 c; 来取得VAO中的glEnableVertexAttribArray(1);的数据
二、代码
先放效果图:
geomtery
class geomtery {
public:
geomtery();
~geomtery();
geomtery(vec3 center, GLfloat w, GLfloat h,vec4 c);
void draw(void);
private:
GLuint _array;
GLuint _vertex;
GLuint _color;
GLuint _normal;
GLuint _index;
};
geomtery::geomtery(vec3 c, GLfloat w, GLfloat h,vec4 cl) {
GLfloat half_w = w / 2.0f, half_h = h / 2.0;
GLfloat vertex[12];
vertex[0] = c.x - half_w; vertex[1] = c.y + half_h; vertex[2] = c.z;
vertex[3] = c.x - half_w; vertex[4] = c.y - half_h; vertex[5] = c.z;
vertex[6] = c.x + half_w; vertex[7] = c.y - half_h; vertex[8] = c.z;
vertex[9] = c.x + half_w; vertex[10] = c.y + half_h; vertex[11] = c.z;
GLfloat color[4];
color[0] = cl.x; color[1] = cl.y; color[2] = cl.z; color[3] = cl.w;
vec3 v1, v2, n;
v1 = vec3(vertex[6], vertex[7], vertex[8]) - vec3(vertex[0], vertex[1], vertex[2]);
v2 = vec3(vertex[9], vertex[10], vertex[11]) - vec3(vertex[3], vertex[4], vertex[5]);
n = cross(v1, v2);
n = normalize(n);
GLfloat normal[3];
normal[0] = n.x; normal[1] = n.y; normal[2] = n.z;
GLuint index[6];
index[0] = 0; index[1] = 1; index[2] = 2; index[3] = 0; index[4] = 2; index[5] = 3;
// 创建VAO对象
glGenVertexArrays(1, &_array);
glBindVertexArray(_array);
// 绑定顶点缓冲对象
glGenBuffers(1, &_vertex);
glBindBuffer(GL_ARRAY_BUFFER, _vertex);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// 绑定颜色缓冲对象
glGenBuffers(1, &_color);
glBindBuffer(GL_ARRAY_BUFFER, _color);
glBufferData(GL_ARRAY_BUFFER, sizeof(color), color, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// 绑定法线缓冲对象
glGenBuffers(1, &_normal);
glBindBuffer(GL_ARRAY_BUFFER, _normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(normal), normal, GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
// 绑定索引缓冲对象
glGenBuffers(1, &_index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
// 解除绑定
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void geomtery::draw(void) {
glBindVertexArray(_array);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
glBindVertexArray(0);
}
main
#include <iostream>
#include <fstream>
#include <GL/glew.h>
#ifdef _WIN32
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#include <sstream>
#include <cmath>
#include "common.h"
#include "geomtery.h"
using namespace std;
#include <vector>
GLuint shader_vert;
GLuint shader_geom;
GLuint shader_frag;
GLuint shader_program;
geomtery * g = nullptr;
GLfloat proj[16];
GLfloat mv[16];
GLuint g_WorldMatrixUniformIndex;
GLuint g_ProjMatrixUniformIndex;
GLfloat light_0_position[4];
GLfloat light_0_ambient[4];
GLfloat light_0_diffuse[4];
GLfloat light_0_specular[4];
GLuint g_LightSource_0_position_Index;
GLuint g_LightSource_0_ambient_Index;
GLuint g_LightSource_0_diffuse_Index;
GLuint g_LightSource_0_specular_Index;
long load_shader(void) {
GLuint *vert = &shader_vert;
GLuint *frag = &shader_frag;
GLuint *program = &shader_program;
*vert = glCreateShader(GL_VERTEX_SHADER);
*frag = glCreateShader(GL_FRAGMENT_SHADER);
fstream in("_vertex.vert");
if (!in.is_open()) {
return -1;
}
ostringstream buff;
buff << in.rdbuf();
string t = std::move(buff.str());
const GLchar * pbuff =t.c_str();
glShaderSource(*vert, 1,&pbuff,NULL);
in.close();
in.open("_fragment.frag");
if (!in.is_open()) {
return -1;
}
ostringstream buff2;
buff2 << in.rdbuf();
string t2 = std::move(buff2.str());
pbuff = t2.c_str();
glShaderSource(*frag, 1, &pbuff, NULL);
in.close();
glCompileShader(*vert);
glCompileShader(*frag);
int l;
int cw;
char* log;
glGetShaderiv(*vert, GL_INFO_LOG_LENGTH, &l);
if (l > 0) {
log = new char[l];
glGetShaderInfoLog(*vert, l, &cw, log);
cout << log << endl;
delete log;
}
glGetShaderiv(*frag, GL_INFO_LOG_LENGTH, &l);
if (l > 0) {
log = new char[l];
glGetShaderInfoLog(*frag, l, &cw, log);
cout << log << endl;
delete log;
}
*program = glCreateProgram();
glAttachShader(*program, *vert);
glAttachShader(*program, *frag);
glLinkProgram(*program);
glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &l);
if (l > 0) {
log = new char[l];
glGetProgramInfoLog(*program, l, &cw, log);
cout << log << endl;
delete log;
}
glUseProgram(*program);
g_WorldMatrixUniformIndex = glGetUniformLocation(*program, "_model_view");
g_ProjMatrixUniformIndex = glGetUniformLocation(*program, "_projection");
glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glUniformMatrix4fv(g_WorldMatrixUniformIndex, 1, GL_FALSE, mv);
glUniformMatrix4fv(g_ProjMatrixUniformIndex, 1, GL_FALSE, proj);
g_LightSource_0_position_Index = glGetUniformLocation(*program, "_light0_position");
glUniform4fv(g_LightSource_0_position_Index, 1, light_0_position);
g_LightSource_0_ambient_Index = glGetUniformLocation(*program, "_light0_ambient");
glUniform4fv(g_LightSource_0_ambient_Index, 1, light_0_ambient);
g_LightSource_0_diffuse_Index = glGetUniformLocation(*program, "_light0_diffuse");
glUniform4fv(g_LightSource_0_diffuse_Index, 1, light_0_diffuse);
g_LightSource_0_specular_Index = glGetUniformLocation(*program, "_light0_specular");
glUniform4fv(g_LightSource_0_specular_Index, 1, light_0_specular);
}
void changed_size(int w, int h) {
// 修改视窗size
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, double(w) / double(h), 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 3.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glUniformMatrix4fv(g_WorldMatrixUniformIndex, 1, GL_FALSE, mv);
glUniformMatrix4fv(g_ProjMatrixUniformIndex, 1, GL_FALSE, proj);
return;
}
// 初始化渲染环境
void init_render_context() {
// 蓝色背景
glClearColor(0.f, 0.f, .3f, 1.f);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
make_vec4(light_0_ambient , .3f,.3f,.3f,1.f );
make_vec4(light_0_diffuse, .7f, .7f, .7f, 1.f);
make_vec4(light_0_specular, .5f, .5f, .5f, 1.f);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_0_specular);
make_vec4(light_0_position, 2.0f, 2.0f, 2.f, 1.f);
glLightfv(GL_LIGHT0, GL_POSITION, light_0_position);
//glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1);
//glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0);
//glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);
}
// 渲染
void render(void) {
// 清除颜色缓冲、深度缓冲、模板缓冲
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if (g != nullptr) {
g->draw();
}
// 交换缓冲区
glutSwapBuffers();
}
int main(int argc, char**argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL");
glutReshapeFunc(changed_size);
glutDisplayFunc(render);
glutIdleFunc(render);
GLenum err = glewInit();
if (GLEW_OK != err) {
std::cerr << "GLEW Error : " << glewGetErrorString(err) << std::endl;
return 1;
}
init_render_context();
/* ========================== */
/*
* shader
*/
load_shader();
g= new geomtery(vec3(0.0, 0.0, 0.0), 1.0, 1.0, vec4(1.0, 1.0, 1.0, 1.0));
glutMainLoop();
return 0;
}
_vertex.vert
#version 440
uniform mat4 _model_view;
uniform mat4 _projection;
uniform vec4 _light0_position;
layout (location = 0) in vec3 v;
layout (location = 1) in vec4 c;
layout (location = 2) in vec3 n;
struct v2f{
vec4 c;
};
out v2f vert_out;
void main(){
vert_out.c = c;
gl_Position = _projection * _model_view * vec4(v,1);
}
_fragment.frag
#version 440
uniform vec4 _light0_position;
uniform vec4 _light0_ambient;
uniform vec4 _light0_diffuse;
out vec4 o;
struct v2f{
vec4 c;
};
in v2f vert_out;
void main() {
o = vert_out.c;
}
glmath
class vec3 {
public:
vec3();
~vec3();
vec3(GLfloat _x,GLfloat _y,GLfloat _z);
GLfloat x,y,z;
};
class vec4:public vec3 {
public:
vec4();
~vec4();
vec4(GLfloat _x, GLfloat _y, GLfloat _z,GLfloat _w );
GLfloat w;
};
vec3 cross(vec3 &v1, vec3 &v2) {
vec3 r;
r.x = (v1.y * v2.z) - (v1.z * v2.y);
r.y = (v1.z * v2.x) - (v1.x * v2.z);
r.z = (v1.x * v2.y) - (v1.y * v2.x);
return r;
}
vec3 normalize(vec3 &v) {
vec3 r;
GLfloat a = 1.0 / sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
r.x = static_cast<GLfloat>(a*v.x);
r.y = static_cast<GLfloat>(a*v.y);
r.z = static_cast<GLfloat>(a*v.z);
return r;
}
vec3 operator+(const vec3& l, const vec3& r) {
vec3 ret;
ret.x = l.x + r.x;
ret.y = l.y + r.y;
ret.z = l.z + r.z;
return ret;
}
vec4 operator+(const vec4& l, const vec4& r) {
vec4 ret;
ret.x = l.x + r.x;
ret.y = l.y + r.y;
ret.z = l.z + r.z;
ret.w = l.w + r.w;
return ret;
}
vec3 operator-(const vec3& l, const vec3& r) {
vec3 ret;
ret.x = l.x - r.x;
ret.y = l.y - r.y;
ret.z = l.z - r.z;
return ret;
}
vec4 operator-(const vec4& l, const vec4& r) {
vec4 ret;
ret.x = l.x - r.x;
ret.y = l.y - r.y;
ret.z = l.z - r.z;
ret.w = l.w - r.w;
return ret;
}