Files
2025-07-03 17:03:00 +08:00

286 lines
12 KiB
Python

from pathlib import Path
import yaml
from datetime import datetime
from pygarment.data_config import Properties
class PathCofig:
"""Routines for getting paths to various relevant objects with standard names"""
def __init__(self,
in_element_path, out_path, in_name, out_name=None,
body_name='', samples_name='', default_body=True,
smpl_body=False,
add_timestamp=False):
"""Specify
* in_element_path
* our_path -- dataset level output path
* body_name -- specify to indicate use of default bodies
* samples_name -- specify to indicate use of body sampling (reading body name from measurments file)
"""
self._system = Properties('./system.json') # TODOlOW More stable path?
self._body_name = body_name
self._samples_folder_name = samples_name
self._use_default_body = default_body
self.use_smpl_seg = smpl_body
# Tags
if out_name is None:
out_name = in_name
self.in_tag = in_name
self.out_folder_tag = f'{out_name}_{datetime.now().strftime("%y%m%d-%H-%M-%S")}' if add_timestamp else out_name
self.sim_tag = out_name
self.boxmesh_tag = out_name
# Base paths
self.input = Path(in_element_path)
self.out = out_path
self.out_el = Path(out_path) / self.out_folder_tag
self.out_el.mkdir(parents=True, exist_ok=True)
# Individual file paths
self._update_in_paths()
self._update_boxmesh_paths()
self.update_in_copies_paths()
self.update_sim_paths()
def _update_in_paths(self):
# Base path
if not self._samples_folder_name or self._use_default_body:
self.bodies_path = Path(self._system['bodies_default_path'])
else:
self.bodies_path = Path(self._system['body_samples_path']) / self._samples_folder_name / 'meshes'
# Body measurements
if not self._samples_folder_name:
self.in_body_mes = self.bodies_path / f'{self._body_name}.yaml'
else:
self.in_body_mes = self.input / 'body_measurements.yaml'
with open(self.in_body_mes, 'r') as file:
body_dict = yaml.load(file, Loader=yaml.SafeLoader)
if 'body_sample' in body_dict['body']: # Not present in default measurements
self._body_name = body_dict['body']['body_sample']
self.in_body_obj = self.bodies_path / f'{self._body_name}.obj'
self.in_g_spec = self.input / f'{self.in_tag}_specification.json'
self.body_seg = Path(self._system['bodies_default_path']) / ('ggg_body_segmentation.json' if not self.use_smpl_seg else 'smpl_vert_segmentation.json')
self.in_design_params = self.input / 'design_params.yaml'
def _update_boxmesh_paths(self):
self.g_box_mesh = self.out_el / f'{self.boxmesh_tag}_boxmesh.obj'
self.g_box_mesh_compressed = self.out_el / f'{self.boxmesh_tag}_boxmesh.ply'
self.g_mesh_segmentation = self.out_el / f'{self.boxmesh_tag}_sim_segmentation.txt'
self.g_orig_edge_len = self.out_el / f'{self.boxmesh_tag}_orig_lens.pickle'
self.g_vert_labels = self.out_el / f'{self.boxmesh_tag}_vertex_labels.yaml'
self.g_texture_fabric = self.out_el / f'{self.boxmesh_tag}_texture_fabric.png'
self.g_texture = self.out_el / f'{self.boxmesh_tag}_texture.png'
self.g_mtl = self.out_el / f'{self.boxmesh_tag}_material.mtl'
def update_in_copies_paths(self):
self.g_specs = self.out_el / f'{self.in_tag}_specification.json'
self.element_sim_props = self.out_el / 'sim_props.yaml'
self.body_mes = self.out_el / f'{self.in_tag}_body_measurements.yaml'
self.design_params = self.out_el / f'{self.in_tag}_design_params.yaml'
def update_sim_paths(self):
self.g_sim = self.out_el / f'{self.sim_tag}_sim.obj'
self.g_sim_glb = self.out_el / f'{self.sim_tag}_sim.glb'
self.g_sim_compressed = self.out_el / f'{self.sim_tag}_sim.ply'
self.usd = self.out_el / f'{self.sim_tag}_simulation.usd'
def render_path(self, camera_name=''):
fname = f'{self.sim_tag}_render_{camera_name}.png' if camera_name else f'{self.sim_tag}_render.png'
return self.out_el / fname
class SimConfig:
def __init__(self, sim_props):
# ---- Paths ----
# Sim props sections
self.props = sim_props
sim_props_option = sim_props['options']
sim_props_material = sim_props['material']
# Basic setup
self.sim_fps = 60.0
self.sim_substeps = 10 #increase?
self.sim_wo_gravity_percentage = 0
self.zero_gravity_steps = self.get_sim_props_value(sim_props, 'zero_gravity_steps', 5)
self.resolution_scale = self.get_sim_props_value(sim_props, 'resolution_scale', 1.0)
self.ground = self.get_sim_props_value(sim_props, 'ground', True)
# Stopping criteria
self.static_threshold = self.get_sim_props_value(sim_props, 'static_threshold', 0.01)
self.max_sim_steps = self.get_sim_props_value(sim_props, 'max_sim_steps', 1000)
self.max_frame_time = self.get_sim_props_value(sim_props, 'max_frame_time', None)
if self.max_frame_time is not None:
self.max_frame_time = int(self.max_frame_time)
self.max_sim_time = int(self.get_sim_props_value(sim_props, 'max_sim_time', 25 * 60))
self.non_static_percent = self.get_sim_props_value(sim_props, 'non_static_percent', 5)
# Quality filter
self.max_body_collisions = self.get_sim_props_value(sim_props, 'max_body_collisions', 0)
self.max_self_collisions = self.get_sim_props_value(sim_props, 'max_self_collisions', 0)
# Self-collision prevention properties
self.enable_particle_particle_collisions = self.get_sim_props_value(
sim_props_option,
'enable_particle_particle_collisions', False)
self.enable_triangle_particle_collisions = self.get_sim_props_value(
sim_props_option,
'enable_triangle_particle_collisions', False)
self.enable_edge_edge_collisions = self.get_sim_props_value(
sim_props_option,
'enable_edge_edge_collisions', False)
self.enable_body_collision_filters = self.get_sim_props_value(
sim_props_option,
'enable_body_collision_filters',
False
)
# Attachment constraints
self.enable_attachment_constraint = self.get_sim_props_value(
sim_props_option,
'enable_attachment_constraint',
False
)
self.attachment_labels = self.get_sim_props_value(
sim_props_option,
'attachment_label_names',
[]
)
self.attachment_frames = self.get_sim_props_value(
sim_props_option,
'attachment_frames',
100
)
self.attachment_stiffness = self.get_sim_props_value(
sim_props_option,
'attachment_stiffness',
[]
)
self.attachment_damping = self.get_sim_props_value(
sim_props_option,
'attachment_damping',
[]
)
if not self.attachment_frames or not self.attachment_labels:
self.enable_attachment_constraint = False
# Global damping properties
self.global_damping_factor = self.get_sim_props_value(
sim_props_option,'global_damping_factor', 1.)
self.global_damping_effective_velocity = self.get_sim_props_value(
sim_props_option,
'global_damping_effective_velocity', 0.0)
self.global_max_velocity = self.get_sim_props_value(
sim_props_option,'global_max_velocity', 50.0)
# Cloth global collision resolution (reference drag) options
self.enable_global_collision_filter = self.get_sim_props_value(
sim_props_option,
'enable_global_collision_filter',
False
)
self.enable_cloth_reference_drag = self.get_sim_props_value(
sim_props_option,
'enable_cloth_reference_drag', False)
self.cloth_reference_margin = self.get_sim_props_value(
sim_props_option,'cloth_reference_margin', 0.1)
self.cloth_reference_k = self.get_sim_props_value(
sim_props_option,'cloth_reference_k', 1.0e7)
# Body smoothing options
self.enable_body_smoothing = self.get_sim_props_value(
sim_props_option,'enable_body_smoothing', True)
self.smoothing_total_smoothing_factor = self.get_sim_props_value(
sim_props_option,
'smoothing_total_smoothing_factor', 1)
self.smoothing_recover_start_frame = self.get_sim_props_value(
sim_props_option,
'smoothing_recover_start_frame', 0)
self.smoothing_frame_gap_between_steps = self.get_sim_props_value(
sim_props_option,
'smoothing_frame_gap_between_steps', 5)
self.smoothing_num_steps = self.get_sim_props_value(
sim_props_option, 'smoothing_num_steps', 100)
self.smoothing_num_steps = max(min(
self.smoothing_num_steps, self.max_sim_steps - self.smoothing_recover_start_frame),
0)
if self.smoothing_num_steps == 0:
self.enable_body_smoothing = False
# ----- Fabric material properties -----
# Bending
self.garment_edge_ke = self.get_sim_props_value(
sim_props_material,'garment_edge_ke', 50000.0) #default = 100.0
self.garment_edge_kd = self.get_sim_props_value(
sim_props_material,'garment_edge_kd',10.0) #default = 0.0
# Area preservation
self.garment_tri_ke = self.get_sim_props_value(
sim_props_material,'garment_tri_ke', 10000.0) #default = 100.0, small number = more elasticity
self.garment_tri_kd = self.get_sim_props_value(
sim_props_material,'garment_tri_kd', 1.0) #default = 10.0
self.garment_tri_ka = self.get_sim_props_value(
sim_props_material, 'garment_tri_ka', 10000.0) # default = 100.0
self.garment_tri_drag = 0.0 # default = 0.0
self.garment_tri_lift = 0.0 #default = 0.0
# Thickness
self.garment_density = self.get_sim_props_value(
sim_props_material,'fabric_density', 1.0)
self.garment_radius = self.get_sim_props_value(
sim_props_material,'fabric_thickness', 0.1)
# Spring properties (Distance constraints)
self.spring_ke = self.get_sim_props_value(
sim_props_material,'spring_ke', 50000)
self.spring_kd = self.get_sim_props_value(
sim_props_material,'spring_kd', 10.0)
# Soft contact properties (contact between cloth and body)
self.soft_contact_margin = 0.2
self.soft_contact_ke = 1000.0
self.soft_contact_kd = 10.0
self.soft_contact_kf = 1000.0
self.soft_contact_mu = self.get_sim_props_value(
sim_props_material, 'fabric_friction', 0.5
)
# Body material
self.body_thickness = self.get_sim_props_value(sim_props_option,'body_collision_thickness', 0.0)
self.body_friction = self.get_sim_props_value(sim_props_option,'body_friction', 0.5)
# particle properties
# Some default values -- not used in cloth sim
self.particle_ke = 1.0e3
self.particle_kd = 1.0e2
self.particle_kf = 100.0
self.particle_mu = 0.5
self.particle_cohesion = 0.0
self.particle_adhesion = 0.0
# After the initialization
self.update_min_steps()
def update_min_steps(self):
self.min_sim_steps = 0
if self.enable_body_smoothing:
self.min_sim_steps = self.smoothing_recover_start_frame + self.smoothing_num_steps
if self.enable_attachment_constraint:
# NOTE: Adding a small number of frames
# to allow clothing movement to restart after attachment is released
self.min_sim_steps = max(self.min_sim_steps, self.attachment_frames + 5)
def get_sim_props_value(self, sim_props, name, default_value):
if name in sim_props:
return sim_props[name]
return default_value