我需要从拾取缓冲区中读取一个像素块,以检查周围的点是否有碰撞,如下图所示:
我点击canvas
上的x
,y
- 所以我定义了一个方块区域,比如11x11像素,以cX
为中心,{{ 1}}然后我从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
定义了拣选缓冲区的中心,并且是Y的起点。在cY = cH - y
选择缓冲区,但无论如何,这在我从中心走到我的采摘方框外面时给出了错误的结果。我对坐标系的解释在哪里错了?
答案 0 :(得分: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>