Exemplo n.º 1
0
class Raycaster(Entity):
    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNP.show()

    def distance(self, a, b):
        return math.sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=math.inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)
        self._pickerNode.clearSolids()
        # if thickness == (0,0):
        if distance == math.inf:
            ray = CollisionRay()
            ray.setOrigin(Vec3(0, 0, 0))
            ray.setDirection(Vec3(0, 1, 0))
        else:
            ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, distance, 0))

        self._pickerNode.addSolid(ray)

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = Hit(hit=False)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
        ]

        if len(self.entries) == 0:
            self.hit = Hit(hit=False)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = self.collision.get_surface_point(nP)
        point = Vec3(point[0], point[2], point[1])
        world_point = self.collision.get_surface_point(render)
        world_point = Vec3(world_point[0], world_point[2], world_point[1])
        hit_dist = self.distance(self.world_position, world_point)

        if nP.name.endswith('.egg'):
            nP = nP.parent

        self.hit = Hit(hit=True)
        for e in scene.entities:
            if e == nP:
                # print('cast nP to Entity')
                self.hit.entity = e

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        normal = self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent)
        self.hit.normal = (normal[0], normal[2], normal[1])

        normal = self.collision.get_surface_normal(render)
        self.hit.world_normal = (normal[0], normal[2], normal[1])
        return self.hit

        self.hit = Hit(hit=False)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=math.inf,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)
        resolution = 3
        rays = list()
        debugs = list()

        for y in range(3):
            for x in range(3):
                pos = origin + Vec3(
                    lerp(-(thickness[0] / 2), thickness[0] / 2, x / (3 - 1)),
                    lerp(-(thickness[1] / 2), thickness[1] / 2, y /
                         (3 - 1)), 0)
                ray = self.raycast(pos, direction, distance, traverse_target,
                                   ignore, False)
                rays.append(ray)

                if debug and ray.hit:
                    d = Entity(model='cube',
                               origin_z=-.5,
                               position=pos,
                               scale=(.02, .02, distance),
                               ignore=True)
                    d.look_at(pos + Vec3(direction))
                    debugs.append(d)
                    # print(pos, hit.point)
                    if ray.hit and ray.distance > 0:
                        d.scale_z = ray.distance
                        d.color = color.green

        from ursina import destroy
        # [destroy(e, 1/60) for e in debugs]

        rays.sort(key=lambda x: x.distance)
        closest = rays[0]

        return Hit(
            hit=sum([int(e.hit) for e in rays]) > 0,
            entity=closest.entity,
            point=closest.point,
            world_point=closest.world_point,
            distance=closest.distance,
            normal=closest.normal,
            world_normal=closest.world_normal,
            hits=[e.hit for e in rays],
            entities=list(set([e.entity
                               for e in rays])),  # get unique entities hit
        )
Exemplo n.º 2
0
class Raycaster(Entity):
    line_model = Mesh(vertices=[Vec3(0, 0, 0), Vec3(0, 0, 1)], mode='line')
    _boxcast_box = Entity(model='cube',
                          origin_z=-.5,
                          collider='box',
                          color=color.white33,
                          enabled=False)

    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)

    def distance(self, a, b):
        return sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)

        self._pickerNode.clearSolids()
        ray = CollisionRay()
        ray.setOrigin(Vec3(0, 0, 0))
        ray.setDirection(Vec3(0, 0, 1))

        self._pickerNode.addSolid(ray)

        if debug:
            temp = Entity(position=origin,
                          model=Raycaster.line_model,
                          scale=Vec3(1, 1, min(distance, 9999)),
                          add_to_scene_entities=False)
            temp.look_at(self.position + direction)
            destroy(temp, 1 / 30)

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = HitInfo(hit=False, distance=distance)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore and self.distance(
                self.world_position, Vec3(
                    *e.get_surface_point(render))) <= distance
        ]

        if len(self.entries) == 0:
            self.hit = HitInfo(hit=False, distance=distance)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = Vec3(*self.collision.get_surface_point(nP))
        world_point = Vec3(*self.collision.get_surface_point(render))
        hit_dist = self.distance(self.world_position, world_point)

        self.hit = HitInfo(hit=True, distance=distance)
        for e in scene.entities:
            if e == nP:
                self.hit.entity = e

        nPs = [e.get_into_node_path().parent for e in self.entries]
        self.hit.entities = [e for e in scene.entities if e in nPs]

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        self.hit.normal = Vec3(*self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent).normalized())
        self.hit.world_normal = Vec3(
            *self.collision.get_surface_normal(render).normalized())
        return self.hit

        self.hit = HitInfo(hit=False, distance=distance)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=9999,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):  # similar to raycast, but with width and height
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)

        Raycaster._boxcast_box.enabled = True
        Raycaster._boxcast_box.collision = True
        Raycaster._boxcast_box.position = origin
        Raycaster._boxcast_box.scale = Vec3(abs(thickness[0]),
                                            abs(thickness[1]), abs(distance))
        Raycaster._boxcast_box.always_on_top = debug
        Raycaster._boxcast_box.visible = debug

        Raycaster._boxcast_box.look_at(origin + direction)
        hit_info = Raycaster._boxcast_box.intersects(
            traverse_target=traverse_target, ignore=ignore)
        if hit_info.world_point:
            hit_info.distance = ursinamath.distance(origin,
                                                    hit_info.world_point)
        else:
            hit_info.distance = distance

        if debug:
            Raycaster._boxcast_box.collision = False
            Raycaster._boxcast_box.scale_z = hit_info.distance
            invoke(setattr, Raycaster._boxcast_box, 'enabled', False, delay=.2)
        else:
            Raycaster._boxcast_box.enabled = False

        return hit_info
Exemplo n.º 3
0
class Raycaster(Entity):
    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNP.show()

    def distance(self, a, b):
        return sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)
        self._pickerNode.clearSolids()
        # if thickness == (0,0):
        if distance == inf:
            ray = CollisionRay()
            ray.setOrigin(Vec3(0, 0, 0))
            # ray.setDirection(Vec3(0,1,0))
            ray.setDirection(Vec3(0, 0, 1))
        else:
            # ray = CollisionSegment(Vec3(0,0,0), Vec3(0,distance,0))
            ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, 0, distance))

        self._pickerNode.addSolid(ray)

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = HitInfo(hit=False)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
        ]

        if len(self.entries) == 0:
            self.hit = HitInfo(hit=False)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = self.collision.get_surface_point(nP)
        # point = Vec3(point[0], point[2], point[1])
        point = Vec3(point[0], point[1], point[2])
        world_point = self.collision.get_surface_point(render)
        # world_point = Vec3(world_point[0], world_point[2], world_point[1])
        world_point = Vec3(world_point[0], world_point[1], world_point[2])
        hit_dist = self.distance(self.world_position, world_point)

        if nP.name.endswith('.egg'):
            nP = nP.parent

        self.hit = HitInfo(hit=True)
        for e in scene.entities:
            if e == nP:
                # print('cast nP to Entity')
                self.hit.entity = e

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        self.hit.normal = Vec3(*self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent).normalized())
        self.hit.world_normal = Vec3(
            *self.collision.get_surface_normal(render).normalized())
        return self.hit

        self.hit = HitInfo(hit=False)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=9999,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)

        temp = Entity(position=origin,
                      model='cube',
                      origin_z=-.5,
                      scale=Vec3(abs(thickness[0]), abs(thickness[1]),
                                 abs(distance)),
                      collider='box',
                      color=color.white33,
                      always_on_top=debug,
                      visible=debug)
        temp.look_at(origin + direction)
        hit_info = temp.intersects(traverse_target=traverse_target,
                                   ignore=ignore)
        if debug:
            temp.collision = False
            destroy(temp, delay=.1)
        else:
            destroy(temp)
        return hit_info