OpenGL缓冲区对象之UBO

  • 概述

UBO(Uniform Buffer Object)是用来存储着色语言中Uniform类型变量的缓冲区对象,使用UBO可以让uniform变量在不同的着色语言程序中实现共用,也可以在着色语言程序中实现uniform类型变量的设置与更新。

提到UBO就必须要提到着色语言GLSL中的Uniform Blocks,它将众多的Uniform类型的变量集中在一起进行统一的管理,对于需要大量Uniform类型变量的程序可以显著地提高性能。

  • 优势

相比传统设置单个uniform类型变量的方式,ubo有着以下一些特点:

  1. 可以通过切换不同的UBO绑定迅速更新程序中的uniform类型变量的值(在单一着色语言程序中)
  2. 可以存储更多的uniform类型变量
  3. 可以在不同的着色语言程序中通过更新UBO中的数据实现所有uniform类型变量的更新
  • 使用

UBO必须配合Uniform Block一起使用,Uniform Block的定义和C/C++中的struct很类似。Uniform Block定义的语法如下:

[cpp] 
storage_qualifier block_name  
  1. {  
  2.   <define members here>  
  3. } instance_name;  
storage_qualifier block_name
{
  <define members here>
} instance_name;
[cpp]
  1. //定义MatrixBlock Uniform Block  
  2. uniform MatrixBlock  
  3. {  
  4.   mat4 projection;  
  5.   mat4 modelview;  
  6. } matrices;  
//定义MatrixBlock Uniform Block
uniform MatrixBlock
{
  mat4 projection;
  mat4 modelview;
} matrices;
  • 关联UBO和Uniform Block

当Uniform Block在着色语言程序中链接之后,会在着色语言中生成很多个绑定索引值,通过这些索引可以找到Uniform Block。获取Uniform Block可以使用如下的API:

[cpp] 
GLuint glGetUniformBlockIndex​( GLuint program​,  const  char *uniformBlockName​ );  
GLuint glGetUniformBlockIndex​( GLuint program​, const char *uniformBlockName​ );

参数中uniformBlockName指的是着色语言程序中的Uniform Block(上文中的MatrixBlock)

获取Uniform Block index的目的是为了使得它和uniformBlock ID值进行绑定,这个Uniform Block的ID值存放在OpenGL Context中,通过它可以作为连接Uniform Block和UBO的桥梁:(通过把Uniform Block和UBO绑定到相同的Binding points(ID)上实现UBO和Uniform Block 的互动)


将Uniform Block 的索引值绑定到binding points需要使用下面的方式:

[cpp] 
  1. void glUniformBlockBinding(GLuint program, GLuint uBlockIndex, GLuint uBlockBinding);  
void glUniformBlockBinding(GLuint program, GLuint uBlockIndex, GLuint uBlockBinding);

其中uBlockIndex是前面通过glGetUniformBlockIndex得到的索引值;uBlockBinding是传入的Binding point值

通过以上两个函数可以完成上面示意图中的左边部分,右边部分的实现通过下面的API完成:

1.glGenBuffers生成缓冲区对象,需要注意的是要创建GL_UNIFORM_BUFFER

2.glBindBuffer绑定GL_UNIFROM_BUFFER

3.glBufferData传入缓冲区对象存储的内容

4.glBindBufferBase来设置缓冲区与binding point的绑定

[cpp] 
void glBindBufferBase(GLenum target, GLuint bindingPoint, GLuint bufferName);  

void glBindBufferBase(GLenum target, GLuint bindingPoint, GLuint bufferName);
target的取值:GL_UNIFORM_BUFFER

bindingPoint:必须和glUniformBlockBinding中的uBlockBinding值一样,这样就让Block Uniform和Uniform Buffer连接起来

bufferName:通过glGenBuffers生成的ID值

整个设置绑定的过程如下所示:

