【问题标题】:gl readPixels coordinate system: read and check more than one pointgl readPixels坐标系:读取并检查多个点
【发布时间】:2023-03-11 20:44:02
【问题描述】:

我需要从拾取缓冲区中读取一块像素来检查周围点是否有碰撞,如下图所示:

我在xy 上单击我的canvas - 所以我定义了一个正方形区域,比如说,11x11 像素,以cXcY 为中心,然后我从采摘中读取从x1y1开始,一口气缓冲:

var w = 11, h = 11, cX = x, cY = cH - y, rc = ~~(0.5*w), x1 = cX - rc, y1 = cY + rc;

gl.readPixels(x1, y1, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pickBuf);

然后,我沿着红色箭头从缓冲区的中心循环到外面,同时检查拾取缓冲区内的积极响应(发现碰撞):

function readAt(i, pickBuf) {
    return pickBuf[i] << 16 | pickBuf[i+1] << 8 | pickBuf[i+2];
}

var l = rc;
while(l--) { 
    /* Top-Left sector */
    var r = rc+(rc-l), c = l, p = r*w + c, i = 4*p;
    found = readAt(i, pickBuf) > 0;
    /* Top-Right sector */
    var r = rc+(rc-l), c = rc+(rc-l), p = r*w + c, i = 4*p;
    found = readAt(i, pickBuf) > 0;
    /* Bottom-Left sector */
    var r = l, c = l, p = r*w + c, i = 4*p;
    found = readAt(i, pickBuf) > 0;
    /* Bottom-Right sector */
    var r = l, c = rc+(rc-l), p = r*w + c, i = 4*p;
    found = readAt(i, pickBuf) > 0;
}

这段代码正在运行,我可以选择一个几何图形,但现在我相信我没有正确理解整个坐标系,因为碰撞结果总是在它应该在的点的上方和左侧。为什么会这样?

在我看来,readPixels 应该读取从canvas 的左下角到右上角的字节。这是真的,还是我遗漏了什么?

我知道gl坐标系与我的canvas 是Y 反转的,所以我将拾取缓冲区的中心定义为cY = cH - y,并将拾取缓冲区的Y 起点定义为y1 = cY + rc ,但无论如何,在我从中心走到我的采摘方盒外面的过程中,这给了我错误的结果。我对坐标系的解释哪里错了?

【问题讨论】:

    标签: html5-canvas webgl coordinate-systems glreadpixels


    【解决方案1】:

    在我看来 readPixels 应该读取从 画布的左下角,到右上角。就是它 是的,还是我遗漏了什么?

    没错

    无论如何,这在我的步行过程中给了我错误的结果

    除了没有检查中间像素外,它对我有用,我怀疑问题出在你代码的其他地方。

    // picking
    c.addEventListener('click',function (e) {
      var
        cX = e.offsetX, // x within canvas
        cY = ctx.drawingBufferHeight - e.offsetY // y within canvas inverted, drawingbufferheight is same as canvas height 
      ;
    
      var
        area = 11,
        halfArea = (area/2)|0,
        sX = cX-halfArea,
        sY = cY-halfArea
      ;
      console.log('Picking from ', sX, sY, area,area);
      // read data
      var data = new Uint8Array(area*area*4);
      ctx.readPixels(sX,sY,area,area,ctx.RGBA,ctx.UNSIGNED_BYTE,data);
      // draw cross
      (function (pickBuf,rc,w) {
      function readAt(i, pickBuf) {
          return pickBuf[i]=pickBuf[i+1]=pickBuf[i+2]=0;
      }
      // this is your unmodified loop
      var l = rc;
      while(l--) { 
          /* Top-Left sector */
          var r = rc+(rc-l), c = l, p = r*w + c, i = 4*p;
          found = readAt(i, pickBuf) > 0;
          /* Top-Right sector */
          var r = rc+(rc-l), c = rc+(rc-l), p = r*w + c, i = 4*p;
          found = readAt(i, pickBuf) > 0;
          /* Bottom-Left sector */
          var r = l, c = l, p = r*w + c, i = 4*p;
          found = readAt(i, pickBuf) > 0;
          /* Bottom-Right sector */
          var r = l, c = rc+(rc-l), p = r*w + c, i = 4*p;
          found = readAt(i, pickBuf) > 0;
      }
      })(data,halfArea,area);
    
      // create preview
      var octx = document.createElement('canvas').getContext('2d');
      octx.canvas.classList.add('preview');
      octx.canvas.width = octx.canvas.height = area;
      var idata = octx.createImageData(area,area);
      idata.data.set(data);
      octx.putImageData(idata,0,0);
      ctx.canvas.parentElement.insertBefore(octx.canvas,ctx.canvas);
    });
    
    
    // context setup
    var ctx = c.getContext('webgl',{preserveDrawingBuffer:true});
    ctx.canvas.width = ctx.canvas.height = 256;
    ctx.viewport(0,0,256,256);
    // shader setup
    var vs=ctx.createShader(ctx.VERTEX_SHADER),fs=ctx.createShader(ctx.FRAGMENT_SHADER),prg=ctx.createProgram();
    ctx.shaderSource(vs,`
      attribute vec2 vPos;
      void main(){gl_Position=vec4(vPos,0,1);}
    `);
    ctx.shaderSource(fs,`
      precision highp float;
      void main(){
      vec2 p=(gl_FragCoord.xy/256.)*2.-1.;
      gl_FragColor=vec4(sign(p),sign(-p.r),1);
      }
    `);
    ctx.compileShader(vs);
    ctx.compileShader(fs);
    ctx.attachShader(prg,vs);
    ctx.attachShader(prg,fs);
    ctx.linkProgram(prg);
    // screenspace setup
    var ssq = ctx.createBuffer();
    ctx.bindBuffer(ctx.ARRAY_BUFFER,ssq);
    ctx.bufferData(ctx.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,1,1,-1,1]),ctx.STATIC_DRAW);
    ctx.vertexAttribPointer(0,2,ctx.FLOAT,false,0,0);
    ctx.enableVertexAttribArray(0);
    // draw
    ctx.useProgram(prg);
    ctx.drawArrays(ctx.TRIANGLE_FAN,0,4);
    h2{text-align:center;font-family: Arial,sans-serif;}
    #c{display:block;margin:0 auto;outline:1px solid red;cursor:crosshair;}
    
    .preview {
    width: 64px;
    height: 64px;
    outline: none;
    display:inline;
    image-rendering: pixelated;
    transform:scaleY(-1);
    margin: 10px;
    }
    <h2>Click 2 Pick</h2>
    <canvas id="c"></canvas>

    【讨论】:

    • 感谢您的时间,为简洁起见,我省略了 cX、cY 的第一次检查。 cX,cY 的选择运行良好,没有什么特别的。老实说,我无法想象其他地方的问题,但我会去进一步调查。
    • 我没有发现问题了,但无论如何,我真的很感谢你的sn-p。
    猜你喜欢
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 2015-03-09
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    相关资源
    最近更新 更多