9#include <corecrt_math_defines.h>
13#include <robin_hood.h>
23 template <
typename numeric1,
typename numeric2,
typename dist_type =
float>
25 numeric1 x, numeric1 y, numeric1 z,
26 numeric2 dx, numeric2 dy, numeric2 dz,
27 dist_type distance = -1.0f,
int mesh_id = -1)
33 hit.ray.org_x = x; hit.ray.org_y = y; hit.ray.org_z = z;
35 hit.ray.dir_x = dx; hit.ray.dir_y = dy; hit.ray.dir_z = dz;
37 hit.ray.tnear = 0.00000001f;
38 hit.ray.tfar = distance > 0 ? distance : INFINITY;
41 hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
47 template <
typename numeric1,
typename numeric2,
typename dist_type =
float>
49 numeric1 x, numeric1 y, numeric1 z,
50 numeric2 dx, numeric2 dy, numeric2 dz,
51 dist_type distance = -1.0f,
int mesh_id = -1)
54 ray.org_x = x; ray.org_y = y; ray.org_z = z;
55 ray.dir_x = dx; ray.dir_y = dy; ray.dir_z = dz;
57 ray.tnear = 0.0000001f;
58 ray.tfar = (distance > 0) ? distance : INFINITY;
70 return rtcGetDeviceError(device);
93 const std::vector<std::array<float, 3>>& vertices,
94 std::vector<Triangle>& Tribuffer,
95 std::vector<Vertex>& Vbuffer
97 robin_hood::unordered_map <std::array<float, 3>,
int> index_map;
100 int vertsize = vertices.size();
102 for (
int i = 0; i < vertsize; i += 3) {
103 std::array<int, 3> ids;
106 for (
int k = 0; k < 3; k++)
108 auto vert = vertices[i + k];
112 if (index_map.count(vert) > 0)
113 current_id = index_map[vert];
115 index_map[vert] = next_id;
116 current_id = next_id;
119 Vbuffer.emplace_back(
Vertex{ vert[0], vert[1], vert[2] });
125 Tribuffer.emplace_back(
Triangle{ ids[0], ids[1], ids[2] });
142 std::vector<float>& in_vertices,
143 std::vector<int>& in_indices,
144 std::vector<Vertex>& out_vertices,
145 std::vector<Triangle>& out_triangles
147 out_vertices.resize(in_vertices.size() / 3);
148 for (
int i = 0; i < in_vertices.size(); i += 3) {
149 out_vertices[i / 3] =
Vertex{
156 out_triangles.resize(in_indices.size() / 3);
157 for (
int i = 0; i < in_indices.size(); i += 3) {
168 this->use_precise =
false;
174 this->use_precise =
true;
177 throw std::logic_error(
"Embree Ray Tracer was passed an empty vector of mesh info!");
191 device = rtcNewDevice(
"");
193 rtcSetSceneBuildQuality(
scene, RTC_BUILD_QUALITY_HIGH);
194 rtcSetSceneFlags(
scene, RTC_SCENE_FLAG_ROBUST);
196 rtcInitIntersectContext(&
context);
208 rtcRetainScene(
scene);
215 rtcAttachGeometryByID(
scene, geom,
id);
222 if (error != RTCError::RTC_ERROR_NONE)
226 return static_cast<int>(rtcAttachGeometry(
scene, geom));
231 x.
y * y.
z - y.
y * x.
z,
232 x.
z * y.
x - y.
z * x.
x,
233 x.
x * y.
y - y.
x * x.
y
238 return (v1.
x * v2.
x + v1.
y * v2.
y + v1.
z * v2.
z);
254 const double EPSILON = 0.0000001;
255 const Vector3D inverted_direction = direction;
260 const double a =
dot(edge1, h);
263 if (a > -EPSILON && a < EPSILON)
266 const double f = 1.0 / a;
268 const double u = f *
dot(s, h);
269 if (u < 0.0 || u > 1.0)
273 const double v = f *
dot(direction, q);
274 if (v < 0.0 || u + v > 1.0)
278 double t_hit = f *
dot(edge2, q);
283 unsigned int geom_id,
284 unsigned int prim_id,
289 auto triangle = this->
GetTriangle(geom_id, prim_id);
305 std::vector<Triangle> tris;
306 std::vector<Vertex> verts;
313 rtcCommitScene(
scene);
319 std::vector<Triangle> tris; std::vector<Vertex> verts;
330 rtcCommitScene(
scene);
333 return (added_id == ID);
338 RTCGeometry geom = rtcNewGeometry(
device, RTC_GEOMETRY_TYPE_TRIANGLE);
342 rtcSetNewGeometryBuffer(
344 RTC_BUFFER_TYPE_INDEX,
352 rtcSetNewGeometryBuffer(
354 RTC_BUFFER_TYPE_VERTEX,
363 std::move(tris.begin(), tris.end(),
triangles);
364 std::move(verts.begin(), verts.end(),
Vertices);
370 rtcCommitGeometry(geom);
381 std::vector<Triangle> tris; std::vector<Vertex> verts;
393 rtcCommitScene(
scene);
401 for (
auto& mesh : Meshes)
406 rtcCommitScene(
scene);
412 std::array<float, 3>& origin,
413 const std::array<float, 3>& dir,
417 return PointIntersection(origin[0], origin[1], origin[2], dir[0], dir[1], dir[2], distance, mesh_id);
430 HitStruct<float> res = Intersect<float>(x, y, z, dx, dy, dz, distance, mesh_id);
447 return Vector3D{buffer[index].
x, buffer[index].
y,buffer[index].
z};
453 Triangle* index_buffer =
reinterpret_cast<Triangle*
>(rtcGetGeometryBufferData(
454 rtcGetGeometry(this->
scene, geomID),
455 RTCBufferType::RTC_BUFFER_TYPE_INDEX,
461 int v1_index = index_buffer[primID].
v0;
462 int v2_index = index_buffer[primID].
v1;
463 int v3_index = index_buffer[primID].
v2;
466 Vertex * vertex_buffer =
reinterpret_cast<Vertex *
>(rtcGetGeometryBufferData(
467 rtcGetGeometry(this->
scene, geomID),
468 RTCBufferType::RTC_BUFFER_TYPE_VERTEX,
473 return std::array<Vector3D, 3>{
481 std::vector<std::array<float, 3>>& origins,
482 std::vector<std::array<float, 3>>& directions,
487 std::vector<char> out_results(origins.size());
490 if (origins.size() > 1 && directions.size() > 1) {
491#pragma omp parallel for if(use_parallel) schedule(dynamic, 128)
492 for (
int i = 0; i < origins.size(); i++) {
493 auto& org = origins[i];
494 auto& dir = directions[i];
496 org[0], org[1], org[2],
497 dir[0], dir[1], dir[2],
498 max_distance, mesh_id
503 else if (origins.size() > 1 && directions.size() == 1) {
504 const auto& dir = directions[0];
505#pragma omp parallel for if(use_parallel) schedule(dynamic, 128)
506 for (
int i = 0; i < origins.size(); i++) {
507 auto& org = origins[i];
509 org[0], org[1], org[2],
510 dir[0], dir[1], dir[2],
511 max_distance, mesh_id
516 else if (origins.size() == 1 && directions.size() > 1) {
517 out_results.resize(directions.size());
518#pragma omp parallel for if(use_parallel) schedule(dynamic, 128)
519 for (
int i = 0; i < directions.size(); i++) {
520 auto org = origins[0];
521 auto& dir = directions[i];
523 org[0], org[1], org[2],
524 dir[0], dir[1], dir[2],
525 max_distance, mesh_id
529 directions[i][0] = org[0];
530 directions[i][1] = org[1];
531 directions[i][2] = org[2];
533 out_results[i] = did_hit;
537 throw std::exception(
"Incorrect usage of castrays");
544 float x,
float y,
float z,
545 float dx,
float dy,
float dz,
546 float max_distance,
int mesh_id)
556 const std::array<float, 3>& origin,
557 const std::array<float, 3>& direction,
560 return Occluded_IMPL(origin[0], origin[1], origin[2], direction[0], direction[1], direction[2]);
564 const std::vector<std::array<float, 3>>& origins,
565 const std::vector<std::array<float, 3>>& directions,
566 float max_distance,
bool use_parallel)
568 std::vector<char> out_array;
569 int cores =
static_cast<int> (std::thread::hardware_concurrency());
570 if (origins.size() < cores || directions.size() < cores)
573 omp_set_num_threads(min(max(origins.size(), directions.size()), cores));
575 if (directions.size() > 1 && origins.size() > 1) {
576 out_array.resize(origins.size());
577#pragma omp parallel for if(use_parallel) schedule(dynamic, 128)
578 for (
int i = 0; i < origins.size(); i++) {
580 origins[i][0], origins[i][1], origins[i][2],
581 directions[i][0], directions[i][1], directions[i][2],
586 else if (directions.size() > 1 && origins.size() == 1) {
587 out_array.resize(directions.size());
588 const auto& origin = origins[0];
589 printf(
"Using multidirection, single origin\n");
590#pragma omp parallel for if(use_parallel) schedule(dynamic, 128)
591 for (
int i = 0; i < directions.size(); i++) {
592 const auto& direction = directions[i];
594 origin[0], origin[1], origin[2],
595 direction[0], direction[1], direction[2],
603 else if (directions.size() == 1 && origins.size() > 1)
605 out_array.resize(origins.size());
606 const auto& direction = directions[0];
609 #pragma omp parallel for if(use_parallel) schedule(dynamic, 256)
610 for (
int i = 0; i < origins.size(); i++) {
611 const auto& origin = origins[i];
612 out_array[i] =
Occluded_IMPL(origin[0], origin[1], origin[2],
613 direction[0], direction[1], direction[2],
618 else if (directions.size() == 1 && origins.size() == 1) {
619 out_array = {
Occluded_IMPL(origins[0], directions[0], max_distance) };
628 return ray.tfar == -INFINITY;
640 rtcRetainScene(
scene);
645 rtcReleaseScene(
scene);
Contains definitions for the Exceptions namespace.
Contains definitions for the MeshInfo class.
Contains definitions for the EmbreeRayTracer
Contains definitions for the RayTracer namespace.
Cast rays to determine if and where they intersect geometry.
A vertex. Used internally in Embree.
A triangle. Used internally in Embree.
Vector3D cross(const Vector3D &x, const Vector3D &y)
RTCError CheckState(RTCDevice &device)
Check an embree device for errors.
Vector3D GetPointFromBuffer(int index, Vertex *buffer)
void vectorsToBuffers(const std::vector< std::array< float, 3 > > &vertices, std::vector< Triangle > &Tribuffer, std::vector< Vertex > &Vbuffer)
Index a list of verticies and place them into a triangle and vertex buffer.
RTCRay ConstructRay(numeric1 x, numeric1 y, numeric1 z, numeric2 dx, numeric2 dy, numeric2 dz, dist_type distance=-1.0f, int mesh_id=-1)
RTCRayHit ConstructHit(numeric1 x, numeric1 y, numeric1 z, numeric2 dx, numeric2 dy, numeric2 dz, dist_type distance=-1.0f, int mesh_id=-1)
double RayTriangleIntersection(const Vector3D &origin, const Vector3D &direction, const Vector3D &v1, const Vector3D &v2, const Vector3D &v3)
Determine the distance between a ray's origin and it's point of intersection with a triangle.
void buffersToStructs(std::vector< float > &in_vertices, std::vector< int > &in_indices, std::vector< Vertex > &out_vertices, std::vector< Triangle > &out_triangles)
Package raw arrays of floats and indices in buffers to the required Embree types.
Vector3D InvertVector(const Vector3D &V)
double dot(const Vector3D &v1, const Vector3D &v2)
The OBJ file was not valid.
A collection of vertices and indices representing geometry.
int meshid
Identifier for this mesh.
int NumTris() const
Calculate the total number of triangles in this mesh.
int NumVerts() const
Determine how many vertices are in this mesh.
std::vector< numeric_type > GetIndexedVertices() const
A copy of every vertex in this array.
std::vector< int > getRawIndices() const
Retrieve a copy of this mesh's index buffer as a 1D array.
A wrapper for Intel's Embree Library.
RTCIntersectContext context
Context to cast rays within.
std::vector< char > PointIntersections(std::vector< std::array< float, 3 > > &origins, std::vector< std::array< float, 3 > > &directions, bool use_parallel=true, float max_distance=-1, int mesh_id=-1)
Cast multiple rays and recieve hitpoints in return.
bool use_precise
If true, use custom triangle intersection intersection instead of embree's.
void SetupScene()
Performs all the necessary operations to set up the scene.
double CalculatePreciseDistance(unsigned int geom_id, unsigned int prim_id, const Vector3D &origin, const Vector3D &direction) const
Calculate the distance from origin to the point of intersection using an algorithm with higher precis...
~EmbreeRayTracer()
Custom destructor to ensure cleanup of embree resources.
std::vector< RTCGeometry > geometry
RTCDevice device
All objects in Embree are created from this. https://www.embree.org/api.html#device-object.
std::array< Vector3D, 3 > GetTriangle(unsigned int geomID, unsigned int primID) const
Get the vertices for a specific triangle in a mesh.
Vertex * Vertices
Vertex buffer. Is used in multiple places but contents are dumped.
bool AddMesh(std::vector< std::array< float, 3 > > &Mesh, int ID, bool Commit=false)
Add a new mesh to this raytracer's BVH with the specified ID.
Triangle * triangles
Triangle buffer. Is used in multiple places, but contents are dumped.
int InsertGeom(RTCGeometry &geom, int id=-1)
Attach geometry to the current scene.
void operator=(const EmbreeRayTracer &ERT2)
Increment reference counters to prevent destruction when a copy is made.
RTCScene scene
Container for a set of geometries, and the BVH. https://www.embree.org/api.html#scene-object.
RTCGeometry ConstructGeometryFromBuffers(std::vector< Triangle > &tris, std::vector< Vertex > &verts)
Create a new instance of RTCGeometry from a triangle and vertex buffer.
bool PointIntersection(std::array< float, 3 > &origin, const std::array< float, 3 > &dir, float distance=-1, int mesh_id=-1)
Cast a ray and overwrite the origin with the hitpoint if it intersects any geometry.
bool Occluded_IMPL(float x, float y, float z, float dx, float dy, float dz, float distance=-1, int mesh_id=-1)
Implementation for fundamental occlusion ray intersection.
RTCRayHit Intersect_IMPL(float x, float y, float z, float dx, float dy, float dz, float max_distance=-1, int mesh_id=-1)
Implementation for fundamental ray intersection.
EmbreeRayTracer(bool use_precise=false)
Construct an empty EmbreeRayTracer;.
std::vector< char > Occlusions(const std::vector< std::array< float, 3 > > &origins, const std::vector< std::array< float, 3 > > &directions, float max_distance=-1, bool use_parallel=true)
Cast multiple occlusion rays in parallel.
A simple hit struct to carry all relevant information about hits.
bool DidHit() const
Determine whether or not this hitstruct contains a hit.
numeric_type distance
Distance from the origin point to the hit point. Set to -1 if no hit was recorded.