Skip to main content

A library for ray-mesh intersections on triangular meshes

Project description

pyraymesh

Description

pyraymesh is a Python library for performing ray intersection and occlusion tests on 3D meshes using a Bounding Volume Hierarchy (BVH). The library uses the C++ library bvh for building the BVH and performing the intersection tests.

While this library is reasonably fast for simpler meshes (benchmarks coming soon), it is not as fast as Embree, espcially for larger and more complex meshes. However, it does not have any dependencies on external libraries, and is thus easier to install and use.

Installation

Install the package either by

pip install pyraymesh

or cloning the repo and using pip:

pip install .

Note that the package requires a C++ compiler to build the C++ extension.

Usage

Building the BVH

To build the BVH for a mesh:

from pyraymesh import Mesh
import numpy as np

vertices = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]])
faces = np.array([[0, 1, 2], [2, 3, 0]])
mesh = Mesh(vertices, faces)
mesh.build("medium")

The build method takes a string argument that specifies the BVH build type, which can be one of the following: "low", "medium" and "high". The build type determines the trade-off between build time and query time. For most cases "medium" is almost always the right choice.

Ray Intersection

To perform ray intersection tests:

ray_origin = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
ray_direction = [[0, 0, -1], [0, 0, 1]]
## or 
ray_origin = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
ray_direction = [0, 0, -1]  # multiple rays with same direction
## or 
ray_origin = [0.1, 0.2, 1]
ray_direction = [[0, 0, -1], [0, 0, 1]]  # multiple rays with same origin

result = mesh.intersect(ray_origin, ray_direction, tnear=0, tfar=1000)
print(result.num_hits)
print(result.coords)
print(result.tri_ids)
print(result.distances)

tnear and tfar can be scalars or lists of the same length as the number of rays. If they are scalars, the same value will be used for all rays. If they are lists, each value will be used for the corresponding ray.

If you set tnear to a value greater than 0, the intersection tests will ignore any intersections that are closer than tnear. Similarly, if you set tfar to a value less than infinity, the intersection tests will ignore any intersections that are farther than tfar. This library does not support negative values for tnear or tfar.

Reflections

If you want to get the reflection of the rays, add the calculate_reflections = True parameter to the intersect method:

ray_origin = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
ray_direction = [[0, 0, -1], [0, 0, 1]]
result = mesh.intersect(ray_origin, ray_direction, tnear=0, tfar=1000, calculate_reflections=True)
print(result.reflections)

results.reflections is a list of noramlized vectors representing the directions of the reflection of the rays. Only do this if you need the reflections, as it will slow down the intersection tests.

Occlusion Test

