def sphere_tracing(self, rays_o, rays_d, near, far, sdf_network, conditional_volume):
        ''' Run sphere tracing algorithm for max iterations from both sides of unit sphere intersection '''

        device = rays_o.device

        unfinished_mask_start = (near < far).reshape(-1).clone()
        unfinished_mask_end = (near < far).reshape(-1).clone()

        # Initialize start current points
        curr_start_points = rays_o + rays_d * near
        acc_start_dis = near.clone()

        # Initialize end current points
        curr_end_points = rays_o + rays_d * far
        acc_end_dis = far.clone()

        # Initizlize min and max depth
        min_dis = acc_start_dis.clone()
        max_dis = acc_end_dis.clone()

        # Iterate on the rays (from both sides) till finding a surface
        iters = 0

        next_sdf_start = torch.zeros_like(acc_start_dis).to(device)

        if self.network_inference:
            sdf_func = sdf_network.sdf
        else:
            sdf_func = sdf_network.sdf_from_sdfvolume

        next_sdf_start[unfinished_mask_start] = sdf_func(
            curr_start_points[unfinished_mask_start],
            conditional_volume, lod=0, gru_fusion=False)['sdf_pts_scale%d' % 0]

        next_sdf_end = torch.zeros_like(acc_end_dis).to(device)
        next_sdf_end[unfinished_mask_end] = sdf_func(curr_end_points[unfinished_mask_end],
                                                     conditional_volume, lod=0, gru_fusion=False)[
            'sdf_pts_scale%d' % 0]

        while True:
            # Update sdf
            curr_sdf_start = torch.zeros_like(acc_start_dis).to(device)
            curr_sdf_start[unfinished_mask_start] = next_sdf_start[unfinished_mask_start]
            curr_sdf_start[curr_sdf_start <= self.sdf_threshold] = 0

            curr_sdf_end = torch.zeros_like(acc_end_dis).to(device)
            curr_sdf_end[unfinished_mask_end] = next_sdf_end[unfinished_mask_end]
            curr_sdf_end[curr_sdf_end <= self.sdf_threshold] = 0

            # Update masks
            unfinished_mask_start = unfinished_mask_start & (curr_sdf_start > self.sdf_threshold).reshape(-1)
            unfinished_mask_end = unfinished_mask_end & (curr_sdf_end > self.sdf_threshold).reshape(-1)

            if (
                    unfinished_mask_start.sum() == 0 and unfinished_mask_end.sum() == 0) or iters == self.sphere_tracing_iters:
                break
            iters += 1

            # Make step
            # Update distance
            acc_start_dis = acc_start_dis + curr_sdf_start
            acc_end_dis = acc_end_dis - curr_sdf_end

            # Update points
            curr_start_points = rays_o + acc_start_dis * rays_d
            curr_end_points = rays_o + acc_end_dis * rays_d

            # Fix points which wrongly crossed the surface
            next_sdf_start = torch.zeros_like(acc_start_dis).to(device)
            if unfinished_mask_start.sum() > 0:
                next_sdf_start[unfinished_mask_start] = sdf_func(curr_start_points[unfinished_mask_start],
                                                                 conditional_volume, lod=0, gru_fusion=False)[
                    'sdf_pts_scale%d' % 0]

            next_sdf_end = torch.zeros_like(acc_end_dis).to(device)
            if unfinished_mask_end.sum() > 0:
                next_sdf_end[unfinished_mask_end] = sdf_func(curr_end_points[unfinished_mask_end],
                                                             conditional_volume, lod=0, gru_fusion=False)[
                    'sdf_pts_scale%d' % 0]

            not_projected_start = (next_sdf_start < 0).reshape(-1)
            not_projected_end = (next_sdf_end < 0).reshape(-1)
            not_proj_iters = 0

            while (
                    not_projected_start.sum() > 0 or not_projected_end.sum() > 0) and not_proj_iters < self.line_step_iters:
                # Step backwards
                if not_projected_start.sum() > 0:
                    acc_start_dis[not_projected_start] -= ((1 - self.line_search_step) / (2 ** not_proj_iters)) * \
                                                          curr_sdf_start[not_projected_start]
                    curr_start_points[not_projected_start] = (rays_o + acc_start_dis * rays_d)[not_projected_start]

                    next_sdf_start[not_projected_start] = sdf_func(
                        curr_start_points[not_projected_start],
                        conditional_volume, lod=0, gru_fusion=False)['sdf_pts_scale%d' % 0]

                if not_projected_end.sum() > 0:
                    acc_end_dis[not_projected_end] += ((1 - self.line_search_step) / (2 ** not_proj_iters)) * \
                                                      curr_sdf_end[
                                                          not_projected_end]
                    curr_end_points[not_projected_end] = (rays_o + acc_end_dis * rays_d)[not_projected_end]

                    # Calc sdf

                    next_sdf_end[not_projected_end] = sdf_func(
                        curr_end_points[not_projected_end],
                        conditional_volume, lod=0, gru_fusion=False)['sdf_pts_scale%d' % 0]

                # Update mask
                not_projected_start = (next_sdf_start < 0).reshape(-1)
                not_projected_end = (next_sdf_end < 0).reshape(-1)
                not_proj_iters += 1

            unfinished_mask_start = unfinished_mask_start & (acc_start_dis < acc_end_dis).reshape(-1)
            unfinished_mask_end = unfinished_mask_end & (acc_start_dis < acc_end_dis).reshape(-1)

        return curr_start_points, unfinished_mask_start, acc_start_dis, acc_end_dis, min_dis, max_dis
 Run sphere tracing algorithm for max iterations from both sides of unit sphere intersection 
mv-diffusion/One-2-3-45/reconstruction/models/fast_renderer.py