[cpp]
  1. // 需要注意的是binding point的值必须小于GL_MAX_UNIFORM_BUFFER_BINDINGS  
  2. GLuint bindingPoint = 1;  
  3. GLuint buffer;   
  4. GLuint blockIndex;  
  5. //复制到缓冲区存储空间的值   
  6. float myFloats[8] = {1.0, 0.0, 0.0, 1.0,   0.4, 0.0, 0.0, 1.0};  
  7. //获取Uniform Block的索引值   
  8. blockIndex = glGetUniformBlockIndex(p, "ColorBlock");  
  9. //将Uniform Block的索引值和binding point关联  
  10.  glUniformBlockBinding(p, blockIndex, bindingPoint);  
  11.  //生成UBO  
  12. glGenBuffers(1, &buffer);  
  13. glBindBuffer(GL_UNIFORM_BUFFER, buffer);  
  14.  //设置UBO存储的数据(用来给Uniform Block中变量赋值)  
  15. glBufferData(GL_UNIFORM_BUFFER, sizeof(myFloats), myFloats, GL_DYNAMIC_DRAW);  
  16. //将UBO与同样的binding point关联  
  17.  glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, buffer);  
// 需要注意的是binding point的值必须小于GL_MAX_UNIFORM_BUFFER_BINDINGS
GLuint bindingPoint = 1;
GLuint buffer; 
GLuint blockIndex;
//复制到缓冲区存储空间的值 
float myFloats[8] = {1.0, 0.0, 0.0, 1.0,   0.4, 0.0, 0.0, 1.0};
//获取Uniform Block的索引值 
blockIndex = glGetUniformBlockIndex(p, "ColorBlock");
//将Uniform Block的索引值和binding point关联
 glUniformBlockBinding(p, blockIndex, bindingPoint);
 //生成UBO
glGenBuffers(1, &buffer);
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
 //设置UBO存储的数据(用来给Uniform Block中变量赋值)
glBufferData(GL_UNIFORM_BUFFER, sizeof(myFloats), myFloats, GL_DYNAMIC_DRAW);
//将UBO与同样的binding point关联
 glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, buffer);
  • 设置和更新Uniform Block

假设我们定义了如下的Uniform Block(具体内容见后面分析)

[cpp] 
layout (std140) uniform ColorBlock {  
  1.     vec4 diffuse;  
  2.     vec4 ambient;  
  3. };  
layout (std140) uniform ColorBlock {
    vec4 diffuse;
    vec4 ambient;
};

为了给diffuse和ambient变量设置值,最关键的地方是我们需要获得这些变量在UBO中相对于UBO存储位置的偏移量,可以通过如下的命令设置:

[cpp] 
  1. void glGetActiveUniformBlockiv(GLuint program, GLuint uBlockIndex, GLenum pname, GLint *params);查询Uniform Block的相关信息  
  2. 参数:<p>program:当前链接好的着色语言程序;</p><p>uBlockIndex:Block Uniform的索引值;</p><p>pname:GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS(查询Block中有多少个Uniform变量);<code>GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES</code>(获取Block中uniform的索引值)</p><p>params:获取得到的结果</p>  
void glGetActiveUniformBlockiv(GLuint program, GLuint uBlockIndex, GLenum pname, GLint *params);查询Uniform Block的相关信息
参数:<p>program:当前链接好的着色语言程序;</p><p>uBlockIndex:Block Uniform的索引值;</p><p>pname:GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS(查询Block中有多少个Uniform变量);<code>GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES</code>(获取Block中uniform的索引值)</p><p>params:获取得到的结果</p>

当我们获得了Block Uniform中某个uniform的索引值之后,可以通过glGetActiveUniformsiv来获取uniform数据:

[cpp] 
void glGetActiveUniformsiv(GLuint program, GLsizei ucount,  const GLuint *uIndices, GLenum pname, GLint *params);  
  1. 参数:  
  2. ucount:索引值的个数  
  3. uindices:索引值数组  
  4. pname:我们需要获取的内容:<code>GL_UNIFORM_TYPE</code>, <code>GL_UNIFORM_OFFSET</code>, <code>GL_UNIFORM_SIZE</code>, <code>GL_UNIFORM_ARRAY_STRIDE</code>, <code>GL_UNIFORM_MATRIX_STRIDE</code>.  
  5. params:获取得到的结果  