If you just care about whether a ray is occluded or not (i.e., you don't care about the intersection point) you can use the occlusion method which is faster than the intersect method and just returns an array of booleans.

ray_origin = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
ray_direction = [[0, 0, -1], [0, 0, 1]]
occluded = mesh.occlusion(ray_origin, ray_direction)
print(occluded)

Count intersections

If you want to know the total number of intersections for each ray along its path, without stopping at the first intersection, you can use the count_intersections method:

total_intersections = mesh.count_intersections(ray_origin, ray_direction)
print(total_intersections)

This method returns an array of integers representing the total number of triangles that each ray intersects between tnear and tfar.

Parallelization

The intersect and occlusion methods can be parallelized by passing threads parameter when calling the methods:

result = mesh.intersect(ray_origin, ray_direction, tnear=0, tfar=1000, threads=4)

The threads parameter specifies the number of threads to use for the intersection tests. If set to -1, the number of threads will be equal to the number of cores on the machine. In general you shouldn't set the number of threads to be greater than the number of cores on the machine.

For a small number of rays, the overhead of parallelization might make the parallel version slower than the serial version, so it is recommended to test the performance of both versions for your specific use case.

Ray Direction Utilities

The library includes several utility methods for generating ray directions distributed on a sphere. The sphere_direction_vectors function generates points evenly distributed on a sphere using a Fibonacci spiral pattern, providing excellent uniformity even with small sample counts. For an alternative distribution, hammersley_sphere_direction_vectors implements the low-discrepancy Hammersley sequence. When you need to sample within a specific angle, the cone_direction_vectors function creates rays distributed within a cone of a specified angle around a central direction. For completely random sampling, random_sphere_direction_vectors provides uniformly distributed random directions.

from pyraymesh.ray_functions import (
    sphere_direction_vectors,
    hammersley_sphere_direction_vectors,
    cone_direction_vectors,
    random_sphere_direction_vectors,
)

# Generate 1000 rays distributed on a sphere (using Fibonacci spiral pattern)   
sphere_rays = sphere_direction_vectors(1000) 
# Generate 1000 rays distributed on a sphere (using Hammersley sequence)
hammersley_rays = hammersley_sphere_direction_vectors(1000)
# Generate 1000 rays distributed within a cone of 30 degrees around the z-axis
cone_rays = cone_direction_vectors(1000, [0, 0, 1], 30)
# Generate 1000 uniformly distributed random rays
random_rays = random_sphere_direction_vectors(1000)

Test line-of-sight

If you want to know if two points are visible to each other, you can use the line_of_sight method:

origin_point = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
target_point = [[0, 0, -1], [0, 0, 1]]
## or 
origin_point = [[0.1, 0.2, 1], [0.2, 0.1, 1]]
target_point = [0, 0, -1]  # multiple origin points with same target
## or 
origin_point = [0.1, 0.2, 1]
target_point = [[0, 0, -1], [0, 0, 1]]  # multiple target points with same origin

visible = mesh.line_of_sight(origin_point, target_point)

visible is a list of booleans representing whether the target point is visible from the origin point.

Visibility Matrix

If you want to know the visibility matrix between all pairs of a list of points, you can use the visibility_matrix method: For N points it returns an NxN matrix where the element at (i, j) is True if the j-th point is visible from the i-th point.

points = [[0.1, 0.2, 1], [0.2, 0.1, 1], [0.3, 0.4, 1]]
vis_matrix = mesh.visibility_matrix(points)
# vis_matrix is a 3x3 array of booleans

Traverse the BVH

If you want to traverse the BVH and get all triangles that are along a ray in the BVH, you can use the traverse or traverse_all method. These are useful if you want to do some custom processing on the triangles that are potentially intersected by a ray. The traverse_all method returns a list of triangle IDs of all triangles potentially intersected by the ray. The traverse method returns a generator that you can use to traverse the BVH. If you know you will need all, or most, of the triangles, it is recommended to use traverse_all as it is faster. If you are likely to break early from the loop, you can use traverse fpr better performance and use less memory.

origin = [0, 0, 10]
direction = [0, 0, -1]

for t_id in mesh.traverse(origin, direction):
    print(f"Triangle {mesh.vertices[mesh.faces[t_id]]} is the first triangle in the BVH traversed by the ray.")
    break

all_triangles = mesh.traverse_all(origin, direction)   
for t_id in all_triangles:
    print(f"Triangle {mesh.vertices[mesh.faces[t_id]]} is potentially intersected by the ray.")

Testing

To run the tests:

pytest

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (142.5 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64

pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl (148.3 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ i686

pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_x86_64.whl (580.8 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_i686.whl (627.8 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (144.6 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl (150.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ i686

pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_x86_64.whl (580.8 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_i686.whl (627.8 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (144.7 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl (150.4 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ i686

pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_x86_64.whl (581.6 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_i686.whl (628.9 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (145.8 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl (151.6 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ i686

pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_x86_64.whl (581.7 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_i686.whl (629.2 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (146.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl (151.8 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ i686

File details

Details for the file pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b987ae4bdb07a73ae79b48b67313705552026fae7ac3c851104dede9ee3e1430
MD5 f324a6d574b26e8cfb9cd5c4153c58b9
BLAKE2b-256 6961aca7934339bf6bbf3af0a327295c126f48f65a7c7912773227dae134fdfa

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 dec3f3e01d386f2e58819899d9746621042c0c85b58e92da0932cda73ed176a1
MD5 2088eb44183ed3a258be55af3af250a2
BLAKE2b-256 99c3864a7ef3e93d77e571cc82315fa39aa659226bd352bdfa9df772e2ccbe36

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 51175d8320471203d88f2cad41a8b2a2f7b17c1ea1ac91e916121b3481cc90f3
MD5 838e0a5b88b30f51f0eb1623bb303dd2
BLAKE2b-256 275572fdcda0570b67333551029052a2d391a144312ce7457493cd29c70e4f84

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 bee8ff8b36b9a4daf677cbea9a7627956a9dcce4b0f423019ce1e795a2528335
MD5 e96fa5060091e71b221fbe758ec9a995
BLAKE2b-256 a15b1728f9a6742af4f9398f18c4e3b680703ca75ec36760df87685835baeed6

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c2c993ed4d13c6b2354c5acb2827a3657239ffe00a576b6c5e0ab35976d98810
MD5 535bd882aefd053be55740fbd8c3a78c
BLAKE2b-256 fb91840a7d0810d740202b45e4581d1635edc1e5edc5b0e3df2378026b261760

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 0c6e7d501131801806cf3a479b7f78838d0e3bae1abaa029a3ea5ba20b59070a
MD5 96a305417aaf8f72560c229bf48b712b
BLAKE2b-256 0d6c2e0bfa87ddf597dfaa20fa121c61239380aa7f2396fa86a14443e11a69df

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 66a1f88ca19c178160e7d6b6095b2e68277dfc93ed3eea6ac6dff3ad46959a5c
MD5 21a9f73fb4c89405140abfb7090ff3c5
BLAKE2b-256 73e8fd614200cf2c11e2f3192aaab58fe685473d7497ea4e7aa51368cd4010fc

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 b0d9b2b1cdbcf946e2ccffd9bd188e12347fa4fc8d7656347a32adc15cbefec1
MD5 c86bbe239ef60bca8edf35db7dabe52d
BLAKE2b-256 f2096c1bfe170f72f9d222e4fadb291d4aa56d14c1faae735eb1c68c82c1e4e8

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a362cde7804b0f19d0855a339ab4e5756d92167ee621df2d2710cb4c4259661f
MD5 a6335dde9166dad5439e4cef648e9c19
BLAKE2b-256 99fa45243fbb06ac3e812aef0e3c47136e96b5736e520db58a75749f39010071

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 8d7c91c51ae0b2b870626f072a721a8cc5d9757dd960c8a7540c6d0afb4f4cbf
MD5 7cd2795bad43f23415a97231e0cdd0fc
BLAKE2b-256 6581eeb16433a4d43116de73f3bdcf0f3d96039df48bbb9f4f20f21075944500

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 fe3dc12fdca0b8ca5ff7e6832a45175ffffc719284afdf2cfa44786851ff7941
MD5 0fc8e4a3de936581dabf1a8a10faac88
BLAKE2b-256 7a2a6bdbe01aa4c6ad8f8acc4c799a4baf56166fa812a5a2a851641a35aacf7c

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 1e3a1bf8ac7767771ad2d2df839e7d7dc9485692a9bfd26f9a9b45247a51a230
MD5 5679ec21976e71aec10a48f401d267fc
BLAKE2b-256 3eeaab2fb7be6a4b9497b3cdfd416f7a16d95cf7624404e6bf670b7dd5d01fa9

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0659e8c6ea89ecf9fe2ebfbc4308c6c361b2efd82149fb84ae9d8dad9421db3c
MD5 07ab2bc2ef0d62f9bfad9cebae68478d
BLAKE2b-256 6e73d2d41e46b1c3d900c8cfabeb928ccbb3127964ef7464cfde4c77304ebedc

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 285665392a1fbe364f1741d70b4ba71eeba48e829fbeeeb22e7042c23ef4afe8
MD5 a365e346bff6f6071dd09a6aab242d36
BLAKE2b-256 1f502b17f9e5cc576996081a2d06a49b5bda7a45d137e2b83781d2872dc8f85b

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 19cab2b67f862b605fa9a925149c7275929d42aa7f02de27d83e0f6887852813
MD5 ddb1b8e9023c79cfdd169d6bd5b540d8
BLAKE2b-256 f51e85ee3ed9567a9f98a28e649c87547871828e7f1adb681705fa022c3914da

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 e2eb6317eb333b6a9736dfe927e62f125eb766c6552c129bd0819621a7e31cd7
MD5 f019b75363fca2e7cac1188e743e89aa
BLAKE2b-256 6cd7541b9ba3123a00f4fdd9dee2ef6a6a783816676682aa15356bbc9065f747

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 12e8fff83dcccc15f603698d44bfb8202f529984a7f4a84ef50986fe2121f424
MD5 4a74c1a94828bab307a93f5e93925794
BLAKE2b-256 29f991648da1e51d989c42072352cf0d2d826e578792ccfeec3b91aeec3d3528

See more details on using hashes here.

File details

Details for the file pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyraymesh-0.2.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 615121d7e723eb399f0de81a866bb3b777f2bbc4f19e23fc3a8e4523f5935dd0
MD5 af885fae2b0bbe43a855915200424929
BLAKE2b-256 296a8d0a05fa272b717fe3c7c0ec2cc0cdd26ac4eaae38177467ca8e75fa4ad8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page