注:uniform变量类似于D3D11中的const buffer中的变量。

      在这篇教程中,我们会使渲染的物体在屏幕上运动,实现动画的效果。主要通过绑定一个uniform变量以及一个idle回调函数来实现,uniform变量的值在每帧中都会变化。

      GLUT不会重复调用我们的渲染函数,只有发生一些特殊事件的时候,才会执行渲染操作,比如窗口最大化、最小化,当前窗口被别的窗口遮挡等等,如果程序执行后,我们不做任何变化,则渲染函数只会执行一次,我们可以通过在渲染函数中增加一个print函数来验证它,在最大化、最小化窗口时候,该函数会在控制台窗口会打印相关信息。如果实现静态物体的渲染,这种方法当然可以,但是在本教程中,我们要实现动画,需要重复调用渲染函数,该怎么实现呢?我们可以注册一个idle回调函数,把渲染函数放在该函数中,或者直接把渲染函数注册成idle函数,在GLUT不接受windows系统事件时,idle函数会重复执行,这样结合idle函数和变化的uniform变量,我们就可以实现动画的效果。

主要代码:

glutIdleFunc(RenderSceneCB);

       通过上面的代码,我们把渲染函数注册成idle函数,需要注意的是在渲染函数的末尾要加上glutPostRedisplay()函数调用,否则的话idle函数会反复执行,但渲染函数却没有,glutPostRedisplay()会重绘当前显示窗口,并保证下一次glut消息循环中,渲染函数会被调用。

gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");        
assert(gScaleLocation != 0xFFFFFFFF);

第一种就是变量名字拼写错误,或者就是compiler进行的优化操作,这时也不能得到正确的索引值。

static float Scale = 0.0f;        
Scale += 0.001f;         
glUniform1f(gScaleLocation, sinf(Scale));

      我们定义一个缩放因子变量,每次渲染函数调用时候,该变量都增加0.001。该变量的sin值通过函数glUniform1f传输到shader中去。使用sin函数值可以保证Scale范围在[-1,1]之间,注意sinf的参数是以弧度为单位。opengl提供了glUniform{1234}{if}函数的多个版本,分别用来装入1维、2维、3维、4维向量,i表示变量是整数,f表示变量是浮点,该函数也有向量和矩阵的版本,可以用来设置向量或矩阵类型的uniform变量。该函数的第一个参数是我们用glGetUniformLocation函数得到的uniform变量索引值。

下面我们看下VS中的代码变化(注意:FS和上篇教程中一致,没有变化)。

uniform float gScale;

首先在shader中声明该uniform类型变量。

gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0);

我们用uniform变量gScale,改变顶点的x、y值,这样每帧中x、y坐标值都不同,从而实现动画的效果。

程序运行后效果如下:

android opengl 使用shadertoy opengl shader教程_句柄