加载图像,缩放,然后重叠 - 标记图像

时间:2016-09-03 10:45:01

标签: javascript canvas webgl

我当前的所有代码都在一个工人中。我现在需要一个简单的图形问题。我有两个已知宽度/高度的方形图像。我需要取第一个并以64x64绘制它,然后取第二个并以16x16绘制它并位于右下角。最终图像是64x64。我基本上试图让第二张图像成为第一张图像上的徽章。

所以现在这在2d画布上是小菜一碟,但是我不能(由于某些原因)与doc进行通信,我必须在画布上完成所有这些,在Firefox中我们支持自Firefox 44(去年)以来webgl画布。所以我试图在这完成。

以下是我在网上整理的内容。我的drawImage方法需要正常工作我将其设置为接受参数,但我删除了所有尊重它的代码,因为它确实破坏了它。我必须编辑vec4第二个arg进行缩放(例如1.5将使其缩放到一半大小),但我无法弄清楚如何定位。

function doit() {
	var img, tex, vloc, tloc, vertexBuff, texBuff;

	var cvs3d = document.getElementById('cvs');
	var ctx3d = cvs3d.getContext('experimental-webgl');
	var uLoc;

	// create shaders
	var vertexShaderSrc =
		'attribute vec2 aVertex;' +
		'attribute vec2 aUV;' +
		'varying vec2 vTex;' +
		'uniform vec2 pos;' +
		'void main(void) {' +
		'  gl_Position = vec4(aVertex + pos, 0.0, 1.0);' +
		'  vTex = aUV;' +
		'}';

	var fragmentShaderSrc =
		'precision highp float;' +
		'varying vec2 vTex;' +
		'uniform sampler2D sampler0;' +
		'void main(void){' +
		'  gl_FragColor = texture2D(sampler0, vTex);' +
		'}';

	var vertShaderObj = ctx3d.createShader(ctx3d.VERTEX_SHADER);
	var fragShaderObj = ctx3d.createShader(ctx3d.FRAGMENT_SHADER);
	ctx3d.shaderSource(vertShaderObj, vertexShaderSrc);
	ctx3d.shaderSource(fragShaderObj, fragmentShaderSrc);
	ctx3d.compileShader(vertShaderObj);
	ctx3d.compileShader(fragShaderObj);

	var progObj = ctx3d.createProgram();
	ctx3d.attachShader(progObj, vertShaderObj);
	ctx3d.attachShader(progObj, fragShaderObj);

	ctx3d.linkProgram(progObj);
	ctx3d.useProgram(progObj);

	ctx3d.viewport(0, 0, 64, 64);

	vertexBuff = ctx3d.createBuffer();
	ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
	ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), ctx3d.STATIC_DRAW);

	texBuff = ctx3d.createBuffer();
	ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
	ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]), ctx3d.STATIC_DRAW);

	vloc = ctx3d.getAttribLocation(progObj, 'aVertex');
	tloc = ctx3d.getAttribLocation(progObj, 'aUV');
	uLoc = ctx3d.getUniformLocation(progObj, 'pos');

	var drawImage = function(imgobj, x, y, w, h) {
		tex = ctx3d.createTexture();
		ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
		ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MIN_FILTER, ctx3d.NEAREST);
		ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MAG_FILTER, ctx3d.NEAREST);
		ctx3d.texImage2D(ctx3d.TEXTURE_2D, 0, ctx3d.RGBA, ctx3d.RGBA, ctx3d.UNSIGNED_BYTE, imgobj);

		ctx3d.enableVertexAttribArray(vloc);
		ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
		ctx3d.vertexAttribPointer(vloc, 2, ctx3d.FLOAT, false, 0, 0);

		ctx3d.enableVertexAttribArray(tloc);
		ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
		ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
		ctx3d.vertexAttribPointer(tloc, 2, ctx3d.FLOAT, false, 0, 0);

		ctx3d.drawArrays(ctx3d.TRIANGLE_FAN, 0, 4);
	};

	img = new Image();
	img.src = 'data:image/png;base64,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';

	img.onload = function() {
		console.log('drawing base image now');
		drawImage(this, 0, 0, 64, 64);

		var img2 = new Image();
		img2.src = 'data:image/png;base64,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';
		img2.onload = function() {
		 	drawImage(img2, 64-16, 64-16, 16, 16); // draw in bottom right corner
		}
	};
}

window.onload = function() {
	doit();
}
#cvs {
  border: 1px solid red;
}
<canvas id="cvs" width=64 height=64></canvas>

