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

Optimze terrain #801

Merged
merged 19 commits into from
Jan 19, 2025
22 changes: 11 additions & 11 deletions metadrive/component/map/base_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ def get_semantic_map(
pixels_per_meter=8,
color_setting=MapTerrainSemanticColor,
line_sample_interval=2,
polyline_thickness=1,
yellow_line_thickness=1,
white_line_thickness=1,
layer=("lane_line", "lane")
):
"""
Expand All @@ -212,23 +213,23 @@ def get_semantic_map(
points_to_skip = math.floor(PGDrivableAreaProperty.STRIPE_LENGTH * 2 / line_sample_interval)
for obj in all_lanes.values():
if MetaDriveType.is_lane(obj["type"]) and "lane" in layer:
polygons.append((obj["polygon"], MapTerrainSemanticColor.get_color(obj["type"])))
polygons.append((obj["polygon"], color_setting.get_color(obj["type"])))
elif "lane_line" in layer and (MetaDriveType.is_road_line(obj["type"])
or MetaDriveType.is_road_boundary_line(obj["type"])):
if MetaDriveType.is_broken_line(obj["type"]):
for index in range(0, len(obj["polyline"]) - 1, points_to_skip * 2):
if index + points_to_skip < len(obj["polyline"]):
polylines.append(
(
[obj["polyline"][index], obj["polyline"][index + points_to_skip]],
MapTerrainSemanticColor.get_color(obj["type"])
[obj["polyline"][index],
obj["polyline"][index + points_to_skip]], color_setting.get_color(obj["type"])
)
)
else:
polylines.append((obj["polyline"], MapTerrainSemanticColor.get_color(obj["type"])))
polylines.append((obj["polyline"], color_setting.get_color(obj["type"])))

size = int(size * pixels_per_meter)
mask = np.zeros([size, size, 1], dtype=np.float32)
mask = np.zeros([size, size, 1], dtype=np.uint8)
mask[..., 0] = color_setting.get_color(MetaDriveType.GROUND)
# create an example bounding box polygon
# for idx in range(len(polygons)):
Expand All @@ -247,8 +248,8 @@ def get_semantic_map(
int((p[1] - center_p[1]) * pixels_per_meter) + size / 2
] for p in line
]
thickness = polyline_thickness * 2 if color == MapTerrainSemanticColor.YELLOW else polyline_thickness
thickness = min(thickness, 2) # clip
thickness = yellow_line_thickness if color == MapTerrainSemanticColor.YELLOW else white_line_thickness
# thickness = min(thickness, 2) # clip
cv2.polylines(mask, np.array([points]).astype(np.int32), False, color, thickness)

if "crosswalk" in layer:
Expand All @@ -269,9 +270,8 @@ def get_semantic_map(
)
# 0-2pi
angle = np.arctan2(*dir) / np.pi * 180 + 180
# normalize to 0.4-0.714
angle = angle / 1000 + MapTerrainSemanticColor.get_color(MetaDriveType.CROSSWALK)
cv2.fillPoly(mask, np.array([points]).astype(np.int32), color=angle.tolist())
angle = int(angle / 2) + color_setting.get_color(MetaDriveType.CROSSWALK)
cv2.fillPoly(mask, np.array([points]).astype(np.int32), color=angle)

# self._semantic_map = mask
# return self._semantic_map
Expand Down
17 changes: 8 additions & 9 deletions metadrive/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,8 @@ class MapTerrainSemanticColor:
Do not modify this as it is for terrain generation. If you want your own palette, just add a new one or modify
class lMapSemanticColor
"""
YELLOW = 0.1
WHITE = 0.3
YELLOW = 10
WHITE = 30

@staticmethod
def get_color(type):
Expand All @@ -426,18 +426,18 @@ def get_color(type):
return MapTerrainSemanticColor.YELLOW
elif MetaDriveType.is_lane(type):
# return (0, 1, 0, 0)
return 0.2
return 20
elif type == MetaDriveType.GROUND:
# return (0, 0, 1, 0)
return 0.0
return 00
elif MetaDriveType.is_white_line(type) or MetaDriveType.is_road_boundary_line(type):
# return (0, 0, 0, 1)
return MapTerrainSemanticColor.WHITE
elif type == MetaDriveType.CROSSWALK:
# The range of crosswalk value is 0.4 <= value < 0.76,
# so people can save the angle (degree) of the crosswalk in attribute map
# the value * 10 = angle of crosswalk. It is a trick for saving memory.
return 0.4 # this value can be overwritten latter
return 40 # this value can be overwritten latter
else:
raise ValueError("Unsupported type: {}".format(type))
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Expand Down Expand Up @@ -487,8 +487,7 @@ class TerrainProperty:
"""
Define some constants/properties for the map and terrain
"""
map_region_size = 512
terrain_size = 2048
map_region_size = 2048

