在Webgl中剪切图像 [英] Clipping images in Webgl

查看:171
本文介绍了在Webgl中剪切图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

2-D画布提供了一个叫做绘图的api:
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
其中 sx 图片剪辑开始的位置。





纹理坐标从0到1,所以如果你想转换 drawImage 那么给定

  drawImage(image,srcX,srcY,srcWidth,srcHeight,
dstX,dstY,dstWidth,dstHeight);

在WebGL中你必须使用 src调整texcoord 值和使用 dst 值绘制的位置的顶点坐标。

  u0 = srcX / image.width; 
v0 = srcY / image.height;

u1 =(srcX + srcWidth)/ image.width;
v1 =(srcY + srcHeight)/ image.height;

现在更新你的texcoords。在您链接的示例中

  gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([
u0,v0,
u1,v0,
u0,v1,
u0,v1,
u1,v0,
u1,v1]),gl.STATIC_DRAW);

您还可以为着色器添加一些数学运算。使用与从此处开始的文章相同的技术,您可以使用数学调整着色器中的texcoordinates就像那些文章正在调整位置一样。



例如,你可以保持UV坐标从0到1,就像它们最初一样,但更新着色器,因此您可以传入一个偏移量和一个比例,将它们相乘以得到它们所需的位置。或者,如果继续这些文章,您可以使用矩阵更灵活地操作它们。



同样对于目标大小,您可以使用各种顶点而不是更新顶点着色器中的数学可以移动一个简单的单位正方形,缩放和大小为您想要的任何大小。



至于您发布此行的代码

  var u1 =(50 + image.width)/ image.width; 

基本上是说要读取纹理中距离右边50像素的像素。这就是你变黑的原因。



第二个问题是这一行

  setRectangle(gl,x ,y,image.width,image.height); 

除非您打算拉伸图像,否则您需要剪切图像(例如 image.width - 50 )要绘制 image.width 像素,所以如果你的图像是75像素你将得到25像素的源拉伸到目的地的75个像素



不确定你想要的是什么。这是固定版本



