Jun 19, 2011

Coliseum Wall Flooring Issues

(Again Updated!)

If you ever tried to make a floor out of the Coliseum walls, you undoubtedly came across the issue where the walls get off angle slightly when you reload the map in forge or customs. This phenomena is a product of the game engine and cannot be prevented. In this article, I hope to explain the root problem and work around solutions.


This article is based upon an excellent explanation of the same phenomena in Halo 3 by Bungie. A special thanks to Ladnil at Forge Hub for providing me with the article. I include the article as an appendix to this article. 

Updated 

After I wrote the first edition of this article, I applied the 3 step Bungie work around that I had at the bottom of this article to a map I was building that used Coliseum walls in a 30x48 unit layout. Along the way I realized the work around I originally provided, as simplified as it was, is more complicated than it needs to be. So I am updating this article with more detail on how truncation works and how to use that to your advantage. I kept the Bungie work around in this article, but I also provide a more stream line (2 step) work around that I would recommend you use.



The Problem Explained

According to Bungie engineers, all objects that are added by a forger to a map have two pieces of information necessary to describe their orientation in space (not the same as describing their location in space). They include the object's up vector and the object's rotation around it's up vector. According to Bungie, both these pieces of information are stored in a fixed size of memory when the map is stored on disk. When the tilt angle of the up vector is not altered (when it is pointing straight up), the rotation around the object's up vector enjoys the entire size of the memory structure used to describe the object's orientation in the map file on disk. But if the object's up vector is altered (e.g., when you lay the object on its side), then that same memory structure is cut into two pieces, one for the up vector and the other for the object's rotation around its up vector.

This means that when you lay a coliseum wall on its side, your rotation information is destined to suffer major precision loss, as some of the bits of information are used by the up vector orientation information. This precision loss is seen in any object, but is more pronounced in large objects, because the larger the object, the more a tiny error in angle can show itself way out at the edge of the object. This precision loss is not seen until you reload the map from the stored file, either in forge or customs; because, while in forge, the full precision is maintained by forge. Remember, precision is only lost when writing to the map file on disk.

Figure 1 - Walls A and B mated together in forge

Figure 1 shows two walls, A and B, mated along their short edge. The long edge and the face are flush. This is what the two look like before their rotational information suffers precision loss.


Figure 2 - Walls A and B mated after reloading map in forge (or customs)


Figure 2 shows the two walls, A and B, mated along the same short edge as before, but after they were reloaded from the disk file. The loss of rotational precision information is apparent.

Diagram A  - Angular Rotation Along Two Axis

Diagram A shows how each of the two corners turn in opposite directions from each other in two directions, because the walls turn in the same direction to each other. The reference is the high precision orientation of both walls correctly mated before saving the map to disk file.

Never Ending Correction 

Remember that grabbing the walls with rotation lock (I recommend 45 degrees) reintroduces the high precision information. But this doesn't fix the problem, because that same high precision is again lost the next time you save the map to disk.This is why in forge you can make the problem appear to go away, but it keeps coming back with each reload of the map.

Truncation - Losing Precision

After thinking hard about this section of the article, I rewrote it to better present how truncating the rotation values works. I use the term truncation to explain what appears to be happening and to present a model in harmony with Bungie's explanation. The numbers are my own and are for teaching purposes only. I do not know how the numbers are represented internally, and I am certainly not going to go into explaining numeric representation in binary formats.

The problem that we see is due to truncating of the precision of the angles of rotation. With all of the precision, the walls' edges mate perfectly. When we lose precision, the original accuracy cannot be obtained.

Take the two walls mated along their short edge. Their full precision angle is, say, 90 degrees. But in a binary format, this may look like 0.355030.

Then you truncate this number to the one-thousandth resolution, you get 0.355. This is stored in the map file on disk. When it is read back out, the value 0.355 loaded into a higher precision memory structure (in the XBOX, not in the disk file) results in 0.355000, not 0.355030. So each wall's rotation is now off by 0.000030. This is what you see after you reload them (e.g., Figure 2). 

Now if each wall tilts the same way, then the mated ends pull in opposite directions. For one wall, the edge at the mating plane appears to pull up when it truncates. For the other wall, it appears to pull down. This is expected, since they are tilting the same way with the same precision loss.

If wall A's mating edge pulls up and wall B's mating edge pulls down, then we know that truncating the rotation value on wall A causes the mating edge to pull in the upward direction at the mating plane, while truncation causes wall B's mating edge to pull downward. We can use this to our advantage, by giving wall B the rotation necessary where when it is truncated it will "fall down" to the angle necessary to sit flush with wall A. We do this by rotating wall B up and just past where we want it to sit when it is reloaded. We know where that position is, since wall A is already at that position. See Diagram B.




Diagram B - Rotating wall B just above wall A to fall back down flush with wall A. 

