10.纹理

1.纹理坐标:st坐标系统,纹理左边的原点位于图像左下角,图像右上角的坐标始终是(1.0,1.0)

2.纹理坐标与WebGL坐标的映射:

3.纹理映射:根据纹理图像,为之前光栅化后的每个图元图上合适的颜色,组成纹理图像的元素称为纹素。
4.纹理映射的过程:
    (1)准备好映射到几何图形上的纹理图像
    (2)为几何图像配置纹理映射方式(几何图形的某个片元的颜色取决于纹理图像中哪个像素)
    (3)加载纹理图像,对其进行一些配置,以在WebGL中使用
    (4)在片元着色器中将相应的纹理从纹理中抽取出来,并将纹素颜色赋给片元
5.纹理单元:
    WebGL通过一种称作纹理单元的机制来同时使用多个纹理,每个纹理单元有一个编号来管理一张纹理图像,纹理单元的个数却决于硬件和浏览器的WebGL实现,但是默认情况下WebGL至少支持8个纹理单元
6.为WebGL配置纹理
    (1)将图像y轴进行反转,图像坐标系与WebL坐标系Y轴方向相反
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);
    API:gl.pixelStorei(pname,param)
            pname:可以是gl.UNPACK_FLIP_WEBGL(对图像进行y轴反转,默认是false),也可以是gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL(将图像的RGB值的每一个分量乘以A,默认为false)
            param:指定非0(true)或0(false)
    (2)激活纹理单元:
gl.activeTexture(gl.TEXTURE0);
    API:gl.activeTexture( texUnit )
            texUnit:指定激活的纹理单元:gl.TEXTURE0.....gl.TEXTURE7,最后的数字表示纹理单元编号
    (3)绑定纹理对象:WebGL支持两种类型纹理:gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
gl.bindTexture(gl.TEXTURE_2D,texture)
    API:gl.bindTexture(target,texture)
            target:纹理对象类型
            texture:绑定的纹理单元
    注意:该方法完成了两个任务:开启纹理对象和绑定到纹理单元(之前已经激活了纹理单元)。在WebGL中无法直接操作纹理对象,必须将纹理对象绑定到纹理单元,然后通过操作纹理单元来操作对象
    (3)配置纹理对象参数:设置纹理图像映射到图形上的具体方式(如何根据纹理坐标获取纹素颜色、和按哪种方式重复填充纹理)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
//注意:如果图片的分辨率不是2的次幂,那么需要配置以下两个参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    API:gl.textParameteri( target , pname, param)
            target:纹理类型,gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
            pname:纹理参数
            param:纹理参数的值
            纹理参数及其默认值;
                    gl.TEXTURE_MAG_FILTER        纹理放大        gl.LINEAR
                    gl.TEXTURE_MIN_FILTER         纹理缩小        gl.NEAREST_MIPMAP_LINEAR
                    gl.TEXTURE_WRAP_S               纹理水平填充    gl.REPEAT
                    gl.TEXTURE_WRAP_T               纹理垂直填充    gl.REPEAT

        可以赋值给gl.TEXTURE_MAG_FILTER和gl.TEXTURE_MIN_FILTER的非金字塔纹理类型常量:

            gl.NEAREST:使用原纹理上距离映射后像素(新像素)中心最近的哪个像素的颜色值,作为新像素的值(使用曼哈顿距离,即x1,x2到y1,y2的值是|x1-x2|+|y1-y2|)

            gl.LINEAR:使用距离新像素中心最近的四个像素的加权平均作为新像素的值(该方法开销较大,图像质量更好)

        可以赋值给gl.TEXTURE_WRAP_S和gl.TEXTURE_WRAP_T的常量:

            gl.REPEAT:平铺式重复纹理

            gl.MIRRORED_PEREAT:镜像对称式重复纹理

            gl.CLAMP_TO_EDGE:使用纹理图像边缘值

    (4)将纹理图像分配给纹理对象:

gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image)

API:gl.textImage2D(target,level,internalformat,format,type,image)

        target:纹理类型,gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理

        level:传入0(该参数为金字塔准备)

        internalformat:图像内部格式,和图片格式有关(jpg,png,jpeg,bmp等)。流明表示我们感知到的物体表面亮度,使用RGB分量值的加权平均值来计算

        format:纹理数据格式,必须和internalformat一致

        type:纹理数据类型,后面几种数据格式通常用来压缩数据,减少浏览器加载时间

        image:包含纹理图像的Image图像

    (5)将纹理单元传递给片元着色器:通过指定纹理单元编号将纹理对象传给u_Sampler()取样器使用多个纹理

gl.uniform1i(u_Sampler,0);

7.通过上述步骤,纹理图像已经全部设置完成,顶点着色器接收到顶点的纹理坐标之后会光栅化内插出所有片元的纹理坐标,接下来由片元着色器进行处理,texture2D是GLSL ES的内置方法,只需传入纹理单元编号和纹理坐标,就可以得到纹理上的像素颜色。通过varying变量可以将片元的纹理坐标由顶点着色器传入片元着色器。

