纹理坐标 s,t

把一张图片贴到几何图形上,就是使用纹理坐标来确定纹理图像的哪部分将覆盖到几何图形上。纹理坐标以s、t来命名,取值范围从0.0到1.0。 右上角的纹理坐标始终是(1.0, 1.0),无论图像的长宽是多少。而 jpg、png ... 等图片的 y 轴是向下的,所以当图片加载完后,要先进行 y 轴反转 gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true )。

贴图流程

GLSL ES 1. 在片元着色器中声明采样器 uniform sampler2D u_Sampler;
2. 从顶点着色器向片元着色器传递纹理坐标 attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
3. 在片元着色器中获取纹理像素颜色 gl_FragColor = texture2D(u_Sampler, v_TexCoord);
JavaScript 坐标 1. 设置顶点坐标、纹理坐标 var verticesTexCoords = new Float32Array([ ])
2. 获取 attribute 变量的存储位置,并对其出入坐标数据 attribute
JavaScript 配置像素 1. 创建纹理对象 gl.createTexture()
2. 获取 uniform 变量的存储位置,用来接收纹理图像 gl.getUniformLocation()
3. 加载图像 var image = new Image(); image.onload = ...
4. 图像加载完后,设置像素的存储格式 gl.pixelStorei()
5. 激活纹理单元 gl.activeTexture()
6. 绑定纹理对象 gl.bindTexture()
7. 配置纹理对象的参数 gl.texParameteri()
8. 将图像分配给纹理对象 gl.texImage2D()
9. 将纹理单元传递给片元着色器 gl.uniform1i()

在 Fragment Shader 中,声明一个 uniform 变量的类型是 sampler2D 的采样器, 它用来访问纹理。sampler2D 用于平面,samplerCube 用于立体模型。GLSL ES 用内置函数 texture2D() 来抽取二维的纹素颜色。 在 JavaScript 中用 gl.uniform1i( location, v0 ) 来进行赋值, 后面的参数出入第几个纹理单元。

// GLSL ES uniform sampler2D u_Sampler; gl_FragColor = texture2D(u_Sampler, v_TexCoord); // JavaScript var u_Sampler = gl.getUniformLocation( gl.program, 'u_Sampler' ); gl.uniform1i( u_Sampler, 0 );

纹理单元从0号开始,一般至少有8个,个数由计算机硬件及浏览器的 WebGL 来做决定。它是我们操作 gl.createTexture( ) 出来的纹理对象的工具。 所以要先激活它 gl.activeTexture()。在 GLSL ES 中,采样器是二维的 sampler2D,那么在 JavaScript 中,需要把纹理单元和一个纹理类型为 gl.TEXTURE_2D 的纹理类型绑定在一起 gl.bindTexture()。 接着用 gl.texParameteri( gl.TEXTURE_2D, pname, param ) 配置参数。

pname param
gl.TEXTURE_MAG_FILTER 纹理放大 gl.LINEAR (default value), gl.NEAREST
gl.TEXTURE_MIN_FILTER 纹理缩小 gl.LINEAR, gl.NEAREST, gl.NEAREST_MIPMAP_NEAREST, gl.LINEAR_MIPMAP_NEAREST, gl.NEAREST_MIPMAP_LINEAR (default value), gl.LINEAR_MIPMAP_LINEAR
gl.TEXTURE_WRAP_S 纹理水平填充 gl.REPEAT (default value),gl.CLAMP_TO_EDGE, gl.MIRRORED_REPEAT
gl.TEXTURE_WRAP_T 纹理垂直填充 gl.REPEAT (default value),gl.CLAMP_TO_EDGE, gl.MIRRORED_REPEAT
如果你的图片的尺寸为非2次幂时,使用了 gl.TEXTURE_MIN_FILTER,会有报错:
TEXTURE_2D at unit 0 is incomplete: Mipmapping requires power-of-two sizes. 或者
Non-power-of-two textures must have a wrap mode of CLAMP_TO_EDGE.

<script id="vertexShader" type="x-shader/x-vertex"> attribute vec4 a_Position; attribute vec2 a_TexCoord; varying vec2 v_TexCoord; void main(){ gl_Position = a_Position; v_TexCoord = a_TexCoord; } </script> <script id="fragmentShader" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D u_Sampler; // 采样器 varying vec2 v_TexCoord; void main(){ gl_FragColor = texture2D(u_Sampler, v_TexCoord); } </script> function init(){ var canvas = document.getElementById('canvas'); gl = canvas.getContext('webgl'); if (!gl) { console.log('Failed to get WebGL.'); return; } if (!initShaders(gl, "vertexShader", "fragmentShader")) { console.log('Failed to initShaders.'); return; } gl.clearColor( 0.0, 0.0, 0.0, 1.0); initVertexBuffer(gl); // a_Position, a_TexCoord initTexture(gl); // u_Sampler } function initVertexBuffer(gl){ var verticesTexCoords = new Float32Array([ // 顶点 纹理 -1.0, 1.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0 ]), element_size = verticesTexCoords.BYTES_PER_ELEMENT; var verticesTexCoordBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, verticesTexCoordBuffer ); 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, element_size * 4, 0 ); gl.enableVertexAttribArray( a_Position ); var a_TexCoord = gl.getAttribLocation( gl.program, 'a_TexCoord' ); gl.vertexAttribPointer( a_TexCoord, 2, gl.FLOAT, false, element_size * 4, element_size * 2 ); gl.enableVertexAttribArray( a_TexCoord ); } function initTexture(gl){ var texture = gl.createTexture(); var u_Sampler = gl.getUniformLocation( gl.program, 'u_Sampler' ); var image = new Image(); image.onload = function(){ loadTexture(gl, texture, u_Sampler, image); }; image.src = '../assets/textures/view.png'; } function loadTexture(gl, texture, u_Sampler, image){ gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true ); gl.activeTexture( gl.TEXTURE0 ); gl.bindTexture( gl.TEXTURE_2D, texture ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); gl.uniform1i( u_Sampler, 0 ); gl.clear( gl.COLOR_BUFFER_BIT ); gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 ); }

多幅纹理

请转到 多幅纹理