注意我使用画布制作图像,因为dataURL使编辑非常痛苦。



  var gl,program,positionLocation,originalImageTexture,canvas; var x = 10; var y = 20; function setupWebGL(){var canvas = document.getElementById(canvas); gl = canvas.getContext(webgl); if(!gl){return; } // setup GLSL program var program = webglUtils.createProgramFromScripts(gl,[2d-vertex-shader,2d-fragment-shader]); gl.useProgram(程序); //查找顶点数据需要去的地方。 positionLocation = gl.getAttribLocation(program,a_position); texCoordLocation = gl.getAttribLocation(program,a_texCoord); var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,texture); // lookup uniforms var resolutionLocation = gl.getUniformLocation(program,u_resolution); textureSizeLocation = gl.getUniformLocation(program,u_textureSize); colorLocation = gl.getUniformLocation(program,u_color); //设置分辨率gl.uniform2f(resolutionLocation,canvas.width,canvas.height); //设置参数,以便我们可以渲染任何大小的图像。 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.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); gl.disable(gl.DEPTH_TEST);} function draw(){//使用canvas来模拟图像var image = document.createElement(canvas); document.body.appendChild(图像); //所以我们可以看到源图像image.width = 200; image.height = 150; var ctx = image.getContext(2d); ctx.fillRect(0,0,image.width,image.height); for(var py = 0; py< image.height; py + = 25){for(var px = 0; px< image.width; px + = 25){ctx.fillStyle =rgb(+( py / image.height * 255 | 0)+,+(px / image.width * 255 | 0)+,+ 255 +); ctx.beginPath(); ctx.arc(px + 12,py + 12,10,0,Math.PI * 2); ctx.fill(); setupWebGL(); var srcX = 50; var srcY = 0; var srcWidth = image.width  -  50; var srcHeight = image.height; var dstX = x; var dstY = y; var dstWidth = srcWidth; var dstHeight = srcHeight; var u0 = srcX / image.width; var v0 = srcY / image.height; var u1 =(srcX + srcWidth)/ image.width; var v1 =(srcY + srcHeight)/ image.height; //为矩形提供纹理坐标。 var texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([u0,v0,u1,v0,u0,v1,u0,v1,u1,v0,u1,v1]),gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordLocation); gl.vertexAttribPointer(texCoordLocation,2,gl.FLOAT,false,0,0); gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image); //设置图像的大小gl.uniform2f(textureSizeLocation,image.width,image.height); //为矩形角的位置创建缓冲区。 var positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0,0); setRectangle(gl,dstX,dstY,dstWidth,dstHeight); gl.drawArrays(gl.TRIANGLES,0,6);函数setRectangle(gl,x,y,width,height){var x1 = x; var x2 = x +宽度; 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);} draw();  

  canvas {border:1px solid red; }  

 < canvas width =400height = 300id =canvas>< / canvas>< script src =// webglfundamentals.org/webgl/resources/webgl-utils.js\"></script><!-- vertex shader - >< script id =2d-vertex-shadertype =x-shader / x-vertex> attribute vec2 a_position; attribute vec2 a_texCoord; uniform vec2 u_resolution; varying vec2 v_texCoord; void main(){ //将矩形从像素转换为0.0到1.0 vec2 zeroToOne = a_position / u_resolution; //从0-> 1转换为0-> 2 vec2 zeroToTwo = zeroToOne * 2.0; //从0-> 2转换为-1-> +1(剪辑空间)vec2 clipSpace = zeroToTwo  -  1.0; gl_Position = vec4(clipSpace * vec2(1,-1),0,1); //将texCoord传递给片段着色器// GPU将在点之间插入此值。 v_texCoord = a_texCoord;}< / script><! - 片段着色器 - >< script id =2d-fragment-shadertype =x-shader / x-fragment> precision mediump float; //我们的textureuniform sampler2D u_image; //从顶点着色器传入的texCoords.varying vec2 v_texCoord; void main(){gl_FragColor = texture2D(u_image,v_texCoord);}< / script>  



我还想再次强调这通常不是我做的方式。就像我之前说过的这个特殊情况一样,我会使用单位正方形位置和单位正方形用于texcoords。然后我会使用矩阵来翻译和偏移两者。这将让我做2D画布API可以做的所有事情。缩放图像,剪切图像,旋转图像,翻转图像。它甚至可以让我做画布API无法做的事情,就像旋转矩形内的纹理一样。



  var gl,program,positionLocation,originalImageTexture,canvas; function setupWebGL(){var canvas = document.getElementById(canvas); gl = canvas.getContext(webgl); if(!gl){return; } // setup GLSL program var program = webglUtils.createProgramFromScripts(gl,[2d-vertex-shader,2d-fragment-shader]); gl.useProgram(程序); //查找顶点数据需要去的地方。 positionLocation = gl.getAttribLocation(program,a_position); texCoordLocation = gl.getAttribLocation(program,a_texCoord); var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,texture); // lookup uniforms matrixLocation = gl.getUniformLocation(program,u_ma​​trix); texMatrixLocation = gl.getUniformLocation(program,u_texMatrix); //设置参数,以便我们可以渲染任何大小的图像。 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); //为矩形提供纹理坐标。 var texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordLocation); gl.vertexAttribPointer(texCoordLocation,2,gl.FLOAT,false,0,0); gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image); //为矩形角的位置创建缓冲区。 var positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer); gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0,0); gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); gl.disable(gl.DEPTH_TEST);} var originX,originY,srcX,srcY,srcWidth,srcHeight,dstX,dstY,dstWidth,dstHeight,angleInRadians,texAngle; function draw(time){time * = 0.001; //以秒为单位的时间切换(((time / 4)| 0)%5){case 0:originX = 0; originY = 0; srcX = 50; srcY = 0; srcWidth = image.width  -  50; srcHeight = image.height; dstX = 10; dstY = 20; dstWidth = srcWidth; dstHeight = srcHeight; angleInRadians = 0; texAngle = 0;打破;情况1://剪辑更多srcX = 50 + Math.sin(时间)* 20; srcY = 50 + Math.sin(时间* 1.3)* 20; srcWidth = image.width  - (50 + Math.sin(time)* 20) -  srcX; srcHeight = image.height  - (50 + Math.sin(time * 1.3)* 20) -  srcY; dstWidth = srcWidth; dstHeight = srcHeight;打破;情况2://左上角旋转图像angleInRadians = time;打破;情况3://围绕中心角旋转图像InRadians = time; dstX = 100; dstY = 100; originX = -srcWidth / 2; originY = -srcHeight / 2;打破;情况4://围绕中心旋转纹理texAngle = -time;打破; } var x = dstX; var y = dstY; //我们有1个单位的正方形。如果将按destWidth和destHeight进行缩放,我们将把它拉伸到我们想要的大小var xScale = dstWidth; var yScale = dstHeight; //我们还有1个单位的texcoords广场。我们可以将其缩放为剪辑var texXOff = srcX / image.width; var texYOff = srcY / image.height; var texXScale = srcWidth / image.width; var texYScale = srcHeight / image.height; //计算矩阵var projectionMatrix = make2DProjection(gl.canvas.clientWidth,gl.canvas.clientHeight); var translationMatrix = makeTranslation(x,y); var rotationMatrix = makeRotation(angleInRadians); var originMatrix = makeTranslation(originX,originY); var scaleMatrix = makeScale(xScale,yScale); //乘以矩阵。 var matrix = matrixMultiply(scaleMatrix,originMatrix); matrix = matrixMultiply(matrix,rotationMatrix); matrix = matrixMultiply(matrix,translationMatrix); matrix = matrixMultiply(matrix,projectionMatrix); //计算纹理矩阵texPreRot = makeTranslation(-0.5,-0.5); var texRot = makeRotation(texAngle); var texPostRot = makeTranslation(0.5,0.5); var texOffMat = makeTranslation(texXOff,texYOff); var texScaleMat = makeScale(texXScale,texYScale); var texMatrix = matrixMultiply(texScaleMat,texOffMat); texMatrix = matrixMultiply(texMatrix,texPreRot); texMatrix = matrixMultiply(texMatrix,texRot); texMatrix = matrixMultiply(texMatrix,texPostRot); //设置矩阵gl.uniformMatrix3fv(matrixLocation,false,matrix); gl.uniformMatrix3fv(texMatrixLocation,false,texMatrix); gl.drawArrays(gl.TRIANGLES,0,6); requestAnimationFrame(draw);} //使用canvas来模拟图像image = document.createElement(canvas); document.body.appendChild(图像); //所以我们可以看到源图像image.width = 200; image.height = 150; var ctx = image.getContext(2d); ctx.fillRect(0,0,image.width,image.height); for(var py = 0; py< image.height; py + = 25){for(var px = 0; px< image.width; px + = 25){ctx.fillStyle =rgb(+( py / image.height * 255 | 0)+,+(px / image.width * 255 | 0)+,+ 255 +); ctx.beginPath(); ctx.arc(px + 12,py + 12,10,0,Math.PI * 2); ctx.fill(); setupWebGL(); requestAnimationFrame(draw);  

  canvas {border:1px solid red; }  

 < canvas width =400height = 300id =canvas>< / canvas>< script src =// webglfundamentals.org/webgl/resources/webgl-utils.js\"></script><script src =/ /webglfundamentals.org/webgl/resources/webgl-2d-math.js\"></script><!-- vertex shader  - >< script id =2d-vertex-shadertype = x-shader / x-vertex>属性vec2 a_position;属性vec2 a_texCoord; uniform mat3 u_matrix; //操纵positionuniform mat3 u_texMatrix; //操纵texcoordsvarying vec2 v_texCoord; void main(){gl_Position = vec4((u_matrix * vec3(a_position,1))。xy,0,1); //将texCoord传递给片段着色器// GPU将在点之间插入此值。 v_texCoord =(u_texMatrix * vec3(a_texCoord,1))。xy;}< / script><! - 片段着色器 - >< script id =2d-fragment-shadertype =x-shader / x-fragment> precision mediump float; //我们的textureuniform sampler2D u_image; //从顶点着色器传入的texCoords.varying vec2 v_texCoord; void main(){gl_FragColor = texture2D(u_image,v_texCoord);}< / script>  


The 2-D canvas provides an api called draw image : context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); where sx is the position from where the image clipping starts .

http://www.w3schools.com/tags/canvas_drawimage.asp,

I am trying to use webgl to render a 2D image using texImage2D. i wanted to check if there is a way to implement clipping with webgl.

I am using the following tutorial to render 2d images with webgl. http://webglfundamentals.org/webgl/lessons/webgl-image-processing.html

Original Image:

Clipping with drawImage(2D):

Clipping with webgl:

var gl,program,positionLocation,originalImageTexture,canvas;
var x = 10;
var y = 20;
function setupWebGL(){

	var canvas = document.getElementById("canvas");
	gl = canvas.getContext("webgl");
  	if (!gl) {
    	return;
  	}
  	// setup GLSL program
  	var program = createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
  	gl.useProgram(program);
  	// look up where the vertex data needs to go.
  	positionLocation = gl.getAttribLocation(program, "a_position");
 	texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
  	var texture = gl.createTexture();
  	gl.bindTexture(gl.TEXTURE_2D, texture);
  
  	// lookup uniforms
  	var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
  	textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
  	colorLocation = gl.getUniformLocation(program, "u_color");
   	// set the resolution
  	gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
  
  	// Set the parameters so we can render any size image.
  	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.enable(gl.BLEND);
  	gl.blendEquation( gl.FUNC_ADD );
  	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  	gl.disable(gl.DEPTH_TEST);
}

    function draw() {
    // use canvas to simulate an image
  	var image = document.createElement("canvas");
    document.body.appendChild(image); // so we can see the source image
    image.width  = 200;
    image.height = 150;
    var ctx   = image.getContext("2d");
    ctx.fillRect(0, 0, image.width, image.height);
    for (var py = 0; py < image.height; py += 25) {
      for (var px = 0; px < image.width; px += 25) {
        ctx.fillStyle = "rgb(" + (py / image.height * 255 | 0) + "," + 
                                 (px / image.width  * 255 | 0) + "," + 
                                  255 + ")";
        ctx.beginPath();
        ctx.arc(px + 12, py + 12, 10, 0, Math.PI * 2);
        ctx.fill();
      }
    }
      
  	setupWebGL();
      
    var srcX = 12;
    var srcY = 35;
    var srcWidth = 75;
    var srcHeight = 50;
      
    var dstX = 100;
    var dstY = 110;
    var dstWidth  = srcWidth;
    var dstHeight = srcHeight;
  		
    var u0 = 50 / image.width;
    var v0 = 0 / image.height;
    var u1 = (50 + image.width) / image.width;
    var v1 = (0 + image.height) / image.height;
      
  	// provide texture coordinates for the rectangle.
  	var texCoordBuffer = gl.createBuffer();
  	gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
  	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([u0, v0, u1,v0, u0,v1, u0,v1, u1,v0, u1,v1]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

  
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,gl.RGBA, gl.UNSIGNED_BYTE, image);
  
    // set the size of the image
    gl.uniform2f(textureSizeLocation, image.width, image.height);
    // Create a buffer for the position of the rectangle corners.
    var positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    setRectangle( gl, x, y, image.width, image.height);
    
 
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  
}

    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);
}

