Compare commits

..

11 Commits

Author SHA1 Message Date
stilobique 88f5deeda0 Automatized the thumbnail generation, and adding easily all lights 2024-06-07 11:56:09 +02:00
stilobique 4017020909 Packed the HDR texture 2024-06-07 11:14:29 +02:00
stilobique 65ef02eb26 Clear import lib 2024-06-07 10:59:26 +02:00
stilobique 44b0781b94 Setup thumbnail param
Update export to find export path without the operator
2024-06-07 10:49:41 +02:00
stilobique cfb7a8b514 Fix character error 2024-06-06 22:11:22 +02:00
stilobique c61ba477ad Write a basic operator to generate the thumbnail 2024-06-06 22:03:56 +02:00
stilobique 83d321c69d Make a class panel to easily draw each class 2024-06-06 19:55:46 +02:00
stilobique cd8301e29c Refactoring, split the panel 2024-06-06 19:41:11 +02:00
stilobique a9564255da WIP to convert curve to geometry 2024-05-31 17:46:07 +02:00
stilobique 0821574902 WIP Lighting build 2024-05-31 17:31:39 +02:00
stilobique 4fa3170b93 Clear git ignore file 2024-05-31 11:02:05 +02:00
14 changed files with 212 additions and 95 deletions
-15
View File
@@ -7,24 +7,9 @@
__pycache__/ __pycache__/
**/__pycache__/ **/__pycache__/
# Unit Test #
*.zip
tests/blender/**
tests/blender/*.dmg
!tests/blender/.keep
### Blender ### ### Blender ###
*.blend1 *.blend1
### Unreal ###
tests/unreal_sample/DerivedDataCache
tests/unreal_sample/Intermediate
tests/unreal_sample/Saved
# Secret file
**/token.txt
# Virtual Environment # Virtual Environment
**/venv/** **/venv/**
venv/ venv/
+12 -5
View File
@@ -1,10 +1,17 @@
import bpy import bpy
from .ui.export import GRAOU_PT_panel # UI and Interface
from .operators.outline import ConfigBlendScene from .ui.asset import GraouPanel_asset
from .ui.export import GRAOU_PT_export
from .ui.icon import GraouPanel_thumbnail
from .ui.setup import GRAOU_PT_setup
# All operators
from .operators.exports import ExportForFange from .operators.exports import ExportForFange
from .operators.outline import ConfigBlendScene
from .operators.misc import MakeBasicCollision from .operators.misc import MakeBasicCollision
from .operators.lighting import ConfigLighting from .operators.lighting import ConfigLighting
from .operators.thumbnails import ConfigRendering
# Preferences and properties
from .preference import GRAOU_AddonPreference from .preference import GRAOU_AddonPreference
from .properties.main import FangeProperties from .properties.main import FangeProperties
@@ -22,9 +29,9 @@ bl_info = {
modules_class = [ modules_class = [
# Main operators property # Main operators property
ExportForFange, MakeBasicCollision, ConfigBlendScene, ConfigLighting, ExportForFange, MakeBasicCollision, ConfigBlendScene, ConfigLighting, ConfigRendering,
# UI # UI, the order are the way to select how show each panel
GRAOU_PT_panel, GRAOU_PT_setup, GraouPanel_asset, GRAOU_PT_export, GraouPanel_thumbnail,
# Preference # Preference
GRAOU_AddonPreference, FangeProperties GRAOU_AddonPreference, FangeProperties
] ]
+9 -34
View File
@@ -1,7 +1,6 @@
import bpy import bpy
from ..properties.models import FangeProject from ..utils import get_export_path, get_asset_name
from pathlib import Path
class ExportForFange(bpy.types.Operator): class ExportForFange(bpy.types.Operator):
@@ -12,11 +11,11 @@ Requiert your blend file are write on your hard-drive."""
def __init__(self): def __init__(self):
self.coll_layout = bpy.data.collections.get('Placeholder') self.coll_layout = bpy.data.collections.get('Placeholder')
self.path = FangeProject() self.asset = get_asset_name()
self.asset = self.get_asset_name() self.category = get_export_path()
self.category = self.get_asset_type()
self.instance_type_dict = {} self.instance_type_dict = {}
self.temp_copy = {}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@@ -48,7 +47,7 @@ Requiert your blend file are write on your hard-drive."""
for ob in child.all_objects: for ob in child.all_objects:
print(f'\tLook "{ob.name}", his type are "{type(ob.data)}"') print(f'\tLook "{ob.name}", his type are "{type(ob.data)}"')
# TODO Support another type object, not only SM/SK # TODO Support another type object, not only SM/SK
if ob.type == 'MESH' or 'EMPTY': if ob.type == 'MESH' or 'EMPTY' or 'CURVE':
print(f'[Pipeline] Check ob {ob.name} and is type {type(ob)}') print(f'[Pipeline] Check ob {ob.name} and is type {type(ob)}')
ob.select_set(True) ob.select_set(True)
@@ -57,6 +56,10 @@ Requiert your blend file are write on your hard-drive."""
self.instance_type_dict[ob.name] = ob.instance_type self.instance_type_dict[ob.name] = ob.instance_type
ob.instance_type = 'NONE' ob.instance_type = 'NONE'
if ob.type == 'CURVE':
# Make a new objet with the Geo
bpy.ops.object.convert(target='CURVE')
abs_export = self.category.joinpath(self.asset, "Meshes") abs_export = self.category.joinpath(self.asset, "Meshes")
if not abs_export.exists(): if not abs_export.exists():
abs_export.mkdir(parents=True) abs_export.mkdir(parents=True)
@@ -115,34 +118,6 @@ Requiert your blend file are write on your hard-drive."""
self.report({'INFO'}, 'Placeholder exported') self.report({'INFO'}, 'Placeholder exported')
return {'FINISHED'} return {'FINISHED'}
def get_asset_type(self) -> Path:
"""Look the file path, to understand if the asset are a Character, Buildings or Props"""
abs_blend_path = Path(bpy.data.filepath)
print(f'[Pipeline] Get blend file path "{abs_blend_path}"')
print(f'[Pipeline] Convert to List "{abs_blend_path.parts}"')
if 'Buildings' in abs_blend_path.parts:
print(f'[Pipeline] Export here "{self.path.buildings}"')
return self.path.buildings
elif 'Pros' in abs_blend_path.parts:
print(f'[Pipeline] Export here "{self.path.props}"')
return self.path.props
elif 'Characters' in abs_blend_path.parts:
print(f'[Pipeline] Export here "{self.path.characters}"')
return self.path.characters
else:
print(f'[Pipeline] Can\'t find asset category')
return Path()
@staticmethod
def get_asset_name() -> str:
"""From the .blend file, return the blend name."""
abs_blend_path = Path(bpy.data.filepath)
return abs_blend_path.stem
def set_instance_type(self): def set_instance_type(self):
for key, value in self.instance_type_dict.items(): for key, value in self.instance_type_dict.items():
ob = bpy.data.objects.get(key) ob = bpy.data.objects.get(key)
+53 -1
View File
@@ -1,5 +1,7 @@
import bpy import bpy
from pathlib import Path
class ConfigLighting(bpy.types.Operator): class ConfigLighting(bpy.types.Operator):
"""Add or conform a lighting build""" """Add or conform a lighting build"""
@@ -7,6 +9,56 @@ class ConfigLighting(bpy.types.Operator):
bl_label = 'Config or update a lighting' bl_label = 'Config or update a lighting'
def execute(self, context): def execute(self, context):
print(f'[Pipeline] Start lighting operator') # Look if a light object are in the scene to clear
self.clear_light_on_scene()
r = self.get_blend_resources_file()
world = bpy.data.worlds.get('WorldIconRendering')
if not world:
with bpy.data.libraries.load(r, link=True) as (data_from, data_to):
data_to.worlds = data_from.worlds
world = bpy.data.worlds.get('WorldIconRendering')
context.scene.world = world
if not bpy.data.collections.get('Lighting'):
print(f'[Pipeline] Need to import the lighting collection')
with bpy.data.libraries.load(r, link=False) as (data_from, data_to):
for collection in data_from.collections:
print(f'[Pipeline] Collection can be import "{collection}"')
if 'Lighting' in collection:
print(f'[Pipeline] Append {collection}.')
data_to.collections.append(collection)
print('[Pipeline] Link lighting collection with the scene collection')
bpy.data.collections['Scene'].children.link(bpy.data.collections.get('Lighting'))
return {'FINISHED'} return {'FINISHED'}
@staticmethod
def get_blend_resources_file():
"""Get the blend file shared with the addon"""
addon_folder = Path(bpy.utils.user_resource('SCRIPTS'))
addon_name = __name__.split(".")[0]
return addon_folder.joinpath("addons", addon_name, "resources", "Lighting.blend").as_posix()
def clear_light_on_scene(self):
bpy.ops.object.select_all(action='DESELECT')
for ob in bpy.data.objects:
if ob.type == 'LIGHT' and not self.find_collection(ob):
ob.select_set(True)
bpy.ops.object.delete()
else:
ob.select_set(False)
@staticmethod
def find_collection(ob, name='Lighting'):
"""Check if an object are attached with the Lighting collection"""
for collection in ob.users_collection:
if collection.name == name:
return True
+1
View File
@@ -11,4 +11,5 @@ class MakeBasicCollision(bpy.types.Operator):
return bpy.context.object return bpy.context.object
def execute(self, context): def execute(self, context):
# TODO
return {'FINISHED'} return {'FINISHED'}
+2
View File
@@ -86,5 +86,7 @@ class SetCollectionSocket(bpy.types.Operator):
def __init__(self): def __init__(self):
self.socket = bpy.data.collections.get('Socket') self.socket = bpy.data.collections.get('Socket')
def execute(self, context): def execute(self, context):
# TODO
return {'FINISHED'} return {'FINISHED'}
+44
View File
@@ -0,0 +1,44 @@
import bpy
from ..utils import get_export_path, get_asset_name
from pathlib import Path
class ConfigRendering(bpy.types.Operator):
"""Setup camera and rendering config"""
bl_idname = 'graou_config.rendering_thumbnail'
bl_label = 'Setup the blend file to be ready'
def __init__(self):
self.scene = bpy.data.scenes['Scene']
self.path_export = get_export_path()
self.asset_name = get_asset_name()
self.filename_export = Path(self.path_export, self.asset_name, f'TX_Icon{self.asset_name}.tga')
def execute(self, context):
self.set_camera_used()
self.set_rendering_panel()
self.set_output_file()
bpy.ops.render.render(write_still=True, use_viewport=True)
return {'FINISHED'}
def set_rendering_panel(self):
self.scene.render.engine = 'BLENDER_EEVEE'
self.scene.eevee.use_gtao = True
self.scene.eevee.use_ssr = True
self.scene.render.use_high_quality_normals = True
self.scene.render.film_transparent = True
def set_output_file(self):
self.scene.render.resolution_x = self.scene.render.resolution_y = 512
self.scene.render.image_settings.file_format = 'TARGA'
self.scene.render.image_settings.color_mode = 'RGBA'
self.scene.render.filepath = self.filename_export.as_posix()
def set_camera_used(self):
"""Find the best camera position"""
# TODO
pass
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
from .main import GraouPanel
class GraouPanel_asset(GraouPanel):
bl_idname = 'GRAOU_PT_asset'
bl_label = 'Generate Assets'
def draw(self, context):
layout = self.layout
layout.label(text='Asset:')
layout.operator('graou.make_collision', text='Generate collision', icon='MOD_PHYSICS')
+3 -35
View File
@@ -1,45 +1,13 @@
import bpy from .main import GraouPanel
# import os
# from pathlib import Path
#
# preview_collection = {}
# icon_sauropod_path = Path(os.path.dirname(os.path.abspath(__file__)), "icons")
#
# pcoll = bpy.utils.previews.new()
#
# for entry in os.scandir(icon_sauropod_path):
# if entry.name.endswith(".png"):
# name = os.path.splitext(entry.name)[0]
# print(f'[Pipeline] Add icon "{name}"')
# pcoll.load(name.upper(), entry.path, "IMAGE")
class GRAOU_PT_panel(bpy.types.Panel): class GRAOU_PT_export(GraouPanel):
bl_idname = 'GRAOU_PT_MAIN' bl_idname = 'GRAOU_PT_MAIN'
bl_space_type = 'VIEW_3D' bl_label = 'Export'
bl_region_type = 'UI'
bl_label = 'Pipeline'
bl_category = 'Graou Studio'
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
# layout.label(text='Graou Pipeline', icon_value=pcoll["GRAOU"].icon_id)
col = layout.column(align=True)
col.label(text='Main Config:')
col.operator('graou.build_scene', text='Init Scene', icon='OUTLINER')
col.prop(context.scene.graou_props, 'socket_collection', text='Use socket', toggle=True)
col.operator('graou.lighting', text='Set basic lighting', icon='OUTLINER_OB_LIGHT')
layout.separator()
layout.label(text='Asset:')
layout.operator('graou.make_collision', text='Generate collision', icon='MOD_PHYSICS')
layout.separator()
layout.label(text='Export scene:') layout.label(text='Export scene:')
box = layout.box() box = layout.box()
box.label(text='Sanity Check') box.label(text='Sanity Check')
+13
View File
@@ -0,0 +1,13 @@
from .main import GraouPanel
class GraouPanel_thumbnail(GraouPanel):
bl_idname = 'GRAOU_PT_thumbnail'
bl_label = 'Thumbnail'
def draw(self, context):
layout = self.layout
layout.label(text='Thumbnail:')
layout.operator('graou_config.rendering_thumbnail', text='Generate Thumbnail', icon='FILE_IMAGE')
# TODO Add the thumbnail view
+25
View File
@@ -0,0 +1,25 @@
import bpy
# import os
# from pathlib import Path
#
# preview_collection = {}
# icon_sauropod_path = Path(os.path.dirname(os.path.abspath(__file__)), "icons")
#
# pcoll = bpy.utils.previews.new()
#
# for entry in os.scandir(icon_sauropod_path):
# if entry.name.endswith(".png"):
# name = os.path.splitext(entry.name)[0]
# print(f'[Pipeline] Add icon "{name}"')
# pcoll.load(name.upper(), entry.path, "IMAGE")
# layout.label(text='Graou Pipeline', icon_value=pcoll["GRAOU"].icon_id)
class GraouPanel(bpy.types.Panel):
bl_idname = 'GRAOU_PT_MAIN'
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = 'Export'
bl_category = 'Graou Studio'
+15
View File
@@ -0,0 +1,15 @@
from .main import GraouPanel
class GRAOU_PT_setup(GraouPanel):
bl_idname = 'GRAOU_PT_setup'
bl_label = 'Setup Pipeline'
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
col.label(text='Main Config:')
col.operator('graou.build_scene', text='Init Scene', icon='OUTLINER')
col.prop(context.scene.graou_props, 'socket_collection', text='Use socket', toggle=True)
col.operator('graou.lighting', text='Set basic lighting', icon='OUTLINER_OB_LIGHT')
+23 -5
View File
@@ -1,5 +1,6 @@
import bpy import bpy
from .properties.models import FangeProject
from pathlib import Path from pathlib import Path
@@ -21,8 +22,25 @@ def get_export_preset():
print(f'[Pipeline] Preset folder not found') print(f'[Pipeline] Preset folder not found')
def apply_mesh_and_join(): def get_export_path():
""" """Look the file path, to understand if the asset are a Character, Buildings or Props"""
This function make a new mesh with all selected asset. abs_blend_path = Path(bpy.data.filepath)
""" game_path = FangeProject()
pass
if 'Buildings' in abs_blend_path.parts:
return game_path.buildings
elif 'Props' in abs_blend_path.parts:
return game_path.props
elif 'Characters' in abs_blend_path.parts:
return game_path.characters
else:
return Path()
def get_asset_name() -> str:
"""From the .blend file, return the blend name."""
abs_blend_path = Path(bpy.data.filepath)
return abs_blend_path.stem