From 8b3ae73bce06ee885ce85c36192dd5ddcfe27f5f Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Sun, 4 Apr 2021 19:48:08 +0200 Subject: [PATCH] feat: Implement material export Signed-off-by: Lucas Schwiderski --- addon/bitsquid/__init__.py | 96 +++++++++++++++++++++++----- addon/bitsquid/material/export.py | 101 ++++++++++++++++++++++++++++++ addon/bitsquid/unit/export.py | 50 ++++++++++++++- 3 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 addon/bitsquid/material/export.py diff --git a/addon/bitsquid/__init__.py b/addon/bitsquid/__init__.py index 4a96ce0..b67647d 100644 --- a/addon/bitsquid/__init__.py +++ b/addon/bitsquid/__init__.py @@ -28,8 +28,11 @@ bl_info = { # Reload sub modules if they are already loaded if "bpy" in locals(): import importlib - importlib.reload(unit_export) - importlib.reload(unit) + if "unit_export" in locals(): + importlib.reload(unit_export) + if "material_export" in locals(): + importlib.reload(material_export) + import bpy from bpy.types import ( @@ -38,17 +41,19 @@ from bpy.types import ( PropertyGroup, ) from bpy.props import ( - StringProperty, EnumProperty, + BoolProperty, + StringProperty, PointerProperty, ) from bpy_extras.io_utils import ( ExportHelper, + axis_conversion, orientation_helper, path_reference_mode, - axis_conversion, ) from bitsquid.unit import export as unit_export +from bitsquid.material import export as material_export class BitsquidSettings(PropertyGroup): @@ -65,7 +70,6 @@ class SCENE_PT_bitsquid(Panel): bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "scene" - # bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout @@ -84,6 +88,12 @@ class BitsquidObjectSettings(PropertyGroup): subtype='DIR_PATH', ) + export_materials: BoolProperty( + name="Export materials", + description="Automatically export all referenced materials", + default=True, + ) + class OBJECT_OT_bitsquid_export(Operator): """Export this object into a Bitsquid Unit file""" @@ -91,15 +101,18 @@ class OBJECT_OT_bitsquid_export(Operator): bl_label = "Export .unit" bl_options = {'REGISTER'} - filepath: StringProperty(subtype='DIR_PATH') - @classmethod def poll(cls, context): - return bpy.data.is_saved and context.active_object is not None + object = context.active_object + return bpy.data.is_saved and object is not None and object.type == 'MESH' def execute(self, context): - print("Export .unit") - return unit_export.save(self, context, context.object.bitsquid.unit_filepath) + object = context.active_object + if object.bitsquid.export_materials: + for material_slot in object.material_slots.values(): + material_export.save(self, context, material_slot.material) + + return unit_export.save(self, context, object) class OBJECT_PT_bitsquid(Panel): @@ -107,16 +120,67 @@ class OBJECT_PT_bitsquid(Panel): bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "object" - # bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + object = context.object + layout = self.layout + + if object.type != 'MESH': + layout.label(text="Only objects of type 'MESH' are supported.") + return + + layout.use_property_split = False + layout.use_property_decorate = False + + bitsquid = object.bitsquid + layout.prop(bitsquid, "unit_filepath", text="Unit File Path") + layout.prop(bitsquid, "export_materials", text="Export materials") + layout.operator("object.bitsquid_export_unit", text="Export .unit") + + +class BitsquidMaterialSettings(PropertyGroup): + material_filepath: StringProperty( + name="Material File Path", + description="The directory to store the .material file in. Needs to be within the project root.", + default="//", + subtype='DIR_PATH', + ) + + +class MATERIAL_OT_bitsquid_export(Operator): + """Export this material into a Bitsquid Material file""" + bl_idname = "object.bitsquid_export_material" + bl_label = "Export .material" + bl_options = {'REGISTER'} + + @classmethod + def poll(cls, context): + return bpy.data.is_saved and context.active_object is not None + + def execute(self, context): + material = context.active_material + return unit_export.save(self, context, material) + + +class MATERIAL_PT_bitsquid(Panel): + bl_label = "Bitsquid" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "material" + + @classmethod + def poll(cls, context): + object = context.active_object + return len(object.material_slots) > 0 def draw(self, context): layout = self.layout layout.use_property_split = False layout.use_property_decorate = False - bitsquid = context.object.bitsquid - layout.prop(bitsquid, "unit_filepath", text="Unit File Path") - layout.operator("object.bitsquid_export_unit", text="Export .unit") + bitsquid = context.material.bitsquid + layout.prop(bitsquid, "material_filepath", text="Material File Path") + layout.operator("object.bitsquid_export_material", text="Export .material") # Register @@ -126,6 +190,9 @@ classes = [ BitsquidObjectSettings, OBJECT_PT_bitsquid, OBJECT_OT_bitsquid_export, + BitsquidMaterialSettings, + MATERIAL_PT_bitsquid, + MATERIAL_OT_bitsquid_export, ] @@ -136,6 +203,7 @@ def register(): bpy.types.Scene.bitsquid = PointerProperty(type=BitsquidSettings) bpy.types.Object.bitsquid = PointerProperty(type=BitsquidObjectSettings) + bpy.types.Material.bitsquid = PointerProperty(type=BitsquidMaterialSettings) def unregister(): diff --git a/addon/bitsquid/material/export.py b/addon/bitsquid/material/export.py new file mode 100644 index 0000000..e32276a --- /dev/null +++ b/addon/bitsquid/material/export.py @@ -0,0 +1,101 @@ +# Bitsquid Blender Tools +# Copyright (C) 2021 Lucas Schwiderski +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import bpy +from bitsquid import step + + +template = """ +parent_material = "core/stingray_renderer/shader_import/standard" + +textures = {} + +variables = { + base_color = { + type = "vector3" + value = [ + 1 + 0.333333333333333 + 0 + ] + } + emissive = { + type = "vector3" + value = [ + 0 + 0 + 0 + ] + } + emissive_intensity = { + type = "scalar" + value = 1 + } + metallic = { + type = "scalar" + value = 0 + } + roughness = { + type = "scalar" + value = 0.91 + } + use_ao_map = { + type = "scalar" + value = 0 + } + use_color_map = { + type = "scalar" + value = 0 + } + use_emissive_map = { + type = "scalar" + value = 0 + } + use_metallic_map = { + type = "scalar" + value = 0 + } + use_normal_map = { + type = "scalar" + value = 0 + } + use_roughness_map = { + type = "scalar" + value = 0 + } +} + +""" + + +def build_filepath(material): + dir = bpy.path.abspath(material.bitsquid.material_filepath) + return os.path.join(dir, "{}.material".format(material.name)) + + +def save(self, context, material): + filepath = build_filepath(material) + self.report({'INFO'}, "Saving material to " + filepath) + + namespace = { + 'material': material, + } + content = step.Template(template).expand(namespace) + + self.report({'INFO'}, content) + + return {'FINISHED'} diff --git a/addon/bitsquid/unit/export.py b/addon/bitsquid/unit/export.py index fb4829b..4e9f64f 100644 --- a/addon/bitsquid/unit/export.py +++ b/addon/bitsquid/unit/export.py @@ -14,11 +14,57 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import os import bpy +from bpy_extras import io_utils +from bitsquid import step +from bitsquid.material import export as material_export + +template = """ +%if len(materials) > 0: +materials = { + %for item in materials: + {{ item['name'] }} = "{{ item['path'] }}" + %endfor +} +%endif + +renderables = { + {{ object.name }} = { + always_keep = false + culling = "bounding_volume" + generate_uv_unwrap = false + occluder = false + shadow_caster = true + surface_queries = false + viewport_visible = true + } +} +""" -def save(self, context, unit_filepath): - filepath = bpy.path.abspath(unit_filepath) +def build_filepath(object): + dir = bpy.path.abspath(object.bitsquid.unit_filepath) + return os.path.join(dir, "{}.unit".format(object.name)) + + +def save(self, context, object): + filepath = build_filepath(object) self.report({'INFO'}, "Saving unit to " + filepath) + materials = [] + for material_slot in object.material_slots.values(): + materials.append({ + 'name': material_slot.name, + 'path': material_export.build_filepath(material_slot.material), + }) + + namespace = { + 'object': object, + 'materials': materials, + } + content = step.Template(template).expand(namespace) + + self.report({'INFO'}, content) + return {'FINISHED'}