【问题标题】:How to draw image in WebGL using another canvas buffer Data?如何使用另一个画布缓冲区数据在 WebGL 中绘制图像?
【发布时间】:2016-05-20 15:32:52
【问题描述】:

我正在尝试将图像从 2d 画布绘制到 webgl 画布。

如果我使用:

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

,它可以正常工作并成功渲染图像,但如果我使用:

gl.texImage2D(gl.TEXTURE_2D, 0,  gl.RGBA, c.width, c.height, 0,  gl.RGBA, gl.UNSIGNED_BYTE, dataTypedArray);

,它只是显示一个黑屏。

这是我的代码:

顶点着色器

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

片段着色器

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

Javascript

window.onload = main;
var buffer = null;
function main() {
    var image = new Image();
    image.src = "images/GL.jpg"
    image.onload = function() {
        render(image);
    }
}

function render(image) {
    var c = document.getElementById("c");
    c.width = window.innerWidth*0.90;
    c.height = window.innerHeight*0.90;
    var context = c.getContext('2d');
    context.drawImage(image, 0, 0);

    var imageData = context.getImageData(0,0,image.width,image.height);
    buffer = imageData.data.buffer;  // ArrayBuffer
    var canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth*0.90;
    canvas.height = window.innerHeight*0.90;

    //Get A WebGL context
    var gl = getWebGLContext(canvas);
    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.
    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.
    var dataTypedArray = new Uint8Array(buffer);
    //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    textureFromPixelArray(gl, buffer, gl.RGBA, canvas.width, canvas.height);

    var dstX = 20;
    var dstY = 30;
    var dstWidth = canvas.width;
    var dstHeight = canvas.height;

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


 function textureFromPixelArray(gl, dataArray, type, width, height)        {
      var dataTypedArray = new Uint8Array(dataArray); // Don't need to do this if the data is already in a typed array
      var texture = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.texImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, type, gl.UNSIGNED_BYTE, dataTypedArray);
      // Other texture setup here, like filter modes and mipmap generation
      console.log(dataTypedArray);
      return texture;
  }

【问题讨论】:

  • dataTypedArray 长什么样子?在此处发布。
  • 对我来说,图像的大小看起来很奇怪。您从上下文中读取 [image.width, image.height] 纹素到图像数据中,然后告诉 gl 图像的大小为 [canvas.width, canvas.height]。
  • 如何将dataTypedArray 传递到您的textureFromPixelArray 方法中。截至目前dataTypedArray 是您的render 方法的本地,因此在textureFromPixelArray 中不可见。在非严格模式下,这将导致 undefined 被传递,这将使 texImage2D 用黑色填充纹理。
  • 不,我现在得到了答案,实际上我没有使用正确的高度和宽度,BDL 的评论在上面是正确的。谢谢
  • 抱歉,我明白了。

标签: javascript glsl webgl


【解决方案1】:

首先,您可以将画布直接传递给gl.texImage2D。没有充分的理由首先致电ctx.getImageData 并获取数据。只需拨打电话

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, someCanvas);

其次,查看您的代码,您首先创建纹理,然后设置过滤。然后调用textureFromPixelArray创建新纹理,该纹理没有过滤设置,因此如果它不是 2 的幂,则不会渲染。只是猜测,但您检查过 JavaScript 控制台吗?我只是猜测它可能打印了一个关于你的纹理不可渲染的警告。

最重要的是,即使textureFromPixelArray 创建了一个新纹理,代码也会忽略返回值。

为了让代码按原样工作,我想你想把它改成这样

// not needed -- var texture = gl.createTexture();
// not needed --  gl.bindTexture(gl.TEXTURE_2D, texture);

// moved from below
// Upload the image into the texture.
var dataTypedArray = new Uint8Array(buffer);
//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
var texture = textureFromPixelArray(gl, buffer, gl.RGBA, 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-08
    • 2018-02-12
    • 1970-01-01
    • 2012-11-07
    • 2016-07-08
    • 2014-04-04
    相关资源
    最近更新 更多