-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from ZeroGravitasIndeed/main
Code Sync with ZG SWTOR Tools version
- Loading branch information
Showing
12 changed files
with
1,045 additions
and
178 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file modified
BIN
-4.52 KB
(97%)
swtor_character_assembler/Legacy SWTOR Shaders and Materials.blend
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import bpy | ||
import addon_utils | ||
from pathlib import Path | ||
import os | ||
|
||
|
||
|
||
ADDON_ROOT = __file__.rsplit(__name__.rsplit(".")[0])[0] + __name__.rsplit(".")[0] | ||
|
||
|
||
|
||
def requirements_checks(): | ||
'''Returns a dict with both boolean and string reports on the existence | ||
and validity of some resources necessary for certain tools to work''' | ||
|
||
checks = {} | ||
|
||
|
||
|
||
|
||
# ----------------------------- | ||
# .gr2 Add-on checks | ||
|
||
checks["gr2"] = addon_utils.check("io_scene_gr2")[1] | ||
|
||
if "io_scene_gr2" not in addon_utils.addons_fake_modules: | ||
checks["gr2_status"] = "NOT INSTALLED" | ||
checks["gr2_status_verbose"] = "NOT INSTALLED. No .gr2 Importer Add-on is currently installed." | ||
|
||
if addon_utils.check("io_scene_gr2")[1]: | ||
checks["gr2_status"] = "ENABLED" | ||
checks["gr2_status_verbose"] = "ENABLED. A .gr2 Importer Add-on is installed and enabled." | ||
else: | ||
checks["gr2_status"] = "DISABLED" | ||
checks["gr2_status_verbose"] = "DISABLED. A .gr2 Importer Add-on is installed, but still needs to be enabled." | ||
|
||
|
||
|
||
|
||
# ----------------------------- | ||
# 'resources' folder checks | ||
|
||
swtor_resources_folderpath = getattr(bpy.context.preferences.addons["zg_swtor_tools"].preferences, "swtor_resources_folderpath", "") | ||
is_badly_written = os.sep not in swtor_resources_folderpath | ||
is_unfilled = swtor_resources_folderpath == "Choose or type the folder's path" | ||
is_a_folder = Path(swtor_resources_folderpath).exists() | ||
is_a_resources_folder = ( Path(swtor_resources_folderpath) / "art/shaders/materials").exists() | ||
|
||
checks["resources"] = is_a_resources_folder | ||
|
||
if is_unfilled: | ||
checks["resources_status"] = "NOT SET" | ||
checks["resources_status_verbose"] = "NOT SET." | ||
else: | ||
if is_badly_written: | ||
checks["resources_status"] = "NOT VALID" | ||
checks["resources_status_verbose"] = "NOT VALID. This is not a folder path." | ||
else: | ||
if is_a_resources_folder: | ||
checks["resources_status"] = "SET" | ||
checks["resources_status_verbose"] = "SET. This is a valid 'resources' folder." | ||
else: | ||
if is_a_folder: | ||
checks["resources_status"] = "NOT VALID" | ||
checks["resources_status_verbose"] = "NOT VALID. This folder isn't a valid 'resources' directory root." | ||
else: | ||
checks["resources_status"] = "NOT FOUND" | ||
checks["resources_status_verbose"] = "NOT FOUND. No folder can't be found at the specified path." | ||
|
||
|
||
|
||
|
||
# ----------------------------- | ||
# custom shaders checks | ||
|
||
# Default one | ||
default_custom_shaders_blend_filepath = os.path.join(ADDON_ROOT, "rsrc", "Custom SWTOR Shaders.blend") | ||
|
||
# Current one | ||
custom_shaders_blend_filepath = getattr(bpy.context.preferences.addons["zg_swtor_tools"].preferences, "swtor_custom_shaders_blendfile_path", "") | ||
|
||
blend_file_badly_written = (".blend" not in custom_shaders_blend_filepath or os.sep not in custom_shaders_blend_filepath) | ||
blend_file_exists = Path(custom_shaders_blend_filepath).is_file() | ||
blend_file_is_internal = (custom_shaders_blend_filepath == default_custom_shaders_blend_filepath) | ||
|
||
# Check .blend file's insides for a custom Garment shader to validate it: | ||
# (see https://devtalk.blender.org/t/traverse-blend-file-to-get-list-of-collections/10348/14 | ||
# the '_' avoids actually loading anything ) | ||
if blend_file_exists: | ||
with bpy.data.libraries.load(str(custom_shaders_blend_filepath)) as (data_from, _): | ||
blend_file_is_valid = "SWTOR - Garment Shader" in data_from.node_groups | ||
else: | ||
blend_file_is_valid = False | ||
|
||
checks["custom_shaders"] = blend_file_exists | ||
|
||
if blend_file_exists: | ||
if blend_file_is_valid: | ||
checks["custom_shaders"] = True | ||
if blend_file_is_internal: | ||
checks["custom_shaders_status"] = "INTERNAL" | ||
checks["custom_shaders_status_verbose"] = "INTERNAL. Uses the Custom SWTOR Shaders .blend file inside the Add-on." | ||
else: | ||
checks["custom_shaders_status"] = "EXTERNAL" | ||
checks["custom_shaders_status_verbose"] = "EXTERNAL. Uses a Custom SWTOR Shaders .blend file outside the Add-on." | ||
else: | ||
checks["custom_shaders"] = False | ||
checks["custom_shaders_status"] = "NOT VALID" | ||
checks["custom_shaders_status_verbose"] = "NOT VALID. This .blend file doesn't contain valid Custom SWTOR Shaders." | ||
else: | ||
if blend_file_badly_written: | ||
checks["custom_shaders"] = False | ||
checks["custom_shaders_status"] = "NOT VALID" | ||
checks["custom_shaders_status_verbose"] = "NOT VALID. This is not a .blend file path." | ||
else: | ||
checks["custom_shaders"] = False | ||
checks["custom_shaders_status"] = "NOT FOUND" | ||
checks["custom_shaders_status_verbose"] = "NOT FOUND. No .blend file can't be found at the specified path." | ||
|
||
return checks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
import bpy | ||
import os | ||
from pathlib import Path | ||
|
||
|
||
def merge_material_nodes(source_material_name, destination_material_name): | ||
# Get the source and destination materials | ||
source_material = bpy.data.materials.get(source_material_name) | ||
destination_material = bpy.data.materials.get(destination_material_name) | ||
|
||
# Check if both materials exist | ||
if not source_material or not destination_material: | ||
print("Error: One or both materials do not exist.") | ||
return | ||
|
||
# Get the node trees of the materials | ||
source_node_tree = source_material.node_tree | ||
destination_node_tree = destination_material.node_tree | ||
|
||
# Create a mapping between source and destination nodes | ||
node_mapping = {} | ||
|
||
# Add nodes to the destination node tree | ||
for source_node in source_node_tree.nodes: | ||
new_node = destination_node_tree.nodes.new(type=source_node.bl_idname) | ||
new_node.name = source_node.name | ||
new_node.label = source_node.label | ||
new_node.location = source_node.location | ||
new_node.hide = source_node.hide | ||
new_node.use_custom_color = source_node.use_custom_color | ||
new_node.color = source_node.color | ||
|
||
|
||
# Add the mapping between source and destination nodes | ||
node_mapping[source_node] = new_node | ||
|
||
# Add links to the destination node tree | ||
for source_link in source_node_tree.links: | ||
source_socket = node_mapping.get(source_link.from_node).outputs[source_link.from_socket.name] | ||
destination_socket = node_mapping.get(source_link.to_node).inputs[source_link.to_socket.name] | ||
destination_node_tree.links.new(source_socket, destination_socket) | ||
|
||
|
||
|
||
# ------------------------------------------------------------- | ||
class SWTOR_OT_baking_tools(bpy.types.Operator): | ||
bl_idname = "swtor.baking_tools" | ||
bl_label = "Bake Legacy SWTOR Materials into simple Principled BSDF Shader ones" | ||
bl_description = "Converts all Legacy SWTOR materials in the Blender project to simple Principled Shader-based ones\nwith just baked texturemaps or direct values as inputs, ready for exporting as FBX.\n\n• Requires the presence of Legacy-type SWTOR Materials" | ||
bl_options = {'REGISTER', 'UNDO'} | ||
|
||
|
||
# Check that there is a selection of objects either | ||
# in the 3D Viewer or in any Outliner in order to | ||
# enable the operator. | ||
@classmethod | ||
def poll(cls,context): | ||
true_or_false = False | ||
if bpy.context.selected_objects and bpy.context.mode == "OBJECT": | ||
true_or_false = True | ||
else: | ||
for window in context.window_manager.windows: | ||
screen = window.screen | ||
for area in screen.areas: | ||
if area.type == 'OUTLINER': | ||
with context.temp_override(window=window, area=area): | ||
if context.selected_ids: | ||
true_or_false = True | ||
break | ||
return true_or_false | ||
|
||
|
||
|
||
# # Property for the UI buttons to call different actions. | ||
# # See: https://b3d.interplanety.org/en/calling-functions-by-pressing-buttons-in-blender-custom-ui/ | ||
# action: bpy.props.EnumProperty( | ||
# name="Bake Channel", | ||
# items=[ | ||
# ("DIFFUSE", "Diffuse", "Diffuse"), | ||
# ("NORMAL", "Normals", "Normals"), | ||
# ("GLOSSY", "Glossiness", "Glossiness"), | ||
# ("EMIT", "Emissiveness", "Emissiveness"), | ||
# ("TRANSMISSION", "Opacity", "Opacity"), | ||
# ] | ||
# ) | ||
|
||
# Property for the UI buttons to call different actions. | ||
# See: https://b3d.interplanety.org/en/calling-functions-by-pressing-buttons-in-blender-custom-ui/ | ||
use_selection_only: bpy.props.BoolProperty( | ||
name="Selection-only", | ||
description='Applies the material processing to the current selection of objects only', | ||
default = False, | ||
options={'HIDDEN'} | ||
) | ||
|
||
|
||
# @staticmethod | ||
# def bake_diffuse(): | ||
# bpy.context.window.cursor_set("WAIT") | ||
# for mat in bpy.data.materials: | ||
# if " - LGC" in mat.name: | ||
# for node in mat.node_tree.nodes: | ||
# if node.label == "BAKED MATERIAL'S DIFFUSE": | ||
# mat.node_tree.nodes.active = node | ||
# context.scene["Scene"].cycles.bake_type = 'DIFFUSE' | ||
# context.scene.render.bake.use_pass_direct = False | ||
# context.scene.render.bake.use_pass_indirect = False | ||
# context.scene.render.bake.use_pass_color = True | ||
# context.scene.render.bake.use_pass_color = True | ||
# context.scene.render.bake.view_from = 'ABOVE_SURFACE' | ||
# context.scene.render.bake.use_clear = True | ||
# break | ||
|
||
|
||
|
||
|
||
def execute(self, context): | ||
|
||
# # Make duplicates of the objects' materials, prefixing them as "BAKEDMAT" | ||
# # and assign them, unless they exist and are assigned already | ||
|
||
# for obj in bpy.data.objects: | ||
# pass | ||
|
||
|
||
# Append the baked material template from the auxiliary .blend file inside the Add-on | ||
|
||
aux_blendfile_name = "Legacy SWTOR Shaders and Materials.blend" | ||
|
||
legacy_materials_blend_filepath = os.path.join(os.path.dirname(__file__), aux_blendfile_name) | ||
|
||
if Path(legacy_materials_blend_filepath).exists() == False: | ||
self.report({"WARNING"}, "Unable to find the custom SWTOR shaders .blend file inside this Addon's directory.") | ||
return {"CANCELLED"} | ||
|
||
legacy_materials_path = bpy.path.native_pathsep(legacy_materials_blend_filepath + "/Material") | ||
|
||
baked_mat_template_name = "BAKED MATERIAL TEMPLATE" | ||
if baked_mat_template_name not in bpy.data.materials: | ||
try: | ||
bpy.ops.wm.append( | ||
filename=baked_mat_template_name, | ||
directory=legacy_materials_path, | ||
do_reuse_local_id=True, # This seems to be failing, hence the checking | ||
set_fake=True, | ||
link=False, | ||
) | ||
except: | ||
self.report({"WARNING"}, "Unable to find the " + baked_mat_template_name + " in the .blend file holding the Legacy SWTOR Materials in this Addon's directory.") | ||
return {"CANCELLED"} | ||
|
||
|
||
# Append the baked material template node tree's nodes | ||
# to the existing Legacy SWTOR materials in the project | ||
|
||
for mat in bpy.data.materials: | ||
if " - LGC" in mat.name and "BAKED MATERIAL'S OUTPUT" not in mat.node_tree.nodes: | ||
merge_material_nodes(baked_mat_template_name, mat.name) | ||
|
||
|
||
# Set general render and baking settings | ||
|
||
# Render engine | ||
context.scene.render.engine = "CYCLES" | ||
|
||
# Bake settings | ||
context.scene.render.use_bake_multires = True | ||
context.scene.cycles.bake_type = 'DIFFUSE' | ||
context.scene.render.bake.view_from = "ABOVE_SURFACE" | ||
|
||
context.scene.render.bake.use_pass_direct = False | ||
context.scene.render.bake.use_pass_indirect = False | ||
context.scene.render.bake.use_pass_color = True | ||
|
||
context.scene.render.bake.use_selected_to_active = False | ||
|
||
context.scene.render.bake.target = 'IMAGE_TEXTURES' | ||
context.scene.render.bake.use_clear = True | ||
|
||
context.scene.render.bake.margin_type = 'ADJACENT_FACES' | ||
context.scene.render.bake.margin = 16 | ||
|
||
# Color management | ||
|
||
context.scene.display_settings.display_device = 'sRGB' | ||
context.scene.view_settings.look = 'None' | ||
context.scene.view_settings.use_curve_mapping = False | ||
context.scene.view_settings.exposure = 0 | ||
context.scene.view_settings.gamma = 1 | ||
|
||
# Cycle through materials, set target, and bake | ||
|
||
for mat in bpy.data.materials: | ||
nodes=mat.node_tree.nodes | ||
if "BAKED MATERIAL'S OUTPUT" in nodes: | ||
|
||
# Determine texturemap size | ||
if "_d DiffuseMap" in nodes: | ||
tx_size = nodes["_d DiffuseMap"].width | ||
else: | ||
tx_size = 1024 | ||
|
||
# Create texturemap image and assign to baking target | ||
tx_name = mat.name + "DIFFUSE" | ||
if not tx_name in bpy.data.images: | ||
bpy.ops.image.new( | ||
name=tx_name, | ||
width=tx_size, | ||
height=tx_size, | ||
color=None, | ||
alpha=False, | ||
) | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
self.report({'INFO'}, "Conversion finished") | ||
return {"FINISHED"} | ||
|
||
|
||
|
||
# ------------------------------------------------------------- | ||
# Registrations | ||
|
||
def register(): | ||
bpy.utils.register_class(SWTOR_OT_baking_tools) | ||
|
||
|
||
|
||
def unregister(): | ||
bpy.utils.unregister_class(SWTOR_OT_baking_tools) | ||
|
||
if __name__ == "__main__": | ||
register() |
Oops, something went wrong.