Wednesday, June 18, 2014

Revisiting the Lava Texturing Problem

In a previous post, I commented on a texturing problem with the lava in the scene lav. As I indicated in that post, while the work around that I submitted did fix the problem for the scenes with issues, the workaround itself was sort of a hack. I had assumed that if a texture was larger than 128 pixels on a side, then that texture should be clamped at the edges. Clamping prevents the OpenGL renderer from repeating the texture over the surface, resulting in lines when the textures don't repeat cleanly. So why not just always use clamping? Well, in many cases we DO want the texture to repeat. Think of a typical grass pattern or a sandy beach texture, or in this case, the lava!

Although my approach did fix the problem, the solution was a hack. There's nothing that really indicates that that is a cutoff for which approach to take. To investigate possible solutions, I used apitrace, a tool that records OpenGL state information, allowing you to replay, investigate and examine what OpenGL calls a program is executing to render the screen.

To capture a trace, we'll use this command with the retail version:
  • apitrace trace -o retail.trace wine ./Monkey4.exe -gl -w
And this with ResidualVM:
  • apitrace trace -o residual.trace residualvm
Of note, to trace 32-bit Windows applications in wine, you will need a 32-bit version of apitrace.

To view the traces, I used the program qapitrace, a GUI viewer for replaying traces from apitrace. To run qapitrace on an existing trace:
  • qapitrace retail.trace
With these traces in hand and in the viewer, I took a look at the size of the textures and when the glTexParameteri function was used on them in the retail version. To make the trace more manageable, I filtered the results for Texture Events using Trace->Options and configuring it like shown below.
Filtering for Texture Events
After some investigation, I found that there were definitely textures that used clamping when the size was lower than 128 pixels and repeating when greater. Rats, that approach definitely was wrong!

It was at this point that Akz- suggested that I try clamping sprites, which are generally images painted on top of the scene (such as the candles' flame or the Dainty at dock on Lucre Island) and repeat all other textures. This approach seemed to work well, also resolving all of the issues resolved by the previous patch. For this approach, I had originally thought of passing a texture parameter to the Material (which loads the texture) using an enum, but I ran into the issue of having to predeclare the enum when used in places that had also predeclared the Material class. In C++, unlike C, the enum has a variable storage size and isn't assumed to be int. In C++11, there is support for predeclaring the type, but ResidualVM targets the C++03 standard, which doesn't include this feature.

In the end, I realized that the retail version only used GL_CLAMP_TO_EDGE and GL_REPEAT, so instead of using an enum, I replaced it with a bool indicating that the texture should be clamped when true. The completed patch for this work can be found in PR #910. It fixes both the lava, as shown in the previous post, with a repeating texture, and the Dainty at the dock on Lucre Island, where the texture needed to be clamped to remove the lines as shown below. Note that in these pictures, they're not exactly in the same place because the Dainty texture moves to simulate waves.

Without Clamping
With Clamping
In the next post, I will get back to collisions and the actual lava puzzle issues.

No comments:

Post a Comment