Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Background Settings #120

Merged
merged 1 commit into from
Jan 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.<br>

⛔️ 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.<br><br>

![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.<br>
You can also apply some advanced settings to the map generation process.<br>

### DEM Advanced settings

Expand All @@ -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.
Expand Down
56 changes: 52 additions & 4 deletions maps4fs/generator/background.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.

Expand All @@ -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
)
Expand Down Expand Up @@ -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])
Expand Down
4 changes: 2 additions & 2 deletions maps4fs/generator/grle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions maps4fs/generator/i3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions maps4fs/generator/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion maps4fs/generator/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
20 changes: 20 additions & 0 deletions webui/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading