Shader
Encyclopedia : S : SH : SHA : Shader
A shader is a computer program used in 3D computer graphics to determine the final surface properties of an object or image. This often includes arbitrarily complex descriptions of light absorption, diffusion, texture mapping, reflection, refraction, shadowing, surface displacement and post-processing effects.
By design, shaders are ideal candidates for parallel execution by multiple graphic processors, which are usually located on a video card, allowing for scalable multiprocessing and lessening the burden on the CPU for rendering scenes.
Because of the goals shaders are designed to address, they are usually written using a shading language, a specifically designed programming language built around the intrinsic strengths and weaknesses of the different computational model. Although limited in some ways when compared to traditional approaches, the parallel architecture exposed by shaders has been used to combine highly scalable processing power with the flexibility of programmable devices, which is a boon in addressing the growing demands for graphics quality.
The increasing performance and programmability of shader-based architectures attracted researchers trying to exploit the new parallel model for General Purpose computation on GPUs. This demonstrated that shaders could be used to process a large variety of information, and not just rendering-specific tasks. This new programming model, which resembles stream processing, allows high computational rates at extremely low cost that will operate on wide installed base (e.g. the common home PC).
Real-time Shader Structure
There are different approaches to shading, mainly because of the various applications of the targeted technology. Production shading languages are usually at a higher abstraction level, avoiding the need to write specific code to handle lighting or shadowing. In contrast, real-time shaders integrate light and shadowing computations. In those languages, the lights are passed to the shader itself as parameters.There are actually two different applications of shaders in real-time shading languages. Although the feature set actually converged (so it's possible to write a vertex shader using the same functions of a fragment shader), the different purposes of computation impose limitations to be acknowledged.
Vertex Shaders
Vertex shaders are applied for each vertex and run on a programmable vertex processor. Vertex shaders define a method to compute vector space transformations and other linearizable computations.A vertex shader expects various inputs:
- Uniform variables are constant values for each shader invocation. It is allowed to change the value of each uniform variable between different shader invocation batches. This kind of variable is usually a 3-component array but this does not need to be. Usually, only basic datatypes are allowed to be loaded from external APIs so complex structures must be broken down[#endnote_glslangUniforms]. Uniform variables can be used to drive simple conditional execution on a per-batch basis. Support for this kind of branching at a vertex level has been introduced in shader model 2.0.
- Vertex attributes, which are a special case of variant variables, which are essentially per-vertex data such as vertex positions. Most of the time, each shader invocation performs computation on different data sets. The external application usually does not access these variables "directly" but manages as large arrays. Besides this little detail, applications are usually capable of changing a single vertex attribute with ease. Branching on vertex attributes requires a finer degree of control which is supported with extended shader model 2.
Some examples of vertex shader's functionalities include arbitrary mesh deformation (possibly faking lens effects such as fish-eye) and vertex displacements in general, computing linearizable attributes for later pixel-shaders such as texture coordinate transformations. Actually, vertex shaders cannot create vertices.
Pixel Shaders
Pixel shaders are used to compute properties which, most of the time, are recognized as pixel colors.Pixel shaders are applied for each pixel. They are run on a pixel processor, which usually features much more processing power than its vertex-oriented counterpart. As of October 2005, some architectures are merging the two processors in a single one to increase transistor usage and provide some kind of load balancing.
As previously stated, the pixel shaders expects input from interpolated vertex values. This means there are three sources of information:
- Uniform variables can still be used and provide interesting opportunities. A typical example is passing an integer providing a number of lights to be processed and an array of light parameters. Textures are special cases of uniform values and can be applied to vertices as well, although vertex texturing is often more expensive.
- Varying attributes is a special name to indicate fragment's variant variables, which are the interpolated vertex shader output. Because of their origin, the application has no direct control on the actual value of those variables.
A fragment shader is allowed to discard the results of its computation, meaning that the corresponding framebuffer position must retain its actual value.
Fragment shaders also don't need to write specific color information because this is not always wanted. Not producing color output when expected however gives undefined results in GLSL.
Fragment shaders have been employed to apply accurate lighting models, simulate multi-layer surface properties, simulating natural phenomena such as turbulence (vector field simulations in general) and applying depth of field to a scene or other color-space transformations.
Texturing
Note: the following information on texture mapping with shaders applies specifically to GLSL. Those statements may not hold true for DirectX HLSL.The functionality by itself continues to be applied "as usual"[#endnote_multitexturing] with shading languages providing special ad-hoc functions and opaque objects.
It has been stated that textures are special uniform variables. The shading languages define special variables to be used as textures called samplers. Each sampler does have a specific lookup mode assigned explicitly in the name. Looking up a texture actually means to get an interpolated texel color at a specified position. For example, in GLSL sampler2D will access a specific texture performing bidimensional texturing and filtering to be used with a tex2D function call. Other details are specified by the function used to actually perform the lookup. For cube map textures, a samplerCube would be used with a textureCube function call.
Understanding completely the model also needs to know a little about the previous shading model, commonly referred as multitexturing or texture cascade. For our purposes, we'll just assume there is a limited set of units which can be linked to specific textures and somehow produce color results, possibly combining them in a sequential order. This is redundant with the new programming model which allows much greater flexibility.
To lookup to a specific texture, the sampler really needs to know what of those texture units needs to be used with the specified lookup mode. This means samplers are really integers referring to the texture unit used to carry on the lookup. It will now be possible to bind to each texture unit an image texture just as usual. It will happen that those units are actually a subset of "legacy" texture units and are referred as image units. Most implementation actually allow more image units than texture units because of the lower complexity to implement them but also to push for the new programming model. In short, samplers are really linked to image units, which are bound to textures[#endnote_glslangSamplers].
For final users, this extra flexibility results in both improved performance and richer content because of the better hardware utilization and resources.
Lighting & Shadowing
Considering the lighting equation, we have seen the trend to move evaluations to fragment granularity. Initially, the lighting computations were performed at vertex level (phong lighting model) but improvements in fragment processor designs allowed to evaluate much more complex lighting equations such as the blinn lighting model, often commonly referred as bump mapping (in this case however note the two terms are not technically synonimous but they are commonly used interchangeably because of wrong marketing issues). In this latter technique, vertex shaders are used to set up a vertex local space (also called tangent space)[#endnote_nvdeveloper] which is then used to compute per-pixel lighting vectors. The actual math for this can be quite involved and is beyond the scope of this article.It is well acknowledged that lighting really needs hardware support for dynamic loops (this is often referred as DirectX Pixel Shader Model 3.0) because this allows to process many lights of the same type with a single shader. By contrast, previous shading models would have need the application to use multi pass rendering (an expensive operation) because of the fixed loops. This approach would also have needed more complicated machinery. For example, after finding there are 13 "visible" lights, the application would have the need to use a shader to process 8 lights (suppose this is the upper hardware limitation) and another shader to process the remaining 5. If there are 7 lights the application would have needed a special 7-light shader. By contrast, with dynamic loops the application can iterate on dynamic variables thus defining a uniform array to be 13 (or 7) "lights long" and get correct results, provided this actually fits in hardware capabilities[#endnote_glslangResources]. At the time this is being written (27 October 2005) there are enough resources to evaluate over 50 lights per pass when resources are managed carefully. Compare this to old programming models.
Computing accurate shadows make this much more complicated, depending on the algorithm used. Compare stencil shadow volumes and shadow mapping. In the first case, the algorithm requires at least some care to be applied to multiple lights at once and there's no actual proof of a multi-light shadow volume based version. Shadow mapping by contrast seems to be much more well suited to future hardware improvements and to the new shading model which also evaluates computations at fragment level. Shadow maps however needs to be passed as samplers, which are limited resources: actual hardware (27 October 2005) support up to 16 samplers so this is a hard-limit, unless some tricks are used. It is speculated that future hardware improvements and packing multiple shadow maps in a single 3D-texture will rapidly raise this resource availability.
Further reading
- Steve Upstill: The RenderMan Companion: A Programmer's Guide to Realistic Computer Graphics, Addison-Wesley, ISBN 0-201-50868-0
- David S. Elbert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley: Texturing and modeling: a procedural approach, AP Professional, ISBN 0-12-228730-4. Ken Perlin is the author of Perlin noise, an important procedural texturing primitive.
- Randima Fernando, Mark Kilgard. The Cg Tutorial: The Definitive Guide to Programmable Real-Time Graphics, Addison-Wesley Professional, ISBN 0-32119-496-9
- Randi Rost: OpenGL Shading Language, Addison-Wesley Professional, ISBN 0-321-19789-5
References
- ↑ Search [ARB_shader_objects] for the issue "32) Can you explain how uniform loading works?". This is an example of how a complex data structure must be broken in basic data elements.
- ↑ Required machinery has been introduced in OpenGL by [ARB_multitexture] but this specification is no more available since its integration in core OpenGL 1.2.
- ↑ Search again [ARB_shader_objects] for the issue "25) How are samplers used to access textures?". You may also want to check out "Subsection 2.14.4 Samplers".
- ↑ Search [NVIDIA developer resources] for various papers on per-pixel lighting.
- ↑ You'll be glad to see those limits are (at least theorically) rather high. Check out [The OpenGL® Shading Language] for the string "52) How should resource limits for the shading language be defined?" and look for your favorite video card at [Delphi3d.net hardware database].
From Wikipedia, the Free Encyclopedia. Original article here. Support Wikipedia by contributing or donating.
All text is available under the terms of the GNU Free Documentation License See Wikipedia Copyrights for details.
