关于javascript:JavaScript-WebGL-使用图片

11次阅读

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

引子

JavaScript WebGL 设置色彩成果始终无限,这时候就会想到应用图片,这就波及到 WebGL 中的纹理应用,比料想中要麻烦的多。

  • Origin
  • My GitHub

应用图片

纹理 (texture) 能够用来增加模仿物体的细节,在 3D 游戏中各种模仿的物体都应用了纹理。在绘制矩形的根底上次要有以下几个方面的变动:

  • 数据
  • 顶点着色器
  • 片元着色器
  • 缓冲纹理坐标数据
  • 加载并创立纹理
  • 绘制

数据

先筹备一张图片,而后为了把纹理映射到对应的矩形上,须要指定矩形每个顶点各自对应纹理的那个地位。

纹理二维坐标在 x 和 y 轴上,范畴为 0 到 1 之间。纹理坐标起于(0, 0),对应图片的左下角,终于(1, 1),对应图片的右上角。所以对应的纹理坐标为:

  const texCoords = [
    1.0,
    1.0, // 右上角
    0.0,
    1.0, // 左上角
    0.0,
    0.0, // 左下角
    1.0,
    0.0, // 右下角
  ];

顶点着色器

纹理坐标须要进行缓冲并进行传递,在顶点着色器中减少了变量 aVertexTextureCoord,其值会传递到片元着色器。

  const source = `
    attribute vec3 aVertexPos;
    attribute vec2 aVertexTextureCoord;

    varying highp vec2 vTextureCoord;
    void main(void){gl_Position = vec4(aVertexPos, 1);
      vTextureCoord = aVertexTextureCoord;
    }
  `;

片元着色器

在片元着色器中承受纹理坐标,定义纹理采样器 uSampler,留神这个是全局变量,在任何阶段都能够拜访,目前还没有值。内置的办法 texture2D 取得最终的色彩。

  const fragmentSource = `
    varying highp vec2 vTextureCoord;
    uniform sampler2D uSampler;
    void main(void){gl_FragColor = texture2D(uSampler, vTextureCoord);
    }
  `;

缓冲纹理坐标数据

纹理坐标数据同样须要进入缓冲。

/**
 * 缓冲纹理坐标数据并激活
 * @param {*} gl WebGL 上下文
 * @param {*} shaderProgram 着色器程序
 * @param {*} data 纹理坐标数据
 */
function setTextureBuffers(gl, shaderProgram, data) {
  // 创立空白的缓冲对象
  const buffer = gl.createBuffer();
  // 绑定指标
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  // WebGL 不反对间接应用 JavaScript 原始数组类型,须要转换
  const dataFormat = new Float32Array(data);
  // 初始化数据存储
  gl.bufferData(gl.ARRAY_BUFFER, dataFormat, gl.STATIC_DRAW);

  // 获取对应数据索引
  const texCoord = gl.getAttribLocation(
    shaderProgram,
    "aVertexTextureCoord"
  );
  // 解析顶点数据
  gl.vertexAttribPointer(texCoord, 2, gl.FLOAT, false, 0, 0);
  // 启用顶点属性,顶点属性默认是禁用的。gl.enableVertexAttribArray(texCoord);
}

加载并创立纹理

要保障图片加载实现后能力应用。失去图片数据后须要创立纹理对象。

function loadImage(gl) {var img = new Image();
  img.onload = (e) => {createTexture(gl, e.target);
  };
  img.src = "./1.jpg";
}

function createTexture(gl, source) {const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  // 反转图片 Y 轴方向
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  // 纹理坐标程度填充 s
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  // 纹理坐标垂直填充 t
  gl.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 并绑定到对应的指标,这里是二维的图片,第一个参数值取 gl.TEXTURE_2D 示意二维纹理,第二个参数是纹理对象,当为 null 时示意勾销绑定。绑定之后能力对纹理进行进一步操作。

pixelStorei 办法对图像进行反转 Y 方向坐标,这是因为图片的坐标零碎和纹理参考的坐标系不一样。

texParameteri 办法设置纹理的各种参数,这里须要顺便阐明一下,如果心愿应用各种尺寸的图片,须要对程度和垂直填充进行下面的设置,否则只能显示特定尺寸的图片。

texImage2D 办法把纹理源赋值给纹理对象,这里就是把图像的像素数据传给纹理对象,这样能力在绘制纹理的时候看到图像。

activeTexture 办法激活指定的纹理,纹理单元的范畴是 0 到 gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1,这里只有一个,取值为 gl.TEXTUREI0。默认的第一个纹理单元总是激活的,所以这行代码能够去掉。

绘制

在片元着色器中申明的全局变量,绘制时应用 uniform1i 办法指定对应的值,第二个参数示意纹理单元,这里 0 就是第一个纹理单元。

/**
 * 绘制
 * @param {*} gl WebGL 上下文
 * @param {*} shaderProgram 着色器程序
 */
function draw(gl, shaderProgram) {
  // 获取纹理采样器
  const samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
  // 指定全局变量关联的纹理单元
  gl.uniform1i(samplerUniform, 0);
  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}

成果

这是示例,成果如下:

如果比照原图的话,能够发现这张图片变形了,并没有自适应。

参考资料

  • WebGL 图像处理
  • WebGL 纹理详解之一:纹理的根本应用
  • 纹理
正文完
 0