本章主要内容:
(1) 将顶点的其他(非坐标)数据 —— 如颜色等 —— 传入顶点着色器
(2)发生在顶点着色器和片元着色器之间的从图形到片元的转化,又称图元光栅化(rasterzation process)
(3)将图形(或称纹理)映射到图形或三维对象的表面上。
- 将顶点坐标传入着色器,步骤:
(1)创建缓冲区对象。
(2)将缓冲区对象绑定到tartget
上。
(3)将顶点坐标数据写入缓冲区对象。
(4)将缓冲区对象分配给对应的attribute
变量。
(5)开启attribute
变量。
交错组织
(interleaving):将顶点坐标和尺寸数据打包到同一缓冲区对象中。gl.vertexAttribPointer()
varying 变量
: 从顶点着色器向片元着色器中传入数据。
varying 变量只能是float(以及相关的vec2,vec3,vec4,mat2,mat3,mat4)。在顶点着色器和片元着色器之间,有两个步骤:
[1]图形装配过程:将孤立的顶点坐标装配成几何图形。几何图形的类别由
gl.drawArray() `函数的第一个参数决定。
输入数据:gl_Position
[2] 光栅化过程:将装配好的几何图形转为片元。
步骤:
(1)根据 gl.drawArrays()
的参数n,将执行顶点着色器n次(执行顶点着色器结果:将坐标传入并存储在装配区)
(2)开始装配图形。使用传入的点坐标,根据 gl.drawArrays()
的第一个参数信息(如:gl.TRANGLES)来决定如何装配。
(3)光栅化
- 颜色内插(interpolation)
-
纹理映射
(texture mapping):根据纹理图像,为之前光栅化后的每个片元涂上合适的颜色。
纹素
(texels, texture elements):组成纹理图像的像素。每一个纹素的颜色都是用RGB或RGBA格式编码。
在WebGL中,要进行纹理映射,需遵循以下四步:
(1)准备好映射到几何图形上的纹理图像。
(2)为几何图形配置纹理映射方式。
(3)加载纹理图像,对其进行一些配置,以在WebGL中使用它。
(4)在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素的颜色赋给片元。纹理坐标
纹理坐标
是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色。
WebGL系统中的纹理坐标系统是二维的。
WebGL中使用s和t命名纹理坐标。(st坐标系统)
- 将纹理图像粘贴到几何图形上
在WebGL中,我们通过纹理图像的纹理坐标与几何图形顶点坐标间的映射关系,来确定怎样将纹理图像贴上去。
- 纹理映射过程详解
步骤:
(1)顶点着色器中接收定点的纹理坐标,光栅化后传递给片元着色器。
(2)片元着色器根据片元的纹理坐标,从纹理图像中抽取出纹素颜色,赋给当前片元。
(3)设置顶点的纹理坐标(initVertexBuffers()
)
var verticesTexCoords = new Float32Array([
-0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, 0.0, 0.0,
0.5, 0.5, 1.0, 1.0,
0.5, -0.5, 1.0, 0.0,
])
将顶点坐标和纹理坐标写入缓冲区对象,将其中的顶点坐标分配给a_Position变量并开启之。
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
gl.enableVertexAttribArray(a_Position);
获取a_TexCoord
变量的存储位置,将缓冲区中的纹理坐标分配给该变量更开启。
var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
gl.enableVertexAttribArray(a_TexCoord);
(4)准备待加载的纹理图像,令浏览器读取它(initTextures())
initTextures() => 配置和加载问题
调用gl.createTexture()
创建纹理对象
var texture = gl.createTexture();
同样,也可以使用gl.deleteTeture()来删除一个纹理对象。如果试图删除一个已经被删除的纹理对象,不会报错也不会产生任何影响。
调用gl.getUniformLocation()
从片元着色器中获取uniform
变量u_Sampler
(取样器)的存储位置,该变量用来接收纹理图像
var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
创建image对象
var image = new Image();
注册图像加载事件的响应函数
image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
浏览器开始加载图像
image.src = '../resources/sky.jpg';
(5)监听纹理图像的加载事件,一旦加载完成,就在WebGL系统中使用纹理(loadTexture())。
loadTexture()
=> 配置纹理供WebGL使用
对纹理图像进行y轴翻转(WebGL纹理坐标中的t轴的方向和PNG、BMP、JPG等格式图片的坐标系统的Y轴方向是相反的。)
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
开启0号纹理单元
WebGL通过纹理单元的机制来同时使用多个纹理。
每个纹理单元有一个单元编号来管理一张纹理图像。
系统支持的纹理单元格数取决于硬件和浏览器的WebGL实现,但是在默认情况下,WebGL至少支持8个纹理单元。
在使用纹理单元之前,还需要调用gl.aactiveTexture()
来激活它。
gl.activeTexture(gl.TEXTURE0);
绑定纹理对象(设置纹理的类型)
gl.bindTexture(gl.TEXTURE_2D, texture);
配置纹理对象的参数 => 设置纹理图像映射到图形上的具体方式
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
配置纹理图像 => 将纹理图像分配给纹理对象,同时允许你告诉WebGL系统关于该图像的一些特性。
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
format标示纹理数据的格式,必须根据纹理图像的格式来选择这个参数
JPG => gl.RGB
PNG => gl.RGBA
BMP => gl.RGB
gl.LUMUNANCE
和 gl.LUMINANCE_ALPHA
通常用在灰度图像上等等
流明
(luminance)标示我们感知到的物体表面的亮度。通常使用物体表面红、蓝颜色分量指的加权平均来计算流明。
type
参数制定了纹理数据类型。通常使用gl.UNSIGNED_BYTE
数据类型。
分配后的WebGL系统:
将0号纹理传递给着色器中的取样器变量
gl.uniform1i(u_Sampler, 0);
uniform sampler2D u_Sampler;
分配给unform
变量后的WebGL系统:
绘制矩形
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
从顶点着色器向片元着色器传输纹理坐标
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec2 a_TexCoord;\n' +
'varying vec2 v_TexCoord;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' v_TexCoord = a_TexCoord;\n' +
'}\n';
在片元着色器中获取纹理像素颜色(texture2D())
gl_FragColor = texture2D(u_Sampler, v_TexCoord);