286 lines
12 KiB
Python
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
|
||
|
|
|