《WebGL 编程指南》笔记 —— 第五章 颜色与纹理

2017-10-01  本文已影响351人  fehysunny

本章主要内容:
(1) 将顶点的其他(非坐标)数据 —— 如颜色等 —— 传入顶点着色器
(2)发生在顶点着色器和片元着色器之间的从图形到片元的转化,又称图元光栅化(rasterzation process)
(3)将图形(或称纹理)映射到图形或三维对象的表面上。

  1. 将顶点坐标传入着色器,步骤:
    (1)创建缓冲区对象。
    (2)将缓冲区对象绑定到tartget上。
    (3)将顶点坐标数据写入缓冲区对象。
    (4)将缓冲区对象分配给对应的 attribute 变量。
    (5)开启 attribute 变量。
使用两个缓冲区对象向顶点着色器传输数据
  1. 交错组织(interleaving):将顶点坐标尺寸数据打包到同一缓冲区对象中。

  2. gl.vertexAttribPointer()

gl.vertexAttribPointer()
  1. varying 变量: 从顶点着色器向片元着色器中传入数据。
    varying 变量只能是float(以及相关的vec2,vec3,vec4,mat2,mat3,mat4)。

  2. 在顶点着色器和片元着色器之间,有两个步骤:
    [1] 图形装配过程:将孤立的顶点坐标装配成几何图形。几何图形的类别由gl.drawArray() `函数的第一个参数决定。
    输入数据:gl_Position
    [2] 光栅化过程:将装配好的几何图形转为片元。

顶点着色器和片元着色器之间的图形装配和光栅化

步骤:
(1)根据 gl.drawArrays()的参数n,将执行顶点着色器n次(执行顶点着色器结果:将坐标传入并存储在装配区)
(2)开始装配图形。使用传入的点坐标,根据 gl.drawArrays()的第一个参数信息(如:gl.TRANGLES)来决定如何装配。
(3)光栅化

几何图形装配和光栅化过程
  1. 颜色内插(interpolation)
颜色值的内插
  1. 纹理映射(texture mapping):根据纹理图像,为之前光栅化后的每个片元涂上合适的颜色。
    纹素(texels, texture elements):组成纹理图像的像素。每一个纹素的颜色都是用RGBRGBA格式编码。
纹素
  1. 在WebGL中,要进行纹理映射,需遵循以下四步:
    (1)准备好映射到几何图形上的纹理图像。
    (2)为几何图形配置纹理映射方式。
    (3)加载纹理图像,对其进行一些配置,以在WebGL中使用它。
    (4)在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素的颜色赋给片元。

  2. 纹理坐标
    纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色。
    WebGL系统中的纹理坐标系统是二维的。
    WebGL中使用s和t命名纹理坐标。(st坐标系统)

WebGL的纹理坐标系统
  1. 将纹理图像粘贴到几何图形上
    在WebGL中,我们通过纹理图像的纹理坐标与几何图形顶点坐标间的映射关系,来确定怎样将纹理图像贴上去。
将纹理图像映射到顶点上
  1. 纹理映射过程详解
    步骤:
    (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.createTexture()

同样,也可以使用gl.deleteTeture()来删除一个纹理对象。如果试图删除一个已经被删除的纹理对象,不会报错也不会产生任何影响。

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);
图像坐标系统和WebGL纹理坐标系统 gl.pixelStorei()

开启0号纹理单元
WebGL通过纹理单元的机制来同时使用多个纹理。
每个纹理单元有一个单元编号来管理一张纹理图像。
系统支持的纹理单元格数取决于硬件和浏览器的WebGL实现,但是在默认情况下,WebGL至少支持8个纹理单元。
在使用纹理单元之前,还需要调用gl.aactiveTexture()来激活它。

gl.activeTexture(gl.TEXTURE0);
gl.activeTexture()

绑定纹理对象(设置纹理的类型)

gl.bindTexture(gl.TEXTURE_2D, texture);
纹理类型 gl.bindTexture() 将纹理坐标绑定到目标上

配置纹理对象的参数 => 设置纹理图像映射到图形上的具体方式

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri() param 参数值 四种纹理参数及它们锁产生的效果 纹理参数及它们的默认值

配置纹理图像 => 将纹理图像分配给纹理对象,同时允许你告诉WebGL系统关于该图像的一些特性。

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
gl.texImage2D() 纹素数据的数据格式

format标示纹理数据的格式,必须根据纹理图像的格式来选择这个参数
JPG => gl.RGB
PNG => gl.RGBA
BMP => gl.RGB
gl.LUMUNANCEgl.LUMINANCE_ALPHA 通常用在灰度图像上等等
流明(luminance)标示我们感知到的物体表面的亮度。通常使用物体表面红、蓝颜色分量指的加权平均来计算流明。

纹理数据的数据格式

type参数制定了纹理数据类型。通常使用gl.UNSIGNED_BYTE数据类型。

分配后的WebGL系统:

将图像分配给纹理对象

将0号纹理传递给着色器中的取样器变量

gl.uniform1i(u_Sampler, 0);

uniform sampler2D u_Sampler;
专用于纹理的数据类型

分配给unform变量后的WebGL系统:

将纹理单元分配给uniform变量

绘制矩形

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);
texture2D()
上一篇下一篇

猜你喜欢

热点阅读