Material optimization: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Shader fallbacks)
Line 1: Line 1:
When working with materials, there are a couple performance bottlenecks to keep in mind: fillrate (which usually affects all DirectX levels), and reducing vertex processing (which only is a bottleneck on DirectX7). As a level designer, the only real choice that you've got to combat any of these performance bottlenecks is to either reduce the amount of a particular expensive material on screen, or to turn off some of the expensive features in the material (like bumpmapping, for example). Note that you can make different choices about which features to use at each separate DirectX support level.
{{toc-right}}


One other important aspect of dealing with performance bottlenecks is that you're going to have to measure framerates to see how well you're doing. For Half-Life 2, we used 3 target machines (determined based on looking at our hardware survey stats) for measuring performance at various DirectX levels. These were:
== Shader fallbacks ==
 
It goes without saying that not all PCs are equal. Your map will need to run on a wide range of specifications, and the best way of achieving acceptable performance at the low-end without sacrificing fidelity at the high-end is with [[shader]] fallbacks.
 
The good news is that Valve's stock materials are already set up with fallbacks, where appropriate, and in most cases you won't need to do any work in this area at all. The even better news is that if you ''do'' need to create a fallback, all of the hard work of benchmarking different hardware has already been done by Valve and all you need do is choose between a handful of coarse [[DirectX Versions|DirectX levels]].


{|
=== Usage ===
!DX (DirectX) Level || Minimum Platform
|-
| DX9 || ATI 9800, 1 GB, P4 3.0 GHz
|-
| DX8 || NVidia GeForce4 Ti4600, 512 MB, P4 2.0 GHz
|-
| DX7 || NVidia GeForce2 MX, 256MB, P4 1.2 GHz
|}


== Shader fallbacks ==
Shader fallbacks are parameters of the material like any other, and should go inside the material's original pair of curly braces (<code>{</code> and <code>}</code>).


Here's how you specify different material parameters for different DX support levels: Each shader has a specific fallback shader it uses if the shader determines it can't run on the particular DX level on the card currently being run. Within the definition of your material, you add a field with the same name as the fallback shader and a sub-block of fields which are the values of those fields that you want to use if that fallback shader is being used. A list of the most commonly used shaders and their fallback shaders is shown below.  
;Conditional statements
<dd><pre><dx90
{
<Sub-DX9 parameters>
}</pre></dd>
:This command applies its parameters only if its opening statement is true. Accepted operators are:
:*'''<code>></code>''' (above the value)
:*'''<code>>=</code>''' (above or equal to the value)
:*'''<code><</code>''' (below the value)
:*'''<code><=</code>''' (below or equal to the value)
:Accepted ''values'' are probably the same as those of [[mat_dxlevel]]; 70, 80, 81, 90, 95 and 98.
;Specific shaders
<dd><pre>LightmappedGeneric_HDR_DX9
{
<DX9 with HDR parameters>
}</pre></dd>
:While we might call 'top-level' shaders in the first line of our materials, actual rendering is passed down to one of several more specific members of the family. You can give commands that only apply to a single 'fallback shader' by passing its name as seen in the example above. [[Half-Life 2 Shader Fallbacks|There is a full list of fallback shaders here.]]


Here's an example:
=== Example ===


  LightmappedGeneric
  LightmappedGeneric
  {
  {
  $basetexture metal/metalwall063a
  $basetexture metal/metalwall078a
  $surfaceprop metal
  $surfaceprop metal
  $envmap env_cubemap
  $envmap env_cubemap
$envmaptint [ .56 .56 .75 ]
$envmapcontrast 1
$envmapsaturation 1
   
   
  LightmappedGeneric_DX9
  LightmappedGeneric_DX9
  {
  {
  $bumpmap metal/metalwall063a_normal
  $bumpmap metal/metalwall078a_normal
  $normalmapalphaenvmapmask 1
  $normalmapalphaenvmapmask 1
$envmaptint [ .09 .1 .12]
  }
  }
   
   
  LightmappedGeneric_DX8
  LightmappedGeneric_DX8
  {
  {
  $basetexture metal/citadel_metalwall063a
  $bumpmap metal/metalwall078a_normal
  $basealphaenvmapmask 1
  $nodiffusebumplighting 1
$normalmapalphaenvmapmask 1
  }
  }
   
   
  LightmappedGeneric_DX6
  LightmappedGeneric_NoBump_DX8
  {
  {
  $fallbackmaterial metal/metalwall063b
  $basetexture metal/citadel_metalwall078a
$basealphaenvmapmask 1
  }
  }
  }
  }


In this example, the <code>$envmap</code> field is used no matter what DirectX level the game is being run at. The <code>$basetexture</code> field <code>metal/metalwall063a</code> is used for every fallback shader except <code>LightmappedGeneric_dx8</code> (used for running under DX8), which uses <code>metal/citadel_metalwall063a</code> for its <code>$basetexture.</code> Also under DX8 only, we add a field specifying that the special base texture used by dx8 has an envmap mask in its alpha channel. When using the <code>LightmappedGeneric_DX9</code> shader (used by DX9), we add a bumpmap and specify that the envmap mask is in the alpha channel of the bumpmap. Note that it's also possible to cause the material system to use a completely different material with a totally different set of shaders by specifying a <code>$fallbackmaterial</code> in a fallback block, which is done in this example when falling back to the <code>LightmappedGeneric_DX6</code> shader (used by DX7 and DX6).
(This material was created before conditionals were added, so is not future-proof: systems running HDR_DX9 and, eventually, DX10, will not see bump maps. However, this works in our favour when dropping back to DX7.)
 
