WebGL之图像处理

栏目: 编程工具 · 发布时间: 5年前

内容简介:在webgl中处理图像其实也比较简单,我们先来画一个矩形,然后为这个矩形加上纹理(本例中就是一张图片)。渲染纹理需要使用纹理坐标而不是像素坐标,纹理坐标和顶点着色器需要的裁剪空间坐标类似,坐标范围始终是0.0到1.0。如果还不知道顶点找色器是什么可以看一下之前的文章——WebGL之入门。这里我们用到了一种叫做用片段找色器寻找纹理上对应的颜色值。

在webgl中处理图像其实也比较简单,我们先来画一个矩形,然后为这个矩形加上纹理(本例中就是一张图片)。渲染纹理需要使用纹理坐标而不是像素坐标,纹理坐标和顶点着色器需要的裁剪空间坐标类似,坐标范围始终是0.0到1.0。如果还不知道顶点找色器是什么可以看一下之前的文章——WebGL之入门。

着色器

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;

void main() {
   // 将像素坐标转化为裁剪空间坐标
   vec2 zeroToOne = a_position / u_resolution;
   vec2 zeroToTwo = zeroToOne * 2.0;
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
   // 将纹理坐标传递给片段着色器
   // 在绘制像素点调用片段着色器的时候webgl会根据顶点之间的插值设置颜色
   v_texCoord = a_texCoord;
}
</script>
复制代码

这里我们用到了一种叫做 varying 的变量类型,这种变量叫做"可变量",他的值在程序执行的过程中是可变的。webgl会用顶点着色器中的值进行插值,然后传递给对应像素执行片段找色器。

<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
// 纹理
uniform sampler2D u_image;
 
// 从顶点着色器传入的纹理坐标
varying vec2 v_texCoord;
 
void main() {
   // 在纹理上寻找对应颜色值
   gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>
复制代码

用片段找色器寻找纹理上对应的颜色值。

创建纹理

首先我们需要加载一个图像

function main() {
  var image = new Image();
  image.src = "http://image/url";  // 必须在同一域名下
  image.onload = function() {
    render(image);
  }
}
复制代码

定义渲染函数:

render(image){
  var canvas = document.getElementById("canvas");
  var gl = canvas.getContext("webgl");
  if (!gl) {
    return;
  }
  // 创建着色器程序,注意因为创建找色器程序的代码基本为模版代码所以我们这里使用webglUtils来创建,webglUtils的代码可以在这里下载https://webglfundamentals.org/webgl/resources/webgl-utils.js
  var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
  
  // 为矩形提供缓冲区数据
  var positionLocation = gl.getAttribLocation(program, "a_position");
  var positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  setRectangle(gl, 0, 0, image.width, image.height);
  
  // 为矩形提供纹理坐标
  var texcoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
      0.0,  0.0,
      1.0,  0.0,
      0.0,  1.0,
      0.0,  1.0,
      1.0,  0.0,
      1.0,  1.0,
  ]), gl.STATIC_DRAW);
  
  // 创建纹理坐标
  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // 设置纹理纹理参数,这样我们就可以随便设置图片大小了,参数具体含义可以查一下MDN文档
  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.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

  // 为纹理设置图片
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

  // 设置u_resolution变量
  var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
  gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
  
  // 下面这些操作在webgl之入门都介绍过
  webglUtils.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.useProgram(program);
  
  // 告诉position属性如何从缓冲区获取数据
  gl.enableVertexAttribArray(positionLocation);
  var size = 2;         
  var type = gl.FLOAT;  
  var normalize = false; 
  var stride = 0;       
  var offset = 0;        
  gl.vertexAttribPointer(
      positionLocation, size, type, normalize, stride, offset);
      
  // 告诉texcoord如何从缓冲区获取数据
  gl.enableVertexAttribArray(texcoordLocation);
  var size = 2;         
  var type = gl.FLOAT;  
  var normalize = false;
  var stride = 0;       
  var offset = 0;       
  gl.vertexAttribPointer(
      texcoordLocation, size, type, normalize, stride, offset);

  // 开始画矩形
  var primitiveType = gl.TRIANGLES;
  var offset = 0;
  var count = 6;
  gl.drawArrays(primitiveType, offset, count);
}

function setRectangle(gl, x, y, width, height) {
  var x1 = x;
  var x2 = x + width;
  var y1 = y;
  var y2 = y + height;
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
     x1, y1,
     x2, y1,
     x1, y2,
     x1, y2,
     x2, y1,
     x2, y2,
  ]), gl.STATIC_DRAW);
}
main();
复制代码

ok到这里图片就已经画出来了。

WebGL之图像处理

假如我们想调换一下红色和蓝色那么我们只需要这样做:

...
gl_FragColor = texture2D(u_image, v_texCoord).bgra;
...
复制代码
WebGL之图像处理

或者我们可以将每个像素的值设置为左右像素的平均值,这样就可以达到图片模糊的效果了。

<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
 
// 纹理
uniform sampler2D u_image;
uniform vec2 u_textureSize;
 
// 从顶点着色器传入的像素坐标
varying vec2 v_texCoord;
 
void main() {
   // 计算1像素对应的纹理坐标
   vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;
 
   // 对左中右像素求均值
   gl_FragColor = (
       texture2D(u_image, v_texCoord) +
       texture2D(u_image, v_texCoord + vec2(onePixel.x, 0.0)) +
       texture2D(u_image, v_texCoord + vec2(-onePixel.x, 0.0))) / 3.0;
}
</script>
复制代码

我们需要在JavaScript中传入图片的大小。

...
 
var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
 
...
 
// 设置图像的大小
gl.uniform2f(textureSizeLocation, image.width, image.height);
 
...
复制代码

总之现在你可以操控图片的每个像素了。


以上所述就是小编给大家介绍的《WebGL之图像处理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

像计算机科学家一样思考Python

像计算机科学家一样思考Python

(美)Allen B.Downey / 赵普明 / 人民邮电出版社 / 2013-8 / 49

《像计算机科学家一样思考python》按照培养读者像计算机科学家一样的思维方式的思路来教授python语言编程。全书贯穿的主体是如何思考、设计、开发的方法,而具体的编程语言,只是提供一个具体场景方便介绍的媒介。《像计算机科学家一样思考python》并不是一本介绍语言的书,而是一本介绍编程思想的书。和其他编程设计语言书籍不同,它不拘泥于语言细节,而是尝试从初学者的角度出发,用生动的示例和丰富的练习来......一起来看看 《像计算机科学家一样思考Python》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具