1 个答案:

答案 0 :(得分:2)

这个问题有一百万个答案,因为 WebGL是一个光栅化库

所以例如

  1. 您可以调整视口

  2. 您可以在uniform vec2 scale之上添加pos,因为如果没有比例尺,则无法使四边形更小/更大

  3. 您可以在绘图前更新顶点。

  4. 您可以将aVertex乘以uniform mat3 matrix,这样可以让您随意定位,缩放和旋转

  5. 您可以将aVertex乘以uniform mat4 matrix,这样可以任意定位,缩放,旋转和投影到3d

  6. ...等...

    5这是标准解决方案,因为它是最灵活的。 This article goes over using a mat3并在其之前显示您的方法以及为什么使用矩阵是一个更好的选择,然后将其扩展为mat4以执行完整的3d。

    所以不清楚你想要什么。你想学习“好方法”(#5)还是只想让你的代码尽可能少地工作。

    只是为了好玩,这里是#1

    function doit() {
      var img, tex, vloc, tloc, vertexBuff, texBuff;
    
      var cvs3d = document.getElementById('cvs');
      var ctx3d = cvs3d.getContext('experimental-webgl', { 
        preserveDrawingBuffer: true, 
      });
      var uLoc;
    
      // create shaders
      var vertexShaderSrc =
          'attribute vec2 aVertex;' +
          'attribute vec2 aUV;' +
          'varying vec2 vTex;' +
          'uniform vec2 pos;' +
          'void main(void) {' +
          '  gl_Position = vec4(aVertex + pos, 0.0, 1.0);' +
          '  vTex = aUV;' +
          '}';
    
      var fragmentShaderSrc =
          'precision highp float;' +
          'varying vec2 vTex;' +
          'uniform sampler2D sampler0;' +
          'void main(void){' +
          '  gl_FragColor = texture2D(sampler0, vTex);' +
          '}';
    
      var vertShaderObj = ctx3d.createShader(ctx3d.VERTEX_SHADER);
      var fragShaderObj = ctx3d.createShader(ctx3d.FRAGMENT_SHADER);
      ctx3d.shaderSource(vertShaderObj, vertexShaderSrc);
      ctx3d.shaderSource(fragShaderObj, fragmentShaderSrc);
      ctx3d.compileShader(vertShaderObj);
      ctx3d.compileShader(fragShaderObj);
    
      var progObj = ctx3d.createProgram();
      ctx3d.attachShader(progObj, vertShaderObj);
      ctx3d.attachShader(progObj, fragShaderObj);
    
      ctx3d.linkProgram(progObj);
      ctx3d.useProgram(progObj);
    
      vertexBuff = ctx3d.createBuffer();
      ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
      ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), ctx3d.STATIC_DRAW);
    
      texBuff = ctx3d.createBuffer();
      ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
      ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]), ctx3d.STATIC_DRAW);
    
      vloc = ctx3d.getAttribLocation(progObj, 'aVertex');
      tloc = ctx3d.getAttribLocation(progObj, 'aUV');
      uLoc = ctx3d.getUniformLocation(progObj, 'pos');
    
      var drawImage = function(imgobj, x, y, w, h) {
        tex = ctx3d.createTexture();
        ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
        ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MIN_FILTER, ctx3d.NEAREST);
        ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MAG_FILTER, ctx3d.NEAREST);
        ctx3d.texImage2D(ctx3d.TEXTURE_2D, 0, ctx3d.RGBA, ctx3d.RGBA, ctx3d.UNSIGNED_BYTE, imgobj);
    
        ctx3d.enableVertexAttribArray(vloc);
        ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
        ctx3d.vertexAttribPointer(vloc, 2, ctx3d.FLOAT, false, 0, 0);
    
        ctx3d.enableVertexAttribArray(tloc);
        ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
        ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
        ctx3d.vertexAttribPointer(tloc, 2, ctx3d.FLOAT, false, 0, 0);
    
        ctx3d.viewport(x, y, w, h);
        ctx3d.drawArrays(ctx3d.TRIANGLE_FAN, 0, 4);
      };
    
      img = new Image();
      img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAnUlEQVR42u3byQ3AIAwEQKpPH2kkrZE0wCEQR8RY2i/Y8/IDQowx9OSruDjZKvYPAAAAAAAAAGge8L6epekFAgAAAAAAAE4G2H3AGUAAAAAAAAAAgDaA0YCj+wMAAAAAAAAAWIQAAAAAAAAAAPMXmQ3uBwAAAAAAAE4G+PX7gYr+Qi4AAAAAAAAAgHRVHLD0w0SpPwAAAAAAAABAMi8E/hnSV9Q3nQAAAABJRU5ErkJggg==';
    
      img.onload = function() {
        console.log('drawing base image now');
        drawImage(this, 0, 0, 64, 64);
    
        var img2 = new Image();
        img2.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAnUlEQVR42u3byQ3AIAwEQKpPH2kkrZE0wCEQR8RY2i/Y8/IDQowx9OSruDjZKvYPAAAAAAAAAGge8L6epekFAgAAAAAAAE4G2H3AGUAAAAAAAAAAgDaA0YCj+wMAAAAAAAAAWIQAAAAAAAAAAPMXmQ3uBwAAAAAAAE4G+PX7gYr+Qi4AAAAAAAAAgHRVHLD0w0SpPwAAAAAAAABAMi8E/hnSV9Q3nQAAAABJRU5ErkJggg==';
        img2.onload = function() {
          drawImage(img2, 64-16, 64-16, 16, 16); // draw in bottom right corner
        }
      };
    }
    
    window.onload = function() {
      doit();
    }
    #cvs {
      border: 1px solid red;
    }
    <canvas id="cvs" width=64 height=64></canvas>

    请注意,默认情况下,WebGL会在您下次渲染时清除画布,因此您在每次加载图像后渲染两次这一事实意味着您只会得到第二个结果。为了防止您需要将{ preserveDrawingBuffer: true, }作为第二个参数传递给getContext

    我说实话,这感觉就像是“为我做功课”。就像你在WebGL上查一篇文章一样?我想我应该给你怀疑的好处,但这里有很多。

    您知道WebGL only cares about clip space coordinates吗?

    你知道WebGL -1在底部,而+1在顶部吗?

    除非你设置了各种纹理参数,否则你知道WebGL can't draw non-power of 2 images吗?您的示例有效,因为图像是64x64但如果它是65x64则会失败。

    因此提出了更多问题。

    纹理颠倒了。同样,由你决定如何解决它们。

    你可以

    1. 翻转纹理坐标

    2. 使用gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

    3. 加载纹理
    4. 使用负标度(假设您使用上面的解决方案#2)。这会使您的pos设置

    5. 复杂化
    6. 在着色器中调整纹理坐标

    7. 在着色器中取消gl_Position.y

    8. 使用上面的解决方案#4(mat3)或#5(mat4)创建一个投影矩阵,使翻转空间。

    9. ...等...

      矩阵解决方案再次成为最佳解决方案,您应该阅读我发布的文章。

      那就是说,攻击#2解决方案中的当前代码

      function doit() {
        var img, tex, vloc, tloc, sloc, vertexBuff, texBuff;
      
        var cvs3d = document.getElementById('cvs');
        var ctx3d = cvs3d.getContext('experimental-webgl', { 
          preserveDrawingBuffer: true, 
        });
        var uLoc;
      
        // create shaders
        var vertexShaderSrc = `
            attribute vec2 aVertex;
            attribute vec2 aUV;
            varying vec2 vTex;
            uniform vec2 pos;
            uniform vec2 scale; 
            void main(void) {
              gl_Position = vec4(aVertex * scale + pos, 0.0, 1.0);
              vTex = aUV;
            }`;
      
        var fragmentShaderSrc = `
            precision highp float;
            varying vec2 vTex;
            uniform sampler2D sampler0;
            void main(void){
              gl_FragColor = texture2D(sampler0, vTex);
            }`;
      
        var vertShaderObj = ctx3d.createShader(ctx3d.VERTEX_SHADER);
        var fragShaderObj = ctx3d.createShader(ctx3d.FRAGMENT_SHADER);
        ctx3d.shaderSource(vertShaderObj, vertexShaderSrc);
        ctx3d.shaderSource(fragShaderObj, fragmentShaderSrc);
        ctx3d.compileShader(vertShaderObj);
        ctx3d.compileShader(fragShaderObj);
      
        var progObj = ctx3d.createProgram();
        ctx3d.attachShader(progObj, vertShaderObj);
        ctx3d.attachShader(progObj, fragShaderObj);
      
        ctx3d.linkProgram(progObj);
        ctx3d.useProgram(progObj);
      
        vertexBuff = ctx3d.createBuffer();
        ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
        ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), ctx3d.STATIC_DRAW);
      
        texBuff = ctx3d.createBuffer();
        ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
        ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]), ctx3d.STATIC_DRAW);
      
        vloc = ctx3d.getAttribLocation(progObj, 'aVertex');
        tloc = ctx3d.getAttribLocation(progObj, 'aUV');
        uLoc = ctx3d.getUniformLocation(progObj, 'pos');
        sLoc = ctx3d.getUniformLocation(progObj, 'scale');
      
        var drawImage = function(imgobj, x, y, w, h) {
          tex = ctx3d.createTexture();
          ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
          ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MIN_FILTER, ctx3d.NEAREST);
          ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MAG_FILTER, ctx3d.NEAREST);
          ctx3d.texImage2D(ctx3d.TEXTURE_2D, 0, ctx3d.RGBA, ctx3d.RGBA, ctx3d.UNSIGNED_BYTE, imgobj);
      
          ctx3d.enableVertexAttribArray(vloc);
          ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
          ctx3d.vertexAttribPointer(vloc, 2, ctx3d.FLOAT, false, 0, 0);
      
          ctx3d.enableVertexAttribArray(tloc);
          ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
          ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
          ctx3d.vertexAttribPointer(tloc, 2, ctx3d.FLOAT, false, 0, 0);
          
          // convert x, y to clip space (assuming viewport matches canvas size)
          var cx = x / ctx3d.canvas.width * 2 - 1;
          var cy = y / ctx3d.canvas.height * 2 - 1;
          
          // convert w, h to clip space (quad is 2 units big)
          var cw = w / ctx3d.canvas.width;
          var ch = h / ctx3d.canvas.height;
          
          // because the quad centered over 0.0 we have to add in 
          // half the width and height (cw, ch are already half because
          // it's 2 unit quad
          cx += cw;
          cy += ch;
          
          // then we negate cy and ch because webgl -1 is at the bottom
          ctx3d.uniform2f(uLoc, cx, -cy)
          ctx3d.uniform2f(sLoc, cw, -ch);
      
          ctx3d.drawArrays(ctx3d.TRIANGLE_FAN, 0, 4);
        };
      
        img = new Image();
        img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAnUlEQVR42u3byQ3AIAwEQKpPH2kkrZE0wCEQR8RY2i/Y8/IDQowx9OSruDjZKvYPAAAAAAAAAGge8L6epekFAgAAAAAAAE4G2H3AGUAAAAAAAAAAgDaA0YCj+wMAAAAAAAAAWIQAAAAAAAAAAPMXmQ3uBwAAAAAAAE4G+PX7gYr+Qi4AAAAAAAAAgHRVHLD0w0SpPwAAAAAAAABAMi8E/hnSV9Q3nQAAAABJRU5ErkJggg==';
      
        img.onload = function() {
          console.log('drawing base image now');
          drawImage(this, 0, 0, 64, 64);
      
          var img2 = new Image();
          img2.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAnUlEQVR42u3byQ3AIAwEQKpPH2kkrZE0wCEQR8RY2i/Y8/IDQowx9OSruDjZKvYPAAAAAAAAAGge8L6epekFAgAAAAAAAE4G2H3AGUAAAAAAAAAAgDaA0YCj+wMAAAAAAAAAWIQAAAAAAAAAAPMXmQ3uBwAAAAAAAE4G+PX7gYr+Qi4AAAAAAAAAgHRVHLD0w0SpPwAAAAAAAABAMi8E/hnSV9Q3nQAAAABJRU5ErkJggg==';
          img2.onload = function() {
            drawImage(img2, 64-16, 64-16, 16, 16); // draw in bottom right corner
          }
        };
      }
      
      doit();
      #cvs {
        border: 1px solid red;
      }
      <canvas id="cvs" width=64 height=64></canvas>

      我个人建议您read up on WebGL包括how to implement drawImagehow to create a matrix stack

      让我补充说pos&amp; scale解决方案本身。 4x4矩阵需要多达64次乘法来计算并以标准方式使用它们,drawImage克隆必须至少进行2次矩阵乘法,这样才能得到128个数*乘法。而pos&amp; scale解决方案仅使用6次乘法。换句话说,它在技术上更快,但不太可能成为瓶颈。

      pos&amp; scale解决方案是它仅使用2个vec2制服(4个浮点数),而mat4矩阵解决方案使用mat4(16个浮点数)。由于你可以使用的制服数量最多,可能会出现在pos&amp; scale解决方案更好。这就是WebGL的乐趣,由您来决定使用哪种技术

      PS:pngcrush是你的朋友