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

标签 javascript canvas webgl

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

所以现在这是 2d Canvas 中的小菜一碟,但是我不能(由于某些原因)与文档进行通信,我必须在 Canvas 中完成这一切,在 Firefox 中,我们从 Firefox 44(去年)开始支持 webgl Canvas 。所以我试图在其中完成这件事。

这是我从网络上收集的内容。我的 drawImage方法是需要正常工作的我将它设置为接受参数,但我删除了所有尊重它的代码,因为它真的破坏了东西。我必须编辑 vec4用于缩放的第二个参数(例如 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,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAM9JREFUeNrs2+EJgzAQBtBccTIXcQ8HcA8XcbV0gjZiONKS9/1VAnl43KExaq2lJxHRt0B/4tvF1v5eZfIAAAAAAICZE60+2erz53EN3cC2r11zghIAAAAAAAAzzwGllJ/u89lzghIAAAAAAAATZ8nus71zRPb6SgAAAAAAAJgDnif7fUH2+koAAAAAAACYA/Jy4/u9OUAJAAAAAACAMYkb9/z1OcHzuJwTBAAAAAAAAB7OAa0+v+3r0P8GW33eEwAAAAAAAAB8zBsAAP//AwB6eysS2pA5KAAAAABJRU5ErkJggg==';

	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>

最佳答案

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

所以例如

  • 您可以调整视口(viewport)
  • 您可以添加 uniform vec2 scale在您的 pos 上因为没有刻度,您无法使四边形更小/更大
  • 您可以在绘制之前更新顶点。
  • 你可以乘 aVertex通过 uniform mat3 matrix可以让您任意定位、缩放和旋转
  • 你可以乘 aVertex通过 uniform mat4 matrix它可以让您任意定位、缩放、旋转和投影到 3d

  • ...等等...

    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 会在您下次渲染时清除 Canvas ,因此您渲染两次,每次图像加载后一次,这意味着您只会得到第二个结果。为防止您需要通过 { 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,它将失败。

    所以这带来了更多的问题。

    纹理是颠倒的。同样,由您决定如何修复它们。

    你可以
  • 翻转你的纹理坐标
  • 加载使用 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); 翻转的纹理
  • 使用负比例(假设您使用上面的解决方案#2)。这会使您的 pos 复杂化设置
  • 在着色器中调整纹理坐标
  • 在着色器中否定 gl_Position.y
  • 使用上面的解决方案 #4 (mat3) 或 #5 (mat4) 并创建一个投影矩阵,使空间翻转。

  • ..等等...

    再次,矩阵解决方案是最好的解决方案,你真的应该去阅读我发布的文章。

    也就是说,在#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 drawImage how to create a matrix stack

    让我补充一下 pos 没有任何问题& scale解决方案本身。 4x4 矩阵最多需要 64 次乘法来计算并以标准方式使用它们,而 drawImage 克隆必须至少进行 2 次矩阵乘法运算,即 128 次乘法运算。而pos & scale解决方案仅使用 6 次乘法。换句话说,它在技术上更快,但不太可能成为瓶颈。
    pos 的另一个优势& scale解决方案是它仅使用 2 个 vec2 制服(4 个浮点数),而 mat4矩阵解决方案使用 mat4(16 个浮点数)。由于您可以使用的制服数量已达到上限,因此可能会在某些情况下为其他东西挤出空间 pos & scale解决方案更好。这就是 WebGL 的乐趣所在,由您决定使用哪些技术

    PS:pngcrush是你的 friend

    关于javascript - 加载图像,缩放,然后重叠 - 标记图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39306030/

    相关文章:

    google-chrome - WebGL:INVALID_OPERATION:uniform1i:位置不适用于当前程序

    javascript - JS 多函数执行

    javascript - Facebook FB.ui oauth 在 Canvas 页面上弹出

    javascript - Camanjs 在初始化 Caman() 时清除 Canvas ?

    javascript - 阻止长时间的 webgl 进程卡住 chrome

    javascript - 编译顶点着色器时出错 : ERROR: 0:1: '/' : syntax error

    javascript - 极速: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

    javascript - 谷歌图表设置网格线颜色

    javascript - 如何替换active x控件表单javascript项目

    javascript - 将数据 URI 转换为图像数据