How can I render object according to depth in cetz?

In the simplest case, suppose I wanted to render two circles, like so

canvas({
    circle((0, 0, 0), radius: 2, fill: orange)
    circle((0, 2, 2), radius: 2, fill: blue)
})

The problem I’m facing is that depending on the order of these lines, the blue circle can appear to be on ‘top’ of the orange one and the other way around. Instead, I would like it to be dependent on the coordinates and the camera position, i.e., an object that is closer to the camera is displayed ‘on top’.

Perhaps one way would be to order them based on their ‘depth’ from the camera, but I’m not sure how to do that. I also have a snippet I found from another post on how to position the camera, so ideally this depth would be calculated based on this new perspective.

let perspective() = {
    let FOVx = 90deg // field of view
    let FOVy = 70deg
    let near = 0.1
    let far = 1000
    draw.set-transform((
        (1 / calc.tan(FOVx / 2), 0, 0, 0),
        (0, 1 / calc.tan(FOVy / 2), 0, 0),
        (0, 0, -(far + near) / (far - near), -2 * (near * far) / (far - near)),
        (0, 0, -1, 0),
    ))
}

Any help appreciated.

Hi, welcome to the forum!

I’m not sure you’re making 2D or 3D graphics, but the overlay.push trick might help:

#import "@preview/cetz:0.4.2"

#cetz.canvas({
  import cetz.draw: *
  // Items outside `overlay` will be drawn first,
  // then items in `overlay.a`,
  // then items in `overlay.b`.

  // Items to be drawn at last.
  let overlay = (a: (), b: ())

  // In this example, y is sorted by the order of being drawn.
  
  overlay.b.push(circle((1, -1.2), radius: 2, fill: red))
  overlay.b.push(circle((2, -1.6), radius: 2, fill: purple))

  circle((3, -0.0), radius: 2, fill: yellow)

  overlay.a.push({
    circle((4, -0.4), radius: 2, fill: green)
    circle((5, -0.8), radius: 2, fill: blue)
  })

  // Draw overlays
  overlay.values().flatten()
})

A more complex example: source code, result.

Sounds similar to How can I draw a line in cetz over any other regardless? - #2 by jwolf.