Making a *.map based Level in Blender: Game entities, prep & export (pt5)
In previous chapters were learnt to set up Blenders grid for level design as well as using prefabs blocks to make a simple level with some curved features. We then UVW unwrap the map and assigned bitmap images to each object to make sure we don't export a blank scene.
Next we need to look at entities and how we can 'mark' the map to make entity placement easier once in the level editor. We can also start to look at the crucial steps required to properly optimising the scene before it is then export as a .map file.
Game entity support ^
To make fully compatible levels in Blender we need to be able to do two things; 1) make architecturally featured structures and 2) place game specific entities. Whilst we can do the former, we cannot do the latter because there are currently no equivalent objects to .map based game entities in Blender.
Entities also tend to be specific to the game to which they belong so although there are a number of commonalities, such as "func_player_start" and other 'core' entities, much of what entities are and do differs between game sets - Call of Duty entities are not exactly the same as those for Return to Castle Wolfenstein, as those are not the same as for Quake III Arena and so on. This makes having access to or using a 'common' or generic sets of objects in Blender problematic.
Instead what we have to do is use a set of "placeholders" objects to mark or represent entities in the level; we can make these elements generic in a general sense (like the entity helper kit we'll be using) or specific to a given game being edited or made. Having said this, there is one exception, lights, which we'll now discuss.
Lights as entities ^
Although there are five different types of lighting ("Lamp") object in Blender, "Spot", "Sun", "Hemi", "Area" and "Point", only the latter, "Point" lamps, work in a way that replicates the behaviour of .map based 'light' entities. This means lamp placement in Blender will generally approximate the final outcome of a levels lighting once compiled (lightmaps), without necessarily requiring any additional work in a level editor after-the-fact.
To add a lamp press "Shift+A" to open the "Add" menu, select "Lamp" then "Point" from the list ("main menu: Add » Lamp » Point"). A lamp object will be placed into the scene where-ever the cursor is located, so it may need to be repositioned using the widget tool (hold "Ctrl" to grid snap), or through adjusting the lamps "X", "Y" and "Z" "Location:" values in "View Properties" ("N"). If more lamps are needed we can either select the initial object and "Shift+D" duplicate it (or "Alt+D" to 'link' duplicate), or simply repeat the menu addition process - "Add", "Lamp" and "Point".
Lamps can be placed in the level but only "Point" lights are directly equivalent to the light 'entities' used by map based level editors - "Shift+A" to add
Once we have a lamp or lamps added to the scene we can use "Object Data" to edit their respective options and settings. Simply RMB select a lamp item, then from the "Properties" panel click the "Object Data" button. This will display a set of options that are relative to the type of lamp being edited - in this instance a "Point" lamp. For .map based level design we are only interested in two particular settings, "Distance:" and "color".
"Distance:" effects the area illuminated by the lamp based on a 'unit' measurement, i.e. a "512" unit 'lamp' in Blender directly equates to a "512" editor unit 'light' - the light/lamp will light/effect/are the same size in both applications. In level editor terms, "Distance:" is the same as the "light/[n]" key/value entity pairing (where "[n]" is a number). Changing the lamps "color" via the "Light Color" sampler effects both the colour and colour related brightness of the light. In level editing terms again this is the same as the "color_/[RGB]" key/value entity pairing (where "RGB" are numerical values, i.e. "0.000000" for each "R", "G" and "B" colour).
Design note: It needs to be pointed out here that in .map based level design we cannot alter the 'brightness' of a lamp directly - the equivalent of a lamps "Energy:" setting in Blender. This is done indirectly by altering both the general tone of the objects colour so it's closer to 'white', and by increasing the lamps size (distance); a small powerful light in editing terms for example, is usually a much larger light entity with an off-white colour (if a tone is needed).
To change "Distance:" simply "Ctrl+LMB" click in the input field and type a number, i.e. "64", "512", "700" - do not use decimal points, i.e. "62.5", "297.2" etc. Press "Enter" to set the value. To change the colour of the lamp click the "Light Color" sampler, which is 'white' by default, and LMB click select a tone from the 'chooser'. Alternatively LMB+drag and slide each of the "R", "G" and "B" input fields to set a numerical value, or "Ctrl+LMB" click to enter said same specifically.
The final setting to change relates specifically to Blender and simply helps with visualising lamp size by displaying the objects 'bounding box'. To active this click the checkbox to the left of "Sphere", a dotted outline will appear in the 3D view showing the extent of the lamps influence.
Design note: depending on the situation, remember when placing lights it's better to use more entities with smaller radius values than fewer with larger because it reduces "over-bright" problems and potential for "spotting", this is where large light volumes effect certain surfaces more than others causing over-bright 'spots'.
A number of basic settings can be assigned and exported including colour and size - 1) "Point" light is active. 2) the lights colour can be set (green is shown). 3) The 'size' of the light is relative to a "Distance:" value (in units). 4) enable "Sphere" so the light volume can be seen relative to the area it will eventually effect. Note: colour highlighting in the image above is for clarity only, lamp colour is not normally visible [see *.blend "38"]
Additional entity support ^
Lamps are currently the only type of object that export correctly as entities. Whilst we can use an "Empty" or similar item to aid marking up a map, on export these types of objects and any resulting entity layouts are typically ignored or not properly converted. The only option then is to fall back on what we know can be exported, meshes. Here we can use a simple collection of objects in Blender, colour-coded and sized to represent the various entity types available - "info_", "ammo_", "target_" etc., as "placeholders" which can be swapped out at a later stage in the level editor. Generally speaking it's highly recommended some form of entity layout is done in Blender whilst a level is being built as it's often easier to get an immediate sense of placement and how doing so affects a levels construction as opposed to puzzling about it after-the-fact.
To place entity helpers we can either; "Append" a set of objects from an external file, and/or simply "Add" a series of extra "Cube" primitives to the scene ("Shift+A » Add » Cube"). Using "Append" means we can externalise the objects into another file so we don't have to keep remaking the same objects over and over again. It also allows for different entity 'sets' to be made that can be called into use when necessary. To "Append" a single item or group of objects, from the "File" menu select "Append" ("File » Append"). In the open "File Browser" find and select the required "*.blend" file - it will automatically 'drill down' into the file to reveal its subcomponants. Click "Object", select the individual items that need to be loaded into the scene and then click the "Link/Append from Library" button top-right ("File » Append » Object » [object name]"). Blender will return to the "3D View" loading the selected items into the scene (active layer) which can then be edited and manipulated as normal.
Design note: when using "Append", each of the named entries in the "Object" subsection is the actual mesh object itself; when making the file containing these items it's always best to name the items appropriately, "ammo_9mm" for example, rather than leaving them as "cube.001" et-al. Placeholders do not necessarily need material or texture assignments, although this can help distinguish each class/type of item, because they will be assigned 'caulk/null' on export.
'Entities' placed in Blender are not 'real' nor converted into proper entities (export as brush volumes) so they should be used as positional markers only. Note the "Grid Floor" has been disabled in the above to show the scene better - do this from "View Properties" ("N") under "Display:" [see *.blend "39"]
Preparing meshes for map export ^
Whilst making a level many of the objects used will have been altered or manipulated in some way, and/or duplicates of other objects. If the map were to be exported in this 'raw' state it would typically result in missing or misplaced brush volumes, or a broken .map file of some description. This is due to the way objects in Blender default to using a "Local" coordinates system - each objects 'size', 'scale' and 'rotation' coordinate data is relative to itself rather than the scene. To export a fully functional .map file this needs to be changed so objects are relative, in their entirety, to the scene. This is done using the "Apply" function which 'fixes' or 'makes real' object data through the application of a "Global" coordinate system. In addition we also need to make sure that, as a result of using "Apply", each surface of an object is pointing in the right direction, outwards. Preparing a scene is generally not optional.
Design note: if "Apply" isn't used the coordinate data associated with an objects scale and rotation may be lost and/or reset on export.
To use the "Apply" function RMB select an individual item, or "Shift+RMB" select a group of mesh objects. Press "Ctrl+A" to access the "Apply" menu and select "Rotation & Scale" from the list ("Object » Apply » Rotation & Scale"). This will make the selected objects data 'real' - its "Scale:" will be set to "1.0000" on the "X", "Y" and "Z" axis, making it actual size. And its "Rotation:" set to "0°", again on the "X", "Y" and "Z" axis. If this is not done, objects may export as they were originally before being changed.
Design note: depending on which objects in the scene need to be fixed, individual items can be selected using RMB, groups using "Shift+RMB" or Border/Circle select ("B"/"C"), or the entire contents of the scene using "A" - be sure to check the appropriate layers are visible beforehand. We can check progress before and after by taking note of the numerical values in each respective input field of the "Transform" subsection of "View Properties" ("N").
Objects need to be 'fixed' using "Ctrl+A" relative to their ('Location') 'Rotation' and 'Scale' otherwise they may cause problems when exported as a map - inverted meshes do export but they're not seen as 'valid' elements of the map format so will make a level unusable [see *.blend "35"]
Preparing for export - inverted faces ^
As a result of making coordinate data 'real' when using "Apply", a number of meshes will likely turn inside-out, largely as a side-effect of having been mirrored. We need to fix this by inverting problematic surfaces before an object or level containing such objects can be exported, otherwise it will cause problems for the map. This can be done by reorientating the "face normals" of a mesh.
To fix a mesh, RMB select an inverted or broken object and "Tab" into "Edit" mode. If the entire mesh is inside out use "A" to select everything, or alternatively "Shift+RMB" to select individual elements. Next, in the "ToolShelf" ("T") on the left-hand side, find the "Normals:" sub-section and click the "Flip Direction" button (or "Mesh » Normal's » Invert") - the mesh (or selected faces) will invert. Alternatively, when a mesh contains both inward and outward facing surfaces, "Recalculate Outside" using "Ctrl+N" ("Mesh » Normals » Recalculate Outside") will similarly reorient all the selected surfaces 'outwards'. As each broken object needs to be corrected we simply repeat the process for any other remaining inverted mesh.
Design note: both "Flip Direction" and "Recalculate Outside" can be used on individual faces, groups or everything; the function is only available in "Edit" mode ("Tab"). Note also it's not expressly necessary to fix an objects "Location:", doing so will simply re-centre each objects "Point of Origin" to the cursors current location.
In Edit mode, select all faces and use "Flip Direction" or "Recalculate Outside" to in/revert the mesh so that it's not inside-out. This needs to be done on all inverted objects [see *.blend "36"]
Preparing meshes - merged vertices ^
We also need to check that meshes are completely solid and 'closed', i.e. there should not be any detached or split faces (shown below) as these cause problems on export. This can be fixed using "Remove Doubles". In Edit mode select all, "A", then in the "Remove:" sub-section of the ToolShelf, "T", click the "Remove Doubles" button. This merges any separate or stray vertices together, in effect making meshes 'watertight'.
Design note: making .map based levels in Blender generally means not being able to use any form of "Smooth Shading" ("mesh smoothing"/"smooth groups"); if the "Edge Split" modifier has been assigned to any object/s it will need to removed prior to export.
Make sure faces are not 'loose'. Use "Remove Doubles" to merge all vertices and seal objects together [see *.blend "37"]
Exporting a scene as a map ^
Once the prep work is done, exporting the scenes contents is relatively straightforward. First make sure that all layers containing objects are visible ("Shift+LMB" click each "Layer" button in the header menu), then select all the elements to be exported - including lamps and entity placeholders. From the main "File" menu top-left, select "Export » Quake MAP (.map)" ("File » Export » Quake MAP (.map)"). This will open the "File Browser". In the opened window, change the name of the file (if required) and the 'save' location[1,2]. Then from the "Export MAP" sub-section, change "Scale:" to "1.00" - this ensures the map is exported actual size, and "Tex Null:" to "common/caulk" - this ensures all unwanted faces are textured using the 'caulk' shader. Once done click the "Export MAP" button. Depending on the file size this may take a few second or minutes. Upon completion Blender will return to the previous view being used.
Design note: do not tessellate meshes. For proper, trouble free export meshes ideally need to remain in 'quadratic' form and not broken down into triangles. If objects are triangulated, use "Alt+J" to revert groups of faces back into "quads".
Select all the objects that need to be exported - make sure one is the 'active' element of the selection group, it will be highlighted a lighter colour. Export using the Quake MAP exporter (needs to be enabled) [see *.blend "40"]
Rename the file where necessary, browse the location the file is to be saved[1,2] and then change export options so that "Face Thickness:" is set to "8.00" (optional when making maps from mesh primitives), "Scale:" is "1.00" and "Tex Null:" changed to "common/caulk", then click the "Export MAP" button. Once done Blender will switch back to the previous 3D view [see *.map "40"]
We can check to see if the export process completed properly by looking at the text output by Blender in the console; if successful we should simply see the file being reference and the respective output data[2,3,4]. If it failed or there was a problem error messages will be displayed instead (there are many things that can go wrong so the message will vary depending on the problem causing it).
Design note: the Console is usually a separate screen underneath the main application, accessed by clicking another task bar button/icon usually titled "Blender [n]" (where [n] is the version number being used, i.e. "Blender8a"). If it's not visible try "Help » Toggle System Console" to display the window.
Console output after export from Blender showing the file being referenced, the process writing data including the lamps it finds and finally the total number of objects converted and written to file as 'brushes' and 'entities' (lamps)
Opening the map in a level editor ^
The .map file exported from Blender is 'generic' in nature so it should open it in to any level editor that understands the basic format. As there are a number of different editors available - QeRadiant, GtkRadiant, QuArK et-al - we'll focus on using GtkRadiant 1.4 for the remainder of the tutorial.
Design note: Hammer (Source SDK), Unreal Edit et-al don't support the generic .map format produced by Blender directly; there are tools available to convert the files but support and results may vary.
There are two ways we can load the file into GtkRadiant; "Open" ("File » Open"), which will 'open' the map as normal; and "Load" ("File » Load"), which will 'load' the files contents into the active scene (similar to "Append" in Blender) - this allows entire maps, or segments of, to be loaded into another file without loosing any data in the current scene. Simply browse to the files location in either instance, select, and 'load'/'open'. Once done, and before doing any further work, save the scene into the projects "/maps" folder using "Save" ("File » Save") or "Save As.." ("File » Save As..").
Design note: assuming the .map being made is for use with an idtech game directly as a custom level, Total Conversion or other modification, or indirectly via a project based on the technologies specifications, then the file will likely be loaded or opened from, and saved to, the "/maps" folder by default. Where-ever possible do not over-ride this as it's essential for the proper compilation of a level. In other words, if the Blender project folder is outside the game directory and the file is loaded from there, a copy must be saved into the "/maps" folder. For example if the Blender working directory is as follows;
Loading or opening the .map file from there will have GtkRadiant 1.4 default to the following on saving the file irrespective;
The file needs to be saved in that location regardless.
Note: there are potential issues and problems working with .map files and versions of GtkRadiant 1.4 or below on Windows Vista or Windows 7 based computers. For details see the following link - GtkRadiant won't save files: problem and solution.
The map file open in QuArk using a 'four view' split layout - "Top", "Front", "Side" and "Camera" views. Other editor support will vary and may necessitate the file being converted before being usable
Exported map opened into GtkRadiant 1.4 using the default 'four way' view layout - "Front", "Top", "Side" and "Camera" (similar to QuArk above)
Basic editing, replacing entities and textures ^
Once the file is loaded into GtkRadiant 1.4 it can be edited in exactly the same way as any other normal .map project. Lamps are available as entities whose key/value properties can be edited using the "Entity Inspector", "N". For example, changing the size of the light can be done by typing "light/300" into the inspector; colour can be changed by either typing a set of "R", "G" and "B" values for the "color_/[RGB]" pairing or using the "Color Chooser", "K" to make a selection.
Mesh objects, now converted into brush volumes, can be edited as normal; Individual or group selections can be made using "Shift+LMB"; objects can be moved and manipulated using LMB+drag; and brush volumes can be shaped and changed via LMB+drag on the outside of an edge. Entity helpers positioned in Blender can be removed and replaced with game specific objects from the main editor menu. This has to be done manually as these items are exported as simple brush volumes like other mesh object - RMB click the grid to open the entity menu and select "info »" to add the player start point "info_player_start" for instance; choose "ammo »" to replace the ammo helpers; "weapon »" to replace weapons helpers and so on.
Textures and Shaders can be (re)applied by selecting individual brushes, brushes groups or surfaces using "Paint Select" in the camera view ("Shift+LMB" whilst dragging the mouse over surfaces) - once a selection is made shaders from the "Texture List", "T" can be applied. Alternatively we can use "Find & Replace" to swap the same textures/shaders appearance over an entire level - in GtkRadiant 1.4 this is done by opening the "Find / Replace Texture(s)" tool via "Textures » Find / Replace", once open simply select the texture to replace ("Find") with the texture its to be replaced with ("Replace") and click "Apply" (this may need a texture set to be loaded if the replacement is not visible in the "Texture List" when using the tool).
The Blender made level open in GtkRadiant 1.4 showing light entities, brush volumes and entity helpers blocks. Note the extensive use of "Shader Image Missing" indicating 'broken' shaders. N.B. front and ceiling sections are hidden from view for clarity [see *.map "40"]
The amount of time it takes to 'clean up' any map exported from Blender will depend on it's size and how well it was prepared before being converted; this is why it's important to invest the energy in making sure surfaces and objects are 'tidy' with respect to how that data will then appear in GtkRadiant 1.4 or other level editors.
Objects that are not assigned materials or textures (the blocks are 'blank') export with 'Null' shaders applied, as this isn't a valid shader it needs replacing using the "Find & Replace" tool - choose the textures to be replaced then select what it needs to be replaced with, then click "Apply" to update the level. It's best to load in "textures/common" and use "caulk" as the replacement
'Null' texture swapped out showing 'named' texture assignments untouched ('named' textures are those assigned to meshes in Blender, which when exported are used as a shader reference applied to the respective brush faces - even if they are not 'real' and/or not found by the level editor). (N.B. front and ceiling sections are hidden from view for clarity) [see *.blend "41"]
At this point and for all intents and purposes, we have a working level. However, being in it's 'raw' state (as it was exported from Blender) it's not properly optimised so this is what we'll do next now that the level is open in GtkRadiant 1.4.