RCG Init: migration from gitlab:robossembler/framework
This commit is contained in:
parent
dc41dd5ab9
commit
768f372edc
94 changed files with 2126 additions and 84 deletions
256
rcg_pipeline/render_asset.py
Normal file
256
rcg_pipeline/render_asset.py
Normal file
|
@ -0,0 +1,256 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2021-2024 Robossembler LLC
|
||||
#
|
||||
# Created by Ilia Kurochkin (brothermechanic)
|
||||
# contact: brothermechanic@yandex.com
|
||||
#
|
||||
# This file is part of Robossembler Framework
|
||||
# project repo: https://gitlab.com/robossembler/framework
|
||||
#
|
||||
# Robossembler Framework 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
#
|
||||
# coding: utf-8
|
||||
'''
|
||||
DESCRIPTION.
|
||||
Generate render asset from assembly tree and CG libs database.
|
||||
'''
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
|
||||
import bpy
|
||||
from mathutils import Vector, Matrix
|
||||
|
||||
from .utils.collection_tools import remove_collections_with_objects
|
||||
from .utils.cleanup_orphan_data import cleanup_orphan_data
|
||||
from .utils.object_relations import unparenting, parenting
|
||||
from .utils.object_transforms import round_transforms
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def recursive_layer_collection(layer_coll, coll_name):
|
||||
found = None
|
||||
if layer_coll.name == coll_name:
|
||||
return layer_coll
|
||||
for layer in layer_coll.children:
|
||||
found = recursive_layer_collection(layer, coll_name)
|
||||
if found:
|
||||
return found
|
||||
return False
|
||||
|
||||
|
||||
def assembly_builder(item, libs_data, libs_data_dir, collection=None, parent=None):
|
||||
'''
|
||||
'''
|
||||
if not collection:
|
||||
collection = bpy.context.scene.collection
|
||||
|
||||
item_obj = None
|
||||
|
||||
if item['type'] == 'LOCATOR':
|
||||
item_obj = bpy.data.objects.new(item['name'], None)
|
||||
item_obj.empty_display_type = 'CUBE'
|
||||
item_obj.empty_display_size = 0.0005
|
||||
collection.objects.link(item_obj)
|
||||
|
||||
elif item['type'] == 'LCS':
|
||||
item_obj = bpy.data.objects.new(item['name'], None)
|
||||
item_obj.empty_display_type = 'ARROWS'
|
||||
item_obj.empty_display_size = round(random.uniform(0.05, 0.15), 3)
|
||||
item_obj.show_in_front = True
|
||||
collection.objects.link(item_obj)
|
||||
|
||||
elif item['type'] == 'PART':
|
||||
item_data = [
|
||||
data for data in libs_data
|
||||
if data['type'] == 'OBJECT'
|
||||
if data['name'] == item['base_name']]
|
||||
if not item_data:
|
||||
logger.error('No %s in database!', item['base_name'])
|
||||
return False
|
||||
# if there is local base_named object in scene -> rename it
|
||||
local_obj = None
|
||||
# for clones
|
||||
if item['base_name'] != item['name']:
|
||||
local_obj = [
|
||||
loc for loc in bpy.data.objects
|
||||
if loc.name == item['base_name']
|
||||
if not loc.library]
|
||||
if local_obj:
|
||||
local_obj[0].name += '_loc'
|
||||
item_file_path = os.path.join(libs_data_dir, item_data[0]['path'])
|
||||
# TODO already linked
|
||||
bpy.ops.wm.link(
|
||||
filepath=item_file_path,
|
||||
directory=os.path.join(item_file_path, 'Collection'),
|
||||
filename=item['base_name'],
|
||||
relative_path=True,
|
||||
do_reuse_local_id=True,
|
||||
active_collection=True,
|
||||
)
|
||||
item_obj = bpy.data.objects[item['base_name']]
|
||||
# for clones
|
||||
if item['base_name'] != item['name']:
|
||||
item_obj.name = item['name']
|
||||
# rename local back
|
||||
if local_obj:
|
||||
local_obj[0].name = item['base_name']
|
||||
item_obj.empty_display_type = 'PLAIN_AXES'
|
||||
item_obj.empty_display_size = 0.0005
|
||||
|
||||
else:
|
||||
logger.error('Unknown object type %s of %s', item['type'], item['name'])
|
||||
return False
|
||||
|
||||
item_obj.location = Vector(item['pose'][0]['loc_xyz']) * 0.001
|
||||
item_obj.rotation_mode = 'QUATERNION'
|
||||
item_obj.rotation_quaternion = [
|
||||
item['pose'][1]['rot_xyzw'][3]] + item['pose'][1]['rot_xyzw'][:3]
|
||||
|
||||
if item.get('attributes'):
|
||||
for attr in item['attributes']:
|
||||
item_obj[list(attr)[0]] = attr[list(attr)[0]]
|
||||
|
||||
item_obj.parent = parent
|
||||
|
||||
if item.get('children'):
|
||||
for child_item in item.get('children'):
|
||||
assembly_builder(
|
||||
child_item, libs_data, libs_data_dir, collection, parent=item_obj)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def assembly_rebuilder():
|
||||
''' Restructure assembling hierarchy. '''
|
||||
default_origin = [
|
||||
lcs for lcs in bpy.data.objects
|
||||
if lcs.type == 'EMPTY'
|
||||
if lcs.get('Robossembler_SocketFlow') == 'inlet'
|
||||
if lcs.get('Robossembler_DefaultOrigin')]
|
||||
if not default_origin:
|
||||
raise Exception('Default Origin not found!')
|
||||
if len(default_origin) > 1:
|
||||
raise Exception('Several Default Origins do not supported!')
|
||||
default_origin = default_origin[0]
|
||||
|
||||
root_locator = [
|
||||
obj for obj in bpy.data.objects
|
||||
if not obj.parent
|
||||
if not obj.library]
|
||||
for i in root_locator:
|
||||
print(i.name)
|
||||
if len(root_locator) > 1:
|
||||
raise Exception('Render asset should consist of only one hierarchy!')
|
||||
root_locator = root_locator[0]
|
||||
|
||||
# retree_by lcs
|
||||
for lcs in bpy.data.objects:
|
||||
if lcs.type == 'EMPTY':
|
||||
if lcs.get('Robossembler_SocketFlow'):
|
||||
unparenting(lcs)
|
||||
round_transforms(lcs)
|
||||
|
||||
parenting(default_origin, root_locator)
|
||||
|
||||
for lcs in bpy.data.objects:
|
||||
if lcs.type == 'EMPTY':
|
||||
if lcs.get('Robossembler_SocketFlow'):
|
||||
if lcs != default_origin:
|
||||
parenting(default_origin, lcs)
|
||||
|
||||
default_origin.matrix_world = Matrix()
|
||||
|
||||
logger.info('Restructuring assembling hierarchy finished!')
|
||||
|
||||
return default_origin
|
||||
|
||||
|
||||
def build_render_assets(project_dir):
|
||||
'''
|
||||
'''
|
||||
assets_data = []
|
||||
|
||||
libs_data_path = os.path.join(project_dir, 'libs.json')
|
||||
if not os.path.exists(libs_data_path):
|
||||
raise Exception('No libs database found! Check %s directory' % project_dir)
|
||||
with open(libs_data_path, encoding='utf-8') as data:
|
||||
libs_data = json.load(data)
|
||||
trees_path = os.path.join(project_dir, 'trees.json')
|
||||
if not os.path.exists(trees_path):
|
||||
raise Exception('No trees database found! Check %s directory' % project_dir)
|
||||
with open(trees_path, encoding='utf-8') as data:
|
||||
tree_item_list = json.load(data)
|
||||
|
||||
# render assets dir
|
||||
render_assets_dir = os.path.join(project_dir, 'assets', 'render')
|
||||
if os.path.exists(render_assets_dir):
|
||||
shutil.rmtree(render_assets_dir)
|
||||
os.makedirs(render_assets_dir)
|
||||
else:
|
||||
os.makedirs(render_assets_dir)
|
||||
|
||||
for tree_item in tree_item_list:
|
||||
# start from stratch
|
||||
bpy.ops.wm.read_homefile()
|
||||
remove_collections_with_objects()
|
||||
cleanup_orphan_data()
|
||||
|
||||
# create redner collection
|
||||
render_collection = bpy.data.collections.new(tree_item['name'])
|
||||
bpy.context.scene.collection.children.link(render_collection)
|
||||
active_collection = recursive_layer_collection(
|
||||
bpy.context.view_layer.layer_collection,
|
||||
render_collection.name)
|
||||
bpy.context.view_layer.active_layer_collection = active_collection
|
||||
|
||||
# build original hierarchy
|
||||
assembly_builder(tree_item, libs_data, project_dir, render_collection)
|
||||
# rebuild to LCS hierarchy
|
||||
assembly_rebuilder()
|
||||
|
||||
# mark as asset
|
||||
render_collection.asset_mark()
|
||||
# TODO collection thumbnail
|
||||
|
||||
blend_path = os.path.join(render_assets_dir, tree_item['name'] + '.blend')
|
||||
bpy.ops.wm.save_as_mainfile(filepath=blend_path)
|
||||
logger.info('Render asset %s generated!', tree_item['name'])
|
||||
|
||||
assets_data.append(
|
||||
{
|
||||
'type': 'RENDER',
|
||||
'name': tree_item['name'],
|
||||
'path': os.path.relpath(blend_path, project_dir),
|
||||
'thumbnail': ''
|
||||
}
|
||||
)
|
||||
logger.info('%s Render Assets was generated!', len(tree_item_list))
|
||||
# write db file
|
||||
assets_data_path = os.path.join(project_dir, 'assets.json')
|
||||
with open(assets_data_path, 'w', encoding='utf-8') as assets_data_file:
|
||||
json.dump(assets_data, assets_data_file, ensure_ascii=False, indent=4)
|
||||
logger.info('Database saved successfully to %s!', assets_data_path)
|
||||
|
||||
return render_assets_dir
|
Loading…
Add table
Add a link
Reference in a new issue