The blue arrows in Diagram B show how the walls "fall" into position as a result of their rotation values being truncated. We will return back to Diagram B (as Diagram C) later when we explore the work around.


The Bungie Work Around

Bungie suggests a work around, but in and of itself it is not adequate. I expand upon what they instruct to give a three step process that should always help you create a perceived to be flat surface to play on.

Step 1: Eliminate the Appearance of Surface Dips and Rises

According to Bungie, one way to fix the problem is to rotate every other wall so that the mating edges switch sides. The resulting vertical rise or dip are matched at mated edges, and the perceived error is alleviated. But there is another issue that this introduces that is very undesirable.

 Figure 3 - Wall A mated with Wall B rotated 180 degrees after reloading

In Figure 3, the two corners near you are both slightly rotated up and slightly rotated away from their mating plane. Thus the top surfaces appear flush, but the edge facing you has a gap between their corners.

According to Bungie, the two walls' up vectors are now pointing toward each other. You would expect the rotation error to be identical, but 180 degrees rotated relative to each other. It appears that one of the rotated angles truncates slightly more than the other. 


Step 2: Eliminate the Wedge Gap

The way to solve this problem is to turn off rotation snap, grab wall B (the rotated wall), and nudge its rotation ever so slightly so that there is a tiny gap on the other end of the mated edge. This will take the rotation value just past the truncated value point so that when the rotation value is truncated again (when it is saved to the disk file again), it will sit at the proper angle to match wall A. 


Figure 4 - Wall A mated with Wall B rotated 180 degrees plus nudge after reload.

Figure 4 shows the resulting end of the mated edge. Notice that the walking surface is flush as we want it, but now the side edge is jagged. This is because each wall has an identical rotation error (due to loss of precision) and that error has them both slightly turned to form the jagged edge. Since this edge is very minor in size, it can easily be hidden within a wall, especially if that wall is a coliseum wall (several units thick!).


Step 3: Eliminate the Jagged Edge Effect (optional)

Since the edge is jagged due to a slight rotation, if you have four of these walls mated together in a 2 by 2 formation, you would expect to see a tiny hole at their junction. In Figure 5, we see such a hole.


Figure 5 - Junction Hole Due To Jagged Edge Formation



The natural thing to do is shift the two upper walls to the left ever so slightly. This also has the effect of smoothing out the jagged edges on the left and right sides of the 2x2 formation. But you must remember that what you are doing is simply adding to the error of the rotation over the length of the flooring. Again, if the wall is thick enough to cover for you, then you are fine.


Figure 6 - Junction Hole Closed By Sliding Two Walls Over

The beauty of this sliding of the walls is that the rotation and height values stored in the disk file and reloaded with identical (loss) precision will remain unaltered if you do not snap the walls to either a rotation lock or the grid settings. You can nudge the walls along the x-axis and y-axis without having to redo any of the work described above again.

The Straight Forward Work Around

After I published the first edition of this article, I applied the Bungie work around to my latest map and found that it works, but that you really need to understand truncation and how to rotate any pieces that are still off a bit to get them lined up properly. Later, I realized that Bungie's explanation of rotating the wall around was completely unnecessary and quite often produced the gap along the mating plane.

If you understand truncation of the rotation values, then you realize that all you need to do is rotate wall B slightly past the point you want it to sit with respect to wall A and it's new high precision rotation value will truncate to the value that you want, with a flush surface to wall A.

The benefits of this approach include:

1.This work around does not alter any other rotation or position value. This means that the process is faster to complete and there is a lot less clean up to perform.

2. This also means that the walls are in a very accurate position to each other when you are done, since they were originally lined up with each other using the coordinate and rotation snaps.

3. If you grab one of the walls later, it is very easy to reposition it. Using the snaps, you can get it back into alignment, less the rotation necessary to make the flush surface. Then you reload the map, perform step 1 below, and reload to verify the correction.

4. You don't have to concern yourself with what direction the wall's up vector is orientated, though I recommend they all be pointing in the same direction.

5. You should never get a "gap" along the mating edge that you then need to compensate for with an additional step. The mating edges should remain completely aligned through out the first step.

Step 1:
 
Rotate every other wall ever so slightly so that the mating edge just barely moves past the mating edge of the other wall. The difference of their flat surfaces (the floor) should be about 1/4 the difference you originally witnessed after reload and in the opposite direction. When you reload the file, the wall you adjusted will "fall" in the opposite direction into place. See Diagram C.

Diagram C - Rotating wall B just above wall A to fall back down flush with wall A.

In Diagram C, the green line shows the top surface of walls A and B when first laid down in forge with high precision. Notice that reloading causes the mating edge of wall B to fall down below the green line and wall A to fall up above the green line. Now the red line is the new reference for where the mating edges should sit to make their surfaces appear to be flush.

