Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js Ray ignore transparent pixels

I have some Vector3ds that contain plane geometries that use tranparent pngs as they're materials.

The trouble I'm having is the Raycaster is picking up the entire object, so clicking near the material is enough to activate the corresponding functions.

Is it possible to hide the tranparent parts of a mesh from the raycaster ?

Further to Alex's assistance, I've got the actual point on the object.

How do I now convert this into an pixel on the image, to test for transparency?

like image 552
beek Avatar asked Sep 01 '14 02:09

beek


1 Answers

I'm not familiar with Three.js, but the online documentation suggests to me that the Raycast algorithm is calculated based on the distribution of objects in space, and not on their composition. In this regard, I don't think there'd be any specific way to inform the Raycast that we'd only like opaque pixels to be tested.

I'm thinking that first, use Three.js's Raycast.intersectObjects(pObjects, pRecursive) to get an analysis of which of your objects broadly collide with the spatial expanse of the ray. Once the Objects have been filtered, you need to perform a specific test to determine whether the ray collides with opaque pixels or not.

A simple way of doing this would be to take the Object which we guarantee is colliding with the ray and determine the centre location of the ray when it crosses the Object. (This will increase incomplexity depending on whether your objects can be scaled, or if your objects/ray can be rotated.) The absolute location of the point of intersection of the ray in 3D space can be found using trigonometry, which will need to account for the near and far values of your ray.

By knowing the location and dimensions of your image, you can convert the co-ordinate of raycast intersection in your 3D world into discrete 2D co-ordinates relative to that of the image you're using.

As an example, imagine a simple 2D case. If you had a 50px² image sat at the origin, and the ray intersects with the image at position (25,25), you could use this information to index the pixel data array and test the alpha values of the pixel. Since PNG image data stores RGBA data, you're looking at four bytes per pixel. Therefore, you'd need an implementation looking something like the example below, as image data is stored contiguously.

byte lPixelRed   = bitmap.getData()[(X  + Y*bitmap.getWidth())*4];
byte lPixelGreen = bitmap.getData()[(X  + Y*bitmap.getWidth())*4 + 1];
byte lPixelBlue  = bitmap.getData()[(X  + Y*bitmap.getWidth())*4 + 2];
byte lPixelAlpha = bitmap.getData()[(X  + Y*bitmap.getWidth())*4 + 3];

Once you've found the area of pixel data, you can test the alpha bytes to determine whether they're opaque (0xFF) or transparent (0x00). You can use this to qualify whether the raycast has successfully collided with your objects or not.

like image 79
Mapsy Avatar answered Oct 20 '22 21:10

Mapsy