[CG Pipeline] Refactor

This commit is contained in:
brothermechanic 2023-11-13 13:07:33 +00:00 committed by Igor Brylyov
parent 6538f70d54
commit b3612d8655
23 changed files with 634 additions and 645 deletions

View file

@ -15,158 +15,148 @@ DESCRIPTION.
Reorganization and restructuring of assembly structure
based on LCS point objects.
'''
__version__ = '0.1'
__version__ = '0.2'
import logging
import math
import bpy
from mathutils import Matrix
import mathutils
from blender.utils.object_relations import (parenting,
unparenting)
from blender.utils.object_transforms import round_transforms
from blender.utils.collection_tools import unlink_from_collections
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
# COLLECTIONS NAMIG CONVENTION
parts_col_name = 'Parts'
lcs_col_name = 'LCS'
hierarchy_col_name = 'Hierarchy'
lowpoly_col_name = 'Lowpoly'
# LCS POINT'S SUFFIXES CONVENTION
inlet = '_in'
outlet = '_out'
root = '_root'
# CG ASSETS SUFFIXES CONVENTION
hightpoly = '_hp'
lowpoly = '_lp'
render = '_render'
def restruct_hierarchy(lcs_names, parts_sequence=None, **cg_config):
''' Execute restructurisation. '''
main_locators = [obj for obj in bpy.data.objects if not obj.parent]
assert len(main_locators) == 1, (
'Scene should have only one root parent locator!')
def retree_by_lcs(lcs_objects, root_lcs):
''' Organizing project structure based on LCS. '''
for lcs in lcs_objects:
lcs_inlet_objects = []
lcs_outlet_objects = []
for name in lcs_names:
if name.endswith(cg_config['lcs_inlet']):
lcs_inlet_objects.append(bpy.data.objects[name])
if name.endswith(cg_config['lcs_outlet']):
lcs_outlet_objects.append(bpy.data.objects[name])
if len(lcs_inlet_objects) > 1:
assert parts_sequence, (
'Parts sequence do not assign! Process stopped!')
for locator in main_locators[0].children:
assert locator.name in parts_sequence, (
'Can not find {} in "parts_sequence" config!'
.format(locator.name))
first_part_obj = bpy.data.objects[parts_sequence[0]]
elif len(lcs_inlet_objects) == 1:
first_part_obj = lcs_inlet_objects[0].parent
else:
# TODO
first_part_obj = None
assert lcs_inlet_objects, (
'Scene do not contain any inlet lcs! Process stopped!')
# create root lcs by parts sequence
root_lcs = None
for lcs in first_part_obj.children:
if lcs.name not in lcs_names:
continue
if lcs.name.endswith(cg_config['lcs_outlet']):
continue
root_lcs_name = cg_config['lcs_root']
root_lcs = bpy.data.objects.new(root_lcs_name, None)
root_lcs.empty_display_type = 'ARROWS'
root_lcs.empty_display_size = 0.15
root_lcs.show_in_front = True
root_lcs.location = lcs.location
root_lcs.rotation_euler = lcs.rotation_euler
root_lcs.parent = lcs.parent
bpy.data.collections[cg_config['lcs_col_name']].objects.link(root_lcs)
logger.info('Root Inlet LCS object created!')
unparenting(root_lcs)
round_transforms(root_lcs)
parenting(root_lcs, main_locators[0])
# retree_by lcs
for lcs in lcs_inlet_objects:
locator = lcs.parent
if lcs.name.endswith(inlet):
unparenting(lcs)
round_transforms(lcs)
unparenting(lcs)
round_transforms(lcs)
if locator:
if locator.parent:
unparenting(locator)
parenting(lcs, locator)
parenting(root_lcs, lcs)
for lcs in lcs_objects:
if lcs.name.endswith(outlet):
unparenting(lcs)
round_transforms(lcs)
parenting(
lcs_objects[lcs_objects.index(
bpy.data.objects[
'{}{}'.format(lcs.name.split(outlet)[0], inlet)])],
lcs)
parenting(root_lcs, lcs)
for lcs in lcs_outlet_objects:
unparenting(lcs)
round_transforms(lcs)
parenting(
lcs_inlet_objects[lcs_inlet_objects.index(bpy.data.objects[
'{}_{}'.format(lcs.name.rpartition('_')[0], cg_config['lcs_inlet'])
])],
lcs)
# reset transforms for root_lcs
root_lcs.matrix_world = mathutils.Matrix()
root_lcs.matrix_world = Matrix()
return lcs_objects
def closest_lcs(lcs_objects):
''' Finding closest outlet to inlet LCS. '''
target_dists = {}
for target in lcs_objects:
if target.name.endswith(inlet):
dists = {}
for lcs in lcs_objects:
if lcs.name.endswith(outlet):
dist = math.dist(
target.matrix_world.translation,
lcs.matrix_world.translation)
dists[lcs.name] = dist
min_dist = min(dists.values())
if min_dist < 0.01:
min_lcs = [k for k, v in dists.items() if v == min_dist][0]
target_dists[target.name] = min_lcs
return target_dists
def lcs_constrainting(lcs_objects, root_lcs):
''' Placing inlet right on outlet LCS. '''
closests = closest_lcs(lcs_objects)
for lcs in lcs_objects:
if lcs.name in closests:
constraint = lcs.constraints.new(type='COPY_TRANSFORMS')
constraint.target = bpy.data.objects[closests[lcs.name]]
if lcs.name.endswith(outlet):
constraint = lcs.constraints.new(type='COPY_TRANSFORMS')
constraint.target = root_lcs
constraint.enabled = False
for lcs in lcs_objects:
if len(lcs.constraints) == 0:
constraint = lcs.constraints.new(type='COPY_TRANSFORMS')
constraint.target = root_lcs
constraint.enabled = False
return lcs_objects
def unlink_from_col(obj):
''' Unlinking object from all collections. '''
for col in bpy.data.collections:
if obj.name in col.objects:
col.objects.unlink(obj)
return obj
def lcs_collections(root_lcs, lcs_objects):
''' Create LCS based hierarchy. '''
# lcs collections
part_names = []
for lcs in root_lcs.children:
lcs_col = bpy.data.collections.new(
'{}{}'.format(lcs.name.split(inlet)[0], hightpoly))
bpy.data.collections[parts_col_name].children.link(lcs_col)
# remove unmarked parts
if lcs not in lcs_inlet_objects:
for obj in lcs.children_recursive:
bpy.data.objects.remove(obj, do_unlink=True)
bpy.data.objects.remove(lcs, do_unlink=True)
continue
# collect part names
part_name = None
for locator in lcs.children:
if locator not in lcs_outlet_objects:
part_name = locator.name
part_names.append(part_name)
# pack parts to collections
part_col = bpy.data.collections.new('{}_{}'.format(
part_name, cg_config['hightpoly']))
bpy.data.collections[cg_config['parts_col_name']].children.link(part_col)
for obj in lcs.children_recursive:
unlink_from_col(obj)
lcs_col.objects.link(obj)
if lcs not in lcs_objects:
unlink_from_col(lcs)
lcs_col.objects.link(lcs)
return root_lcs.children
# outlet lcs objects are already in place, don't move it
if obj in lcs_outlet_objects:
continue
unlink_from_collections(obj)
part_col.objects.link(obj)
# parts assembling TODO clones
if len(lcs_inlet_objects) > 1:
for idx, part_name in enumerate(parts_sequence):
# for clones
if part_name not in part_names:
continue
def restruct_hierarchy(lcs_names):
''' Execute restructurisation. '''
lcs_in = bpy.data.objects[part_name].parent
constraint = lcs_in.constraints.new(type='COPY_TRANSFORMS')
if idx == 0:
constraint.target = root_lcs
continue
# if asm pair exists
if bpy.data.objects.get(parts_sequence[idx - 1]):
lcs_target = [
lcs_out
for lcs_out in bpy.data.objects[parts_sequence[idx - 1]].parent.children
if lcs_out in lcs_outlet_objects][0]
constraint.target = lcs_target
else:
constraint.target = root_lcs
constraint.enabled = False
# for reseet transforms when exporting
for lcs in lcs_outlet_objects:
constraint = lcs.constraints.new(type='COPY_TRANSFORMS')
constraint.target = root_lcs
constraint.enabled = False
#lcs_objects = bpy.data.collections[lcs_col_name].objects
lcs_objects = []
root_lcs = None
if lcs_names:
for obj_name in lcs_names:
if obj_name.endswith(root):
root_lcs = bpy.data.objects[obj_name]
lcs_objects.append(bpy.data.objects[obj_name])
logger.info('Restructuring pipeline by LCS finished!')
main_locators = [obj for obj in bpy.data.objects if not obj.parent]
if len(main_locators) > 1:
logger.info('Scene has several main (root) locators! '
'This may cause an error!')
if root_lcs:
lcs_objects = [lcs for lcs in lcs_objects if lcs != root_lcs]
root_locator = root_lcs.parent
unparenting(root_lcs)
round_transforms(root_lcs)
unparenting(root_locator)
parenting(root_lcs, root_locator)
parenting(root_lcs, main_locators[0])
retree_by_lcs(lcs_objects, root_lcs)
lcs_constrainting(lcs_objects, root_lcs)
lcs_collections(root_lcs, lcs_objects)
# remove unused for now collection
bpy.data.collections.remove(bpy.data.collections[hierarchy_col_name])
return logger.info('Restructuring pipeline finished!')
else:
return logger.info('Lost root LCS object!')
else:
return logger.info('Restructuring pipeline canceled!')
return part_names