Made map builder and exported first pass of maps
This commit is contained in:
248
BuildScripts/BakeWorldMap.bat
Normal file
248
BuildScripts/BakeWorldMap.bat
Normal file
@@ -0,0 +1,248 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Bakes the world map of the world partition map named at the end of each command below: the whole region as
|
||||
REM one asset, and the same region cut into a grid of pieces as one asset each. Seventeen textures come out of a
|
||||
REM full run, and the map UI in the game switches between them as it zooms: the whole region while the player is
|
||||
REM looking at all of it, and the piece they are looking at once they are close enough for the whole map's pixel
|
||||
REM to be a blur.
|
||||
REM
|
||||
REM The whole map is one texture over the whole region: on this map that is twelve thousand metres at 16384
|
||||
REM pixels, which is 0.73 metres of world per pixel of picture, a map to open and see where one is. The pieces
|
||||
REM are the same region cut into a 4 x 4 grid, so three thousand metres a side, and each piece is baked at 8192
|
||||
REM pixels, which is 0.37 metres of world per pixel: half the world per pixel of the whole map, which is the
|
||||
REM detail the zoomed in view is for. Both layers capture 2048 pixels of their own per tile, so a tile
|
||||
REM of a piece costs the same to render as a tile of the whole map and the difference between the layers is only
|
||||
REM how much world stands behind those pixels.
|
||||
REM
|
||||
REM The two layers are not a level of detail of each other, they are seventeen textures and the UI picks one, so
|
||||
REM they have to agree about where the world is to the pixel: they are baked from the same region by the same
|
||||
REM builder, and the piece a run bakes is the only thing about that the command lines below change. Nothing in
|
||||
REM the game reads one of the seventeen; they are pictures, and where the world is inside one of them is a
|
||||
REM question the settings actor answers separately.
|
||||
REM
|
||||
REM What the map covers is the WorldMapBounds of the OrthoMapCaptureActor in the map, which is the intended place
|
||||
REM to set it: open the map, select the actor, type the bounds in and save the map. A commandlet reads the map
|
||||
REM from disk, so a region that was never saved is not in what it reads.
|
||||
REM
|
||||
REM On this map the island stands on the origin and measures about 375 by 390 metres, centred within about 45
|
||||
REM metres of it, so the region is the twelve kilometre square Min=(-600000,-600000,-100000)
|
||||
REM Max=(600000,600000,100000). The island is then about a thirtieth of the width of the picture and most of the
|
||||
REM rest is sea: ten of the whole map's sixty four tiles have anything in them, which is the island and what
|
||||
REM stands around it near the origin and a second group of tiles away to the west of it. What every run prints
|
||||
REM about its empty tiles is how that is checked. Z is not part of what the map covers, it is the height the
|
||||
REM captures look down from, and the Z in the actor's own box is where a run that passes no region gets one from.
|
||||
REM
|
||||
REM WorldMapBounds is also what the game reads when it turns a position on the map back into a world position, so
|
||||
REM the actor's numbers are the numbers this bake used, and the two cannot be allowed to drift apart. All six of
|
||||
REM them have to be on the actor before the run below, which passes no region of its own.
|
||||
REM
|
||||
REM Four flags exist for running without the editor. All apply to this run only and all override the actor:
|
||||
REM
|
||||
REM -WorldMapBounds=minX,minY,maxX,maxY states the region outright, keeping the actor's Z. It wins over the
|
||||
REM actor's own bounds, so it is the way to try a region out before
|
||||
REM committing it to the map. The whole map run below does not pass it:
|
||||
REM what gets baked is what the actor says.
|
||||
REM -FitBounds takes the region from the partition instead. Do not use it on this
|
||||
REM map. A world partition reports the bounds of its own sparse octree
|
||||
REM grid rather than the bounds of its content, and an actor in this
|
||||
REM map has a world sized bound of its own, which pushes the octree up
|
||||
REM to a level 30 cell either side of the origin. It answers with a box
|
||||
REM of +/-13743895347200 units, and a tile of that at eight tiles is
|
||||
REM 3435973836800 units across, far more than a cell can hold, so
|
||||
REM IsWorldMapGridValid refuses the bake and says so. The button of the
|
||||
REM same name on the actor's details panel has the same problem, so set
|
||||
REM the region by hand.
|
||||
REM -WorldMapPiece=column,row bakes one piece of the region instead of the whole of it. The
|
||||
REM column counts along +X from the region's Min end and the row counts
|
||||
REM along +Y from the same corner, so (0, 0) is the far corner of the
|
||||
REM map and the last piece is at the near one.
|
||||
REM -WorldMapPieceGrid=n says how many pieces a side that index is being read in: four for
|
||||
REM the 4 x 4 grid this script bakes. It has to be given with
|
||||
REM -WorldMapPiece, because the same index in another grid of the same
|
||||
REM region is a different square of the world, and it is only warned
|
||||
REM about when it arrives without one.
|
||||
REM
|
||||
REM A piece run refuses -WorldMapBounds and -FitBounds rather than combining them with a piece, because the two
|
||||
REM say different things about the same region: one states the region the pieces are cut out of, and the other
|
||||
REM states the piece itself. A region that has been stated can be cut into any grid at all, so there is no one
|
||||
REM right answer to what a piece of it means. Set the region on the actor first and then ask for a piece of it.
|
||||
REM A piece index outside the grid is refused too, and so is a piece of a region that is not a whole number of
|
||||
REM pieces across, which is a piece whose edges are not where the game thinks they are.
|
||||
REM
|
||||
REM -MapTextureSize and -TilesPerAxis shrink the map for a trial run: 512 pixels in 2 x 2 tiles walks the whole
|
||||
REM grid in four steps, and still covers the same region, because a region read off the actor is re-aligned to
|
||||
REM whatever grid the run actually walks. Given with -WorldMapPiece the same two shrink one piece instead, and
|
||||
REM that re-alignment is skipped: a piece's box is a window cut out of the region the pieces tile, so it is the
|
||||
REM tiles that follow the piece and not the other way round, and aligning a window to its own tile grid would
|
||||
REM quietly bake a region that is not one of the pieces. The whole map run below passes neither, so it bakes at
|
||||
REM the resolution and tile count set on the actor, which for this map are 16384 in eight tiles; the piece runs
|
||||
REM pass both, because 8192 in four tiles is what a piece is.
|
||||
REM
|
||||
REM The grid, and what the pieces are called. A piece goes beside the whole map in the same folder, named after it
|
||||
REM with the grid and the piece's own place on the end, so this map's seventeen assets are
|
||||
REM WorldMap_Persistent_GameWorld and WorldMap_Persistent_GameWorld_Piece4x4_0_0 through _Piece4x4_3_3. Column 0
|
||||
REM is the end of the region at its Min and row 0 is the same corner, which puts this map's grid like this:
|
||||
REM
|
||||
REM row 3: (0,3) (1,3) (2,3) (3,3) every piece 3000 x 3000 metres
|
||||
REM row 2: (0,2) (1,2) (2,2) (3,2) the region Min=(-600000,-600000) Max=(600000,600000)
|
||||
REM row 1: (0,1) (1,1) (2,1) (3,1) +X runs along a row, +Y up a column
|
||||
REM row 0: (0,0) (1,0) (2,0) (3,0) the origin is the corner the four middle pieces share
|
||||
REM +--------------------------+
|
||||
REM col 0 col 1 col 2 col 3
|
||||
REM
|
||||
REM The island stands on the origin, so it falls across the four middle pieces (1,1) (2,1) (1,2) and (2,2), and
|
||||
REM Min=(-300000,-300000) Max=(300000,300000) covers those four and no others. The other twelve pieces are open
|
||||
REM sea: a bake of one of those that reports a tile with the island in it has the region wrong, and one of the
|
||||
REM four that reports nothing at all has it wrong the other way.
|
||||
REM
|
||||
REM Where the baked map goes is set on the actor too, by OutputPackageFolder, and the asset in it is named after
|
||||
REM the map it was baked from: this map bakes to /Game/Maps/Generated/WorldMap_Persistent_GameWorld, and baking
|
||||
REM it again replaces that same asset rather than making a second one. A piece is named the same way with its
|
||||
REM grid, column and row on the end, so the sixteen of them sit beside the whole map in the same folder and
|
||||
REM re-baking one piece is a change to one asset. That folder and WorldMapWarmupFrames are read off the actor as
|
||||
REM well and have to be set there, so a bake of a map whose actor has no output folder is refused before it
|
||||
REM renders anything.
|
||||
REM
|
||||
REM -DebugCapture also writes every tile it captures to Intermediate\WorldMap as a bitmap, and the stitched map as
|
||||
REM a PNG, and both are named after the asset the run is baking and after the tile's own place in the grid that
|
||||
REM run walked:
|
||||
REM
|
||||
REM WorldMap_Persistent_GameWorld-Tile_<column>_<row>.bmp the whole map, one file a tile
|
||||
REM WorldMap_Persistent_GameWorld.png the whole map, stitched
|
||||
REM WorldMap_Persistent_GameWorld_Piece4x4_<c>_<r>-Tile_<c>_<r>.bmp one piece, one file a tile
|
||||
REM WorldMap_Persistent_GameWorld_Piece4x4_<c>_<r>.png one piece, stitched
|
||||
REM
|
||||
REM Those two are the pair to look at when a bake comes out wrong: the tiles say whether each square captured
|
||||
REM what it should have, and the stitched map says whether they were placed in the right squares. The asset name
|
||||
REM in front of the tile index is what keeps the tiles of one piece from overwriting another's, which is in turn
|
||||
REM what makes the strip of tiles along a shared edge worth comparing: a seam between two pieces that is in the
|
||||
REM world reads as one line in each of them, and a seam the bake made reads as a difference.
|
||||
REM
|
||||
REM It is not on by default because it is a great deal of bitmap. A tile of this bake is 2048 pixels square at
|
||||
REM four bytes a pixel, which is sixteen megabytes, so the sixty four of the whole map are most of a gigabyte and
|
||||
REM the sixteen of one piece are a quarter of that. Add it to a command line below, or to the end of a manual
|
||||
REM run, when there is something to look at, and to one piece at a time when it is a seam being looked at.
|
||||
REM
|
||||
REM A full run of this script is seventeen commandlet runs: sixty four tiles for the whole map and sixteen for
|
||||
REM each of the sixteen pieces, which is three hundred and twenty tiles in all. On the machine this was written on
|
||||
REM all seventeen took eight and a half minutes, first log line to last. Almost none of that is capture: the whole
|
||||
REM map walks its sixty four tiles in seventeen seconds and a piece its sixteen in three to five, so the great
|
||||
REM majority of every run is the editor starting, reading the map and building the texture. Building is where the
|
||||
REM memory goes rather than the time: the whole map run peaks at eleven and a half gigabytes of physical memory,
|
||||
REM against the twelve gigabytes its sixteen thousand pixel texture reports needing while it is built, and a piece
|
||||
REM run peaks at five and a half against the three its eight thousand pixel one does. The runs are one after
|
||||
REM another rather than at once for the same reason a bake is one at a time: two of them at once would be two
|
||||
REM editors with a renderer each, holding two of these textures at the same time.
|
||||
REM
|
||||
REM What comes out is seventeen virtual textures, which is what lets a renderer hold a map of this size at all: a
|
||||
REM sixteen thousand pixel one that covers the whole region and sixteen eight thousand pixel ones that each cover a
|
||||
REM sixteenth of its area. They are small on disk because the region is all but empty. This map's own bake wrote the
|
||||
REM whole map as one and a half megabytes, the six pieces that have anything in them as between a third of a
|
||||
REM megabyte and two, and the ten that hold nothing but sea as fourteen kilobytes each, eight megabytes for the
|
||||
REM seventeen together. Where a map this size is large is on the card rather than on disk: what showing one needs is
|
||||
REM a virtual texture pool big enough for the part of it that is on screen, and this project's pool section gives it
|
||||
REM sixty four megabytes by default and, with bPoolAutoGrowInEditor off, does not grow while the editor runs. Sixty
|
||||
REM four megabytes is a great many of the pages these are cut into, and one of them on a screen is a small part of
|
||||
REM the pool; the entry to raise, if a UI ever shows more of them at once than the pool holds, is
|
||||
REM DefaultSizeInMegabyte in that section of Config\DefaultEngine.ini.
|
||||
REM
|
||||
REM The tiles that come back empty are counted out loud by every run, and that count is the quickest way to see a
|
||||
REM region that no longer covers the world: a region that has shrunk onto the world reports few or none of them
|
||||
REM empty, and one that has grown past the world reports all of them. On this map a whole map bake reports fifty
|
||||
REM four of its sixty four tiles empty, so ten of them have something in them, and the sixteen pieces report
|
||||
REM between ten and sixteen of their sixteen: ten of the pieces are all sea and come back entirely empty, the two
|
||||
REM west of the island report ten, the two the island's own corner is in report thirteen and the two east of those
|
||||
REM report fifteen. Those counts are of the world rather than of the bake, so they move when the map does; what is
|
||||
REM worth reading them for is a count that has gone to all empty or all full, which is the region and not the bake.
|
||||
|
||||
REM -AllowCommandletRendering is not optional. A builder that captures is refused without it, because a
|
||||
REM commandlet has no renderer unless it is told to start one.
|
||||
REM
|
||||
REM The per corner coverage check is only as talkative as its own log category, which does not print its Verbose
|
||||
REM lines by default. A corner that lands outside its own tile is an Error and stops the walk, so a run that
|
||||
REM reaches the end of the grid has passed every corner of it.
|
||||
REM
|
||||
REM The editor commandlet has to be the same configuration the project modules were built in, or it will load
|
||||
REM modules that do not contain this builder. DebugGame is what a local build produces; uncomment the
|
||||
REM Development line to bake with a development build instead, which is the faster of the two.
|
||||
REM
|
||||
REM Every run below is logged to a file of its own under Intermediate\WorldMap as well as to the window: the whole
|
||||
REM map to whole-map.log and a piece to piece-<column>-<row>.log, which is what makes a bake of seventeen runs
|
||||
REM readable after the fact. -abslog takes an absolute path, which is what %PROJECT_ROOT% below is for: the logs
|
||||
REM land in the project's own intermediate folder whatever directory this file is run from. It also moves that
|
||||
REM run's log out of the editor's Saved\Logs, and the file is written as the run goes rather than at its end, so
|
||||
REM one can be read, or tailed, while its bake is still walking the grid.
|
||||
|
||||
SET EDITOR_CMD=C:/Program Files/Epic Games/UE_5.8/Engine/Binaries/Win64/UnrealEditor-Win64-DebugGame-Cmd.exe
|
||||
REM SET EDITOR_CMD=C:/Program Files/Epic Games/UE_5.8/Engine/Binaries/Win64/UnrealEditor-Cmd.exe
|
||||
|
||||
SET PROJECT=C:/Projects/ProjectEleri/ProjectEleri.uproject
|
||||
|
||||
REM The project's own folder, taken from the project file above so that this file can be run from anywhere: the
|
||||
REM per run logs and the trial run both hang off it.
|
||||
FOR %%I IN ("%PROJECT%") DO SET PROJECT_ROOT=%%~dpI
|
||||
|
||||
REM What a run of this file bakes. The whole map is baked at whatever resolution and tile count the settings actor
|
||||
REM carries, which for this map are 16384 in eight tiles; a piece is baked at the two numbers below, because 8192
|
||||
REM pixels over a quarter of the width is what a piece is.
|
||||
SET MAP=/Game/Maps/Persistent_GameWorld
|
||||
SET BUILDER=-run=WorldPartitionBuilderCommandlet -Builder=/Script/ProjectEleriEditor.WorldMapBuilder -AllowCommandletRendering -SCCProvider=None -unattended -Verbose
|
||||
SET PIECE_SIZE=8192
|
||||
SET PIECE_TILES=4
|
||||
SET PIECE_GRID=8
|
||||
SET PIECE_ROOT=%PROJECT_ROOT%Intermediate\WorldMap
|
||||
|
||||
REM Whether to bake the whole map as well as the pieces. Set to 0 to bake only the sixteen pieces, which is what
|
||||
REM a run that changed the piece numbers and nothing else wants.
|
||||
SET WHOLE_MAP=1
|
||||
|
||||
REM Bake one piece instead of all sixteen: its column and row as -WorldMapPiece takes them, or empty for all of
|
||||
REM them. ONLY_PIECE=1,1 is the piece the island's own corner is in, and is the one to bake when the piece layer
|
||||
REM is being tried out rather than built.
|
||||
SET ONLY_PIECE=
|
||||
|
||||
IF NOT EXIST "%PIECE_ROOT%" MKDIR "%PIECE_ROOT%"
|
||||
|
||||
REM The geometry trial of one piece: four tiles of 512 pixels over the whole square a real piece covers, with a
|
||||
REM bitmap of each to look at. It bakes one asset rather than seventeen and its log says which region that was,
|
||||
REM so it is the cheap first thing to run when the piece arithmetic in the builder changes.
|
||||
REM "%EDITOR_CMD%" "%PROJECT%" %BUILDER% %MAP% -WorldMapPiece=0,0 -WorldMapPieceGrid=%PIECE_GRID% -MapTextureSize=512 -TilesPerAxis=2 -DebugCapture -log -stdout
|
||||
|
||||
IF "%WHOLE_MAP%"=="1" (
|
||||
ECHO "Baking the whole map..."
|
||||
"%EDITOR_CMD%" "%PROJECT%" %BUILDER% %MAP% -abslog="%PIECE_ROOT%\whole-map.log" -log -stdout
|
||||
IF ERRORLEVEL 1 GOTO :BAKE_FAILED
|
||||
)
|
||||
|
||||
ECHO "Baking the sixteen pieces..."
|
||||
SET /A PIECE_LAST=%PIECE_GRID% - 1
|
||||
FOR /L %%R IN (0,1,%PIECE_LAST%) DO (
|
||||
FOR /L %%C IN (0,1,%PIECE_LAST%) DO (
|
||||
CALL :bake_piece %%C %%R
|
||||
IF ERRORLEVEL 1 GOTO :BAKE_FAILED
|
||||
)
|
||||
)
|
||||
|
||||
ECHO "DONE! The whole map and the sixteen pieces of it are in the output folder set on the settings actor."
|
||||
PAUSE
|
||||
EXIT /B 0
|
||||
|
||||
:BAKE_FAILED
|
||||
ECHO "A run failed, so the pieces after it were not baked. The run that failed says why in the log above."
|
||||
ECHO "Fix it and run this file again: the runs that succeeded are saved already, and both the failed run and the"
|
||||
ECHO "skipped ones replace what is there rather than making second assets. To bake one of them on its own, set"
|
||||
ECHO "ONLY_PIECE at the top of this file to its column and row and set WHOLE_MAP to 0."
|
||||
PAUSE
|
||||
EXIT /B 1
|
||||
|
||||
REM One piece: the region comes from the actor and the piece from the two arguments, which are its column and its
|
||||
REM row. A piece that is not the one ONLY_PIECE asks for is skipped without a word, which is what makes that
|
||||
REM setting a way to bake one piece through the same loop as all sixteen.
|
||||
:bake_piece
|
||||
IF NOT "%ONLY_PIECE%"=="" IF NOT "%ONLY_PIECE%"=="%1,%2" EXIT /B 0
|
||||
|
||||
ECHO "Baking piece %1,%2..."
|
||||
"%EDITOR_CMD%" "%PROJECT%" %BUILDER% %MAP% -WorldMapPiece=%1,%2 -WorldMapPieceGrid=%PIECE_GRID% -MapTextureSize=%PIECE_SIZE% -TilesPerAxis=%PIECE_TILES% -abslog="%PIECE_ROOT%\piece-%1-%2.log" -log -stdout
|
||||
|
||||
IF ERRORLEVEL 1 EXIT /B 1
|
||||
EXIT /B 0
|
||||
Reference in New Issue
Block a user