draw();

canvas { border: 1px solid black; }

<canvas width="400" height="300" id="canvas"></canvas>
<script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<!-- vertex shader -->
<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() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

   // pass the texCoord to the fragment shader
   // The GPU will interpolate this value between points.
   v_texCoord = a_texCoord;
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

// our texture
uniform sampler2D u_image;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>

解决方案

You need to adjust the texture coordinates to select the part of the texture you're interested in.

Texture coordinates go from 0 to 1 so if you wanted to convert from drawImage then given

drawImage(image, srcX, srcY, srcWidth, srcHeight, 
          dstX, dstY, dstWidth, dstHeight);

In WebGL you'd have to adjust the texcoord using the src values and the vertex coordinates of where to draw using the dst values.

u0 = srcX / image.width;
v0 = srcY / image.height;

u1 = (srcX + srcWidth) / image.width;
v1 = (srcY + srcHeight) / image.height;

Now update your texcoords. In the example you linked to

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  u0,  v0,
  u1,  v0,
  u0,  v1,
  u0,  v1,
  u1,  v0,
  u1,  v1]), gl.STATIC_DRAW);

you could also add some math to the shader. Using the same techniques as the articles starting here you can use math to adjust the texcoordinates in the shader just like those articles are adjusting the positions.

So for example you could leave the UV coordinates going from 0 to 1 like they originally were but update the shader so you can pass in an offset and a scale that multiply them to get them where you want. Or, if you continue with those articles you can use a matrix to manipulate them with more flexibility.

