If we draw out your array on "paper" it will look like this
+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| arr2D[0][0] | arr2D[0][1] | arr2D[0][2] | arr2D[1][0] | arr2D[1][1] | arr2D[1][2] | arr2D[2][0] | arr2D[2][1] | arr2D[2][2] |
+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
Then you have to remember that an array naturally decays to a pointer to its first element. That is plain arr2D when a pointer is expected, is the same as &arr2D[0].
Now if we "redraw" the array, but only for arr2D[0] (which is what is most relevant for your question) with some of the possible pointers:
+-------------+-------------+-------------+-----+
| arr2D[0][0] | arr2D[0][1] | arr2D[0][2] | ... |
+-------------+-------------+-------------+-----+
^
|
&arr2D[0]
|
&arr2D[0][0]
Since we know that arr2D is the same as &arr2D[0], we can then do that substitution in the expression arr2D == *arr2D. That gets us &arr2D[0] == *&arr2D[0].
The dereference * and address-of & operators cancel each other out, so we have &arr2D[0] == arr2D[0].
Now keep up... We know that an array decays to a pointer to its first element, and we know that arr2D[0] is an array; That means it will decay to &arr2D[0][0], leaving us with the expression &arr2D[0] == &arr2D[0][0]. And as shown those two addresses are the same, which means the comparison will be true.
Important note: While &arr2D[0] and &arr2D[0][0] might both point to the same location, their types are different. The type of &arr2D[0] is int (*)[3], while &arr2D[0][0] is of type int *.
Armed with the above information it should be easy to decipher the other comparison *arr2D == arr2D[0], especially since all of the parts of that are already mentioned.