diff --git a/README.md b/README.md
index 3ad8498d..2a9d4807 100644
--- a/README.md
+++ b/README.md
@@ -441,13 +441,8 @@ List of the important DDS files:
- `mapsUS/overview.dds` - 4096x4096 pixels, the overview image of the map (in-game map)
## Advanced settings
-The tool supports the custom size of the map. To use this feature select `Custom` in the `Map size` dropdown and enter the desired size. The tool will generate a map with the size you entered.
-⛔️ Do not use this feature, if you don't know what you're doing. In most cases, the Giants Editor will just crash on opening the file, because you need to enter specific values for the map size.
-
-![Advanced settings](https://github.com/user-attachments/assets/9e8e178a-58d9-4aa6-aefd-4ed53408701d)
-
-You can also apply some advanced settings to the map generation process. Note that they're ADVANCED, so you don't need to use them if you're not sure what they do.
+You can also apply some advanced settings to the map generation process.
### DEM Advanced settings
@@ -467,6 +462,15 @@ You can also apply some advanced settings to the map generation process. Note th
- Resize factor - the factor by which the background terrain will be resized. It will be used as 1 / resize_factor while generating the models. Which means that the larger the value the more the terrain will be resized. The lowest value is 1, in this case background terrain will not be resized. Note, than low values will lead to long processing and enormous size of the obj files.
+- Remove center - if enabled, the playable region (map terrain) will be removed from the background terrain. Note, that it will require low resize factors, to avoid gaps between the map and the background terrain.
+
+- Apply decimation - if enabled, the mesh will be simplified to reduce the number of faces.
+
+- Decimation percent - the target percentage of decimation. The higher the value, the more simplified the mesh will be. Note, that high values will break the 3D model entirely.
+
+- Decimation agression - the aggression of the decimation. The higher the value, the more aggressive the
+decimation will be, which means the higher it will affect the geometry. It's not recommended to make it higher than the default value, otherwise the background terrain will not match the map terrain.
+
### GRLE Advanced settings
- Farmlands margin - this value (in meters) will be applied to each farmland, making it bigger. You can use the value to adjust how much the farmland should be bigger than the actual field. By default, it's set to 3.
diff --git a/maps4fs/generator/background.py b/maps4fs/generator/background.py
index a734f9b2..80deae06 100644
--- a/maps4fs/generator/background.py
+++ b/maps4fs/generator/background.py
@@ -179,7 +179,13 @@ def generate_obj_files(self) -> None:
self.logger.debug("Generating obj file in path: %s", save_path)
dem_data = cv2.imread(self.dem.dem_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
- self.plane_from_np(dem_data, save_path, create_preview=True) # type: ignore
+ self.plane_from_np(
+ dem_data,
+ save_path,
+ create_preview=True,
+ remove_center=self.map.background_settings.remove_center,
+ include_zeros=False,
+ ) # type: ignore
# pylint: disable=too-many-locals
def cutout(self, dem_path: str, save_path: str | None = None) -> str:
@@ -222,17 +228,37 @@ def cutout(self, dem_path: str, save_path: str | None = None) -> str:
)
cv2.imwrite(main_dem_path, resized_dem_data) # pylint: disable=no-member
- self.logger.info("DEM cutout saved: %s", main_dem_path)
+ self.logger.debug("DEM cutout saved: %s", main_dem_path)
return main_dem_path
- # pylint: disable=too-many-locals
+ def remove_center(self, dem_data: np.ndarray, resize_factor: float) -> np.ndarray:
+ """Removes the center part of the DEM data.
+
+ Arguments:
+ dem_data (np.ndarray) -- The DEM data as a numpy array.
+ resize_factor (float) -- The resize factor of the DEM data.
+
+ Returns:
+ np.ndarray -- The DEM data with the center part removed.
+ """
+ center = (dem_data.shape[0] // 2, dem_data.shape[1] // 2)
+ half_size = int(self.map_size // 2 * resize_factor)
+ x1 = center[0] - half_size
+ x2 = center[0] + half_size
+ y1 = center[1] - half_size
+ y2 = center[1] + half_size
+ dem_data[x1:x2, y1:y2] = 0
+ return dem_data
+
+ # pylint: disable=R0913, R0917, R0915
def plane_from_np(
self,
dem_data: np.ndarray,
save_path: str,
include_zeros: bool = True,
create_preview: bool = False,
+ remove_center: bool = False,
) -> None:
"""Generates a 3D obj file based on DEM data.
@@ -241,11 +267,17 @@ def plane_from_np(
save_path (str) -- The path where the obj file will be saved.
include_zeros (bool, optional) -- If True, the mesh will include the zero height values.
create_preview (bool, optional) -- If True, a simplified mesh will be saved as an STL.
+ remove_center (bool, optional) -- If True, the center of the mesh will be removed.
+ This setting is used for a Background Terrain, where the center part where the
+ playable area is will be cut out.
"""
resize_factor = 1 / self.map.background_settings.resize_factor
dem_data = cv2.resize( # pylint: disable=no-member
dem_data, (0, 0), fx=resize_factor, fy=resize_factor
)
+ if remove_center:
+ dem_data = self.remove_center(dem_data, resize_factor)
+ self.logger.debug("Center removed from DEM data.")
self.logger.debug(
"DEM data resized to shape: %s with factor: %s", dem_data.shape, resize_factor
)
@@ -306,12 +338,28 @@ def plane_from_np(
self.logger.debug("Z scaling factor: %s", z_scaling_factor)
mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
+ old_faces = len(mesh.faces)
+ self.logger.debug("Mesh generated with %s faces.", old_faces)
+
+ if self.map.background_settings.apply_decimation:
+ percent = self.map.background_settings.decimation_percent / 100
+ mesh = mesh.simplify_quadric_decimation(
+ percent=percent, aggression=self.map.background_settings.decimation_agression
+ )
+
+ new_faces = len(mesh.faces)
+ decimation_percent = (old_faces - new_faces) / old_faces * 100
+
+ self.logger.debug(
+ "Mesh simplified to %s faces. Decimation percent: %s", new_faces, decimation_percent
+ )
+
mesh.export(save_path)
self.logger.debug("Obj file saved: %s", save_path)
if create_preview:
# Simplify the preview mesh to reduce the size of the file.
- mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
+ # mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
# Apply scale to make the preview mesh smaller in the UI.
mesh.apply_scale([0.5, 0.5, 0.5])
diff --git a/maps4fs/generator/grle.py b/maps4fs/generator/grle.py
index 4400ea44..a37bcca2 100644
--- a/maps4fs/generator/grle.py
+++ b/maps4fs/generator/grle.py
@@ -114,12 +114,12 @@ def _add_farmlands(self) -> None:
self.logger.warning("Fields data not found in textures info layer.")
return
- self.logger.info("Found %s fields in textures info layer.", len(fields))
+ self.logger.debug("Found %s fields in textures info layer.", len(fields))
farmyards: list[list[tuple[int, int]]] | None = textures_info_layer.get("farmyards")
if farmyards and self.map.grle_settings.add_farmyards:
fields.extend(farmyards)
- self.logger.info("Found %s farmyards in textures info layer.", len(farmyards))
+ self.logger.debug("Found %s farmyards in textures info layer.", len(farmyards))
info_layer_farmlands_path = os.path.join(
self.game.weights_dir_path(self.map_directory), "infoLayer_farmlands.png"
diff --git a/maps4fs/generator/i3d.py b/maps4fs/generator/i3d.py
index 1214008d..4e77c05c 100644
--- a/maps4fs/generator/i3d.py
+++ b/maps4fs/generator/i3d.py
@@ -155,7 +155,7 @@ def _add_splines(self) -> None:
self.logger.warning("Roads polylines data not found in textures info layer.")
return
- self.logger.info("Found %s roads polylines in textures info layer.", len(roads_polylines))
+ self.logger.debug("Found %s roads polylines in textures info layer.", len(roads_polylines))
self.logger.debug("Starging to add roads polylines to the I3D file.")
root = tree.getroot()
@@ -300,7 +300,7 @@ def _add_fields(self) -> None:
self.logger.warning("Fields data not found in textures info layer.")
return
- self.logger.info("Found %s fields in textures info layer.", len(fields))
+ self.logger.debug("Found %s fields in textures info layer.", len(fields))
self.logger.debug("Starging to add fields to the I3D file.")
root = tree.getroot()
diff --git a/maps4fs/generator/settings.py b/maps4fs/generator/settings.py
index 9b53c2ba..4fbe910d 100644
--- a/maps4fs/generator/settings.py
+++ b/maps4fs/generator/settings.py
@@ -98,6 +98,10 @@ class BackgroundSettings(SettingsModel):
generate_background: bool = False
generate_water: bool = False
resize_factor: int = 8
+ remove_center: bool = False
+ apply_decimation: bool = False
+ decimation_percent: int = 25
+ decimation_agression: int = 3
class GRLESettings(SettingsModel):
diff --git a/maps4fs/generator/texture.py b/maps4fs/generator/texture.py
index f5cad16a..3f74ee87 100644
--- a/maps4fs/generator/texture.py
+++ b/maps4fs/generator/texture.py
@@ -507,7 +507,7 @@ def dissolve(self) -> None:
cv2.imwrite(sublayer_path, sublayer)
self.logger.debug("Sublayer %s saved.", sublayer_path)
- self.logger.info("Dissolved layer %s.", layer.name)
+ self.logger.debug("Dissolved layer %s.", layer.name)
def draw_base_layer(self, cumulative_image: np.ndarray) -> None:
"""Draws base layer and saves it into the png file.
diff --git a/webui/templates.py b/webui/templates.py
index b9f7b3f6..2005b613 100644
--- a/webui/templates.py
+++ b/webui/templates.py
@@ -127,6 +127,26 @@ class Settings:
"will not be resized. Low values will result with a very long processing and "
"meshes of enormous size. Do not change it unless you know what you are doing."
)
+ REMOVE_CENTER = (
+ "If remove center is enabled, the region of playable map terrain will be removed "
+ "from the background terrain 3D model. Note, that due to resizing, it's recommended "
+ "to use this feature only when **Resize factor** is set to 1, otherwise there will be "
+ "a gap between the background terrain and the playable map terrain."
+ )
+ APPLY_DECIMATION = (
+ "If apply decimation is enabled, the background terrain will be decimated to the "
+ "specified value. It can be useful if you want to reduce the size of the 3D model. "
+ )
+ DECIMATION_PERCENT = (
+ "Decimation percent value is used to set the decimation percent. The higher the value, "
+ "the more decimated the model will be. Be careful with high values, because it may "
+ "completely break the model."
+ )
+ DECIMATION_AGRESSION = (
+ "Decimation aggression value is used to set the decimation aggression. The higher the "
+ "the more faces will be removed. Note, that higher values will break the geometry of the "
+ "3D model and it won't match with the playable terrain. "
+ )
# GRLE Settings