[CG Pipeline] Refactor
This commit is contained in:
parent
6538f70d54
commit
b3612d8655
23 changed files with 634 additions and 645 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue