Skip to content

Levels: Mapper's corner

poVoq edited this page Jun 28, 2013 · 33 revisions

Welcome to the mapper's corner. Here you can learn about creating levels for qfusion. So far this page is only a collection of various details relatively specific to qfusion mapping, mostly based on information from the Warsow wiki or forums. Feel free to expand or correct this page, and specific tutorials are highly welcome!


1. Basic setup

As qfusion is an game engine only, it does not include any textures or other media files required for mapping. It is therefore recommended to map for Warsow for the time being. The recommended level editor for Warsow is NetRadiant a stabilized fork of GTKRadiant. It has the advantage that it is easy to install and includes support for Warsow. However likely you can use other versions of the Radiant family of editors also. Additionally you can also use the Quark editor with also supports Warsow out of the box. A much more recent addition to the BSP level editing toolbox is Trenchbroom which you will likely find a superior editing experience, but it does not support Warsow and many of the advanced features of qfusion (yet). It should be possible to make the geometry in Trenchbroom and convert it with Netradiant though (warning, untested!).

1.2. General editing

Basically level editing for qfusion is very similar as mapping for any Quake3 engine derived game (for example Wolfenstein: Enemy Territory or Jedi Knight Academy). Any feature you find in an vanilla Quake3 tutorial should work almost exactly the same, and most other addons found in later iterations of the Q3 engine should work at least quite similar. As there is an abundance of tutorials and mapping tips for these games available online, this wiki only concentrates on the unusual features of qfusion you are likely to use at some point. This wiki book for GTKRadiant should get you started.

2. Level compiling compiling with q3map2

q3map2 is the official level and lightmap compiler for idTech3 engines. It should have been included with your Netradiant copy and supports Warsow (and qfusion) natively. As it is a quite complex and advanced light rendering program, there is a full wiki-book dedicated to its features. However for now stick to the Netradiant included standard presets for Warsow.

2.1. Special FBSP qfusion format

FBSP is an improvement on the regular q3 bsp level format, specifically developed for qfusion. It is supported by q3map2 and can be activated with the switch:

-game qfusion

It adds higher quality light-maps and light-styles

2.1.1. Using light-styles

Light-styles are a set of different styles on how light entities can behave, allowing them to pulse, flick, etc. Setting up a light with a light-style is as simple as creating a new field inside any light entity called "style", and feed with a number between 1 and 11 (0 is standard lighting).

These are the actual effect names for them:

1. FLICKER (first variety)
2. SLOW STRONG PULSE
3. CANDLE (first variety)
4. FAST STROBE
5. GENTLE PULSE 1
6. FLICKER (second variety)
7. CANDLE (second variety)
8. CANDLE (third variety)
9. SLOW STROBE (fourth variety)
10. FLUORESCENT FLICKER
11. SLOW PULSE NOT FADE TO BLACK

3. Shaders

3.1. Quake3 style shaders

Theses are the classic shaders found in Quake3 that define how a textures looks in the game. The should not be confused with the much more recent GPU based fragment and vertext shaders, even though qfusion has recently included a way to render these directly on the GPU also (which gives a nice speed boost). The original q3map3 shader manual can be found here.

3.1.1. qfusion Q3 style shader manual

Link to the full qfusion q3 style shader manual

3.2. GPU fragment and vertex shaders

The preferred high level GPU shader language in qfusion is GLSL, specifically the OpenGL 2.0 ES subset. qfusion allows for loading these directly from your hard-drive (instead of embedding them in the engine code) which should allow for relative easy editing in theory. As this is a brand new feature there are no additional details available at the time of writing this Please add any information you might have on working with GLSL shaders in qfusion

4. Terrain

Terrain meshes with vertex-color based texture blending and instanced foliage cover is supported. No advanced terrain lods or GPU rendered terrain so far though. Futher details need to be filled

4.1. EasyGen

This is a version of EasyGen including a QFusion preset so it generates the blending shaders with bumpmapped materials. To use it follow the instructions in the included EasyGen tutorials and select the QFusion preset when exporting. A small fix has to be done to the shader files when exporting. There's a 2 lines readme (Warning: Must read or won't work) inside the zip explaining how. It's very simple.

4.2. Mesh with vertex colors blended terrain textures

note: untested An approach similar to the one outlined here will likely work too.

