关于前端:WebGL-系列-08-纹理

38次阅读

共计 8215 个字符,预计需要花费 21 分钟才能阅读完成。

  • 原文地址:Day 8. Textures
  • 原文作者:Andrei Lesnitsky

这是 WebGL 系列的第 8 天教程,每天都有新文章公布。

订阅或者退出邮件列表以便及时获取更新内容。

源代码在这里

嘿???? 欢送回到 WebGL 系列教程。

咱们曾经学习了几种将色彩数据传递到着色器的办法,然而还有另外一种办法,它十分弱小,也就是明天咱们将学习的纹理。

让咱们创立简略的着色器:

???? src/shaders/texture.f.glsl


precision mediump float;

  

void main() {gl_FragColor = vec4(1, 0, 0, 1);

}

  

???? src/shaders/texture.v.glsl


attribute vec2 position;

  

void main() {gl_Position = vec4(position, 0, 1);

}

  

???? src/texture.js


import vShaderSource from './shaders/texture.v.glsl';

import fShaderSource from './shaders/texture.f.glsl';

  

获取 webgl 上下文:

???? src/texture.js


 import vShaderSource from './shaders/texture.v.glsl';

 import fShaderSource from './shaders/texture.f.glsl';

+ 

+ const canvas = document.querySelector('canvas');

+ const gl = canvas.getContext('webgl');

  

创立着色器:

???? src/texture.js


 import vShaderSource from './shaders/texture.v.glsl';

 import fShaderSource from './shaders/texture.f.glsl';

+ import {compileShader} from './gl-helpers';

 const canvas = document.querySelector('canvas');

 const gl = canvas.getContext('webgl');

+ 

+ const vShader = gl.createShader(gl.VERTEX_SHADER);

+ const fShader = gl.createShader(gl.FRAGMENT_SHADER);

+ 

+ compileShader(gl, vShader, vShaderSource);

+ compileShader(gl, fShader, fShaderSource);

  

增加 program

???? src/texture.js


 compileShader(gl, vShader, vShaderSource);

 compileShader(gl, fShader, fShaderSource);

+ 

+ const program = gl.createProgram();

+ 

+ gl.attachShader(program, vShader);

+ gl.attachShader(program, fShader);

+ 

+ gl.linkProgram(program);

+ gl.useProgram(program);

  

创立一个顶点地位缓冲区并填充数据:

???? src/texture.js


 import vShaderSource from './shaders/texture.v.glsl';

 import fShaderSource from './shaders/texture.f.glsl';

 import {compileShader} from './gl-helpers';

+ import {createRect} from './shape-helpers';

+ 

 const canvas = document.querySelector('canvas');

 const gl = canvas.getContext('webgl');

 gl.linkProgram(program);

 gl.useProgram(program);

+ 

+ const vertexPosition = new Float32Array(createRect(-1, -1, 2, 2));

+ const vertexPositionBuffer = gl.createBuffer();

+ 

+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);

+ gl.bufferData(gl.ARRAY_BUFFER, vertexPosition, gl.STATIC_DRAW);

  

设置地位属性:

???? src/texture.js


 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);

 gl.bufferData(gl.ARRAY_BUFFER, vertexPosition, gl.STATIC_DRAW);

+ 

+ const attributeLocations = {+     position: gl.getAttribLocation(program, 'position'),

+ };

+ 

+ gl.enableVertexAttribArray(attributeLocations.position);

+ gl.vertexAttribPointer(attributeLocations.position, 2, gl.FLOAT, false, 0, 0);

  

设置索引缓冲区:

???? src/texture.js


 gl.enableVertexAttribArray(attributeLocations.position);

 gl.vertexAttribPointer(attributeLocations.position, 2, gl.FLOAT, false, 0, 0);

+ 

+ const vertexIndices = new Uint8Array([0, 1, 2, 1, 2, 3]);

+ const indexBuffer = gl.createBuffer();

+ 

+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, vertexIndices, gl.STATIC_DRAW);

  

同时公布一个绘制调用:

???? src/texture.js


 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, vertexIndices, gl.STATIC_DRAW);

+ 

+ gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

  

当初,咱们能够进行纹理的操作:

您能够将图像上传到 GPU 并应用它来计算像素色彩。在通常状况下,当画布大小雷同或至多与图像大小成比例时,咱们能够读取每个像素色彩并将其用作 gl_FragColor

让咱们帮忙加载图像:

???? src/gl-helpers.js


 throw new Error(log);

 }

 }

+ 

+ export async function loadImage(src) {+     const img = new Image();

+ 

+     let _resolve;

+     const p = new Promise((resolve) => _resolve = resolve);

+ 

+     img.onload = () => {+         _resolve(img);

+     }

+ 

+     img.src = src;

+ 

+     return p;

+ }

  

加载图像并创立 webgl 纹理:

???? src/texture.js


 import vShaderSource from './shaders/texture.v.glsl';

 import fShaderSource from './shaders/texture.f.glsl';

- import {compileShader} from './gl-helpers';

+ import {compileShader, loadImage} from './gl-helpers';

 import {createRect} from './shape-helpers';