void glGetActiveUniformsiv(GLuint program, GLsizei ucount, const GLuint *uIndices, GLenum pname, GLint *params);
参数:
ucount:索引值的个数
uindices:索引值数组
pname:我们需要获取的内容:<code>GL_UNIFORM_TYPE</code>, <code>GL_UNIFORM_OFFSET</code>, <code>GL_UNIFORM_SIZE</code>, <code>GL_UNIFORM_ARRAY_STRIDE</code>, <code>GL_UNIFORM_MATRIX_STRIDE</code>.
params:获取得到的结果
当获取到Uniform在Uniform Block中的偏移量之后,我们可以利用glBufferSubData来更新UBO中的数据,这样就实现了设置和修改Uniform Block中相应变量的值

[cpp] 
  1. void glBufferSubData( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);  
void glBufferSubData( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);

例如对于上面我们的ColorBlock,通过查询我们可以看到它占用的空间:

[cpp]
ColorBlock  
  1.     Size 32  
  2.     Block binding point: 0  
  3.     Buffer bound to binding point: 0   
  4.     {  
  5.        ambient  
  6.             GL_FLOAT_VEC4  
  7.             offset: 16  
  8.             size: 16  
  9.        diffuse  
  10.             GL_FLOAT_VEC4  
  11.             offset: 0  
  12.             size: 16  
  13.     }  
ColorBlock
    Size 32
    Block binding point: 0
    Buffer bound to binding point: 0 
    {
       ambient
            GL_FLOAT_VEC4
            offset: 16
            size: 16
       diffuse
            GL_FLOAT_VEC4
            offset: 0
            size: 16
    }

于是,当我们需要更新ambient的数据时,我们可以这样去做:

[cpp] 
  1. float color[4] = {0.3, 0.0, 0.0, 1.0};  
  2. GLuint offset = 16;  
  3. glBindBuffer(GL_UNIFORM_BUFFER, buffer);  
  4. glBufferSubData(GL_UNIFORM_BUFFER, offset , sizeof(color), color);  
float color[4] = {0.3, 0.0, 0.0, 1.0};
GLuint offset = 16;
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
glBufferSubData(GL_UNIFORM_BUFFER, offset , sizeof(color), color);

当我们修改一下ColorBlock中的内容:

[cpp] 
  1. layout (std140) uniform ColorBlock2 {  
  2.     vec3 diffuse;  
  3.     vec3 ambient;  
  4. };  

layout (std140) uniform ColorBlock2 {
    vec3 diffuse;
    vec3 ambient;
};

再次查询ColorBlock占用的空间:

[cpp] 
  1. ColorBlock2  
  2.     Size 28  
  3.     Block binding point: 0  
  4.     Buffer bound to binding point: 0   
  5.     {  
  6.        ambient  
  7.             GL_FLOAT_VEC3  
  8.             <span style="color:#FF0000;">offset: 16</span>  
  9.             size: 12  
  10.        diffuse  
  11.             GL_FLOAT_VEC3  
  12.             offset: 0  
  13.             <span style="color:#FF0000;">size: 12</span>  
  14.     }  
ColorBlock2
    Size 28
    Block binding point: 0
    Buffer bound to binding point: 0 
    {
       ambient
            GL_FLOAT_VEC3
            <span style="color:#FF0000;">offset: 16</span>
            size: 12
       diffuse
            GL_FLOAT_VEC3
            offset: 0
            <span style="color:#FF0000;">size: 12</span>
    }

发现diffuse占用的空间是12个字节,但是ambient却是从16个字节处开始的。这里面就涉及到一个字节对齐的概念,前面我们声明Uniform Block的时候都使用了一个标识符std140,指的是GLSL 1.4版本的时候指定的一个字节对齐的规范,具体的内容如下表:

变量类型

变量大小/偏移量

标量数据类型(bool,int,uint,float)

基于基本机器类型的标量值大小

(例如,sizeof(GLfloat))

二元向量(bvec2,ivec2,uvec2,vec2)

标量类型大小的两倍

三元向量(bvec3,ivec3,uvec3,vec3)

标量类型大小的四倍

三元向量(bvec4,ivec4,uvec4,vec4)

标量类型大小的四倍

标量的数组或向量

数组中每个元素大小是基本类型的大小,偏移量是其索引值(从0开始)与元素大小的乘积。整个数组必须是vec4类型的大小的整数倍(不足将在尾部填充)。

一个或多个C列R行列主序矩阵组成的数组

以C个向量(每个有R个元素)组成的数组形式存储。会像其他数组一样填充。

