function traverseAndSelect(root, frameState) {
  const { selectTile, canTraverse } = Cesium3DTilesetTraversal;
  const { stack, ancestorStack } = selectionTraversal;
  let lastAncestor;

  stack.push(root);

  while (stack.length > 0 || ancestorStack.length > 0) {
    selectionTraversal.stackMaximumLength = Math.max(
      selectionTraversal.stackMaximumLength,
      stack.length,
    );
    selectionTraversal.ancestorStackMaximumLength = Math.max(
      selectionTraversal.ancestorStackMaximumLength,
      ancestorStack.length,
    );

    if (ancestorStack.length > 0) {
      const waitingTile = ancestorStack.peek();
      if (waitingTile._stackLength === stack.length) {
        ancestorStack.pop();
        if (waitingTile !== lastAncestor) {
          waitingTile._finalResolution = false;
        }
        selectTile(waitingTile, frameState);
        continue;
      }
    }

    const tile = stack.pop();
    if (!defined(tile)) {
      // stack is empty but ancestorStack isn't
      continue;
    }

    const traverse = canTraverse(tile);

    if (tile._shouldSelect) {
      if (tile.refine === Cesium3DTileRefine.ADD) {
        selectTile(tile, frameState);
      } else {
        tile._selectionDepth = ancestorStack.length;
        if (tile._selectionDepth > 0) {
          tile.tileset.hasMixedContent = true;
        }
        lastAncestor = tile;
        if (!traverse) {
          selectTile(tile, frameState);
          continue;
        }
        ancestorStack.push(tile);
        tile._stackLength = stack.length;
      }
    }

    if (traverse) {
      const children = tile.children;
      for (let i = 0; i < children.length; ++i) {
        const child = children[i];
        if (child.isVisible) {
          stack.push(child);
        }
      }
    }
  }
}
Traverse the tree and check if their selected frame is the current frame. If so, add it to a selection queue.
This is a preorder traversal so children tiles are selected before ancestor tiles.

The reason for the preorder traversal is so that tiles can easily be marked with their
selection depth. A tile's _selectionDepth is its depth in the tree where all non-selected tiles are removed.
This property is important for use in the stencil test because we want to render deeper tiles on top of their
ancestors. If a tileset is very deep, the depth is unlikely to fit into the stencil buffer.

We want to select children before their ancestors because there is no guarantee on the relationship between
the children's z-depth and the ancestor's z-depth. We cannot rely on Z because we want the child to appear on top
of ancestor regardless of true depth. The stencil tests used require children to be drawn first.

NOTE: 3D Tiles uses 3 bits from the stencil buffer meaning this will not work when there is a chain of
selected tiles that is deeper than 7. This is not very likely.

@private
@param {Cesium3DTile} root
@param {FrameState} frameState