Similarly for the destination size, rather than update the vertices you can use various math in the shader to move a simple unit square around and scale and size to to whatever size you desire.

As for the code you posted this line

var u1 = (50 + image.width) / image.width;

Is basically saying you want to read pixels from the texture 50 pixels past the right edge. That's why you're getting black.

The second problem is this line

setRectangle( gl, x, y, image.width, image.height);

Unless you intended to stretch the image your asking for a clipped image (say image.width - 50) to be drawn image.width pixels, so if your image is 75 pixels your going to get 25 pixels of source stretched to 75 pixels of destination

not sure if that what you wanted. Here's the fixed version

Note I used the canvas the make an image because the dataURL made it really painful to edit.

var gl,program,positionLocation,originalImageTexture,canvas;
var x = 10;
var y = 20;
function setupWebGL(){

	var canvas = document.getElementById("canvas");
	gl = canvas.getContext("webgl");
  	if (!gl) {
    	return;
  	}
  	// setup GLSL program
  	var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
  	gl.useProgram(program);
  	// look up where the vertex data needs to go.
  	positionLocation = gl.getAttribLocation(program, "a_position");
 	texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
  	var texture = gl.createTexture();
  	gl.bindTexture(gl.TEXTURE_2D, texture);
  
  	// lookup uniforms
  	var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
  	textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
  	colorLocation = gl.getUniformLocation(program, "u_color");
   	// set the resolution
  	gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
  
  	// Set the parameters so we can render any size image.
  	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.enable(gl.BLEND);
  	gl.blendEquation( gl.FUNC_ADD );
  	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  	gl.disable(gl.DEPTH_TEST);
}

    function draw() {
    // use canvas to simulate an image
  	var image = document.createElement("canvas");
    document.body.appendChild(image); // so we can see the source image
    image.width  = 200;
    image.height = 150;
    var ctx   = image.getContext("2d");
    ctx.fillRect(0, 0, image.width, image.height);
    for (var py = 0; py < image.height; py += 25) {
      for (var px = 0; px < image.width; px += 25) {
        ctx.fillStyle = "rgb(" + (py / image.height * 255 | 0) + "," + 
                                 (px / image.width  * 255 | 0) + "," + 
                                  255 + ")";
        ctx.beginPath();
        ctx.arc(px + 12, py + 12, 10, 0, Math.PI * 2);
        ctx.fill();
      }
    }
      
  	setupWebGL();
      
    var srcX = 50;
    var srcY = 0;
    var srcWidth = image.width - 50;
    var srcHeight = image.height;
      
    var dstX = x;
    var dstY = y;
    var dstWidth  = srcWidth;
    var dstHeight = srcHeight;
  		
	var u0 = srcX / image.width;
 	var v0 = srcY / image.height;
	var u1 = (srcX + srcWidth)  / image.width;
 	var v1 = (srcY + srcHeight) / image.height;
	
  	// provide texture coordinates for the rectangle.
  	var texCoordBuffer = gl.createBuffer();
  	gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
  	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([u0, v0, u1,v0, u0,v1, u0,v1, u1,v0, u1,v1]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

  
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,gl.RGBA, gl.UNSIGNED_BYTE, image);
  
    // set the size of the image
    gl.uniform2f(textureSizeLocation, image.width, image.height);
    // Create a buffer for the position of the rectangle corners.
    var positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    setRectangle( gl, dstX, dstY, dstWidth, dstHeight);
   
 
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  
}

    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);
}

