Quake 3 Enhancements

Usage Guide

Created:  May 1, 2001

Printed:  April 28, 2002

 

SurfaceSprites

 

Surfacesprites is a shader pass similar to those you are already familiar with.  It shares kinship with surface textures, lightmaps, and other multipass texture layers.  The main difference is that surfacesprites are not flat on the surface they are placed on, but rather stand up away from the surface.  Another important distinction is that a single surfacesprite pass typically doesn’t generate one single image, but rather multiple images evenly distributed over that surface.

 

Example:

Take any shader:

textures/prague/cobblestone

{

    {

        map $lightmap

    }

    {

        map textures/prague/cobblestone

        blendFunc GL_DST_COLOR GL_SRC_COLOR

    }

 

…and add a pass to it like this:

    {

        map textures/colombia/grass_clump

        surfaceSprites vertical 24 24 16 1024

        ssWind 0.5

        alphaFunc GE128

        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA

        depthWrite

    }

}

 

As in any shader pass, the map is the graphic used, but in this case the graphic is not laid on top of the surface, it instead is distributed over it.  The alpha and blend properties are optional as with any shader, but the above configuration is highly recommended for “solid” materials.  Surfacesprites will not be placed unless the polygon is facing more-or-less upward (with a couple of exceptions below), so if cube room is textured with a surfacesprite shader, the stuff will only appear on the floor.

 

Main Command Syntax:

surfaceSprites <type> <width> <height> <density> <fadedist>

 

<type>:  One of three keywords are valid:

vertical: Stuff that sticks up off the ground, such as grass, reeds, etc. 

oriented:  An image that always faces the user.  This can be used for rocks, debris, whatever you want to break up a surface.  These should stay fairly small if possible.

effect:  An image that always faces the user, but it grows and fades out over time.  When the effect fades completely out, it reappears in another location.

 

<width>:  Horizontal size of each individual sprite, in world dimensions.  This is the base width, which can be added to with the variance command below.

<height>:  Vertical size of each individual sprite, in world dimensions.  This is the base height, which can be added to with the variance command below.

<density>:  Density defines the interval at which the sprites are placed, e.g. a 32 means that a sprite will be placed every 32 units on the ground.  Lower equals denser.  Note that the more dense the sprites are, the more slowdown you will see, so you should lower the fadedist if you up the density.

<fadedist>:  Fade distance defines the minimum distance at which the surfacesprites will be drawn in full.  At a distance greater than this, sprites are visible, but various sprites start to fade out at different distances.  1000 is a fair draw distance for normal grass-like items, smaller numbers are more appropriate for smaller sprites.

 

 

Optional Parameters:

The Surfacesprites have several optional parameters that, unless overridden, use default values.  These are entered as separate lines beginning with “ss”, after the initial surfacesprite call:

 

ssFademax <fademax>

            Fade max defines the maximum distance at which any Surfacesprites at all will be drawn at all.  The sprites will fade out between the fadedist and the fademax.  This value defaults to 1.33 times the fadedist.

 

ssFadescale <fadescale>

            Fade scale indicates a fractional amount of the sprite’s width that it will scale between the fadedist and fademax.  That is, if:

            Surfacesprites vertical 8.0 8.0 32 1000

            SsFademax 1500

            SsFadescale 1.0

            …then between distances of 1000 and 1500, this sprite of base width 8 will grow from 8 to 16.  Of course after 1500, the sprites are no longer drawn (see fademax).  Default for fadescale is zero.

 

ssVariance <varwidth> <varheight>

            Variance defines a factored amount to add to the width and height randomly.  That is, if the base width is 8 and the varwidth is 1.0, the width will be randomly between 8 and 16.  If the variance is not specified, they default to zero (e.g. every sprite is the same width and height).

            <varwidth>:  Fraction of the base width of the sprite to add randomly.  Default is zero.

            <varheight>:  Fraction of the base height of the sprite to add randomly.  Default is zero.

 

ssHangdown

ssAnyangle

            Hangdown is an optional keyword that when set, the sprites are placed on the ceiling instead of on the ground, such as for hanging vines.

            Anyangle is an optional keyword that when set, the sprites can come out of any surface, rather than just the top.  Mutually exclusive with hangdown.  NOTE:  FOR SPEED CONSIDERATIONS, ANYANGLE IS NOT CURRENTLY IMPLEMENTED.

 

