racer home

Vertex & fragment shaders - a reference

 

Home Go for the GT5 look using vertex and fragment shaders!


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

Introduction

GPU Shaders (normally called vertex and fragment shaders) are supported in Racer through Cg. Cg was created by nVidia to overcome a lot of the troubles when creating shaders for a multitude of graphics hardware. Racer has always targeted for high-end hardware, and Cg probably is one of the areas where that becomes obvious.

This document is not about teaching you Cg; there's enough of that online. I'd recommend getting the book 'The Cg Tutorial' from nVidia, which can be read online for free at http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter01.html (see also below)

More information on generic Racer shaders (the name 'shader' here is a bit confusing) can be found here; Cg shaders are only a part of the larger concept of Racer shaders.

There is a page that is about (GPU) shading in general that lists all the tutorials & references; go here.

External books/pages to read

There's a lot of information on Cg on the internet. nVidia has made available for free the texts of their excellent GPU Gems series. Try the following (they are all for free):

Entry points

Every Cg shader file must have an entry point for its vertex or fragment program. In Racer, this should be 'main' for both the vertex program and the fragment program. Essentially, this means that each shader must be in its own file (you can't add the vertex & fragment shader in the same file).

Cg Parameters available in vertex/fragment shaders

Cg shader parameters are searched for in Racer. There are a number of ways to determine semantic meaning but I've chosen a (somewhat less elegant, but simple) way of needing exact variable names. So if the variable below states 'modelViewProj' for example, you really need to use 'uniform float4x4 modelViewProj' as the declaration in your shader; something like 'uniform float4x4 modelVwPrj' will NOT work).

Most variables are only available since Racer v0.7.2.

Variable name (in shader) Type Value
atmosMie float Atmospheric Mie scattering (responsible for a haze effect). A good default value is 0.001. Bigger values lead to a sort of smog'like effect.
atmosRayleigh float Atmospheric Rayleigh scattering (responsible for the blue sky effect). A good default value is 0.002.
binormal float3 Binormal (unused currently)
clouds float Amount of clouds (0..1, 0=clear sky, 1=overcast) (v0.7.4+)
dt float Delta time in seconds. Used in motion blur shaders to calculate (screen space) pixel velocity for example. (v0.7.4+)
edgeBlendP float Edge blending curvature (licensed users only)
edgeBlendGamma float Edge blending gamma (licensed users only)
exposure float Exposure for the sky. A good value will be around 2..20.
eye float 0 for left eye, 1 for right eye (stereoscopic rendering). (v0.9.0RC7+)
eyePosW float3 Eye position in world coordinates (camera world 'from' position)
fogColor float3 Uniform fog color
fogDensity float Exponential fog density
fresnelBias float Bias (offset) for fresnel (reflection shaders; f=fresnelBias+fresnelScale*pow(1+dot(I,Normal),fresnelPower) ) (v0.8.10+)
fresnelPower float Power for fresnel
fresnelScale float Linear dependency for fresnel
heat float Heat of wheel (degrees Celcius)
Ka float3 Material ambient color. Final result will normally be lightAmbient*Ka.
Kd float3 Material diffuse. Use as finalColor=textureColor*Kd.
Ke float3 Material emission. Use as finalColor=textureColor*Kd+Ke
Kr float Material reflectivity. Set in a (Racer)shader's 'reflect' property. I.e. shader_carbody.reflect=0.5.
Ks float3 Material specular property. See lighting.cg for lighting examples (normally, use LightingSun() from lighting.cg to do specular calculations, then add the specular (color, so float3) result to your fragment color.
lightDirection float3 Sun direction (from object to sun, so exactly like specified in the track's special.ini)
lightColor float3 Sun color (for example: 0.8 0.4 0.1)
modelMatrix float4x4 Current transformation matrix of geometry being drawn (identity for track objects, dynamic for moving objects such as cars, wheels). This converts original model coordinates (as created by the 3D modeler) to its world location.
modelMatrixInv float4x4 Transposed transformation matrix of drawn geometry
modelViewProj float4x4 ModelView and Projection matrix combined
modelView float4x4 ModelView matrix
modelViewIT float4x4 Inverted/transposed ModelView matrix
night float Night amount (0..1). Goes up to 1 at night time. (v074+)
prevModelViewProj float4x4 Previous frame's modelViewProj. Used in motion blur shaders to determine screen space pixel velocity. (v074+)
scale float (v0.8.10+) A scale parameter. Used in standard_mix*_f.cg to scale texture coordinates, but has other uses, such as scaling extinction in the panorama shaders.
shininess float Material shininess (for specular calculations)
tangent float3 Model texture tangents (for bump-mapping)
time float Simulation time in seconds

Geometrical parameters

Variable Type Value
center float3 Center point (in world coordinates) of object being drawn. In the projective shaders this is the light origin (special case) but all other shaders this is the center of the object. For non-split tracks, this allows you to perform animation for example on separate objects like trees. For things like grass animation you're probably better off using the texture coordinate to determine whether to move a vertex or not (example: pos.xz+=tc0.s*0.1).
size float3 Size of object being drawn. Use this in combination with the center to determine the min/max extents. For example; the height of a vertex relative to the object becomes: float hgt=IN.Position.y-center.y+size.y*0.5;

 

Shader library

Racer (v.0.7.2+) comes with a number of global shaders, located in data/renderer/shaders_hdr and shaders_ldr (HDR since v0.7.4). v0.8.9 also adds shaders_hdr_csm and shaders_ldr_csm for shadowmapping; LDR will disappear in v0.9.0 since HDR is definitely the way to go. The creation of Cg shaders is not trivial and more something that programmers tend to do. Graphics artists do need some technical knowledge to be able to use Cg effectively, but can rely on most often-used Cg shaders being present.

More on HDR can be found here. The main importance is that HDR shaders are stored in a separate directory; data/renderer/shaders_hdr. They are mostly similar to the LDR shaders. LDR though, is deprecated and will not be maintained. HDR looks so much better and is needed to get to the GT5/PGR look.

The shaders are normally prefixed with standard for default effects (such as normal lighting, bumpmapping, detailmapping) and are prefixed with dyn_standard if they are for movable objects; mostly this means car objects. The dyn (for dynamic) Cg shaders use a variable 'modelMatrix' to apply transformations to vertices & normals. The non-dynamic shaders are faster (since they skip on some matrix multiplications); that's there only reason for existing versus the dynamic versions.

A very nasty mistake that is very easy to make, is that by default, all textures are assumed to come from a camera, and are therefore handled as SRGB images. These are converted by the graphics card to linear light. Mathematical textures such as detail maps, normal maps require mode=linear in their layer definition to avoid converting. If not specified, lighting normals and detail normaps will appear a bit sheared; for normal maps the lighting will appear to be darker/lighter from strange angles, and for details maps the end result will be darker than if you omitted the detail map. An example bump shader extract that correctly adds 'mode=linear':

shader_body~vf_bump
{
layer0
{
map=body.tga
}
layer1
{
map=body_normals.tga mode=linear
}
}

Note that mode=linear does NOT affect the alpha channel; that is always linear ('alpha' is always a kind of mathematical operator).

The global shader library consists of the following files (all postfixed with .cg):

Shaders for static objects (non-moving track objects)

File (.cg) Textures Description
atmosphere - Contains atmospherical functions such as CalculateAtmosphere(), CalculateAtmosphereExtinction(). Included in other shaders, such as standard*.cg.
lighting - Contains lighting functions such as LightingSun(). These are default lighting models. Included in other shaders.
panorama_v/f 1, diffuse map

The panorama shader is used for far away objects, such as mountains, or forests. These can be placed within visibility range, and then drawn using these panorama shaders. The map is used without much lighting effects; the diffuse map is multiplied with diffuse and ambient light (lightColor+lightAmbient) to convert the texture color to klux ranges (Racer's lighting unit).

In your shader (in the .shd file) you can use 'scale=...' to scale the extinction amount (atmosphere effect) up or down. Use values between 0 and 1, where 0=full sky color and 1=fully the texture color. Anything inbetween scales the regular extinction up or down a bit. In this case, you may also want to use sky=1 to set the sorting order to let panorama objects render first (no depth writing in that case). For overlapping panorama objects, you probably need sort_offset (small integer numbers normally between -10..+10) to fix the render order between groups of overlapping panorama objects.

sky_v/f 1, RGB plus alpha to cut out clouds

A shader specifically for sky domes. This shader skips on normals and vertex position a bit, so it is not suitable for generic geometry. It renders the sun disc in the sky, something which other shaders don't do (to avoid sun discs showing up in regular 3D geometry). More info on skies here.

This shader uses 1 texture; a black & white image of the clouds, where alpha determines visibility. Use the console command 'clouds <x>' with x=0..1 to influence the amount of clouds. So do NOT use a blueish texture, but rather a black and white image, to avoid over-coloring the sky.

standard_v/f 1, RGB plus alpha for optional transparency (use blending or alpha_to_coverage=1) A standard OpenGL-like shader that takes into account atmosphere. For moving models such as car bodies, use dyn_standard_v/f instead; it will appear to work at first, but your lighting will be directly badly since the normals aren't transformed in standard_v, whereas in dyn_standard_v, they are (!).
standard_vc_v/f 1, RGB The 'standard' shader, only this one adds support for vertex colors (such as used in CarlswoodNT, the default Racer track, a lot).
standard_bump_v/f 2: diffuse, bumpmap Bumpmap shader for track (static) objects. The 2nd texture (shader_<name>.layer1.map) is the bumpmap (this one normally looks blueish, indicating normal=(0,0,1), which is stored as 8 bits as (0,0,0.5) to allow for negative normals as well). Don't forget to specify mode=linear for layer1, otherwise lighting will look strange!
standard_blur_f 2: diffuse, blurmap

The inverse of a detail shader. This shader takes 2 textures; first, the diffuse (regular) texturemap. In the 2nd texture unit, a blur texture is expected that will lighten and darken the diffuse map. The neutral value is (0.5,0.5,0.5) (or RGB=(128,128,128)) which will keep the brightness. Any value below 0.5 will darken the diffuse map, any value above 0.5 will lighten it.

Don't forget to add mode=linear for layer1.

The default texture scaling for the blurring texture is 0.1, so it is stretched 10 times. An example screenshot of the effect for a 2-layer Racer shader that uses standard_v.cg and standard_blur_f.cg:

The following blur image was taken:

standard_burn_f 1: diffuse

Fragment shader only (use in conjunction with standard_v.cg). This does mostly the same thing as standard_f.cg, but burns specularity through the red channel of the texture. This is used in Carlswood for example to map the road; the specularity is burned through the red channel of the road texture, so the specularity isn't a smooth white blot but rather pixely instead.

To get more control over the burning, use standard_burn_a_f.cg instead, which uses the alpha channel.

Just using standard_f.cg:

Using standard_burn_f.cg:

standard_burn_a_f 1: diffuse

(v0892) As standard_burn_f, this burns the specular lighting, but using the alpha channel instead of the red channel. This allows you to finetune the specularity color through the texture's alpha channel. See below for a screenshot that is similar to what is shown in standard_burn_f above. To the right you can see the alpha channel of the road texture.

cg burn alpha cg alpha texture

standard_detail_f 2: diffuse and detail RGB

Diffuse and detail texture. Use standard_v for the vertex shader. The 2nd texture contains the detail texture and texture coordinates are scaled compared to the regular (diffuse) map. So layer0 contains the diffuse (regular) map, layer1 the detail map. (v074+) The detail map must average to 0.5 (50% gray); where darker, the end results gets darkened. Where lighter than 50% gray, the end result is lightened. Use shader_<x>.scale to determine the amount of texture coordinate scaling; the default 'scale' value is 1.0 so make sure to set it 7.5 for example! (don't use an integer value; this increase texture tiling visibility artifacts).

Don't forget to add mode=linear for layer1.

For background info, see http://blogs.msdn.com/b/shawnhar/archive/2008/11/03/detail-textures.aspx

standard_detail_burn_f 2: diffuse and detail Detail texturemap (as standard_detail_f) with burning through the red channel. Useful for roads. Don't forget to add mode=linear for layer1.
standard_detail_burn_a_f 2: diffuse and detail Like standard_detail_burn_f above, only burns through the diffuse texture's alpha channel. (v0.8.11+) Don't forget to add mode=linear for layer1.
standard_grass_v/f 1: diffuse A grass shader. Much like standard_tree_v/f, this forces an up normal. It also forces this normal for shadow calculations, which is something that the standard_tree shaders don't (!). So shadowing is done as if the object is facing up. (v0.8.15+)
standard_heat_f   Heat shader for brake discs that heat up. Use standard_v.cg for the vertex shader, and this one for the fragment shader. v0.7.4+
standard_mix1w_f 1: diffuse A standard shader like standard_f, only it modifies the texture mapping coordinates to use world coordinates. Use shader_<x>.scale to define a scaling on the texture coordinates, which are derived from the world's X and Z coordinates. This shader can be used if you have large stretches of surface which uses 1 texture. To match these up with surfaces near the track, you may want to overrule your 3D model's UV mapping and use world planar mapping instead.
standard_mix2_f 3: diffuse, diffuse and control

Mixes 2 textures using a control texture (the 3rd layer (this was the first layer until Racer v0.8.22)). The control texture's alpha decides the mixing of the 2 diffuse texture: control.a=1 (white in your image editor) means take 100% diffuse1 (the 2nd layer's texture) and control.a=0 means 100% of the 2nd diffuse texture (the 3rd layer). Also, the RGB channels of the control texture are multiplied with the mixed color to enable darkening and lightening. A 50% gray is neutral, meaning no change in brightness. Darker gray darkens the mix results, and lighter gray brightens it.

Make sure to use the most important (prevailing) texture in the first layer: projective lighting uses only the first texture in a shader so that texture will be most prominent when light in dark situations.

Don't forget to add mode=linear for layer2!

standard_mix2w_f 2: diffuse and diffuse.

Like standard_mix2_f above, only it applies world planar mapping to the 2nd diffuse texture. The 1st diffuse texture (in layer1) uses the UV coordinates as defined in the 3D model (.dof). Used to mix trackside materials (such as kerbs) with grass or gravel next to it, where the grass continues on to a large area, all world-mapped using standard_mix1w_f. See also here for a tutorial.

All in all, these mix shaders are a bit of an experiment, and it seems nicer to just do proper mapping in your 3D editor, and not use large surfaces all built out of the same texture.

standard_reflect_v/f 2 (diffuse+cubemap)

Reflection shader. As standard_v/f, only adds a reflection cubemap in the 2nd texture unit. The first texture is the diffuse map, the 2nd texture a cubemap, so $trackenvmap for example.

Uses this set for static (untransformed) object such as track objects. Car objects will need dyn_standard_reflect_v/f to apply model transformation. (v074+)

standard_skinned_v/f   Skinning shaders for animated objects. More info on animation here.
standard_tree_v/f  

(v0.8.9+) Specifically created for trees, this shader ignores the 3D model normals and uses the 'up' vector (0,1,0) directly to light the polygons. The advantage is that the objects will be more evenly lit (see the image below). The problem with trees and grass is that they are often modeled using vertical triangles, while really representing slanted/rotated polygons (such as leaves, or grass leaves). This effectively makes the normals of these triangles point in a wrong direction, giving lighting a hard time.

The solution taken here is thus to ignore the bad normals in the 3D model and acting as if the normals of the triangles all point up, giving a nicer lighting effect.

For grass, use standard_grass_v/f instead.

standard tree

standard_wave_v 1

Wave shader for things such as waving flags. Check out the waving flag tutorial for more info. Just use standard_f.cg for the fragment shader side of things. Use a shaders 'scale' parameter to modify the amount of displacement (v0.8.15+).

waving flag

standard_wave_banner_v 1 Wave shader for banners; the middle of the texture will move the most; outside lines are preserved. See also the waving flag tutorial.
standard_xtree_v/f 1: diffuse For X-trees, this fakes per-pixel normal generation to give the tree a sort of round effect. See also the X-tree tutorial.
standard_xtree_basic_f 1: diffuse Use standard_xtree_v for the vertex shader. This one can be used for certain trees where the UV coordinates give trouble in the lighting direction.
animate_test_v   An example vertex shader that animates, based on a geometrical center. Useful only if the center of the object tells something about the object.

Shaders for dynamic objects

These shaders are used for dynamic objects such as cars. For all these you need at least Racer v0.8.0.

File (.cg) Textures Description
dyn_standard_v 1: diffuse Like standard_v.cg, only this one works for dynamic objects, the car mostly. It uses 'modelMatrix' to transform the normal for example. v0.7.4+
dyn_standard_bump_v/f 2: diffuse, bumpmap

Bumpmap shader set. The 2nd texture contains the bumpmap. The bumpmap's alpha value (in v0.8.24+) indicate 'reflectiveness', where 0=non-reflective, 1=full reflective. The reflectiveness affects the specular component.

Don't forget to add mode=linear for layer1.

dyn_standard_bump_reflect_v/f 3: diffuse, bumpmap, envmap

The mix between dyn_standard_bump_v/f and dyn_standard_reflect_v/f. It uses 3 textures; diffuse map (regular texture), normal (bump) map in the 2nd texture unit and the environment map in the 3rd texture unit. Note that the reflectivity is controlled in the bumpmap texture's alpha channel (0=no reflection, 1=full reflection).

Don't forget to add mode=linear for layer1.

dyn_standard_bump_speca_v/f 2: diffuse, bumpmap

OBSOLETE. use dyn_standard_bump_v/f instead.

OLD DOCUMENTATION: Like dyn_standard_bump_v/f, only this one takes its specularity color from the bumpmap (2nd) texture's alpha channel (NOT the diffuse map). Useful for tires that have both smooth and rough parts, such as F1 tires. See the 'shading cars' tutorial for an example.

The 'scale' parameter (defaults to 1.0) will scale the bumpmap's texture coordinates. Sometimes useful for converted tracks.

dyn_standard_reflect_v/f 2: diffuse, envmap Adds a reflection map (in the 2nd texture). Use a Racer shader's 'reflect' property to determine the amount of reflectivity (passed as 'Kr' in Cg shaders). Note that the first texture's alpha channel determines the amount of reflectiveness; the reflection is added additively like: finalColor=diffuseColor+Kr*diffuseColor.a*envColor.
dyn_standard_reflect_window_v/f 2: diffuse, envmap

This is a diffuse+reflection variant useful for windows. It passes the diffuse texture's alpha channel to the fragment, which results in it being used for blending.

dyn_standard_speca_f 1: diffuse A single diffuse (albedo) map, where diffuse.a controls the specularity. The alpha channel's contents is multiplied with the specular color. Use dyn_standard_v.cg for the vertex shader (no specific dyn_standard_speca_v.cg required). v0.8.12+

Special shaders using in other parts of the render engine

These shaders are not normally used for your cars & tracks, but are explained here for completeness.

File (.cg) Description
projected_texture_v/f Used for the projective lights of cars. Note the fragment shader takes the 1st texture of the Racer shader and uses its alpha to cut lighting. This is needed for partially transparent objects such as trees. Accepts 'scale' and 'alpha' parameters which are defined in the shader as bounce_amount and bounce_alpha parameters.

 

Shader library for debugging

These shaders are normally only used when you need to check things.

File (.cg) Description
check_shader_f

This shader outputs purple with alpha=0 (color 1,0,1,0) for all pixels. For older tracks that you want to convert to use Cg, you can use this fragment shader to quickly colorize all Cg shaded materials. All the objects that don't have shaders yet will still be textured (drawn using regular Racer shaders) so this Cg shader can help to find the object that still need to have Cg (and/or Racer) shaders.

For example, set vertex_shader.file to standard_v.cg and fragment_shader.file to check_shader_f.cg in your track.shd's Racer shader. A full example extract from a track.shd file:

vf_standard
{
  vertex_shader 
  {
    file=standard_v.cg
  }
  fragment_shader
  {
    file=check_shader_f.cg
  }
}
shader_guardrail~vf_standard
{
layer0
{
map=guardrail.tga
}
}

 

 


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

(last updated May 14, 2013 )