Skip to content

Commit

Permalink
fix bis
Browse files Browse the repository at this point in the history
  • Loading branch information
peppsac committed May 29, 2018
1 parent 2176cd6 commit 8cdf21f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
61 changes: 46 additions & 15 deletions src/Core/Picking.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ function hideEverythingElse(view, object, threejsLayer = 0) {

const depthRGBA = new THREE.Vector4();
// TileMesh picking support function
function screenCoordsToNodeId(view, tileLayer, mouse, radius) {
function screenCoordsToNodeId(view, tileLayer, viewCoords, radius) {
const dim = view.mainLoop.gfxEngine.getWindowSize();

mouse = mouse || new THREE.Vector2(Math.floor(dim.x / 2), Math.floor(dim.y / 2));
viewCoords = viewCoords || new THREE.Vector2(Math.floor(dim.x / 2), Math.floor(dim.y / 2));

const restore = tileLayer.level0Nodes.map(n => n.pushRenderState(RendererConstant.ID));

Expand All @@ -30,8 +30,8 @@ function screenCoordsToNodeId(view, tileLayer, mouse, radius) {
const buffer = view.mainLoop.gfxEngine.renderViewToBuffer(
{ camera: view.camera, scene: tileLayer.object3d },
{
x: mouse.x - radius,
y: mouse.y - radius,
x: viewCoords.x - radius,
y: viewCoords.y - radius,
width: 1 + radius * 2,
height: 1 + radius * 2,
});
Expand Down Expand Up @@ -101,10 +101,23 @@ function findLayerIdInParent(obj) {

const raycaster = new THREE.Raycaster();

/**
* @module Picking
*
* Implement various picking methods for geometry layers.
* These methods are not meant to be used directly, see View.pickObjectsAt
* instead.
*
* All the methods here takes the same parameters:
* - the View instance
* - view coordinates (in pixels) where picking should be done
* - radius (in pixels) of the picking circle
* - layer: the geometry layer used for picking
*/
export default {
pickTilesAt: (_view, mouse, radius, layer) => {
pickTilesAt: (_view, viewCoords, radius, layer) => {
const results = [];
const _ids = screenCoordsToNodeId(_view, layer, mouse, radius);
const _ids = screenCoordsToNodeId(_view, layer, viewCoords, radius);

const extractResult = (node) => {
if (_ids.indexOf(node.id) >= 0 && node instanceof TileMesh) {
Expand All @@ -120,7 +133,7 @@ export default {
return results;
},

pickPointsAt: (view, mouse, radius, layer) => {
pickPointsAt: (view, viewCoords, radius, layer) => {
if (!layer.root) {
return;
}
Expand All @@ -139,8 +152,8 @@ export default {
const buffer = view.mainLoop.gfxEngine.renderViewToBuffer(
{ camera: view.camera, scene: layer.object3d },
{
x: mouse.x - radius,
y: mouse.y - radius,
x: viewCoords.x - radius,
y: viewCoords.y - radius,
width: 1 + radius * 2,
height: 1 + radius * 2,
});
Expand Down Expand Up @@ -193,6 +206,9 @@ export default {
* Default picking method. Uses THREE.Raycaster
*/
pickObjectsAt(view, viewCoords, radius, object, target = []) {
// Instead of doing N raycast (1 per x,y returned by traversePickingCircle),
// we force render the zone of interest.
// Then we'll only do raycasting for the pixels where something was drawn.
const zone = {
x: viewCoords.x - radius,
y: viewCoords.y - radius,
Expand All @@ -201,23 +217,36 @@ export default {
};
const pixels = view.mainLoop.gfxEngine.renderViewToBuffer(
{ scene: object, camera: view.camera },
zone, false);
zone);

const clearColor = view.mainLoop.gfxEngine.renderer.getClearColor();
const clearR = Math.round(255 * clearColor.r);
const clearG = Math.round(255 * clearColor.g);
const clearB = Math.round(255 * clearColor.b);

// raycaster use NDC coordinate
// Raycaster use NDC coordinate
const normalized = view.viewToNormalizedCoords(viewCoords);
const tmp = normalized.clone();
const color = new THREE.Color();
traversePickingCircle(radius, (x, y) => {
// x, y are offset from the center of the picking circle,
// and pixels is a square where 0, 0 is the top-left corner.
// So we need to shift x,y by radius.
const xi = x + radius;
const yi = y + radius;
const offset = (yi * (radius * 2 + 1) + xi) * 4;
color.fromArray(pixels, offset);

if (color.r == 0 && color.g == 0 && color.b == 0) {
const r = pixels[offset];
const g = pixels[offset + 1];
const b = pixels[offset + 2];
// Use approx. test to avoid rounding error or to behave
// differently depending on hardware rounding mode.
if (Math.abs(clearR - r) <= 1 &&
Math.abs(clearG - g) <= 1 &&
Math.abs(clearB - b) <= 1) {
// skip because nothing has been rendered here
return;
}

// Perform raycasting
tmp.setX(normalized.x + x / view.camera.width)
.setY(normalized.y + y / view.camera.height);
raycaster.setFromCamera(
Expand All @@ -229,6 +258,8 @@ export default {
inter.layer = findLayerIdInParent(inter.object);
target.push(inter);
}

// Stop at first hit
return target.length == 0;
});

Expand Down
10 changes: 10 additions & 0 deletions test/examples/wfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ describe('wfs', () => {
const result = await exampleCanRenderTest(page, this.test.fullTitle());

assert.ok(result);
});

it('should pick the correct building', async function _() {
const page = await browser.newPage();

await page.setViewport({ width: 400, height: 300 });
await page.goto(`http://localhost:${itownsPort}/examples/wfs.html`);
await page.waitFor('#viewerDiv > canvas');

await exampleCanRenderTest(page, this.test.fullTitle());

// test picking
const buildingId = await page.evaluate(() => picking({ x: 342, y: 243 }).properties.id);
Expand Down

0 comments on commit 8cdf21f

Please sign in to comment.