https://i-blog.csdnimg.cn/blog_migrate/b9818b0a5d9d6f88bc268e39cf07d2c2.pnghttps://i-blog.csdnimg.cn/blog_migrate/b9818b0a5d9d6f88bc268e39cf07d2c2.png
本人在学WebGL,WebGL的资料很少,由于WebGL是OpenGL ES 2.0的子集,所以先学习一下OpenGL ES 2.0的基础知识。OpenGL中既有固定管线处理流程,也可以使用shader进行可编程的管线处理,OpenGL ES 2.0是完全可编程的管线流程,而没有固定管线流程,这给我们增加了更多的灵活度,以前可以让OpenGL替我们做的事情,现在必须要我们在shader中自己去实现,这可以使我们更深入的理解OpenGL ES 2.0图形绘图流程。
本文参考了http://blog.csdn.net/racehorse/article/details/6593719
1.OpenGL中的图形处理固定管线流程:
现在的显卡允许程序员自己编程实现上述流水线中的两个阶段:
·顶点shader实现顶点变换阶段的功能
·片断shader替代片断纹理化和色彩化的功能
2.OpenGL ES 2.0中的可编程管线流程:
3.顶点着色器:
4.片段着色器:
5.Shader开发流程:
a.编写vertex Shader和fragment shader源码。
b.创建两个shader 实例:GLuint glCreateShader(GLenum type); [gl.createShader]
c.给Shader实例指定源码。 glShaderSource [gl.shaderSource]
d.编译shaer源码 void glCompileShader(GLuint shader) [gl.compileShader]
e.创建shader program -- GLuint glCreateProgram(void) [gl.createProgram]
f.绑定shader到program 。 void glAttachShader(GLuint program, GLuint shader)。每个program必须绑定一个vertex shader 和一个fragment shader。 [gl.attachShader] g.链接program 。 void glLinkProgram(GLuint program) [gl.linkProgram]
h.使用porgram 。 void glUseProgram(GLuint program) [gl.useProgram]
i.* 对于使用独立shader编译器编译的二进制shader代码,可使用glShaderBinary来加载到一个shader实例中。
6.Uniforms变量:
Uniform变量是OpenGL ES着色器语言中的一种变量类型修饰符。Uniform变量用来存储只读值,这些值通过OpenGL ES 2.0 API传递给着色器。Uniforms常用于存储着色器需要的各种数据,比如变换矩阵、光线参数以及颜色等。输入着色器的常量参数(顶点或者片段)应该被作为Uniform类型传入进去。
如果顶点着色器和片段着色器被连接到同一个program对象中,它们会分享相同的uniform变量。因此,如果一个Uniform变量在顶点着色器中声明了,并且也在片段着色器中声明了,那么二者的声明必须匹配。当应用程序通过API装载uniform变量时,其值在顶点着色器和片段着色器中均可获得。 Uniform变量常用于在硬件中进行“常量存储”。
7.Attributes变量:
Attribute变量只能够在顶点着色器中使用,用于逐个指定到顶点着色器的输入。Attributes典型的用来存储位置、法线、纹理坐标和颜色。理解的关键在于attributes存储着每个顶点绘制所需要的数据。下面这个例子中,a_position是位置属性,a_texCoord0是纹理坐标属性。
uniform mat4 m_matModelViewProjection;
attribute vec4 a_position;//position attribute
attribute vec4 a_texCoord0;//texture coordinate attribute
varying vec2 v_texCoord;
void main(void)
{
gl_Position =matViewProjection* position;
v_texCoord = a_texCoord0;
}
注:gl_Position是内置的变量。
8.Varyings变量:
Varyings变量用来存储顶点着色器的输出,并且也是片段着色器的输入。每个顶点着色器输出需要传递给片段着色器的的数据,这些数据用一个或多个varying变量来声明。这些变量也同时在片段着色器中声明(有着相同的类型),并且在基元的光栅化过程中会进行线性插值。其声明如下所示:
varying vec2 texCoord;
varying vec4 color;
必须在顶点着色器和片段着色器中同时声明varying,且其声明必须完全相同。
9.给shader中的uniform赋值:
uniform vec3 uAmbientColor;这样给uAmbientColor赋值:
ambientColorLocation = gl.getUniformLocation(shaderProgram,"uAmbientColor");
gl.uniform3f( ambientColorLocation, 1.0,1.0,1.0 );
uniform bool uUseLighting;这样给uUseLighting赋值:
useLightingLocation = gl.getUniformLocation(shaderProgram,"uUseLighting");
gl.uniform1i(useLightingLocation,要赋值的布尔值);
uniform float uAlpha;赋值用到的是
alphaLocation = gl.getUniformLocation(shader, "uAlpha");
gl.uniform1f(alphaLocation,0.7);
uniform mat4 mv;这样给mat4赋值:
mvLocation = gl.getUniformLocation(shaderProgram, "mv");
gl.uniformMatrix4fv(mvLocation,false, new Float32Array([…]);
总结:uniform赋值时,先从shader中根据uniform变量的名称通过gl.getUniformLocation(shaderName,"uniformName")获取其地址,然后根据地址通过gl.uniform*(…)对其进行赋值。
10.给shader中的attribute赋值:
attribute vec3 position;
var positionLocation = gl.getAttribLocation(shader,"position");
gl.enableVertexAttribArray(positionLocation);
//
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array([…]), gl.STATIC_DRAW);
gl.vertexAttribPointer(positionLocation,3, gl.FLOAT, false, 0, 0);
与uniform赋值不同,对attribute进行赋值时,在initShaders时,首先要通过gl.getAttribLocation(shader,"attributeName")获取attribute变量的地址,然后通过调用gl.enableVertexAtribArray(attributeLocation)来启用该attribute变量。上面的操作只需要调用一次即可。然后在循环drawScene的时候,如果buffer之前就已经通过gl.bufferData赋值(比如在initialBuffers()的时候对其赋值),如果buffer的值没有改变(比如坐标值未变)那么就不需要在每次渲染的时候再通过bufferData在对其赋值,只需在每次渲染的时候,通过gl.bindBuffer和gl.vertexAttribPointer将buffer的值传递给着色器中的attribute变量即可,对shader中的attribute变量进行赋值。可参见 一个使用drawElements绘图的简单Demo