1.重绘顶点索引,glPrimitiveRestartIndex在遍历索引缓存绘制中,遇到指定索引值,重新开始绘制同类型的一个新图元,避免开辟多个索引缓存。
2. glew中 glGenBuffers glBindBuffer glBufferData通过NULL指定最近的缓存,
glBufferData(GL_ARRAY_BUFFER, 6 * NumPoints * sizeof(GLfloat), NULL, GL_STATIC_DRAW);可以传递一个空指针地址,glBufferData空地址传入是说明cpu没有数据拷贝到GPU中但是申请这么大的空间只是没有初始化值后面可以用glMapBufffer映射返回当前激活的该类GPU缓冲区对象地址并可以填充返回的指针值。glColorPointer或glDrawElements接着空地址传入填充内存块或取得内存块,传递进去的NULL+ offset指针其实是当前激活的缓存区对象的地址偏移(也是说明CPU中没有传入填充的数据,到GPU当前激活缓冲区中指定的偏移取就可以了)。
缓存区对象都是在GPU显存中的,只是加载顶点数据(传递数据)这个步骤提高传递性能, 绘制时候还是要Draw call调用,除非合并了顶点数据和纹理像素数据才可以减少Draw call。
Specifies a pointer to data that will be copied into the data store for initialization, or NULL
if no data is to be copied.
If data
is NULL
, a data store of the specified size is still created, but its contents remain uninitialized and thus undefined.
3.glBufferData usage
决定数据存储的位置和DX一样,STATIC和STREAM的在显卡中只能修改一次,DYNAMIC的在APG缓存中和系统缓存中
glBufferData(GL_ARRAY_BUFFER, 6 * NumPoints * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
glColorPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), NULL);
glDrawElements(GL_TRIANGLE_STRIP, NumStrips * (NumPointsPerStrip + 1), GL_UNSIGNED_SHORT, NULL);
#include <stdlib.h>
#include <stdio.h>
#define GLEW_STATIC
#include <GL/glew.h>
//#define FREEGLUT_STATIC
#include <GL/freeglut.h>
#define BUFFER_OFFSET(offset) ((const GLubyte *)NULL + (offset))
#pragma comment(lib, "glew32s.lib")
#define XStart -0.8
#define XEnd 0.8
#define YStart -0.8
#define YEnd 0.8
#define NumXPoints 11
#define NumYPoints 11
#define NumPoints (NumXPoints * NumYPoints)
#define NumPointsPerStrip (2 * NumXPoints)
#define NumStrips (NumYPoints - 1)
#define RestartIndex 0xffff
GLfloat color[6][3] = {
{ 1.0, 1.0, 1.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0 },
{ 0.0, 1.0, 0.0 }, { 0.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }
};
void init() {
GLuint vbo = 0;
GLuint ebo = 0;
GLfloat* vertices = NULL;
GLushort* indices = NULL;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//target:可以是GL_ARRAY_BUFFER()(顶点数据)或GL_ELEMENT_ARRAY_BUFFER(索引数据)
//size:存储相关数据所需的内存容量
//data:用于初始化缓冲区对象,可以是一个指向客户区内存的指针,也可以是NULL
//usage:数据在分配之后如何进行读写,如GL_STREAM_READ,GL_STREAM_DRAW,GL_STREAM_COPY
glBufferData(GL_ARRAY_BUFFER, 6 * NumPoints * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
//提供对缓冲区对象包含的整个数据集合的更新
//access:GL_READ_ONLY,GL_WRITE_ONLY,GL_READ_WRITE
vertices = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if (vertices == NULL) {
exit(EXIT_FAILURE);
}
else {
int i;
int j;
GLfloat dx = (GLfloat)(XEnd - XStart) / (NumXPoints - 1);
GLfloat dy = (GLfloat)(YEnd - YStart) / (NumYPoints - 1);
GLfloat* tmp = vertices;
int n = 0;
// 绘制NumYPoints * NumXPoints个顶点,包含了像素和顶点数据
for (j = 0; j < NumYPoints; ++j) {
GLfloat y = (GLfloat)(YStart + j * dy);// y最小为-0.8,最大为0.8
for (i = 0; i < NumXPoints; ++i) {
GLfloat x = (GLfloat)(XStart + i * dx);// x最小为-0.8,最大为0.8
*tmp++ = color[(i + j) % 6][0]; // i,j是0到10
*tmp++ = color[(i + j) % 6][1];
*tmp++ = color[(i + j) % 6][2];
*tmp++ = x;
*tmp++ = y;
*tmp++ = 0;
}
}
//表示当前绑定缓冲区对象的更新已经完成,与glMapBuffer()结合使用
glUnmapBuffer(GL_ARRAY_BUFFER);
// 顶点数据加载,这里从NULL地址中加载
glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), (const GLubyte *)NULL + 3 * sizeof(GLfloat));//BUFFER_OFFSET(3 * sizeof(GLfloat))
// 颜色数据加载,这里从NULL地址中加载
glColorPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), NULL);//BUFFER_OFFSET(0)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
//glInterleavedArrays(GL_C3F_V3F, 0, 0);
}
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// 索引数量,每列顶点有两重索引,比一般索引多了两倍
glBufferData(GL_ELEMENT_ARRAY_BUFFER, NumStrips * (NumPointsPerStrip + 1) * sizeof(GLushort), NULL, GL_STATIC_DRAW);
indices = (GLushort*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
if (indices == NULL) {
exit(EXIT_FAILURE);
}
else {
int i;
int j;
GLushort* index = indices;
// 列数
for (j = 0; j < NumStrips; ++j) {
// 底部顶点的索引开始
GLushort bottomRow = j * NumYPoints;
// 顶部顶点的索引开始
GLushort topRow = bottomRow + NumYPoints;
// 指定列中的两行索引,赋值
for (i = 0; i < NumXPoints; ++i) {
*index++ = topRow + i;
*index++ = bottomRow + i;
}
// 每一列的结尾,都赋值一个重绘索引值
*index++ = RestartIndex;
}
// 结束索引数据的填充
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
}
// 遇到重绘索引值,那么开始重绘相同类型的图元,索引缓存会一直迭代直到没有则绘制结束
glPrimitiveRestartIndex(RestartIndex);
glEnable(GL_PRIMITIVE_RESTART);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1, 1, 1);
// 通过NULL指定最近开启的client端缓存,这里是指定最近操作的索引缓存
glDrawElements(GL_TRIANGLE_STRIP, NumStrips * (NumPointsPerStrip + 1), GL_UNSIGNED_SHORT, NULL);
glutSwapBuffers();
}
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, w, 0.0, h);
}
void keyboardfunc(unsigned char key, int x, int y) {
//std::cout << key << x << y << std::endl;
}
void mouse(int button, int state, int x, int y) {
switch (button)
{
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
glutIdleFunc(NULL);
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) {
glutIdleFunc(NULL);
}
break;
default:
break;
}
}
void move(int x, int y) {
//std::cout << x << y << std::endl;
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutInitContextVersion(3, 1);
glutCreateWindow("hello");
GLenum res = glewInit();
if (GLEW_OK != res)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(res));
}
init();
glutDisplayFunc(display);
//glutReshapeFunc(reshape);
glutMouseFunc(mouse);
//glutMotionFunc(move);
//glutKeyboardFunc(keyboardfunc);
glutMainLoop();
return 0;
}