i
i
i
i
i
i
i
i
322 V Handheld Devices
3.3.2 #define in GLSL
During production of this demo, it became apparent that using Booleans for
if and if-else statements in vertex and fragment shaders resulted in at least an
extra cycle for each decision point. This quickly became an issue because simple
shaders that were covering large portions of the screen, such as the skybox, were
processing needless cycles. Rolling out the code into a number of nearly identical
shader files would provide a way around this issue, but would cause a lot of code
duplication. To allow single shader files to be used repeatedly for multiple code
paths, the #define preprocessor directive was used with #ifdef and #else in
shader files so that code paths could be specified during compilation-time instead
of at runtime.
The SDK allows this when using the method PVRTShaderLoadFromFile()
by providing inputs for the additional parameters aszDefineArray and
uiDefArraySize, where aszDefineArray is a pointer to an array of strings hold-
ing defines the user wants to append and uiDefArraySize is the number of defines
in the array. This method automatically provides the #define and new-line char-
acter that need to be appended to the source code for each define, so the user
only needs to provide an array of strings for the names, e.g., A USEFUL DEFINE.
Once a number of shaders have been loaded in this way, the shader used for
an object can be changed during runtime to a shader with a different code path.
Although this method creates a shader for each decision path (which uses more
memory, but would also have been done if the code was rolled out in different
files), it allows the performance of shaders to be improved by removing redundant
cycles.
3.3.3 Further Optimizations/Improvements
Normalization cube map. On some hardware, the vector normalize() operation is
costly and a texture lookup may be cheaper. On such platforms, normalization on
a three-dimensional vector can be performed using a lookup to a normalization
cube map. For demonstration purposes, the method of generating the normal
map has been left in the code of this example, but time spent initializing the
application could be saved by loading a preexisting normalization map instead.
The theory behind this method is simple; take a directional vector as the
texture coordinate of the lookup and return the color at that position. This
color represents the normalized value of any directional vector that points to its
position. As the value retrieved using this technique is in texture space [0, 1], a
conversion into normal-space [1, 1] is required. On the development platform,
this method approximately halved the number of cycles required to normalize a
vector.
Scale water distortion. Without scaling the amount of distortion that is applied
to each fragment, water in the distance can ultimately sample the reflection and
i
i
i
i
i
i
i
i
3. Shader-Based Water Effects 323
refraction textures at too large an offset, which gives water in the distance an un-
realistic degree of distortion. Additionally, the bigger offset for distant fragments
results in a higher amount of texture-read cache misses.
By scaling the amount of distortion that is applied to a given fragment, the
visual quality of the effect can be improved and the number of stall cycles caused
by texture cache misses can be reduced. This is done in the demo by dividing the
wave’s distortion value by the distance between the camera and the fragment’s
position (so fragments further from the camera are distorted less). The extra cycle
cost has a minimal impact on performance (less than 1% on the test hardware)
because, even though the texture-read stalls are reduced, they still account for
the main bottleneck.
Render the water effect to a texture. Because of the heavy use of the fragment
shader to produce the effect, the demo tends to be fragment limited on most
hardware. To reduce this bottleneck, the water effect can be rendered to a texture
at a lower resolution and then applied to the water plane during the final render
pass. This technique benefits the speed of the demonstration by reducing the
number of fragments that are rendered using the water effect. This can be further
reduced (especially on a TBDR) by rendering objects that will obscure areas of
the water in the final render pass, such as the demo’s terrain. Although the
introduction of numerous objects to the render can improve the speed of the
water effect, the inaccuracies caused by mapping the texture to the final water
plane can result in artifacts around the edges of models that were used during
the low-resolution pass. Such artifacts are generally not that noticeable, provided
that the shaders used for the additional objects in the low-resolution pass are the
same as those used in the final render (i.e., rendering geometry without lighting
during the low-resolution pass will cause highlights around dark edges of models
in the final pass, so this should be avoided). One of the best ways to steer
clear of the problems caused by the scaling is to avoid drawing objects that are
very detailed around their edges that overlap the water because this reduces the
likelihood of artifacts occurring. In the demo, the boat is omitted from the water’s
render pass because it is too detailed to be rendered without causing artifacts
and does not afford as great a benefit as the terrain when covering areas of the
water.
When rendering to a texture at a 256 × 256 resolution and performing the
final render pass to a 640 × 480 screen, the reduction in quality is only slightly
noticeable, but on the test hardware the performance level is increased by 18%.
Removing artifacts at the water’s edge. One of the biggest problems with shader
effects that perturb texture coordinates is the lack of control over the end texel
that is chosen. Due to the clipping that is implemented in the reflection and
refraction render passes, it is very easy for artifacts to appear along the edges
of objects intersecting the water plane. The occurrence of artifacts occurs when
i
i
i
i
i
i
i
i
324 V Handheld Devices
Figure 3.15. Full effect using artifact fix.
the sampled texel is taken from behind the object intersecting the water, which
results in the texture sample being either the clear color, or geometry that ought
to be obscured, resulting in visible seams near the water’s edge. The edge artifact
can be seen in Figure 3.8. To compensate, the clip-plane location is set slightly
above the water surface (a small offset along the positive y-axis). In the case of
the refraction render pass, such an offset will cause some of the geometry above
the water to be included in the rendered image, which helps to hide the visible
seams by sampling from this above-the-water geometry.
Although another inaccuracy is introduced because of the deliberately im-
perfect clipping, it is barely noticeable, and the effect of the original artifact is
effectively removed for very little additional computation. The same benefit ap-
plies to the reflected scene, although in this case the offset direction is reversed,
and clipping occurs slightly below the water. Figure 3.15 shows the scene with
the artifact fix in place.
Another way to compensate for the artifacts, and improve the aesthetics of
the effect, is to use fins or particle effects along the edges of objects intersecting
the water to give the appearance of a wake where the water is colliding with the
objects. The drawback of these techniques is that they both require the program
to know where in the scene objects are intersecting the water, which can be very
expensive if the water height is changing or objects in the water are moving
dynamically.
i
i
i
i
i
i
i
i
3. Shader-Based Water Effects 325
3.4 Conclusion
We have presented a technique that allows a water effect to be augmented onto
a simple plane, using several render passes, some simple distortion, and texture
mixing in the fragment shader. Additionally, we have presented optimal tech-
niques for user-defined clip planes, normalization, removing artifacts caused by
texture-coordinate perturbation, and have also highlighted the benefits of utiliz-
ing low-resolution render passes to reduce the fragment shader workload. The
result is a high-performance example with extremely compelling visual results.
Though this example targets the current low-cost OpenGL ES 2.0 capable de-
vices, it can be correspondingly scaled to take advantage of higher resolution
displays and increased GPU power.
Bibliography
[PowerVR 10] Imagination Technologies. “POWERVR SGX OpenGL ES 2.0 Applica-
tion Development Recommendations.” www.imgtec.com/.../POWERVR%20SGX.
OpenGL%20ES%202.0%20Application%20Development%20Recommendations,
2010.
[Feneny 03] Simon Fenney, “Texture Compression using Low-Frequency Signal Modu-
lation.” In Proceedings Graphics Hardware, pp. 84–91. New York: ACM, 2003.
[Lengyel 04] Eric Lengyel. “Modifying the Projection Matrix to Perform Oblique Near-
plane Clipping.” Terathon Software 3D Graphics Library, 2004. Available at http:
//www.terathon.com/code/oblique.html.
[Pelzer 04] Kurt Pelzer. “Advanced Water Effects.” In ShaderX
2
. Plano, TX: Wordware
Publishing, Inc, 2004.
i
i
i
i
i
i
i
i
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.255.55