在opengl中,所有的数据都要放在显存中,通过VBO(Vertex Buffer Object)可将CPU数据传到GPU。
VBO(Vertex Buffer Object)是OpenGL中的一种机制,用于将顶点数据存储在显存中,以便GPU可以快速访问和处理。VBO是一种缓冲对象,类似于CPU中的数组或列表,可以用来存储顶点的位置、颜色、纹理坐标等属性。使用VBO可以避免每次渲染时都需要从CPU到GPU之间复制顶点数据的过程,从而提高了渲染的效率。
GLuint vbo;
void Init()
{
float data[] = {
-0.2f,-0.2f,-0.6f,1.0f,
0.2f,-0.2f,-0.6f,1.0f,
-0.2f,0.2f,-0.6f,1.0f
};
glGenBuffers(1, &vbo); //需要1个VBO,把vbo写入到显卡进去,供后续操作
glBindBuffer(GL_ARRAY_BUFFER, vbo); //把vbo设置到卡槽上
//glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12, nullptr,GL_STATIC_DRAW);//只在GPU上开辟内存不传数据
glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12,data,GL_STATIC_DRAW); //将数据从cpu传到Gpu,此后data数据可删除。
glBindBuffer(GL_ARRAY_BUFFER, 0); //卡槽重新绑定,防止误操作
}
vertex shader,test.vs文件如下:
attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
void main()
{
gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}
在OpenGL中,uniform和attribute是用于在着色器程序中传递数据的两种不同类型。
Uniform变量: Uniform变量是一种全局变量,用于在不同的着色器阶段之间传递数据。它们在着色器程序中的任何地方都可以访问,不受顶点或片段的限制。Uniform变量通常用于传递全局数据,例如变换矩阵、光照参数、纹理等。在程序中,你可以使用glGetUniformLocation函数获取Uniform变量的位置(或插槽),然后使用glUniform函数将值传递给Uniform变量。
Attribute变量: Attribute变量是一种顶点属性,用于在顶点着色器中接收每个顶点的输入数据。它们通常用于表示顶点的位置、颜色、法线等属性。Attribute变量只能在顶点着色器中使用,并且每个顶点都会有对应的属性值。在程序中,你可以使用glGetAttribLocation函数获取Attribute变量的位置(或插槽),然后使用glVertexAttribPointer函数设置属性数据的格式和位置。
关于插槽(location)的分配,Uniform变量和Attribute变量都是从0开始分配的。可以使用glGetUniformLocation和glGetAttribLocation函数获取它们在着色器程序中的位置(或插槽)值。对于Uniform变量,可以使用glUniform函数将值传递给指定位置的Uniform变量。对于Attribute变量,可以使用glVertexAttribPointer函数将属性数据绑定到指定位置的Attribute变量。
需要注意的是,Uniform变量和Attribute变量在不同的着色器阶段之间传递数据的方式和使用方法是不同的。Uniform变量用于在整个着色器程序中传递全局数据,而Attribute变量用于在顶点着色器中接收每个顶点的属性数据。
fragment shader,test.fs文件如下:
#ifdef GL_ES
precision mediump float;
#endif
void main()
{
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
GLuint glCreateShader(GLenum shaderType);
shaderType指示要创建的着色器的类型,支持两种类型的着色器:
glCreateShader创建一个空的着色器对象,并返回一个可以引用的非零值(Shader ID)。着色器对象用于维护定义着色器的源代码字符串。
glShaderSource是OpenGL中用于设置着色器源代码的函数。它的作用是将字符串形式的着色器源代码加载到指定的着色器对象中,以便后续编译和链接。具体来说,glShaderSource函数有四个参数:
void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
glCompileShader是OpenGL中用于编译着色器对象的函数。它的作用是将glShaderSource函数加载的着色器源代码编译成可执行的着色器程序,供OpenGL渲染时使用。
具体来说,glCompileShader函数有一个参数:
void glCompileShader(GLuint shader);
glGetShaderiv是OpenGL中获取着色器对象参数的函数之一,它的作用是获取指定着色器对象的特定参数信息,例如编译状态、参数个数、参数类型等等。具体来说,glGetShaderiv函数有三个参数:
void glGetShaderiv(GLuint shader, GLenum pname, GLint *params);
shader:要查询的着色器对象的ID。
pname:要查询的参数名称,可选值包括:
params:指向存储返回参数值的变量的指针。
glDeleteShader是OpenGL中删除着色器对象的函数之一。它的作用是删除已经创建的着色器对象,释放显存中的资源。具体来说,glDeleteShader函数有一个参数:
void glDeleteShader(GLuint shader);
需要注意的是,如果着色器对象已经被附加到程序对象中,那么在程序对象链接之前无法删除着色器对象。因此,通常建议在使用完着色器对象后立即删除它,以免占用过多的显存资源。
GLuint CompileShader(GLenum shaderType, const char* shaderCode)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderCode, nullptr);
glCompileShader(shader);
GLint compileResult = GL_TRUE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if (compileResult == GL_FALSE) {
char szLog[1024] = { 0 };
GLsizei logLen = 0;
glGetShaderInfoLog(shader, 1024, &logLen, szLog);
printf("Compile Shader fail error log : %s \nshader code :\n%s\n", szLog, shaderCode);
glDeleteShader(shader);
shader = 0;
}
return shader;
}
glCreateProgram是OpenGL中创建着色器程序对象的函数之一。它的作用是创建一个着色器程序对象并返回其ID,用于管理多个着色器对象的链接过程。具体来说,glCreateProgram函数没有参数,只返回一个GLuint类型的着色器程序对象ID:
GLuint glCreateProgram(void);
glAttachShader是OpenGL中将着色器对象附加到程序对象的函数之一。它的作用是将一个或多个着色器对象附加到一个程序对象上,为后续的链接操作做准备。具体来说,glAttachShader函数有两个参数:
void glAttachShader(GLuint program, GLuint shader);
glLinkProgram是OpenGL中链接着色器程序的函数之一,用于将一个程序对象中所有附加的着色器对象链接为一个可执行程序。在链接过程中,OpenGL会将不同着色器之间的变量名和类型进行匹配和连接,最终生成一个可供GPU执行的着色器程序。具体来说,glLinkProgram函数有一个参数:
void glLinkProgram(GLuint program);
需要注意的是,glLinkProgram函数链接完成后会将链接日志存储在程序对象中,我们可以通过调用glGetProgramiv函数查询链接状态,或者通过调用glGetProgramInfoLog函数获取链接日志。另外,如果链接失败,程序对象的状态将会被标记为链接失败,并且该程序对象无法使用。
glDetachShader是OpenGL中将着色器对象从程序对象中分离的函数之一。它的作用是将一个着色器对象从一个程序对象中分离,使该着色器对象可以在其他程序对象中使用。具体来说,glDetachShader函数有两个参数:
void glDetachShader(GLuint program, GLuint shader);
glGetProgramiv是OpenGL中获取着色器程序对象参数的函数之一。它的作用是获取指定着色器程序对象的特定参数信息,例如链接状态、参数个数、参数类型等等。具体来说,glGetProgramiv 函数有三个参数:
void glGetProgramiv(GLuint program, GLenum pname, GLint *params);
program:要查询的着色器程序对象的ID。
pname:要查询的参数名称,可选值包括:
params:指向存储返回参数值的变量的指针。
glDeleteProgram是OpenGL中删除着色器程序对象的函数之一。它的作用是删除已经创建的着色器程序对象,释放显存中的资源。具体来说,glDeleteProgram函数有一个参数:
void glDeleteProgram(GLuint program);
GLuint CreateProgram(GLuint vsShader, GLuint fsShader) {
GLuint program = glCreateProgram();
glAttachShader(program, vsShader);
glAttachShader(program, fsShader);
glLinkProgram(program);
glDetachShader(program, vsShader);
glDetachShader(program, fsShader);
GLint nResult;
glGetProgramiv(program, GL_LINK_STATUS, &nResult);
if (nResult == GL_FALSE) {
char log[1024] = { 0 };
GLsizei writed = 0;
glGetProgramInfoLog(program, 1024, &writed, log);
printf("create gpu program fail,link error : %s\n", log);
glDeleteProgram(program);
program = 0;
}
return program;
}
GLuint program;
void Init()
{
//...
//准备绘图数据
//...
int fileSize = 0;
unsigned char * shaderCode = LoadFileContent("Res/test.vs", fileSize);
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
delete shaderCode;
shaderCode = LoadFileContent("Res/test.fs", fileSize);
GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
delete shaderCode;
program = CreateProgram(vsShader, fsShader);
glDeleteShader(vsShader);
glDeleteShader(fsShader);
}
glGetUniformLocation是OpenGL中用于获取Uniform变量的位置(或插槽)的函数之一。它用于查询指定着色器程序对象中的Uniform变量的位置,以便后续对其进行赋值。具体来说,glGetUniformLocation函数有两个参数:
GLint glGetUniformLocation(GLuint program, const GLchar *name);
glGetAttribLocation是OpenGL中用于获取Attribute变量的位置(或插槽)的函数之一。它用于查询指定着色器程序对象中的Attribute变量的位置,以便后续绑定顶点数据。具体来说,glGetAttribLocation函数有两个参数:
GLint glGetAttribLocation(GLuint program, const GLchar *name);
GLint positionLocation,modelMatrixLocation,viewMatrixLocation,projectionMatrixLocation;
void Init()
{
//...
//准备绘图数据
//...
//...
//读取shader源码到GPU程序
//...
positionLocation = glGetAttribLocation(program, "position");
modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
}
在OpenGL中设置MVP(Model-View-Projection)矩阵是用于进行物体的变换和投影的重要步骤之一。通常,Model矩阵表示物体的模型变换,View矩阵表示摄像机的观察变换,而Projection矩阵表示投影变换。
对于Model矩阵和View矩阵,默认是单位矩阵,所以不需要显式设置它们,可以通过使用glm库中的glm::mat4的默认构造函数创建单位矩阵。
对于Projection矩阵,可以使用glm库中的glm::perspective函数来设置。
glm::mat4 glm::perspective(float fov, float aspect, float near, float far);
该函数将返回一个透视投影矩阵,所有在近平面和远平面内且处于平截头体内的顶点都会被渲染。可以将其应用于Projection矩阵。
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
void SetViewPortSize(float width, float height)
{
projectionMatrix = glm::perspective(glm::radians(45.0f), width / height, 0.1f, 1000.0f);
}
glUniformMatrix4fv是OpenGL中用于将4x4矩阵数据传递给Uniform变量的函数之一。它用于将一个或多个4x4矩阵值传递给在着色器程序中定义的Matrix4类型的Uniform变量。
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
void Draw()
{
glUseProgram(program);//启用着色器程序
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix)); //将模型矩阵传递给着色器程序中的模型矩阵Uniform变量modelMatrixLocation
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix)); //将视图矩阵传递给着色器程序中的视图矩阵Uniform变量viewMatrixLocation
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); //将投影矩阵传递给着色器程序中的投影矩阵Uniform变量projectionMatrixLocation
glUseProgram(0); //停用着色器程序
}
glVertexAttribPointer函数用于指定顶点属性的指针,并设置相关参数。
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
参数解释如下:
glEnableVertexAttribArray函数用于启用指定索引的顶点属性数组。
void glEnableVertexAttribArray(GLuint index);
参数解释如下:
glDrawArrays函数用于执行基于顶点数组的图元绘制操作。
void glDrawArrays(GLenum mode, GLint first, GLsizei count);
参数解释如下:
void Draw()
{
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//...
//设置Uniform变量
//...
glBindBuffer(GL_ARRAY_BUFFER, vbo); //将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0); //定义位置属性
glEnableVertexAttribArray(positionLocation); //启用位置属性索引为positionLocation的顶点属性数组
glDrawArrays(GL_TRIANGLES, 0, 3); //执行绘制操作。该函数指定了绘制的模式、起始顶点索引和顶点数量。
glBindBuffer(GL_ARRAY_BUFFER, 0); //解绑顶点缓冲对象
}
shader通常称为着色器,作用是把CPU上的点渲染出来,shader在GPU上是并行执行的,比如三个顶点的数据,会在三个core上并行处理。
比如我们绘制一个三角形,需要三个顶点数据。顶点着色器将会被执行三次,每次使用不同的顶点数据作为输入。(不需要为每个顶点创建一个单独的vertex shader文件,我们可以使用相同的vertex shader文件来处理所有三个顶点,只需要为每个顶点提供不同的位置属性作为输入),并使用统一变量mvpMatrix进行模型-视图-投影变换。(即:position不一样,m、v、p矩阵相同)
float data[] = {
-0.2f,-0.2f,-0.6f,1.0f,
0.2f,-0.2f,-0.6f,1.0f,
0.0f,0.2f,-0.6f,1.0f
};
attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;