简单将一幅纹理图映射到一个矩形上:

var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec2 a_TexCoord;\n' +
'varying vec2 v_TexCoord;\n' +
'void main(){' +
'gl_Position = a_Position;\n' +
'v_TexCoord = a_TexCoord;\n' +
'}\n';
var FSHADER_SOURCE =
'precision mediump float;\n'+
'uniform sampler2D u_Sampler;\n' +
'varying vec2 v_TexCoord;\n' +
'void main(){\n' +
'gl_FragColor = texture2D(u_Sampler,v_TexCoord);\n' +
'}';

function main()
{
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE);

var n = initVertexBuffers(gl);
initTextures(gl,n);
}

function initVertexBuffers(gl)
{
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
]);
var n = 4;
var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
var vertexTexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER,verticesTexCoords,gl.STATIC_DRAW);
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);

return n;
}
function initTextures(gl,n)
{
//创建纹理对象
var texture = gl.createTexture();
//获取u_Sampler的存储位置
var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
var image = new Image();
//注册图像加载事件的响应函数
image.onload = function (){
//为WebGL配置纹理
loadTexture(gl,n,texture,u_Sampler,image);
};
//浏览器开始加载图形
image.src = 'res/3.png';
return true;
}
function loadTexture(gl,n,texture,u_Sampler,image)
{
//alert("图片加载事件已触发");
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);//对纹理图形进行y轴反转
//开启0号纹理单元8
gl.activeTexture(gl.TEXTURE0);
//向target绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D,texture);
//配置纹理参数
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
//注意:如果图片的分辨率不是2的次幂,那么需要配置以下两个参数
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
//配置纹理图像
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image);
//将0号纹理传给着色器
gl.uniform1i(u_Sampler,0);
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';
var FSHADER_SOURCE =
'precision mediump float;\n'+
'uniform sampler2D u_Sampler0;\n' +
'uniform sampler2D u_Sampler1;\n' +
'varying vec2 v_TexCoord;\n' +
'void main(){\n' +
'vec4 color0 = texture2D(u_Sampler0,v_TexCoord);\n' +
'vec4 color1 = texture2D(u_Sampler1,v_TexCoord);\n' +
'gl_FragColor = color0 * color1;\n' +
'}\n';

function main()
{
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE);
var n = initVertex(gl);
initTextures(gl,n);
}

function initVertex(gl)
{
var vertices = 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
]);
var FSIZE = vertices.BYTES_PER_ELEMENT;
console.log(FSIZE);
var n = 4;
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
var a_TexCoord = gl.getAttribLocation(gl.program,'a_TexCoord');

var vertexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,FSIZE*4,0);
gl.enableVertexAttribArray(a_Position);

gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,FSIZE*4,FSIZE*2);
gl.enableVertexAttribArray(a_TexCoord);
return n;
}

function initTextures(gl,n)
{
var texture0 = gl.createTexture();
var texture1 = gl.createTexture();
var u_Sampler0 = gl.getUniformLocation(gl.program,'u_Sampler0');
var u_Sampler1 = gl.getUniformLocation(gl.program,'u_Sampler1');
var image0 = new Image();
var image1 = new Image();
image0.onload = function(){
loadTexture(gl,n,texture0,u_Sampler0,image0,0);
};
image1.onload = function(){
loadTexture(gl,n,texture1,u_Sampler1,image1,1);
};
image0.src = "res/1.png";
image1.src = "res/3.png";
return true;
}
//标记纹理单元是否就绪
var g_texUnit0 = false,g_texUnit1 = false;

function loadTexture(gl,n,texture,u_Sampler,image,texUnit)
{
//反转纹理图像y轴
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);
//激活纹理
if(texUnit == 0)
{
gl.activeTexture(gl.TEXTURE0);
g_texUnit0 = true;
console.log("激活单元0");
}else {
gl.activeTexture(gl.TEXTURE1);
g_texUnit1 = true;
console.log("激活单元1");
}
//绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D,texture);
//配置纹理参数
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
//注意:如果图片的分辨率不是2的次幂,那么需要配置以下两个参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image)
gl.uniform1i(u_Sampler,texUnit);
if(g_texUnit0 && g_texUnit1)
{
console.log(n);
gl.drawArrays(gl.TRIANGLE_STRIP,0,n);
}
}

 

重点:(1)因为矩形顶点在两幅纹理上的纹理坐标是完全相同的,所以只用处理一次

          (2)使用两个纹素来计算最终的片元颜色。

          (3)由于图像的加载过程是异步的,我们无法知道哪副纹理图像先被加载完成,所以需要添加判断当两幅图像都加载完成时再绘制图像。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值