ssFaceup

Oriented and Effect sprites only

            Faceup is an optional keyword for oriented and effect sprites.  When set, the sprites are placed horizontally on the ground.  Currently the surface must be completely horizontal, or the sprites won’t appear.  Used for stains on the ground, or water rings.  Height is ignored on faceup sprites, they are always square.  Not valid for vertical sprites.

 

ssWind <wind>

Vertical and Effect sprites only

Wind is an optional variable for vertical and effect sprites.  Vertical sprites (such as grass) can wave according to wind settings (see below).  Without this variable, the sprites are not affected by wind.

<wind>:  The wind value is how much to factor in these effects, as a multiple of the effects of wind.  1.0 would be for limp grass blowing in the wind.  0.5 would be more rigid.  0.0 means the sprite sits rigidly upward.  A rigid sprite is cheaper to render, so leave the wind variable out if you don’t need it!  NOTE:  Currently not implemented on effect sprites.  Default is zero.

 

ssWindidle <windidle>

Vertical sprites only

            The wind idle value is a factor from 0 to 1.0.  The higher this number is, the more vertical sprites will sway when there is no wind. 

            <windidle>:  The windidle value is how much to factor in these effects, and typically varies from 0 to 1.  1.0 is limp grass swaying when there is no wind.  0.25 offers very subtle movement.  0.0 means the sprite sits rigidly upward when there is no wind.  A rigid sprite is cheaper to render, so leave windidle at zero if you do not need it.  This value defaults to zero, or to the wind value if it is set. 

 

ssVertSkew <skew>

Vertical sprites only

            The vertical skew value is a random factor that is added to the surfacesprites to make their “base” position something other than vertical.  The best use for this is for example a thin graphic for bamboo, which might stick up at strange angles.

            <skew>:  This value indicates the fraction of the sprites height to add randomly to the sprites’ top point.  For example, if a sprite has a height of 16, and the skew value is 1.0, then the sprite may lean between 16 to the left and 16 to the right.  In exact terminology, the X and Y coordinates of the top of the sprite could be between a -16 and 16 offset.  This value defaults to zero.

 

ssFXDuration <duration>

Effect sprites only

            The duration value is a length of time that an effect sprite grows or shrinks before it disappears.  This is how long the effect lasts before looping, in milliseconds.  That is, 1000 equals 1 second.  Duration defaults to 1000 (1 second).

 

ssFXGrow <growwidth> <growheight>

Effect sprites only

            The grow value is a proportional value that indicates how much of the base width and height changes over an effects lifetime (i.e. its duration).  A base width of 8 and a grow value of 1.0 means the effect grows from 8 to 16.  A negative value means it shrinks, so a sprite with a base width of 8 (or any base width) and a grow value of –1.0, will shrink to nothing over its duration.  The default for growwidth and growheight are 0.0.

 

ssFXAlphaRange <alphastart> <alphaend>

Effect sprites only

            The effect alpha range sets two values between 0 and 1, that indicates what amount to fade out to over the course of the effect’s lifetime.  That is, if the alpha range is 0.8 and 0.3, then an effect surfacesprite will start out with an alpha of 0.8 and end with an alpha of 0.3.

            <alphastart>:  This indicates the alpha value that is shown at the start of each individual surfacesprite effect.  The alpha transparency of a sprite will smoothly go from this value to the alphaend value.  The default for the alphastart is 1.0, or opaque.

            <alphaend>:  This indicates the alpha value that is shown at the end of an individual surfacesprite effect.  The alpha transparency of a sprite will smoothly go from the alphaend value to this value.  The default for the alphaend is 0.0, or fully transparent.

 

SsFXWeather

Effect sprites only

            Weather is an optional keyword for effect sprites.  If this keyword is present, then the density of the sprites is reliant on the r_surfaceWeather cvar as detailed below.

 

--------------------------------------------------------------------------------------------

There are a few cvars that this feature uses right now:

r_surfaceSprites 0:  Turns surfacesprites off.

r_surfaceSprites 1:  Turns surfacesprites on.

r_surfaceSprites 3:  Reports how many are being drawn per frame

 