draw();

canvas { border: 1px solid red; }

<canvas width="400" height="300" id="canvas"></canvas>
<script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<!-- vertex shader -->
<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() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

   // pass the texCoord to the fragment shader
   // The GPU will interpolate this value between points.
   v_texCoord = a_texCoord;
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

// our texture
uniform sampler2D u_image;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>

I also wanted to emphasize again this is not usually the way I'd do it. Like I said before for this particular case I'd use a unit square position and a unit square for texcoords. I'd then use to matrixes to translate and offset both. This would let me do all the things the 2D canvas API can do. Scale the image, clip the image, rotate the image, flip the image. It would even let me do things the canvas API can't do like rotate the texture inside the rectangle.

var gl,program,positionLocation,originalImageTexture,canvas;
function setupWebGL(){

	var canvas = document.getElementById("canvas");
	gl = canvas.getContext("webgl");
  	if (!gl) {
    	return;
  	}
  	// setup GLSL program
  	var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
  	gl.useProgram(program);
  	// look up where the vertex data needs to go.
  	positionLocation = gl.getAttribLocation(program, "a_position");
 	texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
  	var texture = gl.createTexture();
  	gl.bindTexture(gl.TEXTURE_2D, texture);
  
  	// lookup uniforms
  	matrixLocation = gl.getUniformLocation(program, "u_matrix");
  	texMatrixLocation = gl.getUniformLocation(program, "u_texMatrix");
  
  	// Set the parameters so we can render any size image.
  	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);

  	// provide texture coordinates for the rectangle.
  	var texCoordBuffer = gl.createBuffer();
  	gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
  	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,gl.RGBA, gl.UNSIGNED_BYTE, image);
  
    // Create a buffer for the position of the rectangle corners.
    var positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0 , 1, 1]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

  	gl.enable(gl.BLEND);
  	gl.blendEquation( gl.FUNC_ADD );
  	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  	gl.disable(gl.DEPTH_TEST);
}

