返回

WebGL实战篇(五)——图像处理

前端

图像处理是一个非常重要的领域,它在计算机图形学、计算机视觉和数字艺术中都有着广泛的应用。通过对图像进行处理,我们可以增强图像的视觉效果、提取图像中的有用信息,或者创建新的图像。

WebGL是一个非常强大的图形库,它可以帮助我们轻松地实现各种图像处理效果。在本文中,我们将介绍一些常见的图像处理效果,并演示如何使用WebGL实现这些效果。

首先,我们将学习如何使用WebGL缩放图像。图像缩放是一个非常简单但非常实用的操作,它可以帮助我们改变图像的大小,以便适应不同的显示区域。

function scaleImage(image, scaleX, scaleY) {
  const canvas = document.createElement("canvas");
  canvas.width = image.width * scaleX;
  canvas.height = image.height * scaleY;
  const ctx = canvas.getContext("webgl");

  // 创建一个纹理对象
  const texture = ctx.createTexture();

  // 将图像数据绑定到纹理对象
  ctx.bindTexture(ctx.TEXTURE_2D, texture);
  ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);

  // 设置纹理参数
  ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
  ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR);

  // 创建一个顶点着色器
  const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;

    varying vec2 v_texCoord;

    void main() {
      v_texCoord = a_texCoord;
      gl_Position = vec4(a_position, 0.0, 1.0);
    }
  `;

  // 创建一个片段着色器
  const fragmentShaderSource = `
    precision mediump float;

    varying vec2 v_texCoord;

    uniform sampler2D u_texture;

    void main() {
      gl_FragColor = texture2D(u_texture, v_texCoord);
    }
  `;

  // 创建一个着色器程序
  const program = ctx.createProgram();
  ctx.attachShader(program, vertexShader);
  ctx.attachShader(program, fragmentShader);
  ctx.linkProgram(program);

  // 使用着色器程序
  ctx.useProgram(program);

  // 获取属性和uniform变量的位置
  const positionAttributeLocation = ctx.getAttribLocation(program, "a_position");
  const texCoordAttributeLocation = ctx.getAttribLocation(program, "a_texCoord");
  const textureUniformLocation = ctx.getUniformLocation(program, "u_texture");

  // 绑定顶点数据
  const positionBuffer = ctx.createBuffer();
  ctx.bindBuffer(ctx.ARRAY_BUFFER, positionBuffer);
  ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]), ctx.STATIC_DRAW);

  // 绑定纹理坐标数据
  const texCoordBuffer = ctx.createBuffer();
  ctx.bindBuffer(ctx.ARRAY_BUFFER, texCoordBuffer);
  ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0]), ctx.STATIC_DRAW);

  // 绑定纹理对象
  ctx.activeTexture(ctx.TEXTURE0);
  ctx.bindTexture(ctx.TEXTURE_2D, texture);

  // 启用顶点属性
  ctx.enableVertexAttribArray(positionAttributeLocation);
  ctx.enableVertexAttribArray(texCoordAttributeLocation);

  // 设置顶点属性指针
  ctx.vertexAttribPointer(positionAttributeLocation, 2, ctx.FLOAT, false, 0, 0);
  ctx.vertexAttribPointer(texCoordAttributeLocation, 2, ctx.FLOAT, false, 0, 0);

  // 设置uniform变量
  ctx.uniform1i(textureUniformLocation, 0);

  // 绘制图像
  ctx.drawArrays(ctx.TRIANGLE_STRIP, 0, 4);
}

接下来,我们将学习如何使用WebGL旋转图像。图像旋转是一个非常简单但非常实用的操作,它可以帮助我们改变图像的方向,以便适应不同的显示区域。

function rotateImage(image, angle) {
  const canvas = document.createElement("canvas");
  canvas.width = image.width;
  canvas.height = image.height;
  const ctx = canvas.getContext("webgl");

  // 创建一个纹理对象
  const texture = ctx.createTexture();

  // 将图像数据绑定到纹理对象
  ctx.bindTexture(ctx.TEXTURE_2D, texture);
  ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);

  // 设置纹理参数
  ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
  ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR);

  // 创建一个顶点着色器
  const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;

    varying vec2 v_texCoord;

    void main() {
      v_texCoord = a_texCoord;
      gl_Position = vec4(a_position, 0.0, 1.0);
    }
  `;

  // 创建一个片段着色器
  const fragmentShaderSource = `
    precision mediump float;

    varying vec2 v_texCoord;

    uniform sampler2D u_texture;

    void main() {
      gl_FragColor = texture2D(u_texture, v_texCoord);
    }
  `;

  // 创建一个着色器程序
  const program = ctx.createProgram();
  ctx.attachShader(program, vertexShader);
  ctx.attachShader(program, fragmentShader);
  ctx.linkProgram(program);

  // 使用着色器程序
  ctx.useProgram(program);

  // 获取属性和uniform变量的位置
  const positionAttributeLocation = ctx.getAttribLocation(program, "a_position");
  const texCoordAttributeLocation = ctx.getAttribLocation(program, "a_texCoord");
  const textureUniformLocation = ctx.getUniformLocation(program, "u_texture");

  // 绑定顶点数据
  const positionBuffer = ctx.createBuffer();
  ctx.bindBuffer(ctx.ARRAY_BUFFER, positionBuffer);
  ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]), ctx.STATIC_DRAW);

  // 绑定纹理坐标数据
  const texCoordBuffer = ctx.createBuffer();
  ctx.bindBuffer(ctx.ARRAY_BUFFER, texCoordBuffer);
  ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0]), ctx.STATIC_DRAW);

  // 绑定纹理对象
  ctx.activeTexture(ctx.TEXTURE0);
  ctx.bindTexture(ctx.TEXTURE_2D, texture);

  // 启用顶点属性
  ctx.enableVertexAttribArray(positionAttributeLocation);
  ctx.enableVertexAttribArray(texCoordAttributeLocation);

  // 设置顶点属性指针
  ctx.vertexAttribPointer(positionAttributeLocation, 2, ctx.FLOAT, false, 0, 0);
  ctx.vertexAttribPointer(texCoordAttributeLocation, 2, ctx.FLOAT, false, 0, 0);

  // 设置uniform变量
  ctx.uniform1i(textureUniformLocation, 0);

  // 绘制图像
  ctx.drawArrays(ctx.TRIANGLE_STRIP, 0, 4);
}

接下来,我们将学习如何