docstr: march rays to generate points (forward only, for inference)
  Args:
      n_alive: int, number of alive rays
      n_step: int, how many steps we march
      rays_alive: int, [N], the alive rays' IDs in N (N >= n_alive, but we only use first n_alive)
      rays_t: float, [N], the alive rays' time, we only use the first n_alive.
      rays_o/d: float, [N, 3]
      bound: float, scalar
      density_bitfield: uint8: [CHHH // 8]
      C: int
      H: int
      nears/fars: float, [N]
      align: int, pad output so its size is dividable by align, set to -1 to disable.
      perturb: bool/int, int > 0 is used as the random seed.
      dt_gamma: float, called cone_angle in instant-ngp, exponentially accelerate ray marching if > 0. (very significant effect, but generally lead to worse performance)
      max_steps: int, max number of sampled points along each ray, also affect min_stepsize.
  Returns:
      xyzs: float, [n_alive * n_step, 3], all generated points' coords
      dirs: float, [n_alive * n_step, 3], all generated points' view dirs.
      ts: float, [n_alive * n_step, 2], all generated points' ts
docstr_tok: ["march","rays","to","generate","points","(","forward","only",",","for","inference",")","Args",":","n_alive",":","int",",","number","of","alive","rays","n_step",":","int",",","how","many","steps","we","march","rays_alive",":","int",",","[","N","]",",","the","alive","rays","'","IDs","in","N","(","N",">","=","n_alive",",","but","we","only","use","first","n_alive",")","rays_t",":","float",",","[","N","]",",","the","alive","rays","'","time",",","we","only","use","the","first","n_alive",".","rays_o\/d",":","float",",","[","N",",","3","]","bound",":","float",",","scalar","density_bitfield",":","uint8",":","[","CHHH","\/\/","8","]","C",":","int","H",":","int","nears\/fars",":","float",",","[","N","]","align",":","int",",","pad","output","so","its","size","is","dividable","by","align",",","set","to","-1","to","disable",".","perturb",":","bool\/int",",","int",">","0","is","used","as","the","random","seed",".","dt_gamma",":","float",",","called","cone_angle","in","instant-ngp",",","exponentially","accelerate","ray","marching","if",">","0",".","(","very","significant","effect",",","but","generally","lead","to","worse","performance",")","max_steps",":","int",",","max","number","of","sampled","points","along","each","ray",",","also","affect","min_stepsize",".","Returns",":","xyzs",":","float",",","[","n_alive","*","n_step",",","3","]",",","all","generated","points","'","coords","dirs",":","float",",","[","n_alive","*","n_step",",","3","]",",","all","generated","points","'","view","dirs",".","ts",":","float",",","[","n_alive","*","n_step",",","2","]",",","all","generated","points","'","ts"]
code: def forward(
      ctx,
      n_alive,
      n_step,
      rays_alive,
      rays_t,
      rays_o,
      rays_d,
      bound,
      density_bitfield,
      C,
      H,
      near,
      far,
      perturb=False,
      dt_gamma=0,
      max_steps=1024,
      contract=False,
  ):
      """march rays to generate points (forward only, for inference)
      Args:
          n_alive: int, number of alive rays
          n_step: int, how many steps we march
          rays_alive: int, [N], the alive rays' IDs in N (N >= n_alive, but we only use first n_alive)
          rays_t: float, [N], the alive rays' time, we only use the first n_alive.
          rays_o/d: float, [N, 3]
          bound: float, scalar
          density_bitfield: uint8: [CHHH // 8]
          C: int
          H: int
          nears/fars: float, [N]
          align: int, pad output so its size is dividable by align, set to -1 to disable.
          perturb: bool/int, int > 0 is used as the random seed.
          dt_gamma: float, called cone_angle in instant-ngp, exponentially accelerate ray marching if > 0. (very significant effect, but generally lead to worse performance)
          max_steps: int, max number of sampled points along each ray, also affect min_stepsize.
      Returns:
          xyzs: float, [n_alive * n_step, 3], all generated points' coords
          dirs: float, [n_alive * n_step, 3], all generated points' view dirs.
          ts: float, [n_alive * n_step, 2], all generated points' ts
      """
  
      if not rays_o.is_cuda:
          rays_o = rays_o.cuda()
      if not rays_d.is_cuda:
          rays_d = rays_d.cuda()
  
      rays_o = rays_o.float().contiguous().view(-1, 3)
      rays_d = rays_d.float().contiguous().view(-1, 3)
  
      M = n_alive * n_step
  
      xyzs = torch.zeros(M, 3, dtype=rays_o.dtype, device=rays_o.device)
      dirs = torch.zeros(M, 3, dtype=rays_o.dtype, device=rays_o.device)
      ts = torch.zeros(
          M, 2, dtype=rays_o.dtype, device=rays_o.device
      )  # 2 vals, one for rgb, one for depth
  
      if perturb:
          # torch.manual_seed(perturb) # test_gui uses spp index as seed
          noises = torch.rand(
              n_alive, dtype=rays_o.dtype, device=rays_o.device
          )
      else:
          noises = torch.zeros(
              n_alive, dtype=rays_o.dtype, device=rays_o.device
          )
  
      get_backend().march_rays(
          n_alive,
          n_step,
          rays_alive,
          rays_t,
          rays_o,
          rays_d,
          bound,
          contract,
          dt_gamma,
          max_steps,
          C,
          H,
          density_bitfield,
          near,
          far,
          xyzs,
          dirs,
          ts,
          noises,
      )
  
      return xyzs, dirs, ts
  
imports: import torch
  from torch.autograd import Function
  from torch.cuda.amp import custom_bwd, custom_fwd
label_desc: Use image node_id 1 for calling the _march_rays obj's underlying member method code with example usage: obj.forward(ctx, n_alive, n_step, rays_alive, rays_t, rays_o, rays_d, bound, density_bitfield, C, H, near, far, perturb, dt_gamma, max_steps, contract) and returns: xyzs,  dirs,  ts