内容简介:在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到这里图片就已经画出来了。
假如我们想调换一下红色和蓝色那么我们只需要这样做:
... gl_FragColor = texture2D(u_image, v_texCoord).bgra; ... 复制代码
或者我们可以将每个像素的值设置为左右像素的平均值,这样就可以达到图片模糊的效果了。
<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之图像处理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Opencv图像处理系列(六)—— 图像梯度
- Opencv图像处理系列(九)—— 图像轮廓
- Python 图像处理 OpenCV (15):图像轮廓
- Opencv图像处理系列(三)——图像二值化
- Opencv图像处理系列(八)—— 图像金字塔
- Facebook 开源图像处理库 Spectrum,优化移动端图像生成
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。