gl Система координат readPixels: читать и проверять более одной точки

Мне нужно прочитать блок пикселей из буфера выбора, чтобы проверить окружающие точки на коллизии, как на картинке ниже:

введите здесь описание изображения

Я нажимаю на свой canvas в x, y - поэтому я определяю квадратную область, скажем, 11x11 пикселей с центром в cX, cY, а затем я считываю из буфера выбора одним выстрелом, начиная с x1, y1:

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инвертирована по оси Y по сравнению с моей canvas, поэтому я определяю центр буфера для подбора в cY = cH - y и начальную точку Y для буфера для подбора в y1 = cY + rc, но в любом случае это дает мне неправильные результаты во время прогулки. от центра к краям моей квадратной коробки выбора. Где моя интерпретация системы координат неверна?


person deblocker    schedule 04.12.2017    source источник


Ответы (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>

person LJᛃ    schedule 04.12.2017
comment
Спасибо за ваше время, я пропустил первую проверку в cX, cY для краткости. Отмычка на cX,cY работает отлично, особо там ничего нет. Честно говоря, я не могу представить проблему в другом месте, но я пойду исследовать дальше. - person deblocker; 04.12.2017
comment
Я больше не нашел проблему, но в любом случае я очень ценю Ваш фрагмент. - person deblocker; 02.06.2018