[Blender] Baking optimization
This commit is contained in:
parent
90945c0430
commit
25c9cbfbe9
6 changed files with 182 additions and 13 deletions
|
@ -26,6 +26,7 @@ logging.basicConfig(level=logging.INFO)
|
|||
def export_decorator(func):
|
||||
|
||||
def wrapper(**kwargs):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
# add defaults
|
||||
kwargs.setdefault('path', '//')
|
||||
kwargs.setdefault('subdir', '')
|
||||
|
|
78
cg/blender/processing/midpoly_setup.py
Normal file
78
cg/blender/processing/midpoly_setup.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
'''
|
||||
DESCRIPTION.
|
||||
Basic mesh processing for asset pipeline.
|
||||
'''
|
||||
__version__ = '0.1'
|
||||
|
||||
import logging
|
||||
import bpy
|
||||
import math
|
||||
|
||||
from blender.utils.object_relations import parenting
|
||||
from blender.utils.remove_collections import remove_collections
|
||||
from blender.utils.mesh_tools import collect_less_volume_objs
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
# COLLECTIONS NAMIG CONVENTION
|
||||
parts_col_name = 'Parts'
|
||||
lcs_col_name = 'LCS'
|
||||
hierarchy_col_name = 'Hierarchy'
|
||||
midpoly_col_name = 'Midpoly'
|
||||
lowpoly_col_name = 'Lowpoly'
|
||||
# LCS POINT'S SUFFIXES CONVENTION
|
||||
inlet = '_in'
|
||||
outlet = '_out'
|
||||
root = '_root'
|
||||
# CG ASSETS SUFFIXES CONVENTION
|
||||
hightpoly = '_hp'
|
||||
midpoly = 'mp'
|
||||
lowpoly = '_lp'
|
||||
render = '_render'
|
||||
|
||||
|
||||
def hightpoly_collections_to_midpoly(part_names):
|
||||
''' Convert part's collecttions to single objects. '''
|
||||
for part_name in part_names:
|
||||
midpoly_name = '_'.join((part_name, midpoly))
|
||||
midpoly_mesh = bpy.data.meshes.new(midpoly_name)
|
||||
midpoly_obj = bpy.data.objects.new(midpoly_name, midpoly_mesh)
|
||||
bpy.context.view_layer.update()
|
||||
part_inlet = bpy.data.objects.get('{}{}'.format(part_name, inlet))
|
||||
midpoly_obj.matrix_world = part_inlet.matrix_world.copy()
|
||||
parenting(part_inlet, midpoly_obj)
|
||||
midpoly_parts_col = bpy.data.collections['_'.join((parts_col_name, midpoly))]
|
||||
midpoly_parts_col.objects.link(midpoly_obj)
|
||||
for col in midpoly_parts_col.children.keys():
|
||||
if part_name in col:
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
exclude_objs = collect_less_volume_objs(
|
||||
bpy.data.collections[col].objects, min_volume=2.0e-06)
|
||||
for obj in bpy.data.collections[col].objects:
|
||||
if obj not in exclude_objs:
|
||||
obj.select_set(state=True)
|
||||
midpoly_obj.select_set(state=True)
|
||||
bpy.context.view_layer.objects.active = midpoly_obj
|
||||
bpy.ops.object.join()
|
||||
bpy.ops.object.shade_smooth(use_auto_smooth=True)
|
||||
break
|
||||
|
||||
midpoly_parts_col.name = midpoly_col_name
|
||||
for col in midpoly_parts_col.children.keys():
|
||||
remove_collections(col)
|
||||
|
||||
return logger.info('Setup of %s midpoly meshes is finished!', len(part_names))
|
|
@ -28,6 +28,7 @@ def uv_unwrap(obj_names, angle_limit=30):
|
|||
''' UV unwrapping and UV packing processing '''
|
||||
for obj_name in obj_names:
|
||||
obj = bpy.data.objects[obj_name]
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
|
57
cg/blender/utils/collection_tools.py
Normal file
57
cg/blender/utils/collection_tools.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
# coding: utf-8
|
||||
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
'''
|
||||
DESCRIPTION.
|
||||
Various collection tools.
|
||||
'''
|
||||
__version__ = '0.1'
|
||||
|
||||
import bpy
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def copy_objects(from_col, to_col, linked, double_lut):
|
||||
'''Function copying objects from collection to collection.'''
|
||||
for obj in from_col.objects:
|
||||
double = obj.copy()
|
||||
if not linked and obj.data:
|
||||
double.data = double.data.copy()
|
||||
to_col.objects.link(double)
|
||||
double_lut[obj] = double
|
||||
return True
|
||||
|
||||
|
||||
def copy_collections_recursive(collection, suffix='copy', linked=False):
|
||||
'''Function recursive copying collection.'''
|
||||
double_lut = defaultdict(lambda: None)
|
||||
parent = [p for p in (bpy.data.collections[:] + [bpy.context.scene.collection])
|
||||
if collection.name in p.children.keys()][0]
|
||||
|
||||
def _copy(parent, collection, suffix, linked=False):
|
||||
'''Function copying collection.'''
|
||||
clone_collection = bpy.data.collections.new(
|
||||
'_'.join((collection.name, suffix))
|
||||
)
|
||||
copy_objects(collection, clone_collection, linked, double_lut)
|
||||
|
||||
for _collection in collection.children:
|
||||
_copy(clone_collection, _collection, suffix, linked)
|
||||
|
||||
parent.children.link(clone_collection)
|
||||
|
||||
_copy(parent, collection, suffix, linked)
|
||||
for obj, double in tuple(double_lut.items()):
|
||||
parent = double_lut[obj.parent]
|
||||
if parent:
|
||||
double.parent = parent
|
||||
return True
|
|
@ -16,6 +16,7 @@ Various mesh tools for Edit Mode.
|
|||
'''
|
||||
__version__ = '0.1'
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
from math import radians
|
||||
|
||||
|
@ -81,3 +82,22 @@ def select_stratched_edges(me, edge_length_limit=0.002):
|
|||
edge_max.select_set(True)
|
||||
bmesh.update_edit_mesh(me)
|
||||
return me
|
||||
|
||||
|
||||
def collect_less_volume_objs(objs: list, min_volume):
|
||||
''' Separate selection for less volume objects. '''
|
||||
less_volume_objs = []
|
||||
for obj in objs:
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
if obj.type != 'MESH':
|
||||
continue
|
||||
# requed for bmesh
|
||||
obj.hide_set(False)
|
||||
obj.select_set(state=True)
|
||||
if obj.type == 'MESH':
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
if bm.calc_volume() < min_volume:
|
||||
less_volume_objs.append(obj)
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
return less_volume_objs
|
||||
|
|
|
@ -14,10 +14,12 @@ from itertools import zip_longest
|
|||
|
||||
from blender.utils.remove_collections import remove_collections
|
||||
from blender.utils.cleanup_orphan_data import cleanup_orphan_data
|
||||
from blender.utils.collection_tools import copy_collections_recursive
|
||||
from utils.cmd_proc import cmd_proc
|
||||
from blender.import_cad.build_blender_scene import json_to_blend
|
||||
from blender.processing.restruct_hierarchy_by_lcs import restruct_hierarchy
|
||||
from blender.processing.highpoly_setup import setup_meshes
|
||||
from blender.processing.midpoly_setup import hightpoly_collections_to_midpoly
|
||||
from blender.processing.lowpoly_setup import parts_to_shells
|
||||
from blender.processing.uv_setup import uv_unwrap
|
||||
from blender.export.dae import export_dae
|
||||
|
@ -59,6 +61,7 @@ outlet = '_out'
|
|||
root = '_root'
|
||||
# CG ASSETS SUFFIXES CONVENTION
|
||||
hightpoly = '_hp'
|
||||
midpoly = 'mp'
|
||||
lowpoly = '_lp'
|
||||
render = '_render'
|
||||
|
||||
|
@ -68,6 +71,7 @@ def cg_pipeline(**kwargs):
|
|||
|
||||
blend_path = kwargs.pop('blend_path', None)
|
||||
mesh_export_path = kwargs.pop('mesh_export_path', None)
|
||||
config = kwargs.pop('config', None)
|
||||
|
||||
# prepare blend file
|
||||
remove_collections()
|
||||
|
@ -88,7 +92,7 @@ def cg_pipeline(**kwargs):
|
|||
if imported_objects['objs_lcs']:
|
||||
restruct_hierarchy(imported_objects['objs_lcs'])
|
||||
|
||||
# save blender scene
|
||||
# save import in blender scene
|
||||
if blend_path is not None:
|
||||
if not os.path.isdir(os.path.dirname(blend_path)):
|
||||
os.makedirs(os.path.dirname(blend_path))
|
||||
|
@ -105,11 +109,18 @@ def cg_pipeline(**kwargs):
|
|||
for lcs_name in imported_objects['objs_lcs']
|
||||
if lcs_name.endswith(inlet)]
|
||||
|
||||
# prepare lowpoly
|
||||
lowpoly_objs = parts_to_shells(part_names)
|
||||
uv_unwrap(lowpoly_objs)
|
||||
# prepare midpoly
|
||||
copy_collections_recursive(
|
||||
bpy.data.collections[parts_col_name], suffix=midpoly
|
||||
)
|
||||
hightpoly_collections_to_midpoly(part_names)
|
||||
|
||||
# save blender scene
|
||||
|
||||
# prepare lowpoly
|
||||
lowpoly_obj_names = parts_to_shells(part_names)
|
||||
uv_unwrap(lowpoly_obj_names)
|
||||
|
||||
# save lowpoly in blender scene
|
||||
if blend_path is not None:
|
||||
if not os.path.isdir(os.path.dirname(blend_path)):
|
||||
os.makedirs(os.path.dirname(blend_path))
|
||||
|
@ -118,29 +129,30 @@ def cg_pipeline(**kwargs):
|
|||
# export object meshes and urdf
|
||||
to_urdf = collections.defaultdict(list)
|
||||
|
||||
if lowpoly_objs:
|
||||
export_objs = lowpoly_objs
|
||||
if lowpoly_obj_names:
|
||||
export_obj_names = lowpoly_obj_names
|
||||
else:
|
||||
export_objs = sum([imported_objects['objs_foreground'],
|
||||
export_obj_names = sum([imported_objects['objs_foreground'],
|
||||
imported_objects['objs_background']], [])
|
||||
|
||||
link = {}
|
||||
for export_obj in export_objs:
|
||||
for export_obj_name in export_obj_names:
|
||||
link_prop = {}
|
||||
if mesh_export_path is not None:
|
||||
link_prop['visual'] = export_dae(
|
||||
obj_name=export_obj, path=mesh_export_path, subdir='visual')
|
||||
obj_name=export_obj_name, path=mesh_export_path, subdir='visual')
|
||||
link_prop['collision'] = export_stl(
|
||||
obj_name=export_obj, path=mesh_export_path, subdir='collision')
|
||||
obj_name=export_obj_name, path=mesh_export_path, subdir='collision')
|
||||
|
||||
link[export_obj] = link_prop
|
||||
link[export_obj_name] = link_prop
|
||||
|
||||
to_urdf['links'].append(link)
|
||||
|
||||
config = {'sequences': [['cube1', 'cube2', 'cube3', 'cube4'], ['cube2', 'cube1', 'cube4', 'cube3']]}
|
||||
#config = {'sequences': [['cube1', 'cube2', 'cube3', 'cube4'], ['cube2', 'cube1', 'cube4', 'cube3']]}
|
||||
if config:
|
||||
for sequence in config['sequences']:
|
||||
joint = {}
|
||||
# TODO collect pairs 0_1, 1_2, 2_3, 3_4, ...
|
||||
for pair in zip_longest(sequence[0::2], sequence[1::2]):
|
||||
joint_prop = {}
|
||||
if pair[1]:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue