Information About

Vertex And Pixel Shaders




A shader is a Program executed concurrently (with other shaders) by multiple graphic processors running in parallel on a Video Card . This scalable Multiprocessing architecture has been designed to combine the computational power of hardware parallelism with the flexibility of Software Rendering under the growing demands for quality graphics processing. The shaders are predominantly used in 3D Computer Graphics to determine the final surface properties of an object or image. This can include arbitrarily complex descriptions of Light Absorption and Diffusion , Texture Mapping , Reflection and Refraction , Shadow ing, surface Displacement and Post-processing effects. The increasing performance and programmability of the shader architecture attracts researchers for exploiting '''General-Purpose computation on GPUs''' ( GPGPU ). Because the scope of shaders is much more limited than general programs, they are usually written using a Shading Language , a specifically designed Programming Language .

Initially introduced in Pixar 's RenderMan , shaders acquired increasing momentum as the cost of computers lowered. The main benefit of using shaders is their great flexibility, resulting in faster and cheaper development time but also richer experience for the final user.

Programmable shaders are flexible and efficient. Seemingly complicated surfaces can be rendered from simple geometry. For example, a shader can be used to draw a grid of 3D ceramic tiles from a simple Plane .



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 Parameter s.

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 Batch es. This kind of variable is usually a 3-component Array but this does not need to be. Usually, only basic Datatype s are allowed to be loaded from external APIs so complex structures must be broken down. 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.


Vertex shader computations are meant to provide following stages of the graphics pipeline with Interpolable fragment attributes. Because of this, a vertex shader must output ''at least'' the transformed homogeneous vertex position (in GLSL this means the variable ''gl_Position'' must be written).
Outputs from different vertex shader invocations from the same batch will be linearly interpolated across the primitive being rendered. The result of this linear interpolation is fetched to the next pipeline stage.

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

Those kind of 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.


Branching on the pixel processor has also been introduced with an extended pixel shader 2 model but hardware supporting this efficiently is beginning to be commonplace only now ( 6 March 2006 ), usually with full pixel shader model 3 support.

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 Model s, 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


The functionality by itself continues to be applied "as usual" 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.

For final users, this extra flexibility results in both improved performance and richer content because of the better hardware utilization and resources.


Lighting and 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 referred as Bump Mapping . In this latter technique, vertex shaders are used to set up a vertex local space (also called ''tangent space'') 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. 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 Volume s 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

  • 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