Raycaster: Get ID of individual geometries of a mergeBufferGeometry

Hi all,

I have the following object ‘myBeautifulMesh’ in my Scene.

This object has been created using

const geometry = BufferGeometryUtils.mergeBufferGeometries(geom)

Where geom is an array of THREE.BufferGeometry(); the individual hexagonal cells that you can see in the picture. Each cell has its unique ID in the database and I want to access this ID based on the intersection of the raycaster. To do that, I added an attribute the geoms with

geom.setAttribute('id', new THREE.BufferAttribute(id, 1));  // id is is the database id.

I execute the raycaster like this

const m = this.scene.getObjectByName('myBeautifulMesh')
const intersects = this.raycaster.intersectObjects([m],true);
for (let i = 0; i < intersects.length; i++) {
    intersects[ i ].object.material.color.set( 0xff0000 );
    console.log("Clicked on cell" + intersects[i].object.name + " with faceIndex: " + intersects[i].faceIndex );

This returns the name of the merged Object ‘myBeautifulMesh’ and the face index of the intersection. By logging intersects I can also see the BufferGeometries attributes - the id I assigned in setAttribute.

How do I get from the face index to the ID? Is my approach wrong or is there a simpler way of doing this?

I should note that each cell has 6 faces and that there are a total of 6788 cells.


You can use the faceIndex to access data in your buffer attributes. It’s only necessary to distinct between indexed and non-indexed geometries.

If the geometry has an index, faceIndex belongs to the index attribute. Meaning you have to use faceIndex to read the vertex index first and then use this value to access your buffer attributes. If there is no index, you should be able to directly use faceIndex to read values of your id attribute like so:

const idAttribute = geom.getAttribute( 'id' );
const id = idAttribute.getX( faceIndex );

Thank you for your help. I basically build the geometry of each cell according to the webgl_buffergeometry_indexed example and I guess, this index is preserved after BufferGeometryUtils.mergeBufferGeometries(geom).

Do I need to do something like:

const idAttribute = geom.getAttribute( 'id' );
const vertexIndex = ?
const id = idAttribute.getX( vertexIndex );

I tried to solve it over the weekend, but cannot seem to get it to work, though. When logging the face with intersects[i].face I can see the faceIndex and a,b, and c (I assume those are the indices of the vertices?). I tried to get help from your SE answer but that refers only to the position.

Sorry, I’ve realized right now that faceIndex just represents the triangle number of the intersection. Does this work?

const idAttribute = geom.getAttribute( 'id' );
const index = geom.index;
const vertexIndex = index.getX( face.a );
const id = idAttribute.getX( vertexIndex );

BTW: I’m a bit irritated about your geometry structure. You say each cell has a unique ID. That means vertices can’t be shared across faces since otherwise they would have the same ID. So why do you use an index geometry then? The main purpose of an indexed geometry is to share vertices.

Each cell (= hexagon) is calculated based on its center point. The center point (vertex index = 0) is delivered by the database. After some calculation to create the locations of the other vertices of the cell, I create the 6 faces of the hexagon with something like geometry.setIndex([0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 1]). Once I have all the geometries of the cells ready, I run the mentioned mergeBufferGeometries. In that sense, you are right, I do not share vertices in the merged version, only in the individual hexagonal cells.

You can have less amount of triangles (thus index data) per hexagon: Comparing 2 approaches using BufferGeometry - #5 by marquizzo

I couldn’t resist to write a small example :slight_smile: https://jsfiddle.net/prisoner849/jpz78w1L/ (have a look at browser console, when click the hexagons)

I appreciate your input, the idea to create the hexagon out of 4 triangles is good, and the fiddle almost perfectly sums up what I am doing. The only problem I see is this line:

let instIdx = Math.floor(o.faceIndex / 4);

Your example works as you know that each hexagon has 4 faces. However, and I should have mentioned that before, there are 12 locations on the planet where I have a pentagon that does not have 4 faces per cell. I did not bother mentioning that, because I am hoping that there is another solution. I have added an attribute to geomHex (IDs 1000, 1001, and 1002) and that is the ID I would like to get. I added @Mugen87 's code and the right ID shows up if I click on the center face of the first hexagon. https://jsfiddle.net/MichaelJendryke/uoanwxcm/39/

I am also hoping to change the color of the entire cell once I have it’s ID.

Seriously? :slight_smile:
You are the Master of the world you create :muscle: . So, your world, your rules: any n-gon with amount of sides less than 7, and greater than 2, is a hexagon of 4 triangles :smile:



Yeah, right, it is possible :sweat_smile: I just did not adjust my code to the 4 face hexagons and still thought about the version that I currently have with the vertex in the center…

Feel free to use this concept :smile: :beers:

1 Like

Thanks, will do. In the fiddle I can get my ID with


Will try to set the color now…

So, when you know that all your instances have 4 faces, you don’t need that additional attribute with IDs, just get the floor of division of faceId by 4. Though it works only when those IDs are related to the order of adding geometries into the array for merging.

Right, however I need that specific ID. After clicking the cell I make an API request to the database to retrieve more information about that cell/location. Its a spatial information system.

1 Like

You can iterate through the vertices of a face and assign that face index to them. It does not matter if a face has 3 points or 12