For a listing of all of the fallback shaders used in Half-Life 2, see the document [[Half-Life 2 Shader Fallbacks]].


== Overdraw ==
== Overdraw ==

Revision as of 09:18, 17 September 2008

Shader fallbacks

It goes without saying that not all PCs are equal. Your map will need to run on a wide range of specifications, and the best way of achieving acceptable performance at the low-end without sacrificing fidelity at the high-end is with shader fallbacks.

The good news is that Valve's stock materials are already set up with fallbacks, where appropriate, and in most cases you won't need to do any work in this area at all. The even better news is that if you do need to create a fallback, all of the hard work of benchmarking different hardware has already been done by Valve and all you need do is choose between a handful of coarse DirectX levels.

Usage

Shader fallbacks are parameters of the material like any other, and should go inside the material's original pair of curly braces ({ and }).

Conditional statements
<dx90
{
	<Sub-DX9 parameters>
}
This command applies its parameters only if its opening statement is true. Accepted operators are:
  • > (above the value)
  • >= (above or equal to the value)
  • < (below the value)
  • <= (below or equal to the value)
Accepted values are probably the same as those of mat_dxlevel; 70, 80, 81, 90, 95 and 98.
Specific shaders
LightmappedGeneric_HDR_DX9
{
	<DX9 with HDR parameters>
}
While we might call 'top-level' shaders in the first line of our materials, actual rendering is passed down to one of several more specific members of the family. You can give commands that only apply to a single 'fallback shader' by passing its name as seen in the example above. There is a full list of fallback shaders here.

Example

LightmappedGeneric
{
	$basetexture metal/metalwall078a
	$surfaceprop metal

	$envmap	env_cubemap
	$envmaptint [ .56 .56 .75 ]
	$envmapcontrast 1
	$envmapsaturation 1

	LightmappedGeneric_DX9
	{
		$bumpmap metal/metalwall078a_normal
		$normalmapalphaenvmapmask 1
		$envmaptint [ .09 .1 .12]
	}

	LightmappedGeneric_DX8
	{
		$bumpmap metal/metalwall078a_normal
		$nodiffusebumplighting 1
		$normalmapalphaenvmapmask 1
	}

	LightmappedGeneric_NoBump_DX8
	{
		$basetexture metal/citadel_metalwall078a
		$basealphaenvmapmask 1
	}
}

(This material was created before conditionals were added, so is not future-proof: systems running HDR_DX9 and, eventually, DX10, will not see bump maps. However, this works in our favour when dropping back to DX7.)

Overdraw

Using mat_fillrate to investigate overdraw. Problem areas end up bright red.

Fillrate refers to the number of pixels that a video card can shove into its memory per second, independently of the time needed to decide what colour they should be. It becomes an issue when the user tries to run a game at a higher resolution than the card is capable of, or more commonly when a given pixel is being processed and re-processed many times.

This effect is known as 'overdraw' and occurs when a material is translucent (particles are dreadful), uses normal mapping, uses specular reflections and/or is refractive. You can spot overdraw by checking showbudget for an unusually large 'Swap Buffer' bar, and examine its effect precisely with mat_fillrate.

The only solution to overdraw is reducing the number of pixels that needs to be re-processed. This usually happens with a shader fallback or by creating fewer, larger objects, but there are also a few tricks that can be employed (albeit to limited effect).

Particles

See Category:Particle_System#Particle_Performance.

Refraction

Any object that crosses the plane of a refractive material will be rendered twice: once for the direct view, and again for the refracted view (It's also rendered for reflection, but that can't be helped). This becomes avoidable when the water is obscured - for instance, if the object is embedded in a displacement sand drift. By raising the model or cutting the water brush so that it doesn't extend beneath the displacement, a whole rendering pass can be avoided.

You can examine what is being rendered for refraction with mat_showwatertextures 1.

Normal mapping

LightmappedGeneric materials are the prime suspects here. To help a little you can add $nodiffusebumplighting 1 to the material in question, but as ever the only true solution is a fallback.

Tip.pngTip:When creating DirectX 8 fallbacks, use LightmappedGeneric_NoBump_DX8 to differentiate between video cards that have and haven't been deemed suitable for normal mapping by Valve.

Water

With Water, overdraw is caused by both refraction and reflection, often over a large area. You can disable either or both if needed:

$forcecheap 1
Disables both reflection and refraction.
$refracttexture
$reflecttexture
Using these commands without passing a texture bypasses one or both.

If you've got fillrate and CPU to burn, you can forcibly make the water do local reflections regardless of video config settings by specifying $forceexpensive 1, and you can forcibly make the water reflect entities by specifying $reflectentities 1.

Special materials

nodraw

tools\toolsnodraw

tools\toolsnodraw prevents a surface from being drawn at all, prevents lightmaps from being compiled for it, and prevents it from reflecting light (it still casts shadows). Use it on surfaces that will never be seen by the player but can't be sealed off by another brush, such as the tops of roofs and ledges or the far side of building in inaccessible areas, particularly those in background maps.

black, white

Two materials that behave like nodraw, but have a color value. Use at the bottom of deep pits, behind bright lights, etc.

skybox_2d

A 3D Skybox is drawn in full whenever the tools\toolsskybox material is being drawn. You can avoid this by using tools\toolsskybox2d in its place. Obviously, this only has an effect when the normal skybox material isn't visible!


<< Return to Optimization (level design)