+ import textureImageSrc from '../assets/images/texture.jpg';

 const canvas = document.querySelector('canvas');

 const gl = canvas.getContext('webgl');

 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, vertexIndices, gl.STATIC_DRAW);

- gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

+ loadImage(textureImageSrc).then((textureImg) => {+     const texture = gl.createTexture();

+ 

+     gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

+ });

  

[GTI} 增加图片:

???? assets/images/texture.jpg

咱们还须要一个适合的 webpack 辅助加载:

???? package.json


 "homepage": "https://github.com/lesnitsky/webgl-month#readme",

 "devDependencies": {

 "raw-loader": "^3.0.0",

+     "url-loader": "^2.0.1",

 "webpack": "^4.35.2",

 "webpack-cli": "^3.3.5"

 }

  

???? webpack.config.js


 test: /.glsl$/,

 use: 'raw-loader',

 },

+ 

+             {

+                 test: /.jpg$/,

+                 use: 'url-loader',

+             },

 ],

 },

  

要对纹理进行操作,咱们须要与对缓冲区进行雷同的操作 – 将两者绑定:

???? src/texture.js


 loadImage(textureImageSrc).then((textureImg) => {const texture = gl.createTexture();

+     gl.bindTexture(gl.TEXTURE_2D, texture);

+ 

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

 });

  

并将图像上传到绑定的纹理:

???? src/texture.js


 gl.bindTexture(gl.TEXTURE_2D, texture);

+     gl.texImage2D(

+         gl.TEXTURE_2D,

+     );

+ 

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

 });

  

当初临时疏忽第二个参数,咱们稍后再探讨:

???? src/texture.js


 gl.texImage2D(

 gl.TEXTURE_2D,

+         0,

 );

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

  

第三和第四个参数别离指定外部纹理格局和源(图像)格局,也就是图像中的 gl.RGBA。查看此页面以获取无关格局的更多详细信息

???? src/texture.js


 gl.texImage2D(

 gl.TEXTURE_2D,

 0,

+         gl.RGBA,

+         gl.RGBA,

 );

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

  

另一个参数指定源类型 (0..255 示意 UNSIGNED_BYTE)

???? src/texture.js


 0,

 gl.RGBA,

 gl.RGBA,

+         gl.UNSIGNED_BYTE,

 );

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

  

还有图像自身:

???? src/texture.js


 gl.RGBA,

 gl.RGBA,

 gl.UNSIGNED_BYTE,

+         textureImg,

 );

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

  

咱们还须要指定不同的纹理参数。在接下来的教程中,咱们将探讨这个参数。

???? src/texture.js


 textureImg,

 );

+     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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

+     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

+ 

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

 });

  

为了可能在着色器中应用纹理,咱们须要指定一个对立的 sampler2D 类型:

???? src/shaders/texture.f.glsl


 precision mediump float;

+ uniform sampler2D texture;

+ 

 void main() {gl_FragColor = vec4(1, 0, 0, 1);

 }

  

同时对立对 sampler2D 类型指定相应的值。有一种应用多种纹理的办法,咱们将在下一个教程中探讨它

???? src/texture.js


 position: gl.getAttribLocation(program, 'position'),

 };

+ const uniformLocations = {+     texture: gl.getUniformLocation(program, 'texture'),

+ };

+ 

 gl.enableVertexAttribArray(attributeLocations.position);

 gl.vertexAttribPointer(attributeLocations.position, 2, gl.FLOAT, false, 0, 0);

 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

+     gl.activeTexture(gl.TEXTURE0);

+     gl.uniform1i(uniformLocations.texture, 0);

+ 

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

 });

  

咱们还要将画布解析器传递给着色器

???? src/shaders/texture.f.glsl


 precision mediump float;

 uniform sampler2D texture;

+ uniform vec2 resolution;

 void main() {gl_FragColor = vec4(1, 0, 0, 1);

  

???? src/texture.js


 const uniformLocations = {texture: gl.getUniformLocation(program, 'texture'),

+     resolution: gl.getUniformLocation(program, 'resolution'),

 };

 gl.enableVertexAttribArray(attributeLocations.position);

 gl.activeTexture(gl.TEXTURE0);

 gl.uniform1i(uniformLocations.texture, 0);

+     gl.uniform2fv(uniformLocations.resolution, [canvas.width, canvas.height]);

+ 

 gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_BYTE, 0);

 });

  

将蕴含每个像素坐标的非凡变量 gl_FragCoordresolution 联结应用,咱们能够失去一个 texture coordinate(图像像素的坐标),纹理坐标范畴为 [0..1]

???? src/shaders/texture.f.glsl


 uniform vec2 resolution;

 void main() {

+     vec2 texCoord = gl_FragCoord.xy / resolution;

 gl_FragColor = vec4(1, 0, 0, 1);

 }

  

同时应用 texture2D 渲染整个图像。

???? src/shaders/texture.f.glsl


 void main() {

 vec2 texCoord = gl_FragCoord.xy / resolution;

-     gl_FragColor = vec4(1, 0, 0, 1);

+     gl_FragColor = texture2D(texture, texCoord);

 }

  

酷???? 当初咱们能够渲染图像了,然而还有很多对于纹理的常识须要学习,咱们今天见。

正文完
 0