Пример #1
0
RNBoolean R3Model::
Intersects(const R3Ray& ray, 
  R3Point *hit_point, R3Vector *hit_normal, 
  RNScalar *hit_t, int *hit_triangle_index) const
{
  // Check triangles
  if (!triangles) return FALSE;

  // Check bounding box
  if (!R3Intersects(ray, BBox())) return FALSE;

  // Check each triangle for intersection
  RNScalar min_t = FLT_MAX;
  for (int i = 0; i < NTriangles(); i++) {
    const R3Triangle *triangle = Triangle(i);
    R3Point point;
    R3Vector normal;
    RNScalar t;
    if (R3Intersects(ray, *triangle, &point, &normal, &t) == R3_POINT_CLASS_ID) {
      if (t < min_t) {
        if (hit_point) *hit_point = point;
        if (hit_normal) *hit_normal = normal;
        if (hit_triangle_index) *hit_triangle_index = i;
        if (hit_t) *hit_t = t;
        min_t = t;
      }
    }
  }

  // Return whether hit any triangle
  return (min_t == FLT_MAX) ? FALSE : TRUE;
}
Пример #2
0
void R3MeshSearchTree::
FindIntersection(const R3Ray& ray, R3MeshIntersection& closest,
  RNScalar min_t, RNScalar& max_t,
  int (*IsCompatible)(const R3Point&, const R3Vector&, R3Mesh *, R3MeshFace *, void *), void *compatible_data,
  R3MeshFace *face) const
{
  // Check compatibility
  if (IsCompatible) {
    if (!(*IsCompatible)(ray.Start(), ray.Vector(), mesh, face, compatible_data)) return;
  }

  // Check intersection with plane (this is redundant, but allows checking min_t and max_t)
  RNScalar plane_t;
  if (!R3Intersects(ray, mesh->FacePlane(face), NULL, &plane_t)) return;
  if (plane_t >= max_t) return;
  if (plane_t < min_t) return;

  // Check intersection with face
  R3MeshIntersection face_intersection;
  if (!mesh->Intersection(ray, face, &face_intersection)) return;
  if (face_intersection.t >= max_t) return;
  if (face_intersection.t < min_t) return;

  // Update closest intersection
  closest.type = R3_MESH_FACE_TYPE;
  closest.face = face;
  closest.point = face_intersection.point;
  closest.t = face_intersection.t;
  max_t = face_intersection.t;
}
Пример #3
0
void R3MeshSearchTree::
InsertFace(R3MeshFace *face)
{
  // Check if face intersects box
  if (!R3Intersects(mesh, face, BBox())) return;

  // Create container
  R3MeshSearchTreeFace *face_container = new R3MeshSearchTreeFace(mesh, face);
  assert(face_container);

  // Insert face into root
  InsertFace(face_container, root, BBox(), 0);
}
Пример #4
0
void R3MeshSearchTree::
InsertFace(R3MeshSearchTreeFace *face, R3MeshSearchTreeNode *node, const R3Box& node_box, int depth)
{
  // Check if face intersects box
  if (!R3Intersects(mesh, face->face, node_box)) return;

  // Check if interior node
  if (node->children[0]) {
    // Interior node -- Insert into children
    assert(node->children[1]);
    const R3Box& face_box = mesh->FaceBBox(face->face);
    if (face_box[RN_LO][node->split_dimension] <= node->split_coordinate) {
      R3Box node0_box(node_box);
      node0_box[RN_HI][node->split_dimension] = node->split_coordinate;
      InsertFace(face, node->children[0], node0_box, depth + 1);
    }
    if (face_box[RN_HI][node->split_dimension] >= node->split_coordinate) {
      R3Box node1_box(node_box);
      node1_box[RN_LO][node->split_dimension] = node->split_coordinate;
      InsertFace(face, node->children[1], node1_box, depth + 1);
    }
  }
  else {
    // Check face area
    RNScalar node_diagonal = node_box.DiagonalLength();
    if (node_diagonal == 0) return;
    RNScalar node_area = node_diagonal * node_diagonal;
    RNScalar area_ratio = face->area / node_area;
    if ((area_ratio >= max_area_ratio) ||
        (depth >= max_depth)) {
      // Face is too big/deep to be sorted into children, insert into big faces list
      node->big_faces.Insert(face);
      assert(face->reference_count >= 0);
      face->reference_count++;
    }
    else {
      // Leaf node -- Check if there is room for this face
      if (node->small_faces.NEntries() < max_faces_per_node) {
        // Simply insert face into list
        node->small_faces.Insert(face);
        face->reference_count++;
      }
      else {
        // Create two children
        node->children[0] = new R3MeshSearchTreeNode(node);
        node->children[1] = new R3MeshSearchTreeNode(node);
        node->split_dimension = node_box.LongestAxis();
        node->split_coordinate = node_box.AxisCenter(node->split_dimension);
        nnodes += 2;

        // Re-insert faces into subtree
        InsertFace(face, node, node_box, depth+1);
        for (int i = 0; i < node->small_faces.NEntries(); i++) {
          InsertFace(node->small_faces[i], node, node_box, depth+1);
        }

        // Clear out faces from node that is now interior
        for (int i = 0; i < node->small_faces.NEntries(); i++) {
          assert(node->small_faces[i]->reference_count > 0);
          node->small_faces[i]->reference_count--;
        }
        node->small_faces.Empty();
      }
    }
  }
}
Пример #5
0
static RNBoolean
R3Intersects(R3Mesh *mesh, R3MeshFace *face, const R3Box& box)
{
  // Check triangle bounding box and plane
  if (R3Contains(box, mesh->FaceBBox(face))) return TRUE;
  if (!R3Intersects(mesh->FaceBBox(face), box)) return FALSE;
  if (!R3Intersects(mesh->FacePlane(face), box)) return FALSE;

  // Make polygon
  R3Point points[16];
  points[0] = mesh->VertexPosition(mesh->VertexOnFace(face, 0));
  points[1] = mesh->VertexPosition(mesh->VertexOnFace(face, 1));
  points[2] = mesh->VertexPosition(mesh->VertexOnFace(face, 2));
  int npoints = 3;

  // Clip polygon against each side
  for (RNDirection dir = RN_LO; dir <= RN_HI; dir++) {
    for (RNDimension dim = RN_X; dim <= RN_Z; dim++) {
      assert(npoints < 15);
      points[npoints] = points[0];
      for (int i = 0; i < npoints; i++) {
        R3Point& p1 = points[i];
        R3Point& p2 = points[i+1];
        RNScalar d1 = p1[dim] - box[dir][dim];
        RNScalar d2 = p2[dim] - box[dir][dim];
        if (dir == RN_LO) { d1 = -d1; d2 = -d2; }
        if (d1 < 0) { // Inside
          if (d2 > 0) { // Outside
            // Insert a point at crossing
            RNScalar denom = d2 + -d1;
            R3Point p = (d2/denom)*p1 + (-d1/denom)*p2;
            for (int j = npoints; j > i; j--) points[j+1] = points[j];
            points[i+1] = p;
            npoints++;
            i += 2;
          }
        }
        else if (d1 > 0) { // Outside
          if (d2 < 0) { // Inside
            // Replace p1 with point at crossing
            RNScalar denom = -d2 + d1;
            R3Point p = (-d2/denom)*p1 + (d1/denom)*p2;
            points[i] = p;
          }
          else {
            // Remove p1
            for (int j = i; j < npoints; j++) points[j] = points[j+1];
            npoints--;
            i--;
          }
        }
      }

      // Check number of points
      if (npoints == 0) return FALSE;
      assert(npoints < 16);
      assert(npoints > 0);
    }
  }

  // Triangle survived all clips
  return TRUE;
}
Пример #6
0
void R3MeshSearchTree::
FindIntersection(const R3Ray& ray, R3MeshIntersection& closest,
  RNScalar min_t, RNScalar& max_t,
  int (*IsCompatible)(const R3Point&, const R3Vector&, R3Mesh *, R3MeshFace *, void *), void *compatible_data,
  R3MeshSearchTreeNode *node, const R3Box& node_box) const
{
  // Find intersection with bounding box
  RNScalar node_box_t;
  if (!R3Intersects(ray, node_box, NULL, NULL, &node_box_t)) return;
  if (node_box_t > max_t && !R3Contains(node_box, ray.Start())) return;

  // Update based on closest intersection to each big face
  for (int i = 0; i < node->big_faces.NEntries(); i++) {
    // Get face container and check mark
    R3MeshSearchTreeFace *face_container = node->big_faces[i];
    if (face_container->mark == mark) continue;
    face_container->mark = mark;

    // Find closest point in mesh face
    FindIntersection(ray, closest, min_t, max_t,
      IsCompatible, compatible_data, face_container->face);
  }

  // Check if node is interior
  if (node->children[0]) {
    assert(node->children[1]);
    assert(node->small_faces.IsEmpty());

    // Compute distance from query point to split plane
    RNScalar side = ray.Start()[node->split_dimension] - node->split_coordinate;
    RNScalar vec = ray.Vector()[node->split_dimension];
    RNScalar plane_t = (side*vec < 0) ? -side/vec : RN_INFINITY;

    // Search children nodes
    if (side <= 0) {
      // Search negative side first
      if (plane_t >= min_t) {
        R3Box child_box(node_box);
        child_box[RN_HI][node->split_dimension] = node->split_coordinate;
        FindIntersection(ray, closest, min_t, max_t,
          IsCompatible, compatible_data, node->children[0], child_box);
      }
      if (plane_t < max_t) {
        R3Box child_box(node_box);
        child_box[RN_LO][node->split_dimension] = node->split_coordinate;
        FindIntersection(ray, closest, min_t, max_t,
          IsCompatible, compatible_data, node->children[1], child_box);
      }
    }
    else {
      // Search positive side first
      if (plane_t >= min_t) {
        R3Box child_box(node_box);
        child_box[RN_LO][node->split_dimension] = node->split_coordinate;
        FindIntersection(ray, closest, min_t, max_t,
          IsCompatible, compatible_data, node->children[1], child_box);
      }
      if (plane_t < max_t) {
        R3Box child_box(node_box);
        child_box[RN_HI][node->split_dimension] = node->split_coordinate;
        FindIntersection(ray, closest, min_t, max_t,
          IsCompatible, compatible_data, node->children[0], child_box);
      }
    }
  }
  else {
    // Update based on distance to each small face
    for (int i = 0; i < node->small_faces.NEntries(); i++) {
      // Get face container and check mark
      R3MeshSearchTreeFace *face_container = node->small_faces[i];
      if (face_container->mark == mark) continue;
      face_container->mark = mark;

      // Find closest point in mesh face
      FindIntersection(ray, closest, min_t, max_t,
        IsCompatible, compatible_data, face_container->face);
    }
  }
}