4.3. Foliage

This is the ability to automatically place detail models directly onto map surfaces (most likely terrain) in an algorithmic fashion. They are designed primarily for foliage, hence the name, but can be used for adding pebbles or rocks scattered randomly around terrain. One key feature of foliage is that it will fade out over distance and thus render much quicker than if placed regularly. It is also rendered instanced on the GPU, so the overall performance impact should be minimal.

When creating foliage, there are 3 things to set up: the foliage model, the foliage model's shader, and changes to any existing shader, i.e. the terrain texture blending shader, where foliage is desired on.

4.3.1. Adding foliage to existing shaders

There is a new shader directive 'q3map_foliage' that specifies how q3map2 applies foliage to a surface. It takes this form:

q3map_foliage

q3map_foliage models/foliage/grass_5.md3 1.0 16 0.025 0

  • model: models/foliage/grass_5.md3
  • scale: 1.0. This is normal size, 0.5 would be half size, 2.0 would be double
  • density: T16 units. This is the smallest chunk Q3Map will divide a surface up into before it tries to place a foliage instance.
  • odds: 0.025. This means that a random 2.5% of the potential spots for foliage will be placed. Typically you want to use small values for this; otherwise you will end up with ridiculously high polygon counts.
  • inverse alpha: 0. this means to use the straight vertex alpha as a scaling factor against the odds of appearing. This is so that terrain shaders with multiple blending layers can have different foliage on each style and have them fade/blend properly together.

If you have brush on terrain0 and grass on terrain1, then the blend shader would have two q3map_foliage directives like this:

q3map_foliage models/foliage/brush.md3 1.0 16 0.025 1

q3map_foliage models/foliage/grass_5.md3 1.0 16 0.025 0

Where the higher-numbered terrain layer/shader uses normal vertex alpha to modulate the odds-of-occurring and the lower-numbered layer uses inverse alpha.

4.3.2. Creating a foliage model

Foliage models should be kept simple and small. Since they're entirely decorative and non-solid, you should avoid making a foliage model that looks as if it could block the player.

For best results, make your models in your modeling application as a single object (multiple objects will slow down rendering) with a single texture/shader, and try to keep the polygon count as low as possible.

This is how the foliage model shader should look like:

models/foliage/grass_5
{
    surfaceparm trans
    surfaceparm pointlight

    cull disable

    // distanceCull <inner&rt; <outer&rt; <alpha threshold&rt;
    distanceCull 256 1024 0.4

    {
        map models/foliage/grass_tan.tga
        alphaFunc GE128
        rgbGen exactVertex
        alphaGen vertex
    }
}

5. Map models

VBO and instancing is supported by qfusion. Further details need to be filled

5.1 misc_model entity

If you want the model to act as map brushes set misc_model entity spawnflags to 6. Q3map2 accepts md3, lwo, ase and 3ds formats as misc_models. You can have different characteristics by setting other spawnflags:

  • Spawnflag 2: Sets the autoclipping spawnflag, automatically assigning q3map_clipmodel to any shaders used by the model. Use of Q3Map2 autoclipping for models is only recommended for large models with relatively few triangles in their mesh (i.e. terrain). The Q3Map2 autoclipping algorithm is a bit of a hack, and can hurt in-game performance (as well as produce erroneous clipping results) when used on small, dense models.
  • Spawnflag 4: Sets the force meta spawnflag, automatically adding q3map_forcemeta to any shaders used by the model (which, in turn, allows the model to become lightmapped). This, effectively, is the "lightmapped model" spawnflag.
  • Spawnflag 6: Spawnflag math allows autoclipping and autolightmapping to be combined into one spawnflag. The q3map2 wiki didn't say it, but spawnflag 1 toggles the model casting shadows on the map ("on" uses to suck on small models)

IMPORTANT: Models, even if solid, do not block visibility. Never use models to make your walls unless they have a good caulk wall behind.

6. Special FX

6.1. Dynamic sky portals