r_windSpeed <speed>:  Sets the windspeed.  Defaults to 0.  This value is ignored if the weather system is present, as the weather wind will take control.

r_windAngle <angle>:  Sets the angle that the wind blows at.  Defaults to 0.  This value is ignored if the weather system is present, as the weather wind will take control.

r_windDampFactor <factor>:  Sets how quickly the wind responds to changes.  Defaults to 0.1

 

r_surfaceWeather <value>:  Sets the amount of weather-oriented effects to display.  Defaults to 1.0.  This value is typically 0 to 1, representing 0-100% of the weather, so in the case of rain splashes, 0.4 is a light rain.

 

--------------------------------------------------------------------------------------------

You must also add a few elements to make the surface light properly:

First you cannot use lightmaps, the surface must be instead vertex lit, else the light will look fullbright.

            q3map_nolightmap

            q3map_onlyvertexlighting

 

If the polygon surfaces are large, you will not see the sprites fade properly.  You must force the BSP to break up the surface with a command like this:

            q3map_tesssize 256

 

--------------------------------------------------------------------------------------------

The sprites or graphics that it uses are hard-alpha channeled images of reasonable resolution.  They should have sides (e.g. not tile).  Grass is done with “clump” images.  A wide, flat edge at the bottom of the sprite is not usually desirable.  It is highly recommended that the sprites have the same overall coloring as the ground texture.

 

The system currently randomly flips any surfacesprites horizontally for variety. 

 

You can use any blend mode you wish, so if you want the sprites to be additive, simply set blendfunc GL_ONE GL_ONE.  Beware of highly transparent objects if the sprites are very tall (e.g. vertical surfacesprites such as tall grass).  The transparency will reveal sorting issues, and fogged sprites will look especially strange.  So for tall “in your face” sprites such as grass, use a hard-edged alpha mask and an alphatest setting such as alphafunc GE128, or even crisper like alphafunc GE192 (a new alphafunc recently added).  However, there is a tradeoff.  When the alphafunc is set higher, the sprites will not be able to fade as smoothly, and will appear to “pop” in a bit more.

 

If you want additional sprites in a single texture, you can add in another pass, but don’t abuse it or your overtaxed machine will punish you.  If you use the exact same density on a second pass, the second set of sprites will be directly on top of the first, which can be useful.  If you want roughly the same density but don’t wish for this, simply add or subtract a small amount from the density, the overall effect will be the same.  BE CAREFUL WITH THIS SYSTEM, BECAUSE THE SPRITES AIN’T FREE!

 

In the future, there will be adjustments for this feature for scalability, namely, if the user has a weaker machine, the sprites will be less in number and fade out quicker.  The very worst machines might have absolutely no surfacesprites at all.  So, don’t rely on this for 100% of a level’s appearance, so for example you might want to leave in a few grass models just in case.  You can turn off the sprites with the cvar above to see how it looks.

 

If you want to have a texture covered with sprites in some places, not in others (such as raindrops outdoors but not inside), two shaders should be made with the same graphic, but one not possessing the surfacesprite pass.  I’d suggest a clever naming convention for this.

 

Weather such as rain and snow will eventually be on a trigger rather than a cvar.  This, however, requires some coordination with Rick and Jeff D.

 

--------------------------------------------------------------------------------------------

Currently surfacesprites are NOT supported in shaderEd.  This is important, because if a shader with surfacesprites is loaded up in shaderEd, the surfacesprites command will be eliminated when it is saved out again, destroying the surfacesprites effect.  For now, these files must be edited by hand, and you should not put surfacesprites in typically used shader files.

 

--------------------------------------------------------------------------------------------

Shader examples:

 

 

Grasses that blow in the wind:

 

textures/test/grnd01c_sprites

{

        qer_editorimage        textures/kamchatka/grnd01c

        q3map_material Gravel

        q3map_nolightmap

        q3map_onlyvertexlighting

    {

        map textures/kamchatka/grnd01c

          blendFunc GL_DST_COLOR GL_ZERO

    }

  

    {

        map models/objects/colombia/jungle/tall_grass

        surfaceSprites vertical 16 32 48 1000

            ssVariance 1.0 2.0

            ssWind 1.0

        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA

        alphaFunc GE128

        depthWrite

    }

 

}

 

Rain splashes on water:

 

