When developing 3D graphics applications, one of the recurrent challenges that plagues developers is balancing great graphics with end-user compatibility and reach. The more complex the graphics techniques utilized by the application, the fewer end-users will be able to actually run the software. With the explosion of mobile technology on slow and low-power hardware, 3D graphics are even further limited than they were years before.
In order to achieve a compromise between compatibility and graphics quality, a technique called Shader Fallback enables developers to switch to lower-quality graphics when necessary. This enables users with high-powered PCs to run the software at its maximum specifications, while simultaneously providing users on slim hardware with functional access the content and interface of the application.
Hardware graphics shaders are small, high-intensity programs that run directly on the graphics card and provide a framework for drawing 3D models and scenes. Hardware shaders bring high quality real-time graphics to 3D applications. These shaders often incorporate lighting, texture maps, normal maps, and height maps to bring a high level of realism to 3D models. As an example, old or low-power graphics cards might only support Shader Model 2.0 with a limit of 96 instructions per pixel shader. Although this can suffice for simple graphics techniques like normal maps with a minimal set of lights, advanced algorithms require much more code to create a realistic image.
Fortunately, the actual implementation of Shader Fallback is relatively easy; most of the work is in the shader development itself. Ideal graphics fallback will consist of the development of different shaders per targeted shader model. For instance, an application optimized for a wide variety of users might have separate shaders built for Shader Models 4.0, 3.0, and 2.0. Then, during load of a specific material, the following code would enable Shader Fallback:
if (scene.device.Capabilities.PixelShaderVersion.Major >= 4){
shaderpath = "[Pixel Shader 4.0 File Path]";
}
else {
//Show error or fallback to simple shader based on graphics hardware support
if (!NotifyBadGraphics) {
System.Windows.Forms.MessageBox.Show("Please upgrade to the latest graphics hardware in order to for best quality graphics. Pixel shader 4 or higher recommended. Current Pixel Shader version: " + (scene.device.Capabilities.PixelShaderVersion.ToString()));
NotifyBadGraphics = true;
}
if ((scene.device.Capabilities.PixelShaderVersion.Major >= 3) && (scene.device.Capabilities.MaxPShaderInstructionsExecuted >= 512))
shaderpath = "[Pixel Shader 3.0 File Path]";
else
shaderpath = "[Pixel Shader 2.0 File Path]";
}
effect = Effect.FromFile(scene.device, shaderpath, ShaderFlags.None);
Instead of simply loading the Effect from the file, the program first checks the capabilities of the graphics card, and then loads the best quality shader available that will run on the client’s graphics hardware. In addition, if the lower quality shaders are particularly limiting, the software will display a message to the user that more advanced graphics hardware would provide a better experience. This code is particularly effective when implemented as a Proxy pattern, which we will cover in the upcoming series on C# Software Design Patterns.
By integrating Shader Fallback, graphics software can cast a wider net and provide functionality to a larger user base. Instead of requiring developers to choose between compatibility and graphics quality, Shader Fallback lets 3D software have the best of both worlds.
Written by Andrew Palczewski
About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+