workshop rework

This commit is contained in:
Vysyr committed 2026-10-31 17:03:41 +01:00
1 parent a3a80dfa16
commit fb39e290c0
115 files changed
+1865 -497

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
"""Synchronize basic glTF PBR properties preserved by UE mesh reimports."""
import json
import base64
import re
import struct
import unreal
from .paths import PROJECT
def link_textures(source, mesh, destination):
if source.suffix.lower() == ".glb":
data = source.read_bytes()
size, kind = struct.unpack_from("<II", data, 12)
if kind != 0x4E4F534A:
raise ValueError("GLB nie zawiera poczatkowego chunka JSON.")
document = json.loads(data[20:20 + size])
binary = data[28 + size:]
else:
document = json.loads(source.read_text(encoding="utf-8"))
binary = b""
def sanitized(value):
return re.sub(r"[^A-Za-z0-9_]", "_", value)
textures = {}
def load_texture(info, parameter):
index = document["textures"][info["index"]]["source"]
role = "Normal" if parameter == "NormalTexture" else (
"Color" if parameter in {"BaseColorTexture", "EmissiveTexture"} else "Linear")
key = (index, role)
if key in textures:
return textures[key]
image = document["images"][index]
name = f"T_{index:03d}_{sanitized(image.get('name', 'Image'))}_{role}"
uri = image.get("uri", "")
if "bufferView" in image:
view = document["bufferViews"][image["bufferView"]]
offset = view.get("byteOffset", 0)
payload = binary[offset:offset + view["byteLength"]]
elif uri.startswith("data:"):
payload = base64.b64decode(uri.split(",", 1)[1])
else:
from urllib.parse import unquote
payload = (source.parent / unquote(uri)).read_bytes()
extension = ".png" if payload.startswith(b"\x89PNG") else ".jpg" if payload.startswith(b"\xff\xd8") else None
if extension is None:
raise ValueError("Tekstury warsztatowe musza byc zapisane jako PNG lub JPEG.")
file = PROJECT / "build/GltfTextures" / source.stem / (name + extension)
file.parent.mkdir(parents=True, exist_ok=True)
file.write_bytes(payload)
task = unreal.AssetImportTask()
task.filename = str(file)
task.destination_path = destination + "/WorkshopTextures"
task.destination_name = name
task.automated = True
task.replace_existing = True
task.save = True
unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task])
imported = [obj for obj in task.get_objects() if isinstance(obj, unreal.Texture2D)]
if len(imported) != 1:
raise RuntimeError("Nie mozna zaimportowac tekstury " + name)
texture = imported[0]
texture.set_editor_property("srgb", role == "Color")
texture.set_editor_property("flip_green_channel", role == "Normal")
texture.set_editor_property("compression_settings", unreal.TextureCompressionSettings.TC_NORMALMAP
if role == "Normal" else unreal.TextureCompressionSettings.TC_DEFAULT
if role == "Color" else unreal.TextureCompressionSettings.TC_MASKS)
unreal.EditorAssetLibrary.save_loaded_asset(texture)
textures[key] = texture
return texture
materials = {sanitized(item.get("name", "")): item for item in document.get("materials", [])}
lib = unreal.MaterialEditingLibrary
for slot in mesh.static_materials:
material = slot.material_interface
if material is None or material.get_name() not in materials:
continue
spec = materials[material.get_name()]
pbr = spec.get("pbrMetallicRoughness", {})
lib.set_material_instance_vector_parameter_value(
material, "BaseColorFactor", unreal.LinearColor(*pbr.get("baseColorFactor", [1, 1, 1, 1])))
lib.set_material_instance_vector_parameter_value(
material, "EmissiveFactor", unreal.LinearColor(*spec.get("emissiveFactor", [0, 0, 0]), 1))
lib.set_material_instance_scalar_parameter_value(material, "MetallicFactor", pbr.get("metallicFactor", 1))
lib.set_material_instance_scalar_parameter_value(material, "RoughnessFactor", pbr.get("roughnessFactor", 1))
maps = {"BaseColorTexture": pbr.get("baseColorTexture"),
"MetallicRoughnessTexture": pbr.get("metallicRoughnessTexture"),
"NormalTexture": spec.get("normalTexture"),
"OcclusionTexture": spec.get("occlusionTexture"),
"EmissiveTexture": spec.get("emissiveTexture")}
for parameter, info in maps.items():
lib.set_material_instance_static_switch_parameter_value(material, "bHas" + parameter, info is not None)
lib.update_material_instance(material)
for parameter, info in maps.items():
if info is None:
continue
texture = load_texture(info, parameter)
# UE 5.7's setter returns False even when it succeeds; verify by reading.
lib.set_material_instance_texture_parameter_value(material, parameter, texture)
if lib.get_material_instance_texture_parameter_value(material, parameter) != texture:
raise RuntimeError(f"Nie mozna przypisac {parameter} w {material.get_name()}.")
lib.update_material_instance(material)
unreal.EditorAssetLibrary.save_loaded_asset(material)