@classmethod
def get_semantic_map_pixel_per_meter(cls):
Expand All @@ -497,8 +496,8 @@ def get_semantic_map_pixel_per_meter(cls):
Returns: a constant

"""
assert cls.terrain_size <= 2048, "Terrain size should be fixed to 2048"
return 22 if cls.map_region_size <= 1024 else 11
# assert cls.terrain_size <= 2048, "Terrain size should be fixed to 2048"
return 22 if cls.map_region_size != 4096 else 11

@classmethod
def point_in_map(cls, point):
Expand Down
101 changes: 57 additions & 44 deletions metadrive/engine/core/terrain.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
# import numpyf
import math

import os
import pathlib
import sys

import time
#
#
from abc import ABC

import numpy

from metadrive.constants import TerrainProperty, CameraTagStateKey
import cv2
import numpy as np
from panda3d.bullet import BulletRigidBodyNode, BulletPlaneShape
Expand All @@ -20,8 +15,9 @@
from panda3d.core import Vec3, ShaderTerrainMesh, Texture, TextureStage, Shader, Filename

from metadrive.base_class.base_object import BaseObject
from metadrive.constants import CamMask, Semantics
from metadrive.constants import CamMask, Semantics, MapTerrainSemanticColor
from metadrive.constants import MetaDriveType, CollisionGroup
from metadrive.constants import TerrainProperty, CameraTagStateKey
from metadrive.engine.asset_loader import AssetLoader
from metadrive.engine.logger import get_logger
from metadrive.third_party.diamond_square import diamond_square
Expand Down Expand Up @@ -53,7 +49,7 @@ def __init__(self, show_terrain, engine):
self.mesh_collision_terrain = None # a 3d mesh, Not available yet!

# visualization mesh feature
self._terrain_size = TerrainProperty.terrain_size # [m]
self._terrain_size = TerrainProperty.map_region_size # [m]
self._height_scale = engine.global_config["height_scale"] # [m]
self._drivable_area_extension = engine.global_config["drivable_area_extension"] # [m] road marin
# it should include the whole map. Otherwise, road will have no texture!
Expand Down Expand Up @@ -83,7 +79,8 @@ def __init__(self, show_terrain, engine):
# prepare semantic texture
semantic_size = self._semantic_map_size * self._semantic_map_pixel_per_meter
self.semantic_tex = Texture()
self.semantic_tex.setup2dTexture(semantic_size, semantic_size, Texture.TFloat, Texture.F_red)
self.semantic_tex.setup2dTexture(semantic_size, semantic_size, Texture.TUnsignedByte, Texture.F_red)

# prepare height field texture
self.heightfield_tex = Texture()
self.heightfield_tex.setup2dTexture(*self.heightfield_img.shape[:2], Texture.TShort, Texture.FLuminance)
Expand Down Expand Up @@ -258,18 +255,23 @@ def _set_terrain_shader(self, engine, attribute_tex):
# self._mesh_terrain.set_shader_input("side_tex", self.side_tex)
# self._mesh_terrain.set_shader_input("side_normal", self.side_normal)

# road
# rock
self._mesh_terrain.set_shader_input("rock_tex", self.rock_tex)
self._mesh_terrain.set_shader_input("rock_normal", self.rock_normal)
self._mesh_terrain.set_shader_input("rock_rough", self.rock_rough)
self._mesh_terrain.set_shader_input("rock_tex_ratio", self.rock_tex_ratio)

# rock 2
self._mesh_terrain.set_shader_input("rock_tex_2", self.rock_tex_2)
self._mesh_terrain.set_shader_input("rock_normal_2", self.rock_normal_2)
self._mesh_terrain.set_shader_input("rock_rough_2", self.rock_rough_2)
self._mesh_terrain.set_shader_input("rock_tex_ratio_2", self.rock_tex_ratio_2)

# road
self._mesh_terrain.set_shader_input("road_tex", self.road_texture)
self._mesh_terrain.set_shader_input("yellow_tex", self.yellow_lane_line)
self._mesh_terrain.set_shader_input("white_tex", self.white_lane_line)
self._mesh_terrain.set_shader_input("road_tex_ratio", self.road_tex_ratio)
self._mesh_terrain.set_shader_input("road_normal", self.road_texture_normal)
self._mesh_terrain.set_shader_input("road_rough", self.road_texture_rough)
self._mesh_terrain.set_shader_input("elevation_texture_ratio", self._elevation_texture_ratio)

# crosswalk
self._mesh_terrain.set_shader_input("crosswalk_tex", self.crosswalk_tex)
Expand Down Expand Up @@ -410,29 +412,18 @@ def _load_mesh_terrain_textures(self, engine, anisotropic_degree=16, filter_type
self.ts_normal.setMode(TextureStage.M_normal)

# grass
# if engine.use_render_pipeline:
# # grass
# self.grass_tex = self.loader.loadTexture(
# AssetLoader.file_path("textures", "grass2", "grass_path_2_diff_1k.png")
# )
# self.grass_normal = self.loader.loadTexture(
# AssetLoader.file_path("textures", "grass2", "grass_path_2_nor_gl_1k.png")
# )
# self.grass_rough = self.loader.loadTexture(
# AssetLoader.file_path("textures", "grass2", "grass_path_2_rough_1k.png")
# )
# self.grass_tex_ratio = 128.0
# else:
self.grass_tex = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass1", "GroundGrassGreen002_COL_1K.jpg")
)
self.grass_normal = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass1", "GroundGrassGreen002_NRM_1K.jpg")
)
self.grass_rough = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass2", "grass_path_2_rough_1k.png")
)
self.grass_tex_ratio = 64

white = PNMImage(256, 256, 4)
white.fill(1., 1., 1.)
self.grass_rough = Texture("grass rough")
self.grass_rough.load(white)
self.grass_tex_ratio = 64 * self._terrain_size / 512

v_wrap = Texture.WMRepeat
u_warp = Texture.WMMirror
Expand All @@ -454,7 +445,7 @@ def _load_mesh_terrain_textures(self, engine, anisotropic_degree=16, filter_type
self.rock_rough = self.loader.loadTexture(
AssetLoader.file_path("textures", "rock", "brown_mud_leaves_01_rough_1k.png")
)
self.rock_tex_ratio = 128
self.rock_tex_ratio = 512 * self._terrain_size / 2048

v_wrap = Texture.WMRepeat
u_warp = Texture.WMMirror
Expand All @@ -466,6 +457,27 @@ def _load_mesh_terrain_textures(self, engine, anisotropic_degree=16, filter_type
tex.setMagfilter(filter_type)
tex.setAnisotropicDegree(1)

# rock 2
self.rock_tex_2 = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass2", "grass_path_2_diff_1k.png")
)
self.rock_normal_2 = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass2", "grass_path_2_nor_gl_1k.png")
)
self.rock_rough_2 = self.loader.loadTexture(
AssetLoader.file_path("textures", "grass2", "grass_path_2_rough_1k.png")
)
self.rock_tex_ratio_2 = 256 * self._terrain_size / 2048

v_wrap = Texture.WMRepeat
u_warp = Texture.WMMirror

for tex in [self.rock_tex_2, self.rock_normal_2, self.rock_rough_2]:
tex.set_wrap_u(u_warp)
tex.set_wrap_v(v_wrap)
tex.setMinfilter(filter_type)
tex.setMagfilter(filter_type)

# # sidewalk
# self.side_tex = self.loader.loadTexture(AssetLoader.file_path("textures", "sidewalk", "color.png"))
# self.side_normal = self.loader.loadTexture(AssetLoader.file_path("textures", "sidewalk", "normal.png"))
Expand All @@ -481,16 +493,15 @@ def _load_mesh_terrain_textures(self, engine, anisotropic_degree=16, filter_type
# tex.setAnisotropicDegree(1)

# Road surface
# self.road_texture = self.loader.loadTexture(AssetLoader.file_path("textures", "sci", "new_color.png"))
self.road_texture = self.loader.loadTexture(AssetLoader.file_path("textures", "asphalt", "diff_2k.png"))
self.road_texture_normal = self.loader.loadTexture(
AssetLoader.file_path("textures", "asphalt", "normal_2k.png")
)
self.road_texture_rough = self.loader.loadTexture(AssetLoader.file_path("textures", "asphalt", "rough_2k.png"))
self.road_tex_ratio = 128 * self._terrain_size / 2048
v_wrap = Texture.WMRepeat
u_warp = Texture.WMMirror
filter_type = Texture.FTLinearMipmapLinear
anisotropic_degree = 16
for tex in [self.road_texture_rough, self.road_texture, self.road_texture_normal]:
tex.set_wrap_u(u_warp)
tex.set_wrap_v(v_wrap)
Expand All @@ -502,15 +513,15 @@ def _load_mesh_terrain_textures(self, engine, anisotropic_degree=16, filter_type
# self.road_texture.setAnisotropicDegree(1)

# lane line
white_lane_line = PNMImage(1024, 1024, 4)
white_lane_line.fill(1., 1., 1.)
self.white_lane_line = Texture("white lane line")
self.white_lane_line.load(white_lane_line)

yellow_lane_line = PNMImage(1024, 1024, 4)
yellow_lane_line.fill(*(255 / 255, 200 / 255, 0 / 255))
self.yellow_lane_line = Texture("white lane line")
self.yellow_lane_line.load(yellow_lane_line)
# white_lane_line = PNMImage(256, 256, 4)
# white_lane_line.fill(1., 1., 1.)
# self.white_lane_line = Texture("white lane line")
# self.white_lane_line.load(white_lane_line)
#
# yellow_lane_line = PNMImage(256, 256, 4)
# yellow_lane_line.fill(*(255 / 255, 200 / 255, 0 / 255))
# self.yellow_lane_line = Texture("white lane line")
# self.yellow_lane_line.load(yellow_lane_line)

# crosswalk
tex = np.frombuffer(self.road_texture.getRamImage().getData(), dtype=np.uint8)
Expand Down Expand Up @@ -601,14 +612,16 @@ def get_terrain_semantics(self, center_point):
center_point,
size=self._semantic_map_size,
pixels_per_meter=self._semantic_map_pixel_per_meter,
polyline_thickness=int(self._semantic_map_pixel_per_meter / 11),
white_line_thickness=2,
yellow_line_thickness=3,
# 1 when map_region_size == 2048, 2 for others
layer=layer
)
else:
logger.warning("Can not find map. Generate a square terrain")
size = self._semantic_map_size * self._semantic_map_pixel_per_meter
semantics = np.ones((size, size, 1), dtype=np.float32) * 0.2
lane_color = MapTerrainSemanticColor.get_color(MetaDriveType.LANE_SURFACE_STREET)
semantics = np.ones((size, size, 1), dtype=np.uint8) * lane_color # use lane color
return semantics

@staticmethod
Expand Down
11 changes: 6 additions & 5 deletions metadrive/envs/base_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import time
from collections import defaultdict
from typing import Union, Dict, AnyStr, Optional, Tuple, Callable
from metadrive.constants import DEFAULT_SENSOR_HPR, DEFAULT_SENSOR_OFFSET

import gymnasium as gym
import numpy as np
from panda3d.core import PNMImage
Expand All @@ -12,6 +12,7 @@
from metadrive.component.sensors.dashboard import DashBoard
from metadrive.component.sensors.distance_detector import LaneLineDetector, SideDetector
from metadrive.component.sensors.lidar import Lidar
from metadrive.constants import DEFAULT_SENSOR_HPR, DEFAULT_SENSOR_OFFSET
from metadrive.constants import RENDER_MODE_NONE, DEFAULT_AGENT
from metadrive.constants import RENDER_MODE_ONSCREEN, RENDER_MODE_OFFSCREEN
from metadrive.constants import TerminationState, TerrainProperty
Expand Down Expand Up @@ -217,7 +218,7 @@

# ===== Terrain =====
# The size of the square map region, which is centered at [0, 0]. The map objects outside it are culled.
map_region_size=1024,
map_region_size=2048,
# Whether to remove lanes outside the map region. If True, lane localization only applies to map region
cull_lanes_outside_map=False,
# Road will have a flat marin whose width is determined by this value, unit: [m]
Expand Down Expand Up @@ -331,7 +332,7 @@ def _post_process_config(self, config):

# Adjust terrain
n = config["map_region_size"]
assert (n & (n - 1)) == 0 and 0 < n <= 2048, "map_region_size should be pow of 2 and < 2048."
assert (n & (n - 1)) == 0 and 512 <= n <= 4096, "map_region_size should be pow of 2 and < 2048."
TerrainProperty.map_region_size = config["map_region_size"]

# Multi-Thread
Expand Down Expand Up @@ -440,7 +441,7 @@ def step(self, actions: Union[Union[np.ndarray, list], Dict[AnyStr, Union[list,
return self._get_step_return(actions, engine_info=engine_info) # collect observation, reward, termination

def _preprocess_actions(self, actions: Union[np.ndarray, Dict[AnyStr, np.ndarray], int]) \
-> Union[np.ndarray, Dict[AnyStr, np.ndarray], int]:
-> Union[np.ndarray, Dict[AnyStr, np.ndarray], int]:
if not self.is_multi_agent:
actions = {v_id: actions for v_id in self.agents.keys()}
else:
Expand Down Expand Up @@ -637,7 +638,7 @@ def _get_step_return(self, actions, engine_info):

if not self.is_multi_agent:
return self._wrap_as_single_agent(obses), self._wrap_as_single_agent(rewards), \
self._wrap_as_single_agent(terminateds), self._wrap_as_single_agent(
self._wrap_as_single_agent(terminateds), self._wrap_as_single_agent(
truncateds), self._wrap_info_as_single_agent(step_infos)
else:
return obses, rewards, terminateds, truncateds, step_infos
Expand Down
2 changes: 1 addition & 1 deletion metadrive/envs/scenario_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
store_data=True,
need_lane_localization=True,
no_map=False,
map_region_size=512,
map_region_size=2048,
cull_lanes_outside_map=True,

# ===== Scenario =====
Expand Down
Loading
Loading