openGL学习(EBO)
EBO
EBO(Element Buffer Object,也称为 Index Buffer Object)是 OpenGL 中用于存储顶点索引信息的缓冲区对象。它允许开发者指定顶点的绘制顺序,从而可以更有效地使用顶点数据,减少数据量并提高渲染效率。在绘制多边形时,如果顶点数组中出现大量重复点,可以使用索引数组来减少重复性。通过使用EBO,可以有效地减少顶点数据量,提高渲染效率。(数据点的复用)
创建EBO的方式与创建VBO类似,都是使用glGenBuffers。创建完成EBO之后,需要向EBO中传入索引数据,在传入之前需要绑定将EBO(将eboID设置为当前操作的EBO)。当设置完成之后,可以调用 `glDrawElements` 来绘制。
void render()
{//将绑定的ebo进行清0,错误使用//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_CALL(glClear(GL_COLOR_BUFFER_BIT));//渲染操作//1. 使用当前的programglUseProgram(program);//绑定当前的vao,glBindVertexArray(vao);//发出绘制指令ebo不用这个//glDrawArrays(GL_TRIANGLES, 0, 4);//ebo使用这个命令绘制 // 第一个参数:mode:绘制模式// 第二个参数:count:绘制索引数组中的几个点// 第三个参数:type:索引数组的类型 要用GL_UNSIGNED_INT,不能用GL_INT// 第四个参数:indices,使用ebo一般用0// 使用了EBO,不写0代表索引内偏移// 没有使用EBO,可以直接传入索引数组。glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,(void*)0); //绘制的时候vao里要有ebo//glDrawElements(GL_TRIANGLES,3,GL_UNSIGNED_INT,(void*)(sizeof(unsigned int)*3) );}
彩色三角形
fragmentShaser之前需要光栅化。
#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h"
#include "glad/glad.h" //需要先引用glad的头文件。 用于加载 OpenGL 函数指针
#include "GLFW/glfw3.h" // 用于创建窗口和处理输入。
#include <assert.h>
#include "wrapper/checkerror.h"
#include "application/application.h"
using namespace std;/*
* 目标:学习绘制彩色三角形
*
*/GLuint vao, program;void prepareVAO()
{cout << "prepareVAO()" << endl;float vertices[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f,0.5f,0.5f,0.0f};float colors[] = {1.0f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,1.0f};//float vertices[] = {
//-0.5f,-0.5f,0.0f,1.0f,0.0f,0.0f,
//0.5f,-0.5f,0.0f,0.0f,1.0f,0.0f,
//0.0f,0.5f,0.0f,0.0f,0.0f,1.0f//};unsigned int indices[] = {0,1,2,3,1,2//1,2,3//2,1,3};// VBO创建GLuint posVbo,colorVbo;glGenBuffers(1, &posVbo);glBindBuffer(GL_ARRAY_BUFFER, posVbo);glBufferData(GL_ARRAY_BUFFER,sizeof(vertices), vertices, GL_STATIC_DRAW);glGenBuffers(1, &colorVbo);glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);//EBO创建GLuint ebo;glGenBuffers(1, &ebo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//VAO创建glGenVertexArrays(1, &vao);glBindVertexArray(vao);//绑定vbo ebo加入描述信息glBindBuffer(GL_ARRAY_BUFFER, posVbo);glEnableVertexAttribArray(0);glVertexAttribPointer(0,3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//加入ebo到当前的vao --这段代码不能够省略,虽然上面也有了。glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);//将VAO进行解绑glBindVertexArray(0); }void prepareShader()
{cout << "prepareShader()" << endl;//1.完成vs和fs,并且装字符串const char* vertexShaderSource ="#version 460 core\n""layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec3 aColor;\n""out vec3 color;\n""void main()\n""{\n""gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);\n""color = (aColor);\n""}\n\0";const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""in vec3 color;\n""void main()\n""{\n""FragColor = vec4(color,1.0f);\n""}\n\0";//2创建Shader程序(vs和fs)GLuint vertex, fragment;vertex = glCreateShader(GL_VERTEX_SHADER);fragment = glCreateShader(GL_FRAGMENT_SHADER);//3为shader程序输入Shader代码glShaderSource(vertex, 1, &vertexShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。glShaderSource(fragment, 1, &fragmentShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。int success = 0;char infoLog[1024];//4 执行Shader编译glCompileShader(vertex);//5 检查是否正确编译glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Vertex Shaser Complie: " << infoLog << endl;}//4 执行fragment编译glCompileShader(fragment);//5 检查是否正确编译glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Fragment Shader Complie: " << infoLog << endl;}// 创建Program壳子//GLuint program = 0;program = glCreateProgram();//将编译后的结果放进ProgramglAttachShader(program, vertex);glAttachShader(program, fragment);// 执行program链接操作,形成最终的shader程序。glLinkProgram(program);//检查链接错误glGetProgramiv(program, GL_LINK_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetProgramInfoLog(program, 1024, NULL, infoLog); //获取日志信息cout << "Error Program Link: " << infoLog << endl;}//清理glDeleteShader(vertex);glDeleteShader(fragment);}void render()
{//将绑定的ebo进行清0,错误使用glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_CALL(glClear(GL_COLOR_BUFFER_BIT));//渲染操作//1. 使用当前的programglUseProgram(program);//绑定当前的vao,glBindVertexArray(vao);//发出绘制指令ebo不用这个//glDrawArrays(GL_TRIANGLES, 0, 4);//ebo使用这个命令绘制 // 第一个参数:mode:绘制模式// 第二个参数:count:绘制索引数组中的几个点// 第三个参数:type:索引数组的类型 要用GL_UNSIGNED_INT,不能用GL_INT// 第四个参数:indices,使用ebo一般用0// 使用了EBO,不写0代表索引内偏移// 没有使用EBO,可以直接传入索引数组。glDrawElements(GL_TRIANGLES,3,GL_UNSIGNED_INT,(void*)0); //绘制的时候vao里要有ebo//glDrawElements(GL_TRIANGLES,3,GL_UNSIGNED_INT,(void*)(sizeof(unsigned int)*3) );glBindVertexArray(0);}void onResize(int width,int height)
{GL_CALL(glViewport(0, 0, width, height));cout << "onResize " << endl;
}void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;//更新窗体的大小glViewport(0, 0, width, height);}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;if (app->init(800,600) == -1){return -1;}//设置监听帧缓冲窗口大小回调函数。//glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);//glfwSetKeyCallback(win, keyCallback);app->setResizeCallBack(onResize);app->setkeyCallBack(keyCallback);//设置OpenGL视口以及清理颜色glViewport(0,0,800,600);glClearColor(0.2f,0.3f,0.3f,1.0f);prepareVAO();prepareShader();// 3. 执行窗体循环// while (app->update() == 0 ){render();}// 4. 退出程序前做相关清理app->destroy();cout << "===================================" << endl;//const double M_PI = 3.14159265358979323846;//double radians = M_PI / 2; // 90度,转换为弧度//double sineValue = sin(radians);//std::cout << "sin(" << radians << ") = " << sineValue << std::endl;//system("pause");return 0;
}