如果变量是M个列主序矩阵的数组,那么它的存储形式是:M*C个向量(每个有R个元素)组成的数组。

一个或多个R行C列的行主序矩阵组成的数组

以R个向量(每个有C个元素)组成的数组。默认像其他数组一样填充。

如果变量是M个行主序矩阵组成的数组,则存储形式是M*R个向量(每个有C个元素)组成的数组。

单个结构体或多个结构体组成的数组

单个结构体成员的偏移量和大小可以由前面的规则计算出。结构大小总是vec4大小的整数倍(不足在后面补齐)。

由结构组成的数组,偏移量的计算需要考虑单个结构的对齐和补齐。结构的成员偏移量由前面的规则计算出。


也就是说我们有两种方式来更新这些Uniform Block中的Uniform变量的值:

1.使用OpenGL中的查询函数来查询Uniform Block中Uniform变量在UBO中的偏移量,然后使用glBufferSubData更新之;

2.使用std140之后直接寻找到uniform在UBO中的偏移量(由于它是一个标准,因此具体大小可以自己计算),然后使用glBufferSubData更新之。


下面使用一个具体的例子来总结UBO的使用方法:(使用FreeGlut)

[cpp] 
  1. #pragma comment(lib, "glew32.lib")  
  2. #pragma comment(lib, "freeglut.lib")  
  3.   
  4. #include <gl/glew.h>  
  5. #include <gl/freeglut.h>  
  6. #include <iostream>  
  7.   
  8. #include "glshadertools.h"  
  9.   
  10. GLuint      programID;  
  11. GLuint      uboID;  
  12.   
  13. GLuint bindingPoint = 1;  
  14. GLuint ubIndex;  
  15.   
  16. GLfloat color1[] = {1.0f, 0.0f, 0.0f, 0.0f};    
  17. GLfloat color2[] = {0.0f, 1.0f, 0.0f, 1.0f};    
  18.   
  19.   
  20. //  
  21. GLfloat xRot;         
  22. GLfloat yRot;  
  23. GLfloat zoom = -10.0f;  
  24.   
  25. bool mouseLeftDown;  
  26. float mouseX, mouseY;  
  27.   
  28.   
  29.   
  30.   
  31. void    init()  
  32. {  
  33.     programID = gltLoadShaderProgram("hello.vert""hello.frag");  
  34.       
  35.     ubIndex = glGetUniformBlockIndex(programID, "ColorBlock");  
  36.     glUniformBlockBinding(programID, ubIndex, bindingPoint);  
  37.   
  38.     GLint   bufferSize = 0;  
  39.     glGetActiveUniformBlockiv(programID, ubIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &bufferSize);  
  40.   
  41.     glGenBuffers(1, &uboID);  
  42.     glBindBuffer(GL_UNIFORM_BUFFER, uboID);  
  43.     glBufferData(GL_UNIFORM_BUFFER, bufferSize, NULL, GL_DYNAMIC_READ);  
  44.       
  45.     glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, uboID);  
  46.       
  47.     //寻找每一个uniform变量的偏移值  
  48.     const GLchar *names[] = {"color1","color2"};    
  49.     GLuint indices[2];    
  50.     glGetUniformIndices(programID, 2, names, indices);    
  51.     GLint offset[2];  
  52.     glGetActiveUniformsiv(programID, 4, indices, GL_UNIFORM_OFFSET, offset);  
  53.       
  54.     //拷贝数据到UBO中(给Uniform Block中的color1和color2变量赋值)  
  55.     glBufferSubData(GL_UNIFORM_BUFFER, offset[0], 4*sizeof(float), color1);  
  56.     glBufferSubData(GL_UNIFORM_BUFFER, offset[1], 4*sizeof(float), color2);  
  57.   
  58.     glUseProgram(programID);  
  59. }  
  60.   
  61.   
  62. void reshape(int w, int h)  
  63. {  
  64.     glViewport(0, 0, (GLsizei)w, (GLsizei)h);  
  65.     glMatrixMode(GL_PROJECTION);  
  66.     glLoadIdentity();  
  67.     gluPerspective(60.0f, (float)(w)/h, 0.1f, 1000.0f);  
  68.     glMatrixMode(GL_MODELVIEW);  
  69.     glLoadIdentity();  
  70. }  
  71.   
  72.   
  73. void    display()  
  74. {  
  75.     glClearColor(0, 0, 0, 0);  
  76.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  77.     glColor3f(1.0f, 0.0f, 1.0f);  
  78.   
  79.     glLoadIdentity();  
  80.   
  81.     glTranslatef(0, 0, zoom);  
  82.     glRotatef(xRot, 1, 0, 0);   // pitch  
  83.     glRotatef(yRot, 0, 1, 0);   // heading  
  84.   
  85.     glutSolidTeapot(2.0);  
  86.   
  87.     glutSwapBuffers();  
  88. }  
  89.   
  90.   
  91.   
  92. void mouse(int button, int state, int x, int y)  
  93. {  
  94.     mouseX = (float)x;  
  95.     mouseY = (float)y;  
  96.   
  97.     switch (button)  
  98.     {  
  99.     case GLUT_LEFT_BUTTON:  
  100.         {  
  101.             if (state == GLUT_DOWN) {  
  102.                 mouseLeftDown = true;  
  103.             } else if (state == GLUT_UP) {  
  104.                 mouseLeftDown = false;  
  105.             }  
  106.         }  
  107.         break;  
  108.   
  109.     case GLUT_RIGHT_BUTTON:  
  110.         {  
  111.             if (state == GLUT_DOWN) {  
  112.   
  113.             }  
  114.         }  
  115.         break;  
  116.   
  117.     default:  
  118.         break;  
  119.     }  
  120. }  
  121.   
  122.   
  123. void mouseMove(int x, int y)  
  124. {  
  125.     if(mouseLeftDown)  
  126.     {  
  127.         yRot += (x - mouseX);  
  128.         xRot += (y - mouseY);  
  129.         mouseX = (float)x;  
  130.         mouseY = (float)y;  
  131.     }  
  132.     glutPostRedisplay();  
  133. }  
  134.   
  135.   
  136. void mouseWheel(int wheel, int direction, int x, int y)  
  137. {  
  138.     switch (direction)  
  139.     {  
  140.   
  141.     case 1: //means wheel up  
  142.         {  
  143.             zoom -= 1.0f;  
  144.         }  
  145.         break;  
  146.   
  147.     case -1: //means wheel down  
  148.         {  
  149.             zoom += 1.0f;  
  150.         }  
  151.         break;  
  152.   
  153.     default:  
  154.         break;  
  155.     }  
  156.     glutPostRedisplay();  
  157. }  
  158.   
  159.   
  160. void keyboard(unsigned char key, int x, int y)  
  161. {  
  162.     switch(key)  
  163.     {  
  164.     case 27: // ESCAPE  
  165.         exit(0);  
  166.         break;  
  167.   
  168.     default:  
  169.         break;  
  170.     }  
  171.   
  172. }  
  173.   
  174.   
  175. void idle()  
  176. {  
  177.     glutPostRedisplay();  
  178. }  
  179.   
  180.   
  181. int main(int argc, char** argv)  
  182. {  
  183.     glutInit(&argc, argv);  
  184.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);  
  185.     glutInitWindowSize(640, 480);  
  186.     glutCreateWindow(argv[0]);  
  187.     if (glewInit()) {  
  188.         std::cerr << "Unable to initialize GLEW ... exiting" << std::endl;  
  189.         exit(EXIT_FAILURE);  
  190.     }  
  191.     init();  
  192.     glutDisplayFunc(display);  
  193.     glutReshapeFunc(reshape);  
  194.     glutMouseFunc(mouse);  
  195.     glutMotionFunc(mouseMove);  
  196.     glutMouseWheelFunc(mouseWheel);  
  197.     glutKeyboardFunc(keyboard);  
  198.     glutIdleFunc(idle);  
  199.     glutMainLoop();  
  200. }  
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")

