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 givenIn WebGL you'd have to adjust the texcoord using the
src
values and the vertex coordinates of where to draw using thedst
values.Now update your texcoords. In the example you linked to
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
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
Unless you intended to stretch the image your asking for a clipped image (say
image.width - 50
) to be drawnimage.width
pixels, so if your image is 75 pixels your going to get 25 pixels of source stretched to 75 pixels of destinationnot 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.
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.