介绍JavaScriptWebGL对颜色设置有限制。这时候你就会想到使用图片,这涉及到WebGL中纹理的使用,比想象中的要麻烦很多。OriginMyGitHub使用图像纹理(textures)为模拟对象添加细节。纹理用于3D游戏中的各种模拟对象。在绘制矩形的基础上,主要有以下几个方面的变化:datavertexshaderfragmentshaderbuffertexturecoordinatedataloadingandcreatetexturedrawingdata首先准备一张图片,然后将纹理映射到对应的矩形上,这是必要的指定纹理对应的矩形的每个顶点的位置。纹理二维坐标在x轴和y轴上,范围在0到1之间。纹理坐标起始于(0,0),对应图片的左下角,结束于(1,1),对应图片的左上角图片的右上角。所以对应的纹理坐标为:consttexCoords=[1.0,1.0,//右上角0.0,1.0,//左上角0.0,0.0,//左下角1.0,0.0,//右下角];vertexshadertexturecoordinates需要缓冲传递。变量aVertexTextureCoord被添加到顶点着色器中,它的值将被传递给片段着色器。constsource=`属性vec3aVertexPos;属性vec2aVertexTextureCoord;变化的highpvec2vTextureCoord;voidmain(void){gl_Position=vec4(aVertexPos,1);vTextureCoord=aVertexTextureCoord;纹理坐标,定义纹理采样器uSampler,注意这是一个全局变量,可以在任何阶段访问,目前还没有值。内置方法texture2D获取最终颜色。constfragmentSource=`varyinghighpvec2vTextureCoord;统一采样器2DuSampler;voidmain(void){gl_FragColor=texture2D(uSampler,vTextureCoord);}`;缓冲区纹理坐标数据纹理坐标数据也需要进入缓冲区。/***缓冲纹理坐标数据并激活*@param{*}glWebGLcontext*@param{*}shaderProgram着色器程序*@param{*}data纹理坐标数据*/functionsetTextureBuffers(gl,shaderProgram,data){//创建一个空白缓冲区对象constbuffer=gl.createBuffer();//绑定目标gl.bindBuffer(gl.ARRAY_BUFFER,buffer);//WebGL不支持直接使用JavaScript原始数组类型,需要转换constdataFormat=newFloat32Array(data);//初始化数据存储gl.bufferData(gl.ARRAY_BUFFER,dataFormat,gl.STATIC_DRAW);//获取对应的数据索引consttexCoord=gl.getAttribLocation(shaderProgram,"aVertexTextureCoord");//解析顶点数据gl.vertexAttribPointer(texCoord,2,gl.FLOAT,false,0,0);//启用顶点属性,默认情况下禁用。gl.enableVertexAttribArray(texCoord);}加载和创建纹理只能在图像加载后使用。拿到图像数据后,需要创建一个纹理对象。functionloadImage(gl){varimg=newImage();img.onload=(e)=>{createTexture(gl,e.target);};img.src="./1.jpg";}functioncreateTexture(gl,source){consttexture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,纹理);//反转图像Y轴方向gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);//纹理坐标水平Fillsgl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);//纹理坐标垂直填充tgl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);//纹理放大处理gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);//纹理缩小处理gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);//分配给纹理对象的图像数据gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,source);//激活纹理gl.activeTexture(gl.TEXTURE0);}createTexture创建纹理对象,然后使用bindTexture绑定到对应的target上,这里是一张二维图片,第一个参数值取gl.TEXTURE_2D为表示二维纹理,第二个参数为纹理对象,为null时表示解除绑定。纹理只能在绑定后进一步操作。pixelStorei方法将图像的Y方向坐标进行反转,因为图像的坐标系与纹理参考的坐标系不同。texParameteri方法设置纹理的各种参数。在此,需要特别说明一下。如果要使用各种尺寸的图片,需要对水平和垂直的padding进行上述设置,否则只能显示特定尺寸的图片。texImage2D方法将纹理源赋值给纹理对象,这里是将图像的像素数据传递给纹理对象,这样绘制纹理的时候就可以看到图像了。activeTexture方法激活指定的纹理。纹理单元的范围是从0到gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS-1。这里只有一个,值为gl.TEXTUREI0。默认情况下,第一个纹理单元始终处于活动状态,因此可以删除这行代码。绘制片段着色器中声明的全局变量,绘制时使用uniform1i方法指定对应的值,第二个参数代表纹理单元,这里0为第一个纹理单元。/***Draw*@param{*}glWebGLcontext*@param{*}shaderProgram着色器程序*/functiondraw(gl,shaderProgram){//获取纹理采样器constsamplerUniform=gl.getUniformLocation(shaderProgram,"uSampler");//指定与全局变量关联的纹理单元gl.uniform1i(samplerUniform,0);gl.drawElements(gl.TRIANGLES,6,gl.UNSIGNED_SHORT,0);}效果这是一个例子,效果如下:如果对比原图的话,可以发现这张图变形了而且不适应。参考资料WebGL图像处理WebGL纹理详解一:texture纹理的基本使用