textures/colombia/rain_water

{

        qer_editorimage        textures/colombia/water_terrain

        q3map_material Water

        q3map_nolightmap

        q3map_onlyvertexlighting

        q3map_tesssize 256

    {

        map textures/colombia/water_terrain

        blendFunc GL_ONE GL_ONE_MINUS_SRC_ALPHA

        depthWrite

        rgbGen exactVertex

        alphaGen const 0.9

        tcMod turb 0 0.08 0.04 0.08

        tcMod scroll -0.05 -0.001

        tcMod scale 3 3

    }

    {

        map textures/colombia/water_terrain2

        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA

        rgbGen exactVertex

        tcMod turb 0 0.08 0.04 0.08

        tcMod scale 3 3

    }

 

    {  

        map gfx/sprites/rainhit

        surfaceSprites effect 2.5 2.5 16 400

            ssFXDuration 135

            ssFXGrow 6 6

            ssVariance 1.0 0.75

            ssFXWeather

        blendFunc GL_ONE GL_ONE

    }

    {  

        map gfx/sprites/rainring

        surfaceSprites effect 2.0 2.0 28 350

            ssFXDuration 220

    ssFXGrow 2.5 2.5

    ssFaceup

    ssVariance 2.0 1.0

    ssWeather

        blendFunc GL_ONE GL_ONE

    }

}

Random debris on the ground:

 

textures/common/ground

{

qer_editorimage        textures/colombia/ground_jungle

q3map_material gravel

        q3map_nolightmap

        q3map_onlyvertexlighting

    {

        map textures/colombia/ground_jungle

        blendFunc GL_ONE GL_ZERO

    }

    {

        map gfx/sprites/rock1

        surfaceSprites oriented 4 4 80 256

    ssVariance 0.25 0.0

        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA

        alphaFunc GE128

        depthWrite

    }

    {

        map gfx/sprites/rock2

        surfaceSprites oriented 2 2 92 200

    ssVariance 0.25 0.0

        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA

        alphaFunc GE128

        depthWrite

    }

}

 

--------------------------------------------------------------------------------------------

Weather

 

All weather is started and controlled with r_we.

 

Snow:

Start a snow effect:

r_we snow init <particles>

 

Remove the snow effect:

r_we snow remove

 

Set the snow alpha transparency:

r_we snow alpha <float>                     

default: 0.09

Set the area around the player the snow covers:

r_we snow spread ( minX minY minZ ) ( maxX maxY maxZ )                           

default: ( -600 -600 -200 ) ( 600 600 250 )

Set the random range that sets the speed the snow falls:

r_we snow velocity ( minX minY minZ ) ( maxX maxY maxZ )                          

default: ( -15 -15 -20 ) ( 15 15 -70 )

Set an area of snow blowing:

            r_we snow wind ( windOriginX windOriginY windOriginZ ) ( windVelocityX windVelocityY windVelocityZ ) ( sizeX sizeY sizeZ )

 

Set snow blowing data:

r_we snow blowing duration <int>                                                                              

r_we snow blowing low <int>                                                                                                                                                              default: 3

r_we snow blowing velocity ( min max )

                        default: ( 30 70 )

            r_we snow blowing size ( minX minY minZ )

                                    default: ( 1000 300 300 )

Start a fog effect in the snow:

            r_we snow fog

 

Set the density of the snow fog:

r_we snow fog density <alpha>

            default: 0.3

 

Rain:

Start a rain effect:

            r_we rain init <particles>

 

Remove the rain effect:

            r_we rain remove

 

Add a fog effect to the rain:

            r_we rain fog

 

Set the density of the rain fog:

r_we rain fog density <alpha>                                                                                     

            default: 0.3

Set the range of speeds at which the rain falls:

            r_we rain fall ( minVelocity maxVelocity )

            default: ( -60 -50 )

Set the area around the player that the rain falls in:

            r_we rain spread ( radius height )       

            default: ( 20 20 )

Set the alpha transparency of the raindrops:

            r_we rain alpha <float>                                               

                        default: 0.1

Set the height (length) of the raindrops:

            r_we rain height <float>                      

                        default: 5

Set the slope at which the rain falls (in the current wind direction):

            r_we rain angle <float>           

                        default: 1.0

 

Debug:

            r_we debug wind