#include <gl/glew.h>
#include <gl/freeglut.h>
#include <iostream>

#include "glshadertools.h"

GLuint		programID;
GLuint		uboID;

GLuint bindingPoint = 1;
GLuint ubIndex;

GLfloat color1[] = {1.0f, 0.0f, 0.0f, 0.0f};  
GLfloat color2[] = {0.0f, 1.0f, 0.0f, 1.0f};  


//
GLfloat xRot;		
GLfloat yRot;
GLfloat zoom = -10.0f;

bool mouseLeftDown;
float mouseX, mouseY;




void	init()
{
	programID = gltLoadShaderProgram("hello.vert", "hello.frag");
	
	ubIndex = glGetUniformBlockIndex(programID, "ColorBlock");
	glUniformBlockBinding(programID, ubIndex, bindingPoint);

	GLint	bufferSize = 0;
	glGetActiveUniformBlockiv(programID, ubIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &bufferSize);

	glGenBuffers(1, &uboID);
	glBindBuffer(GL_UNIFORM_BUFFER, uboID);
	glBufferData(GL_UNIFORM_BUFFER, bufferSize, NULL, GL_DYNAMIC_READ);
	
	glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, uboID);
	
	//寻找每一个uniform变量的偏移值
	const GLchar *names[] = {"color1","color2"};  
	GLuint indices[2];  
	glGetUniformIndices(programID, 2, names, indices);  
	GLint offset[2];
	glGetActiveUniformsiv(programID, 4, indices, GL_UNIFORM_OFFSET, offset);
	
	//拷贝数据到UBO中(给Uniform Block中的color1和color2变量赋值)
	glBufferSubData(GL_UNIFORM_BUFFER, offset[0], 4*sizeof(float), color1);
	glBufferSubData(GL_UNIFORM_BUFFER, offset[1], 4*sizeof(float), color2);

	glUseProgram(programID);
}


