Drawing an image using WebGL

后端 未结 2 362
南笙
南笙 2021-01-02 04:04

Please could anyone explain how to draw an image on a WebGL canvas? At the moment, on a regular \'2d\' canvas, I\'m using this:

var canvas = document.getElem         


        
相关标签:
2条回答
  • 2021-01-02 04:10

    If it was up to me I'd do it with a unit quad and a matrix like this

    Given these shaders

    vertex shader

    attribute vec2 a_position;
    
    uniform mat3 u_matrix;
    
    varying vec2 v_texCoord;
    
    void main() {
       gl_Position = vec4(u_matrix * vec3(a_position, 1), 1);
    
       // because we're using a unit quad we can just use
       // the same data for our texcoords.
       v_texCoord = a_position;  
    }
    

    fragment shader

    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'd create a unit quad and then fill out a 3x3 matrix to translate, rotate, and scale it where I needed it to be

      var dstX = 20;
      var dstY = 30;
      var dstWidth = 64;
      var dstHeight = 64;
    
      // convert dst pixel coords to clipspace coords      
      var clipX = dstX / gl.canvas.width  *  2 - 1;
      var clipY = dstY / gl.canvas.height * -2 + 1;
      var clipWidth = dstWidth  / gl.canvas.width  *  2;
      var clipHeight = dstHeight / gl.canvas.height * -2;
    
      // build a matrix that will stretch our
      // unit quad to our desired size and location
      gl.uniformMatrix3fv(u_matrixLoc, false, [
          clipWidth, 0, 0,
          0, clipHeight, 0,
          clipX, clipY, 1,
        ]);
    

    "use strict";
    
    window.onload = main;
    
    function main() {
      var image = new Image();
      // using a dataURL because stackoverflow
      image.src = "data:image/png;base64,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";  // MUST BE SAME DOMAIN!!!
      image.onload = function() {
        render(image);
      }
    }
    
    function render(image) {
      // Get A WebGL context
      var canvas = document.getElementById("c");
      var 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.
      var positionLocation = gl.getAttribLocation(program, "a_position"); 
      
      // look up uniform locations
      var u_imageLoc = gl.getUniformLocation(program, "u_image");
      var u_matrixLoc = gl.getUniformLocation(program, "u_matrix");
    
      // provide texture coordinates for the rectangle.
      var positionBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
      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);
      gl.enableVertexAttribArray(positionLocation);
      gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    
      var texture = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, texture);
    
      // 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);
    
      // Upload the image into the texture.
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    
      var dstX = 20;
      var dstY = 30;
      var dstWidth = 64;
      var dstHeight = 64;
    
      // convert dst pixel coords to clipspace coords      
      var clipX = dstX / gl.canvas.width  *  2 - 1;
      var clipY = dstY / gl.canvas.height * -2 + 1;
      var clipWidth = dstWidth  / gl.canvas.width  *  2;
      var clipHeight = dstHeight / gl.canvas.height * -2;
    
      // build a matrix that will stretch our
      // unit quad to our desired size and location
      gl.uniformMatrix3fv(u_matrixLoc, false, [
          clipWidth, 0, 0,
          0, clipHeight, 0,
          clipX, clipY, 1,
        ]);
    
      // Draw the rectangle.
      gl.drawArrays(gl.TRIANGLES, 0, 6);
    }
    canvas { 
      border: 1px solid black;
    }
    <script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
    <canvas id="c"></canvas>  
    <!-- vertex shader -->
    <script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    
    uniform vec2 u_resolution;
    uniform mat3 u_matrix;
    
    varying vec2 v_texCoord;
    
    void main() {
    
       gl_Position = vec4(u_matrix * vec3(a_position, 1), 1);
       v_texCoord = a_position;
    }
    </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>

    Here's some articles that will explain the the matrix math

    0 讨论(0)
  • 2021-01-02 04:31

    Here is a self-contained script that does what you want, if that helps. All you need to provide is image.jpg.

    <canvas id="cvs" width="1024" height="768"></canvas>
    <script>
        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, 1024, 768);
    
        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");
    
        img = new Image();
        img.src = "image.jpg";
    
        img.onload = function(){
            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, this);
    
            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);
        };
    </script>
    
    0 讨论(0)
提交回复
热议问题