qfusion can display Q3map2 skyportals, but it also has support for dynamic skyportals by doing the following:

  • Create a room in your map to be the skyportal. This room must not be connected to any other part of the map.
  • Inside the "sky room" create an entity "misc_skyportal" or "props_skyportal" (they are the same) to be the position and angles where the skyportal camera will be.
  • Optional misc_skyportal parameters "fov": If you want to enforce a stronger or weaker fov than the player view, set it here. If not set, it will use the user fov and fit the rest of the map.
  • Optional misc_skyportal parameters "scale": If specified, defines the world/skyportal volume ratio. It is used to shift the skyportal entity in the direction opposite to the player to create a more realistic feel of the environment. One must use really high values for this parameter for the effect to look good. The shift is defined by formula: shift = (player's_origin - map_centre) / scale
  • Optional misc_skyportal parameters "noents": If set to 1 the entities in the skyroom will be skept at drawing. It is faster, but you can't use them to create movement.
  • Notice that you can use entities in this skyportal (as long as you don't enable noents, of course), so you can put the whole thing into a func_rotating or add a giant pendulum on the sky.
  • Note: On the parts of the map which will show the skyportal, keep using a normal sky shader to cast the light. It will be skept from drawing, so it doesn't matter how it looks, but it will be used for compiling the sun and surface lights. On the skyroom you can use any skyshader and it will be the one drawn ingame, and used to light the room where the skyportal entity is. It, of course, doesn't need to be the same sky shader at both, it doesn't either need to be a different one.

6.2. Sun light entity

Process:

  • Create a light entity anywhere in the map
  • Create a target_position
  • Link the light to the target. It will determine the sun direction.
  • Select the light entity. Open the entities panel.
  • Add the key "_sun 1"
  • Set it a light intensity ("light" key) and color (menu entities->select color).

If the shadows produced seem too pixelated you can smooth them adding the key "_samples " to the light entity. The higher value the smoother. 8 is usually a good enough value.

Maps can use multiple suns, be it by adding multiple suns in the shader, as entities or both. If the sky shader has a sun defined and you want to disable it, select the worldspawn entity and add the key: "_noshadersun 1". Sun light entities are incompatible with _minlight. If you use _minlight the sun entity will be ignored.

6.3. Envshots and cube maps

In qfusion you can capture an envshot (a cubemap shot) of your map at any moment by loading up the map and typing at the console "envshot ". Size is the size of the texture images to be generated, being it a power of 2 value (2, 4, 8, 16, 32, etc). Cubemaps can be used for quick reflections and sky boxes.

Cubemap reflections aren't perfect reflection matches, but they render at very hight speed, not like a real reflection does. This simple map has examples of cubemaps used as skyshot and water reflection.

Here are a pair of examples of their use in a shader:

cubemapped skybox
textures/cubemaps/sky_cube03
{
surfaceparm noimpact
surfaceparm nolightmap
q3map_sun 1 1 0.5 85 220 40
q3map_surfacelight 80
q3map_lightimage env/cube03_py.tga
qer_editorimage env/cube03_ny.tga
skyparms env/cube03 512 -
}
Cubemapped water
textures/wtest1/wtest1_water
{
qer_editorimage env/cube03_ny.tga
q3map_globaltexture
qer_trans .75
surfaceparm trans
surfaceparm nonsolid
surfaceparm water
surfaceparm nolightmap
q3map_surfacelight 25
cull none
tesssize 64
deformVertexes wave 64 sin 1 1 0.25 0.6
//for 3d cards supporting cubemaps
if textureCubeMap
{
cubemap env/wtest1water
blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
alphaGen constant 0.4 //alpha graduated blend
tcMod turb 0.6 0.5 0.5 0.5 //texture 'waves'
}
endif
//this is the first water pass from the wtest1_water shader
{
map textures/wtest1/water2.tga
blendFunc GL_dst_color GL_one
rgbgen identity
tcmod scale .25 .25
tcmod scroll .02 .01
}
//the second water pass from the old wtest1_water shader
if ! textureCubeMap //for 3d cards not supporting cubemaps
{
map textures/wtest1/water1.tga
blendFunc GL_dst_color GL_one
tcmod scale -.25 -.25
tcmod scroll .02 .02
}
endif
//the last pass from wtest1_water shader
{
map $lightmap
blendFunc GL_dst_color GL_zero
rgbgen identity
}
}

Note how the cubemap passes are made inside "if textureCubeMap" conditions, this is for very old cards, which don't support cubemaps. A good practice is to add a second option for those cards, like this: "if ! textureCubeMap". This means if not texture cubemap support.

6.4. Distortion and per pixel lit materials

missing info

6.5. Moving and rotating mirror\portal surfaces

qfusion has support for moving and rotating mirror\portal surfaces. However, there are some restrictions on this feature because of the horrible way mirrors\portals work in Quake3 and compatibility had to be ensured.

  • If your mirror\portal rotates around an axis without moving no restrictions are made on the location of misc_surface_portal entity (however, it should be not further than 64 units at the start).
  • Moving portals are not quite working correctly, they act more like mirrors,projecting the portal view on the surface without adjusting it's bias to match the current origin.

6.6. misc_particles entity

Needs to be filled Some details here

7. Bot navigation

details taken from Warsow SDK

To start load your map with devmap. Join and type in the console: "makenodes" to create a new file from scratch (will delete the current nav file at saving, if any) or "editnodes" to modify the currently loaded nodes.

Then Walk around your map dropping nodes: As you walk, the game will be dropping navigation nodes. These nodes are used by the bots to move. Each time a node is dropped the code tries to determine what type of movement is required to move from the previous node to the new one, and it's guess is printed in the chat screen. This only applies to 'normal' movements, other movements like func_plats, teleporters and jumpads aren't guessed, but directly created by the code, so when going through them it will always be print as LINK_INVALID. Also, LINK_JUMP will never be print, they are found before saving by checking all the nodes together.

The only LINK_INVALID you have to worry about is when turning around a corner, if one node doesn't see the other, and there isn't a third node so the bot can use it as union, the bot will probably never choose that path. In this situation you can force a new node to be dropped by typing in the console "addnode". The node will be dropped right at your current position.

For midair maps, which doesn't use any item, we need to add goals so the bots find some place to go. We use misc_botroam entities for this purpose. They can also be dropped from the console by typing "addbotroam". NOTE: Our botroams don't act the same as Q3 bot roams. Items, even the less interesting one, will always have priority over a bot roam for us, so bot roams will be ignored as long as the bot finds any reachable item to go for.

Then save the nav file: Once you are done walking around and you don't see any more "Dropped node" prints, but only links prints, you can save the navigation file by typing in the console: "savenodes". The code will find any possible link between all the nodes, categorize it, and save it into a file.

Last but not least review them: With the saved navigation file, you can, if you want to review the links, type in the console "showplinks" (NOTE: see EDIT2). This will show lines from the closer node to you, to each node linked from it. If you go walking around you will see the possibilities to move from each place. Type "showplinks" again to disable it.

After all that you can callvote addbots

Other notes:

Don't try to force the bots to follow a path by giving them few options. That was ok with some Q2 bots which used a similar system for dropping the nodes, but their pathing algorithms weren't even similar to Warsow's one. Just make sure all the map has nodes and let the bots do their own decisions.

Since version 0.3 the command showplinks has been removed. The following commands were added:

  • showclosestnode : shows closest node and if links are compiled (nav is saved) also the plinks for the closest node. The command can be enabled during dropping nodes mode.
  • deleteclosestnode : deletes closest node
  • botnotarget : bots don't attack you

These are more commands for bot debugging:

  • botdebug : enables/disables debugging mode. It's a toggle command.
  • bot_showlrgoal : it's a cvar. When set to 1, and sv botdebug enabled, if you are chasecamming a bot, it will print you his "Long Range" goal decisions (meaning, what item is going to search next).
  • bot_showpath : a cvar. When set to 1, and sv botdebug enabled, if you are chasecamming a bot it will draw the path the bot is following.
  • bot_showsrgoal and bot_showcombat are another two cvars, they served a purpose in a past, but they are quite useless now.

8. Map scripting

There is a "hacky" implementation of map scripts. AngelScripts are loaded from "progs/maps/mapname.mp" project files, containing the list of includes (GT scripts are loaded in the same way). Each map can implement spawn functions for custom entities and 4 hooks with hardcoded names:

  • void MAP_Init() for map initialization
  • void Map_Exit() for map shutdown
  • void Map_PreThink() - function which will be called before any world entity has had its think function called and physics run for this frame
  • void Map_PosTthink() - function which will be called after all world entities have had their think functions called and physics run for this frame

Note that the implementation is somewhat hacky due to angelwrap API limitations and may not work correctly in 100% cases.

Clone this wiki locally