RenderTarget을 이용한 picking buffer
Raycaster는 geometry 교차를 계산합니다. 다른 방식으로는 offscreen RenderTarget에 object id 색상을 그리고 pointer 아래 픽셀을 읽는 picking buffer 전략이 있습니다.
화면이 아닌 texture에 그린다
renderer.setRenderTarget(pickingTarget);
renderer.render(pickingScene, camera);
renderer.setRenderTarget(null);
picking scene은 사용자에게 보이는 색이 아니라 node id를 색상으로 인코딩한 material을 사용합니다.
node id를 색상으로 인코딩한다
작은 editor라면 24bit RGB에 integer id를 넣는 방식으로 충분합니다.
function encodeIdToColor(id) {
return new THREE.Color(
((id >> 16) & 255) / 255,
((id >> 8) & 255) / 255,
(id & 255) / 255
);
}
function decodeColorToId(pixel) {
return (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
}
picking material은 lighting, tone mapping, alpha blending이 끼지 않도록 단순한 unlit material로 둡니다.
한 픽셀을 읽어 node id로 바꾼다
renderer.readRenderTargetPixels(
pickingTarget,
x,
y,
1,
1,
pixelBuffer
);
DPR, y축 방향, readback 비용을 반드시 고려해야 합니다.
function readPickingId(renderer, target, pointerCss, canvas, dpr, pixelBuffer) {
const rect = canvas.getBoundingClientRect();
const x = Math.floor((pointerCss.x - rect.left) * dpr);
const y = Math.floor((rect.height - (pointerCss.y - rect.top)) * dpr);
renderer.readRenderTargetPixels(target, x, y, 1, 1, pixelBuffer);
return decodeColorToId(pixelBuffer);
}
Three.js readRenderTargetPixels는 render target의 좌하단 기준 좌표를 사용합니다. DOM pointer는 좌상단 기준이므로 y를 뒤집어야 합니다.
오늘의 핵심
picking buffer는 정확한 GPU 기반 선택 도구입니다. 하지만 readback 비용 때문에 pointer move마다 무조건 쓰기보다 정책을 세워야 합니다.