void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f, (float)(w)/h, 0.1f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


void	display()
{
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f, 0.0f, 1.0f);

	glLoadIdentity();

	glTranslatef(0, 0, zoom);
	glRotatef(xRot, 1, 0, 0);   // pitch
	glRotatef(yRot, 0, 1, 0);   // heading

	glutSolidTeapot(2.0);

	glutSwapBuffers();
}



void mouse(int button, int state, int x, int y)
{
	mouseX = (float)x;
	mouseY = (float)y;

	switch (button)
	{
	case GLUT_LEFT_BUTTON:
		{
			if (state == GLUT_DOWN) {
				mouseLeftDown = true;
			} else if (state == GLUT_UP) {
				mouseLeftDown = false;
			}
		}
		break;

	case GLUT_RIGHT_BUTTON:
		{
			if (state == GLUT_DOWN) {

			}
		}
		break;

	default:
		break;
	}
}


void mouseMove(int x, int y)
{
	if(mouseLeftDown)
	{
		yRot += (x - mouseX);
		xRot += (y - mouseY);
		mouseX = (float)x;
		mouseY = (float)y;
	}
	glutPostRedisplay();
}


void mouseWheel(int wheel, int direction, int x, int y)
{
	switch (direction)
	{

	case 1:	//means wheel up
		{
			zoom -= 1.0f;
		}
		break;

	case -1: //means wheel down
		{
			zoom += 1.0f;
		}
		break;

	default:
		break;
	}
	glutPostRedisplay();
}


void keyboard(unsigned char key, int x, int y)
{
	switch(key)
	{
	case 27: // ESCAPE
		exit(0);
		break;

	default:
		break;
	}

}


void idle()
{
	glutPostRedisplay();
}


int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(640, 480);
	glutCreateWindow(argv[0]);
	if (glewInit()) {
		std::cerr << "Unable to initialize GLEW ... exiting" <<	std::endl;
		exit(EXIT_FAILURE);
	}
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMouseFunc(mouse);
	glutMotionFunc(mouseMove);
	glutMouseWheelFunc(mouseWheel);
	glutKeyboardFunc(keyboard);
	glutIdleFunc(idle);
	glutMainLoop();
}

程序简单地将两个颜色值相加作为最终输出片元的颜色:

顶点Shader:

[cpp] 
  1. #version 330  
  2.   
  3. void main()  
  4. {  
  5.     gl_Position = ftransform();  
  6. }  
#version 330

void main()
{
	gl_Position = ftransform();
}

片元shader:

[cpp] 
  1. #version 330  
  2.   
  3. layout (std140) uniform ColorBlock  
  4. {  
  5.     vec4 color1;  
  6.     vec4 color2;  
  7. };  
  8.   
  9. void main()  
  10. {  
  11.     gl_FragColor = color1 + color2;  
  12. }  

                
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值