Rotating wall B so that it's surface edge just passes the surface edge of wall A allows the truncation of this new rotation value to fall back down to match wall A's mating edge when the map is saved to the disk file again. After that, the new truncated value will always be read out of the file on disk (assuming you don't alter it in forge).

To show this step in action, I created the following video.




Step 2: (optional) 

By this point, you will now have the walls appear to lay flat and aligned along their mating surfaces. However, as explained in the Bungie work around, there will be a tiny hole between any four walls in a 2x2 formation. (See Figure 5.)

Perform step 3 from the Bungie work around, if you find the holes objectionable. 


Final Notes

The same techniques can be used with blocks of any size. For example, if you turn over the XXL platform for flooring decor, you will see the same type of problem. Only the error will look very small. The angular changes you will need to make will be very small, but it can be done. The picture I use at the top of this web site shows such a problem in the flooring. Though the error is very small, it is very noticeable.

The concept of adjusting the rotation around any axis is the same. Once you know which direction a block rotates toward when its rotation value is truncated, you merely rotate it in the opposite direction just a bit past where you want it to rest. Step 2 of the Bungie Work Around is an example of correcting rotation around a different axis.


                                                              





Appendix A: Article by Bungie (reproduced here)

Quantum Mechanical Rules Rule!

Those prone to flipping and rotating Forge's building blocks around their various axes have noticed that after a save and quit, the blasted slabs, partitions, and chutes occasionally end up shifting around and gettin' all "jiggy with it" (to invoke the parlance of 1998).  So, just what maniacal and twisted conspiracy scheme have you unwittingly stumbled into, both literally and figuratively?  Step into our office.


Well, "our office" is a bit of a stretch.  We roped Jon Cable into it, our resident really smart guy who can do maths and such.  The next portion of the update is on him.  If you're interested, here's the explanation of exactly what's going on, and what you can do to smooth out your Forge experience with Sandbox.


Enter the Engineer


The Problem


When using double walls (or some other objects) to create a "floor," sometimes the objects become "bumpy" after saving and reloading the map.


The Cause


There are a near-infinite number of possible orientations that an object can be placed in. While you are editing a map, the objects are allowed to be in pretty much any orientation. When we save the map, we
quantize the orientation in order to save space in storage. What this means is that the orientation you get when you load the map might not quite be what it was when you saved it.

Specifically, we store what direction the object's 'up' vector is pointing, and a rotation around that vector from its default position. When you first create an object in forge, its up vector is pointing straight up, and its rotation is zero. If you leave the object in a straight-up position, we use a special quantization method that preserves more precision for the rotation.


But if you tilt it (on its side, for example), then more of the storage space has to be used for that direction, and the rotation can lose precision. What this means is that when you are creating a floor out of walls, it's using the less precise method. The good news is that it's usually easy to predict which way the quantization error will go.


"Why can't you fix this?"


This problem is really inseparable from the way we store Map Variants on the disk. If we change the way the maps are encoded, then all the content saved in the old method could become invalid. It's a complex problem, and complexity means high risk. And risky changes are not something you want to make in a patch to a console game.


The Forge engine was built before we ever knew that maps like Foundry and Sandbox would exist. And this problem, of course, has been present since day one. It only now became apparent because people are building truly amazing maps and demanding more fidelity out of Forge.


"How about some good news?
"

As outlined above, you should leave objects pointing 'up' if you can. If possible, create your floor out of double boxes instead of double walls. No effort, no bumps!


If you must use double walls for the floor, pay close attention to the location and direction of the helper gizmo (the blue/white orb that shows the origin of the object). When saved, walls placed horizontally tend to rotate such that the "forward" end of the gizmo is pointing slightly downward. You can use this to your advantage by placing walls that are end-to-end rotated 180 degrees from each other, so that both edges will be either high or low. Walls placed side-by-side should have the same gizmo orientation. See the following diagram:


Blame Stosh
Again, this is an issue that only crops up when you are rotating objects around their Z-axis, and most commonly, when shifting objects out of their initial orientation (i.e. laying a wall onto its side).  The easiest solution is to make such shifts to orientation as sparingly as possible, or if you must, to simply follow the diagram Cable has laid out, juxtaposing the objects based upon the "gizmo," so that any variation you come across becomes uniform and therefore, less noticeable to players who traverse your map.

Yanking the network cable from the back of your Xbox 360, as some have suggested, does not resolve this issue.



2 comments:

  1. wow, great post!! but because i´m german, it´s a tough read!!!

    ReplyDelete
  2. I just figured how to take this method to the next step. No fudging or rotational nudging required. I can Forge but i suck at writing tutorials. Let me know if you want to work together on a new article to replace this one.

    ReplyDelete

Note: Only a member of this blog may post a comment.