var originX, originY, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, angleInRadians,texAngle;

function draw(time) {
    time *= 0.001; // make time in seconds
  
  
    switch (((time / 4) | 0) % 5) {
      case 0:
        originX = 0;
        originY = 0;
        srcX = 50;
        srcY = 0;
        srcWidth = image.width - 50;
        srcHeight = image.height;
      
        dstX = 10;
        dstY = 20;
        dstWidth  = srcWidth;
        dstHeight = srcHeight;
            
        angleInRadians = 0;
        texAngle = 0;
        break;
      case 1:
         // clip it more
         srcX = 50 + Math.sin(time      ) * 20;
         srcY = 50 + Math.sin(time * 1.3) * 20;
         srcWidth  = image.width  - (50 + Math.sin(time      ) * 20) - srcX;
         srcHeight = image.height - (50 + Math.sin(time * 1.3) * 20) - srcY;
         dstWidth  = srcWidth;
         dstHeight = srcHeight;
         break;
      case 2:
        // spin image around top left
        angleInRadians = time;
        break;
      case 3:
        // spin image around center
        angleInRadians = time;
        dstX = 100;
        dstY = 100;
        originX = -srcWidth / 2;
        originY = -srcHeight / 2;
        break;
      case 4:
        // spin texture around center
        texAngle = -time;
        break;
    }
  
      
    var x = dstX;
    var y = dstY;
    // We have a 1 unit square. If will scale by destWidth and destHeight we'll stretch
    // it to the size we want
    var xScale = dstWidth;
    var yScale = dstHeight;
    
    // We also have a 1 unit square for the texcoords. We can scale that to clip
    var texXOff   = srcX      / image.width;
    var texYOff   = srcY      / image.height;
    var texXScale = srcWidth  / image.width;
    var texYScale = srcHeight / image.height;

    // Compute the matrices
    var projectionMatrix = make2DProjection(gl.canvas.clientWidth, gl.canvas.clientHeight);
    var translationMatrix = makeTranslation(x, y);
    var rotationMatrix = makeRotation(angleInRadians);
    var originMatrix = makeTranslation(originX, originY);
    var scaleMatrix = makeScale(xScale, yScale);
  
    // Multiply the matrices.
    var matrix = matrixMultiply(scaleMatrix, originMatrix);
    matrix = matrixMultiply(matrix, rotationMatrix);
    matrix = matrixMultiply(matrix, translationMatrix);
    matrix = matrixMultiply(matrix, projectionMatrix);
      
    // compute matrixes for texture
    var texPreRot = makeTranslation(-0.5, -0.5);
    var texRot    = makeRotation(texAngle);
    var texPostRot= makeTranslation(0.5, 0.5);
    var texOffMat = makeTranslation(texXOff, texYOff);
    var texScaleMat = makeScale(texXScale, texYScale);
  
    var texMatrix = matrixMultiply(texScaleMat, texOffMat);
    texMatrix = matrixMultiply(texMatrix, texPreRot);
    texMatrix = matrixMultiply(texMatrix, texRot);
    texMatrix = matrixMultiply(texMatrix, texPostRot);
    

    // Set the matrices
    gl.uniformMatrix3fv(matrixLocation, false, matrix);      
    gl.uniformMatrix3fv(texMatrixLocation, false, texMatrix);
    gl.drawArrays(gl.TRIANGLES, 0, 6);
 
    requestAnimationFrame(draw);
}

    // use canvas to simulate an image
  	image = document.createElement("canvas");
    document.body.appendChild(image); // so we can see the source image
    image.width  = 200;
    image.height = 150;
    var ctx   = image.getContext("2d");
    ctx.fillRect(0, 0, image.width, image.height);
    for (var py = 0; py < image.height; py += 25) {
      for (var px = 0; px < image.width; px += 25) {
        ctx.fillStyle = "rgb(" + (py / image.height * 255 | 0) + "," + 
                                 (px / image.width  * 255 | 0) + "," + 
                                  255 + ")";
        ctx.beginPath();
        ctx.arc(px + 12, py + 12, 10, 0, Math.PI * 2);
        ctx.fill();
      }
    }
      
setupWebGL();
requestAnimationFrame(draw);

canvas { border: 1px solid red; }

<canvas width="400" height="300" id="canvas"></canvas>
<script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="//webglfundamentals.org/webgl/resources/webgl-2d-math.js"></script>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;

uniform mat3 u_matrix;    // manipulates position
uniform mat3 u_texMatrix; // manipulates texcoords

varying vec2 v_texCoord;

void main() {
     gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);

   // pass the texCoord to the fragment shader
   // The GPU will interpolate this value between points.
   v_texCoord = (u_texMatrix * vec3(a_texCoord, 1)).xy;
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

// our texture
uniform sampler2D u_image;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>

这篇关于在Webgl中剪切图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