[692] | 1 | @node Shadows
|
---|
| 2 | @chapter Shadows
|
---|
| 3 | Shadows are clearly an important part of rendering a believable scene - they provide a more tangible feel to the objects in the scene, and aid the viewer in understanding the spatial relationship between objects. Unfortunately, shadows are also one of the most challenging aspects of 3D rendering, and they are still very much an active area of research. Whilst there are many techniques to render shadows, none is perfect and they all come with advantages and disadvantages. For this reason, Ogre provides multiple shadow implementations, with plenty of configuration settings, so you can choose which technique is most appropriate for your scene.@*@*
|
---|
| 4 |
|
---|
| 5 | Shadow implementations fall into basically 2 broad categories: @ref{Stencil Shadows} and @ref{Texture-based Shadows}. This describes the method by which the shape of the shadow is generated. In addition, there is more than one way to render the shadow into the scene: @ref{Modulative Shadows}, which darkens the scene in areas of shadow, and @ref{Additive Light Masking} which by contrast builds up light contribution in areas which are not in shadow. Ogre supports all these combinations.@*@*
|
---|
| 6 |
|
---|
| 7 | @subheading Enabling shadows
|
---|
| 8 | Shadows are disabled by default, here's how you turn them on and configure them in the general sense:
|
---|
| 9 | @enumerate
|
---|
| 10 | @item
|
---|
| 11 | Enable a shadow technique on the SceneManager as the @strong{first} thing you doin your scene setup. It is important that this is done first because the shadow technique can alter the way meshes are loaded. Here's an example:
|
---|
| 12 | @example
|
---|
| 13 | mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
|
---|
| 14 | @end example
|
---|
| 15 | @item
|
---|
| 16 | Create one or more lights. Note that not all light types are necessarily supported by all shadow techniques, you should check the sections about each technique to check. Note that if certain lights should not cast shadows, you can turn that off by calling setCastShadows(false) on the light, the default is true.
|
---|
| 17 | @item
|
---|
| 18 | Disable shadow casting on objects which should not cast shadows. Call setCastShadows(false) on objects you don't want to cast shadows, the default for all objects is to cast shadows.
|
---|
| 19 | @item
|
---|
| 20 | Configure shadow far distance. You can limit the distance at which shadows are considered for performance reasons, by calling SceneManager::setShadowFarDistance.
|
---|
| 21 | @item
|
---|
| 22 | Turn off the receipt of shadows on materials that should not receive them. You can turn off the receipt of shadows (note, not the casting of shadows - that is done per-object) by calling Material::setReceiveShadows or using the receive_shadows material attribute. This is useful for materials which should be considered self-illuminated for example. Note that transparent materials are typically excluded from receiving and casting shadows, although see the @ref{transparency_casts_shadows} option for exceptions.
|
---|
| 23 | @end enumerate
|
---|
| 24 |
|
---|
| 25 | @subheading Opting out of shadows
|
---|
| 26 | By default Ogre treats all non-transparent objects as shadow casters and receivers (depending on the shadow technique they may not be able to be both at once, check the docs for your chosen technique first). You can disable shadows in various ways:
|
---|
| 27 | @table @asis
|
---|
| 28 | @item Turning off shadow casting on the light
|
---|
| 29 | Calling Light::setCastsShadows(false) will mean this light casts no shadows at all.
|
---|
| 30 | @item Turn off shadow receipt on a material
|
---|
| 31 | Calling Material::setReceiveShadows(false) will prevent any objects using this material from receiving shadows.
|
---|
| 32 | @item Turn off shadow casting on individual objects
|
---|
| 33 | Calling MovableObject::setCastsShadows(false) will disable shadow casting for this object.
|
---|
| 34 | @item Turn off shadows on an entire rendering queue group
|
---|
| 35 | Calling RenderQueueGroup::setShadowsEnabled(false) will turn off both shadow casting and receiving on an entire rendering queue group. This is useful because Ogre has to do light setup tasks per group in order to preserve the inter-group ordering. Ogre automatically disables shadows on a number of groups automatically, such as RENDER_QUEUE_BACKGROUND, RENDER_QUEUE_OVERLAY, RENDER_QUEUE_SKIES_EARLY and RENDER_QUEUE_SKIES_LATE. If you choose to use more rendering queues (and by default, you won't be using any more than this plus the 'standard' queue, so ignore this if you don't know what it means!), be aware that each one can incur a light setup cost, and you should disable shadows on the additional ones you use if you can.
|
---|
| 36 | @end table
|
---|
| 37 |
|
---|
| 38 | @node Stencil Shadows
|
---|
| 39 | @section Stencil Shadows
|
---|
| 40 |
|
---|
| 41 | Stencil shadows are a method by which a 'mask' is created for the screen using a feature called the stencil buffer. This mask can be used to exclude areas of the screen from subsequent renders, and thus it can be used to either include or exclude areas in shadow. They are enabled by calling SceneManager::setShadowTechnique with a parameter of either @code{SHADOWTYPE_STENCIL_ADDITIVE} or @code{SHADOWTYPE_STENCIL_MODULATIVE}. Because the stencil can only mask areas to be either 'enabled' or 'disabled', stencil shadows have 'hard' edges, that is to say clear dividing lines between light and shadow - it is not possible to soften these edges.@*@*
|
---|
| 42 |
|
---|
| 43 | In order to generate the stencil, 'shadow volumes' are rendered by extruding the silhouette of the shadow caster away from the light. Where these shadow volumes intersect other objects (or the caster, since self-shadowing is supported using this technique), the stencil is updated, allowing subsequent operations to differentiate between light and shadow. How exactly this is used to render the shadows depends on whether @ref{Modulative Shadows} or @ref{Additive Light Masking} is being used. Objects can both cast and receive stencil shadows, so self-shadowing is possible. @*@*
|
---|
| 44 |
|
---|
| 45 | There are a number of issues to consider which are specific to stencil shadows:
|
---|
| 46 | @itemize @bullet
|
---|
| 47 | @item @ref{CPU Overhead}
|
---|
| 48 | @item @ref{Extrusion distance}
|
---|
| 49 | @item @ref{Camera far plane positioning}
|
---|
| 50 | @item @ref{The Silhouette Edge}
|
---|
| 51 | @item @ref{Be realistic}
|
---|
| 52 | @item @ref{Stencil Optimisations Performed By Ogre}
|
---|
| 53 | @end itemize
|
---|
| 54 |
|
---|
| 55 | @anchor{CPU Overhead}
|
---|
| 56 | @subheading CPU Overhead
|
---|
| 57 | Calculating the shadow volume for a mesh can be expensive, and it has to be done on the CPU, it is not a hardware accelerated feature. Therefore, you can find that if you overuse this feature, you can create a CPU bottleneck for your application. Ogre quite aggressively eliminates objects which cannot be casting shadows on the frustum, but there are limits to how much it can do, and large, elgongated shadows (e.g. representing a very low sun position) are very difficult to cull efficiently. Try to avoid having too many shadow casters around at once, and avoid long shadows if you can. Also, make use of the 'shadow far distance' parameter on the SceneManager, this can eliminate distant shadow casters from the shadow volume construction and save you some time, at the expense of only having shadows for closer objects. Lastly, make use of Ogre's Level-Of-Detail (LOD) features; you can generate automatically calculated LODs for your meshes in code (see the Mesh API docs) or when using the mesh tools such as OgreXmlConverter and OgreMeshUpgrader. Alternatively, you can assign your own manual LODs by providing alternative mesh files at lower detail levels. Both methods will cause the shadow volume complexity to decrease as the object gets further away, which saves you valuable volume calculation time.
|
---|
| 58 |
|
---|
| 59 | @anchor{Extrusion distance}
|
---|
| 60 | @subheading Extrusion distance
|
---|
| 61 | When vertex programs are not available, Ogre can only extrude shadow volumes a finite distance from the object. If an object gets too close to a light, any finite extrusion distance will be inadequate to guarantee all objects will be shadowed properly by this object. Therefore, you are advised not to let shadow casters pass too close to light sources if you can avoid it, unless you can guarantee that your target audience will have vertex program capable hardware (in this case, Ogre extrudes the volume to infinity using a vertex program so the problem does not occur).@*@*
|
---|
| 62 | When infinite extrusion is not possible, Ogre uses finite extrusion, either derived from the attenuation range of a light (in the case of a point light or spotlight), or a fixed extrusion distance set in the application in the case of directional lights. To change the directional light extrustion distance, use SceneManager::setShadowDirectionalLightExtrusionDistance.
|
---|
| 63 |
|
---|
| 64 | @anchor{Camera far plane positioning}
|
---|
| 65 | @subheading Camera far plane positioning
|
---|
| 66 | Stencil shadow volumes rely very much on not being clipped by the far plane. When you enable stencil shadows, Ogre internally changes the far plane settings of your cameras such that there is no far plane - ie it is placed at infinity (Camera::setFarClipDistance(0)). This avoids artefacts caused by clipping the dark caps on shadow volumes, at the expense of a (very) small amount of depth precision.
|
---|
| 67 |
|
---|
| 68 | @anchor{The Silhouette Edge}
|
---|
| 69 | @subheading The Silhouette Edge
|
---|
| 70 | Stencil shadowing is about finding a silhouette of the mesh, and projecting it away to form a volume. What this means is that there is a definite boundary on the shadow caster between light and shadow; a set of edges where where the triangle on one side is facing toward the light, and one is facing away. This produces a sharp edge around the mesh as the transition occurs. Provided there is little or no other light in the scene, and the mesh has smooth normals to produce a gradual light change in its underlying shading, the silhouette edge can be hidden - this works better the higher the tesselation of the mesh. However, if the scene includes ambient light, then the difference is far more marked. This is especially true when using @ref{Modulative Shadows}, because the light contribution of each shadowed area is not taken into account by this simplified approach, and so using 2 or more lights in a scene using modulative stencil shadows is not advisable; the silhouette edges will be very marked. Additive lights do not suffer from this as badly because each light is masked individually, meaning that it is only ambient light which can show up the silhouette edges.
|
---|
| 71 |
|
---|
| 72 | @anchor{Be realistic}
|
---|
| 73 | @subheading Be realistic
|
---|
| 74 | Don't expect to be able to throw any scene using any hardware at the stencil shadow algorithm and expect to get perfect, optimum speed results. Shadows are a complex and expensive technique, so you should impose some reasonable limitations on your placing of lights and objects; they're not really that restricting, but you should be aware that this is not a complete free-for-all.
|
---|
| 75 | @itemize @bullet
|
---|
| 76 | @item Try to avoid letting objects pass very close (or even through) lights - it might look nice but it's one of the cases where artefacts can occur on machines not cabable of running vertex programs.
|
---|
| 77 | @item Be aware that shadow volumes do not respect the 'solidity' of the objects they pass through, and if those objects do not themselves cast shadows (which would hide the effect) then the result will be that you can see shadows on the other side of what should be an occluding object.
|
---|
| 78 | @item Make use of SceneManager::setShadowFarDistance to limit the number of shadow volumes constructed
|
---|
| 79 | @item Make use of LOD to reduce shadow volume complexity at distance
|
---|
| 80 | @item Avoid very long (dusk and dawn) shadows - they exacerbate other issues such as volume clipping, fillrate, and cause many more objects at a greater distance to require volume construction.
|
---|
| 81 | @end itemize
|
---|
| 82 | @*@*
|
---|
| 83 |
|
---|
| 84 | @anchor{Stencil Optimisations Performed By Ogre}
|
---|
| 85 | @subheading Stencil Optimisations Performed By Ogre
|
---|
| 86 | Despite all that, stencil shadows can look very nice (especially with @ref{Additive Light Masking}) and can be fast if you respect the rules above. In addition, Ogre comes pre-packed with a lot of optimisations which help to make this as quick as possible. This section is more for developers or people interested in knowing something about the 'under the hood' behaviour of Ogre.
|
---|
| 87 | @table @asis
|
---|
| 88 | @item Vertex program extrusion
|
---|
| 89 | As previously mentioned, Ogre performs the extrusion of shadow volumes in hardware on vertex program-capable hardware (e.g. GeForce3, Radeon 8500 or better). This has 2 major benefits; the obvious one being speed, but secondly that vertex programs can extrude points to infinity, which the fixed-function pipeline cannot, at least not without performing all calculations in software. This leads to more robust volumes, and also eliminates more than half the volume triangles on directional lights since all points are projected to a single point at infinity.
|
---|
| 90 | @item Scissor test optimisation
|
---|
| 91 | Ogre uses a scissor rectangle to limit the effect of point / spot lights when their range does not cover the entire viewport; that means we save fillrate when rendering stencil volumes, especially with distant lights
|
---|
| 92 | @item Z-Pass and Z-Fail algorithms
|
---|
| 93 | The Z-Fail algorithm, often attributed to John Carmack, is used in Ogre to make sure shadows are robust when the camera passes through the shadow volume. However, the Z-Fail algorithm is more expensive than the traditional Z-Pass; so Ogre detects when Z-Fail is required and only uses it then, Z-Pass is used at all other times.
|
---|
| 94 | @item 2-Sided stencilling and stencil wrapping
|
---|
| 95 | Ogre supports the 2-Sided stencilling / stencil wrapping extensions, which when supported allow volumes to be rendered in a single pass instead of having to do one pass for back facing tris and another for front-facing tris. This doesn't save fillrate, since the same number of stencil updates are done, but it does save primitive setup and the overhead incurred in the driver every time a render call is made.
|
---|
| 96 | @item Agressive shadow volume culling
|
---|
| 97 | Ogre is pretty good at detecting which lights could be affecting the frustum, and from that, which objects could be casting a shadow on the frustum. This means we don't waste time constructing shadow geometry we don't need. Setting the shadow far distance is another important way you can reduce stencil shadow overhead since it culls far away shadow volumes even if they are visible, which is beneficial in practice since you're most interested in shadows for close-up objects.
|
---|
| 98 | @end table
|
---|
| 99 |
|
---|
| 100 |
|
---|
| 101 | @node Texture-based Shadows
|
---|
| 102 | @section Texture-based Shadows
|
---|
| 103 |
|
---|
| 104 | Texture shadows involve rendering shadow casters from the point of view of the light into a texture, which is then projected onto shadow casters while rendering the standard view. The main advantage of texture shadows as opposed to @ref{Stencil Shadows} is that the overhead of increasing the geometric detail is far lower, since there is no need to perform per-triangle calculations. Most of the work in rendering texture shadows is done by the graphics card, meaning the technique scales well when taking advantage of the latest cards, which are at present outpacing CPUs in terms of their speed of development.@*@*
|
---|
| 105 |
|
---|
| 106 | The main disadvantage to texture shadows is that, because they are simply a texture, they have a fixed resolution which means if stretched, the pixellation of the texture becomes obvious. Filtering can reduce this, but the problem still remains. In addition, because these shadows require a render to texture in the direction of the light, omnidirectional lights (point lights) would require 8 renders to totally cover all the directions shadows might be cast. For this reason, Ogre only supports directional lights and spotlights for generating texture shadows; you should turn off shadow casting for point lights if you're using texture shadows.@*@*
|
---|
| 107 |
|
---|
| 108 | @subheading Directional Lights
|
---|
| 109 | Directional lights in theory shadow the entire scene from an infinitely distant light. Now, since we only have a finite texture which will look very poor quality if stretched over the entire scene, clearly a simplification is required. Ogre places a shadow texture over the area immediately in front of the camera, and moves it as the camera moves (although it rounds this movement to multiples of texels so that the slight 'swimming shadow' effect caused by moving the texture is minimised). The range to which this shadow extends, and the offset used to move it in front of the camera, are configurable (@xref{Configuring Texture Shadows}). At the far edge of the shadow, Ogre fades out the shadow based on other configurable parameters so that the termination of the shadow is softened.
|
---|
| 110 |
|
---|
| 111 | @subheading Spotlights
|
---|
| 112 | Spotlights are much easier to represent as renderable shadow textures than directional lights, since they are naturally a frustum. Ogre represents spotlight directly by rendering the shadow from the light position, in the direction of the light cone; the field-of-view of the texture camera is adjusted based on the spotlight falloff angles. In addition, to hide the fact that the shadow texture is square and has definite edges which could show up outside the spotlight, Ogre uses a second texture unit when projecting the shadow onto the scene which fades out the shadow gradually in a projected circle around the spotlight.
|
---|
| 113 |
|
---|
| 114 | @subheading Shadow Casters and Shadow Receivers
|
---|
| 115 | To enable texture shadows, use the shadow technique SHADOWTYPE_TEXTURE_MODULATIVE or SHADOWTYPE_TEXTURE_ADDITIVE; as the name suggests this produces @ref{Modulative Shadows} or @ref{Additive Light Masking} respectively. Because the texture is merely projected onto shadow casters, a shadow caster cannot also be a shadow receiver, so self-shadowing is not possible using this method (there is an alternative method called depth shadowmapping which can do this using similar techniques as modulative shadow textures, but these are not supported by Ogre yet).@*@*
|
---|
| 116 | Ogre divides shadow casters and receivers into 2 disjoint groups. Simply by turning off shadow casting on an object, you automatically make it a shadow receiver (although this can be disabled by setting the 'receive_shadows' option to 'false' in a material script. Similarly, if an object is set as a shadow caster, it cannt receive shadows. If you need more complex shadowing you would be advised to look at @ref{Stencil Shadows}, but this simplified approach can work well in a lot of situations for a pretty low cost.
|
---|
| 117 |
|
---|
| 118 | @anchor{Configuring Texture Shadows}
|
---|
| 119 | @heading Configuring Texture Shadows
|
---|
| 120 | There are a number of settings which will help you configure your texture-based shadows so that they match your requirements.
|
---|
| 121 |
|
---|
| 122 | @itemize bullet
|
---|
| 123 | @item @ref{Maximum number of shadow textures}
|
---|
| 124 | @item @ref{Shadow texture size}
|
---|
| 125 | @item @ref{Shadow far distance}
|
---|
| 126 | @item @ref{Shadow texture offset (Directional Lights)}
|
---|
| 127 | @item @ref{Shadow fade settings}
|
---|
| 128 | @end itemize
|
---|
| 129 |
|
---|
| 130 | @anchor{Maximum number of shadow textures}
|
---|
| 131 | @subheading Maximum number of shadow textures
|
---|
| 132 | Shadow textures take up texture memory, and to avoid stalling the rendering pipeline Ogre does not reuse the same shadow texture for multiple lights within the same frame. This means that each light which is to cast shadows must have its own shadow texture. In practice, if you have a lot of lights in your scene you would not wish to incur that sort of texture overhead.@*@*
|
---|
| 133 | You can adjust this manually by simply turning off shadow casting for lights you do not wish to cast shadows. In addition, you can set a maximum limit on the number of shadow textures Ogre is allowed to use by calling SceneManager::setShadowTextureCount. Each frame, Ogre determines the lights which could be affecting the frustum, and then allocates the number of shadow textures it is allowed to use to the lights on a first-come-first-served basis. Any additional lights will not cast shadows that frame.
|
---|
| 134 | @*@*Note that you can set the number of shadow textures and their size at the same time by using the SceneManager::setShadowTextureSettings method; this is useful because both the individual calls require the potential creation / destruction of texture resources.
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 | @anchor{Shadow texture size}
|
---|
| 138 | @subheading Shadow texture size
|
---|
| 139 |
|
---|
| 140 | The size of the textures used for rendering the shadow casters into can be altered; clearly using larger textures will give you better quality shadows, but at the expense of greater memory usage. Changing the texture size is done by calling SceneManager::setShadowTextureSize - textures are assumed to be square and you must specify a texture size that is a power of 2. Be aware that each modulative shadow texture will take size*size*3 bytes of texture memory. @*@*
|
---|
| 141 | @strong{Important}: if you use the GL render system your shadow texture size cannot be larger (in either dimension) than the size of your primary window surface. That means that for window resolutions lower than 1280x1024 your maximum shadow texture size is 512. If you create a shadow texture larger than this, only the area the size of the primary window surface will be updated, causing severe shadowing artefacts. Direct3D does not suffer from this limitation, so if you intend to use Direct3D only you are free to use whatever shadow texture size you want, subject to texture memory constraints.
|
---|
| 142 |
|
---|
| 143 |
|
---|
| 144 | @anchor{Shadow far distance}
|
---|
| 145 | @subheading Shadow far distance
|
---|
| 146 |
|
---|
| 147 | This determines the distance at which shadows are terminated; it also determines how far into the distance the texture shadows for directional lights are stretched - by reducing this value, or increasing the texture size, you can improve the quality of shadows from directional lights at the expense of closer shadow termination or increased memory usage, respectively.
|
---|
| 148 |
|
---|
| 149 | @anchor{Shadow texture offset (Directional Lights)}
|
---|
| 150 | @subheading Shadow texture offset (Directional Lights)
|
---|
| 151 | As mentioned above in the directional lights section, the rendering of shadows for directional lights is an approximation that allows us to use a single render to cover a largeish area with shadows. This offset parameter affects how far from the camera position the center of the shadow texture is offset, as a proprtion of the shadow far distance. The greater this value, the more of the shadow texture is 'useful' to you since it's ahead of the camera, but also the further you offset it, the more chance there is of accidentally seeing the edge of the shadow texture at more extreme angles. You change this value by calling SceneManager::setShadowDirLightTextureOffset, the default is 0.6.
|
---|
| 152 |
|
---|
| 153 | @anchor{Shadow fade settings}
|
---|
| 154 | @subheading Shadow fade settings
|
---|
| 155 |
|
---|
| 156 | Shadows fade out before the shadow far distance so that the termination of shadow is not abrupt. You can configure the start and end points of this fade by calling the SceneManager::setShadowTextureFadeStart and SceneManager::setShadowTextureFadeEnd methods, both take distances as a proportion of the shadow far distance. Because of the inaccuracies caused by using a square texture and a radial fade distance, you cannot use 1.0 as the fade end, if you do you'll see artefacts at the extreme edges. The default values are 0.7 and 0.9, which serve most purposes but you can change them if you like.
|
---|
| 157 |
|
---|
| 158 | @heading Texture shadows and vertex / fragment programs
|
---|
| 159 | When rendering shadow casters into a modulative shadow texture, Ogre turns off all textures, and all lighting contributions except for ambient light, which it sets to the colour of the shadow (@ref{Shadow Colour}). For additive shadows, it render the casters into a black & white texture instead. This is enough to render shadow casters for fixed-function material techniques, however where a vertex program is used Ogre doesn't have so much control. If you use a vertex program in the @strong{first pass} of your technique, then you must also tell ogre which vertex program you want it to use when rendering the shadow caster; see @ref{Shadows and Vertex Programs} for full details.
|
---|
| 160 |
|
---|
| 161 |
|
---|
| 162 | @node Modulative Shadows
|
---|
| 163 | @section Modulative Shadows
|
---|
| 164 | Modulative shadows work by darkening an already rendered scene with a fixed colour. First, the scene is rendered normally containing all the objects which will be shadowed, then a modulative pass is done per light, which darkens areas in shadow. Finally, objects which do not receive shadows are rendered.@*@*
|
---|
| 165 |
|
---|
| 166 | There are 2 modulative shadow techniques; stencil-based (@xref{Stencil Shadows} : SHADOWTYPE_STENCIL_MODULATIVE) and texture-based (@xref{Texture-based Shadows} : SHADOWTYPE_TEXTURE_MODULATIVE). Modulative shadows are an inaccurate lighting model, since they darken the areas of shadow uniformly, irrespective of the amount of light which would have fallen on the shadow area anyway. However, they can give fairly attractive results for a much lower overhead than more 'correct' methods like @ref{Additive Light Masking}, and they also combine well with pre-baked static lighting (such as precalculated lightmaps), which additive lighting does not. The main thing to consider is that using multiple light sources can result in overly dark shadows (where shadows overlap, which intuitively looks right in fact, but it's not physically correct) and artefacts when using stencil shadows (@xref{The Silhouette Edge}). @*@*
|
---|
| 167 |
|
---|
| 168 | @anchor{Shadow Colour}
|
---|
| 169 | @subheading Shadow Colour
|
---|
| 170 | The colour which is used to darken the areas in shadow is set by SceneManager::setShadowColour; it defaults to a dark grey (so that the underlying colour still shows through a bit).@*@*
|
---|
| 171 |
|
---|
| 172 | @node Additive Light Masking
|
---|
| 173 | @section Additive Light Masking
|
---|
| 174 | Additive light masking is about rendering the scene many times, each time representing a single light contribution whose influence is masked out in areas of shadow. Each pass is combined with (added to) the previous one such that when all the passes are complete, all the light contribution has correctly accumulated in the scene, and each light has been prevented from affecting areas which it should not be able to because of shadow casters. This is an effective technique which results in very realistic looking lighting, but it comes at a price: more rendering passes.@*@*
|
---|
| 175 |
|
---|
| 176 | As many technical papers (and game marketing) will tell you, rendering realistic lighting like this requires multiple passes. Being a friendly sort of engine, Ogre frees you from most of the hard work though, and will let you use the exact same material definitions whether you use this lighting technique or not (for the most part, see @ref{Pass Classification and Vertex Programs}). In order to do this technique, Ogre automatically categorises the @ref{Passes} you define in your materials into 3 types:
|
---|
| 177 | @enumerate
|
---|
| 178 | @item ambient
|
---|
| 179 | Passes categorised as 'ambient' include any base pass which is not lit by any particular light, i.e. it occurs even if there is no ambient light in the scene. The ambient pass always happens first, and sets up the initial depth value of the fragments, and the ambient colour if applicable. It also includes any emissive / self illumination contribution. No textures are rendered in this pass.
|
---|
| 180 | @item diffuse/specular
|
---|
| 181 | Passes categorised as 'diffuse/specular' (or 'per-light') are rendered once per light, and each pass contributes the diffuse ans specular colour from that single light as reflected by the diffuse / specular terms in the pass. Areas in shadow from that light are masked and are thus not updated. The resulting masked colour is added to the exisiting colour in the scene. Again, no textures are used in this pass (except for textures used for lighting calculations such as normal maps).
|
---|
| 182 | @item decal
|
---|
| 183 | Passes categorised as 'decal' add the final texture colour to the scene, which is modulated by the accumulated light built up from all the ambient and diffuse/specular passes.
|
---|
| 184 | @end enumerate
|
---|
| 185 |
|
---|
| 186 | In practice, @ref{Passes} rarely fall nicely into just one of these categories. For each Technique, Ogre compiles a list of 'Illumination Passes', which are derived from the user defined passes, but can be split, to ensure that the divisions between illumination pass categories can be maintained. For example, if we take a very simple material definition:
|
---|
| 187 | @example
|
---|
| 188 | material TestIllumination
|
---|
| 189 | {
|
---|
| 190 | technique
|
---|
| 191 | {
|
---|
| 192 | pass
|
---|
| 193 | {
|
---|
| 194 | ambient 0.5 0.2 0.2
|
---|
| 195 | diffuse 1 0 0
|
---|
| 196 | specular 1 0.8 0.8 15
|
---|
| 197 | texture_unit
|
---|
| 198 | {
|
---|
| 199 | texture grass.png
|
---|
| 200 | }
|
---|
| 201 | }
|
---|
| 202 | }
|
---|
| 203 | }
|
---|
| 204 | @end example
|
---|
| 205 |
|
---|
| 206 | Ogre will split this into 3 illumination passes, which will be the equivalent of this:
|
---|
| 207 | @example
|
---|
| 208 | material TestIlluminationSplitIllumination
|
---|
| 209 | {
|
---|
| 210 | technique
|
---|
| 211 | {
|
---|
| 212 | // Ambient pass
|
---|
| 213 | pass
|
---|
| 214 | {
|
---|
| 215 | ambient 0.5 0.2 0.2
|
---|
| 216 | diffuse 0 0 0
|
---|
| 217 | specular 0 0 0
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | // Diffuse / specular pass
|
---|
| 221 | pass
|
---|
| 222 | {
|
---|
| 223 | scene_blend add
|
---|
| 224 | iteration once_per_light
|
---|
| 225 | diffuse 1 0 0
|
---|
| 226 | specular 1 0.8 0.8 15
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | // Decal pass
|
---|
| 230 | pass
|
---|
| 231 | {
|
---|
| 232 | scene_blend modulate
|
---|
| 233 | lighting off
|
---|
| 234 | texture_unit
|
---|
| 235 | {
|
---|
| 236 | texture grass.png
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 | }
|
---|
| 240 | }
|
---|
| 241 | @end example
|
---|
| 242 | So as you can see, even a simple material requires a minimum of 3 passes when using this shadow technique, and in fact it requires (num_lights + 2) passes in the general sense. You can use more passes in your original material and Ogre will cope with that too, but be aware that each pass may turn into multiple ones if it uses more than one type of light contribution (ambient vs diffuse/specular) and / or has texture units. The main nice thing is that you get the full multipass lighting behaviour even if you don't define your materials in terms of it, meaning that your material definitions can remain the same no matter what lighting approach you decide to use.@*@*
|
---|
| 243 |
|
---|
| 244 | @anchor{Pass Classification and Vertex Programs}
|
---|
| 245 | @subheading Pass Classification and Vertex Programs
|
---|
| 246 | Ogre is pretty good at classifying and splitting your passes to ensure that the multipass rendering approach required by additive lighting works correctly without you having to change your material definitions. However, there is one exception; when you use vertex programs, the normal lighting attributes ambient, diffuse, specular etc are not used, becuase all of that is determined by the vertex program. Ogre has no way of knowing what you're doing inside that vertex program, so you have to tell it.@*@*
|
---|
| 247 |
|
---|
| 248 | In practice this is very easy. Even though your vertex program could be doing a lot of complex, highly customised processing, it can still be classified into one of the 3 types listed above. All you need to do to tell Ogre what you're doing is to use the pass attributes ambient, diffuse, specular and self_illumination, just as if you were not using a vertex program. Sure, these attributes do nothing (as far as rendering is concerned) when you're using vertex programs, but it's the easiest way to indicate to Ogre which light components you're using in your vertex program. Ogre will then classify and potentially split your programmable pass based on this information - it will leave the vertex program as-is (so that any split passes will respect any vertex modification that is being done). @*@*
|
---|
| 249 |
|
---|
| 250 | Note that when classifying a diffuse/specular programmable pass, Ogre checks to see whether you have indicated the pass can be run once per light (iteration once_per_light). If so, the pass is left intact, including it's vertex and fragment programs. However, if this attribute is not included in the pass, Ogre tries to split off the per-light part, and in doing so it will disable the fragment program, since in the absence of the 'iteration once_per_light' attribute it can only assume that the fragment program is performing decal work and hence must not be used per light.@*@*
|
---|
| 251 |
|
---|
| 252 | So clearly, when you use additive light masking as a shadow technique, you need to make sure that programmable passes you use are properly set up so that they can be classified correctly. However, also note that the changes you have to make to ensure the classification is correct does not affect the way the material renders when you choose not to use additive lighting, so the principle that you should be able to use the same material definitions for all lighting scenarios still holds. Here is an example of a programmable material which will be classified correctly by the illumination pass classifier:
|
---|
| 253 | @example
|
---|
| 254 | // Per-pixel normal mapping Any number of lights, diffuse and specular
|
---|
| 255 | material Examples/BumpMapping/MultiLightSpecular
|
---|
| 256 | {
|
---|
| 257 |
|
---|
| 258 | technique
|
---|
| 259 | {
|
---|
| 260 | // Base ambient pass
|
---|
| 261 | pass
|
---|
| 262 | {
|
---|
| 263 | // ambient only, not needed for rendering, but as information
|
---|
| 264 | // to lighting pass categorisation routine
|
---|
| 265 | ambient 1 1 1
|
---|
| 266 | diffuse 0 0 0
|
---|
| 267 | specular 0 0 0 0
|
---|
| 268 | // Really basic vertex program
|
---|
| 269 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture
|
---|
| 270 | {
|
---|
| 271 | param_named_auto worldViewProj worldviewproj_matrix
|
---|
| 272 | param_named_auto ambient ambient_light_colour
|
---|
| 273 | }
|
---|
| 274 |
|
---|
| 275 | }
|
---|
| 276 | // Now do the lighting pass
|
---|
| 277 | // NB we don't do decal texture here because this is repeated per light
|
---|
| 278 | pass
|
---|
| 279 | {
|
---|
| 280 | // set ambient off, not needed for rendering, but as information
|
---|
| 281 | // to lighting pass categorisation routine
|
---|
| 282 | ambient 0 0 0
|
---|
| 283 | // do this for each light
|
---|
| 284 | iteration once_per_light
|
---|
| 285 |
|
---|
| 286 |
|
---|
| 287 | scene_blend add
|
---|
| 288 |
|
---|
| 289 | // Vertex program reference
|
---|
| 290 | vertex_program_ref Examples/BumpMapVPSpecular
|
---|
| 291 | {
|
---|
| 292 | param_named_auto lightPosition light_position_object_space 0
|
---|
| 293 | param_named_auto eyePosition camera_position_object_space
|
---|
| 294 | param_named_auto worldViewProj worldviewproj_matrix
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | // Fragment program
|
---|
| 298 | fragment_program_ref Examples/BumpMapFPSpecular
|
---|
| 299 | {
|
---|
| 300 | param_named_auto lightDiffuse light_diffuse_colour 0
|
---|
| 301 | param_named_auto lightSpecular light_specular_colour 0
|
---|
| 302 | }
|
---|
| 303 |
|
---|
| 304 | // Base bump map
|
---|
| 305 | texture_unit
|
---|
| 306 | {
|
---|
| 307 | texture NMBumpsOut.png
|
---|
| 308 | colour_op replace
|
---|
| 309 | }
|
---|
| 310 | // Normalisation cube map
|
---|
| 311 | texture_unit
|
---|
| 312 | {
|
---|
| 313 | cubic_texture nm.png combinedUVW
|
---|
| 314 | tex_coord_set 1
|
---|
| 315 | tex_address_mode clamp
|
---|
| 316 | }
|
---|
| 317 | // Normalisation cube map #2
|
---|
| 318 | texture_unit
|
---|
| 319 | {
|
---|
| 320 | cubic_texture nm.png combinedUVW
|
---|
| 321 | tex_coord_set 1
|
---|
| 322 | tex_address_mode clamp
|
---|
| 323 | }
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 | // Decal pass
|
---|
| 327 | pass
|
---|
| 328 | {
|
---|
| 329 | lighting off
|
---|
| 330 | // Really basic vertex program
|
---|
| 331 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture
|
---|
| 332 | {
|
---|
| 333 | param_named_auto worldViewProj worldviewproj_matrix
|
---|
| 334 | param_named ambient float4 1 1 1 1
|
---|
| 335 | }
|
---|
| 336 | scene_blend dest_colour zero
|
---|
| 337 | texture_unit
|
---|
| 338 | {
|
---|
| 339 | texture RustedMetal.jpg
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | }
|
---|
| 343 | }
|
---|
| 344 | }
|
---|
| 345 | @end example
|
---|
| 346 |
|
---|
| 347 | At present only one shadow technique supports additive light masking: @ref{Stencil Shadows} through the use of SHADOWTYPE_STENCIL_ADDITIVE.
|
---|
| 348 |
|
---|
| 349 | @subheading Static Lighting
|
---|
| 350 | Despite their power, additive lighting techniques have an additional limitation; they do not combine well with pre-calculated static lighting in the scene. This is because they are based on the principle that shadow is an absence of light, but since static lighting in the scene already includes areas of light and shadow, additive lighting cannot remove light to create new shadows. Therefore, if you use the additive lighting technique you must use it exclusively as your lighting solution (and you can combine it with per-pixel lighting to create a very impressive dynamic lighting solution), you cannot combine it with static lighting.
|
---|
| 351 |
|
---|
| 352 |
|
---|