Only one member of a union is active at a time.
After x1.v2 = 1024;, the member v2 is active. Reading from v1, as you do at the next line, invokes undefined behavior, so any explanation within the bounds of standard C++ (or C) stops right there.
Now, some compilers (for example, gcc), actually do define the behavior in this case, and that definition results in x1.v1 holding the contents of the first byte of the object representation of x1.v2, which is different on different platforms (it is 4 on the computers I use, and it is 0 on most household Intel-compatibles). Either way, after applying bitwise AND with 0xff00, the result is zero.