内容简介:在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,优化移动端图像生成
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
像计算机科学家一样思考Python
(美)Allen B.Downey / 赵普明 / 人民邮电出版社 / 2013-8 / 49
《像计算机科学家一样思考python》按照培养读者像计算机科学家一样的思维方式的思路来教授python语言编程。全书贯穿的主体是如何思考、设计、开发的方法,而具体的编程语言,只是提供一个具体场景方便介绍的媒介。《像计算机科学家一样思考python》并不是一本介绍语言的书,而是一本介绍编程思想的书。和其他编程设计语言书籍不同,它不拘泥于语言细节,而是尝试从初学者的角度出发,用生动的示例和丰富的练习来......一起来看看 《像计算机科学家一样思考Python》 这本书的介绍吧!