diff --git a/addons/io_scene_gltf2_msfs/__init__.py b/addons/io_scene_gltf2_msfs/__init__.py index 7505313..cf4ee1c 100644 --- a/addons/io_scene_gltf2_msfs/__init__.py +++ b/addons/io_scene_gltf2_msfs/__init__.py @@ -25,7 +25,7 @@ "author": "Luca Pierabella, Wing42, pepperoni505, ronh991, tml1024, and others", "description": "This toolkit prepares your 3D assets to be used for Microsoft Flight Simulator", "blender": (3, 1, 0), - "version": (1, 1, 3), + "version": (1, 1, 4), "location": "File > Import-Export", "category": "Import-Export", "tracker_url": "https://github.com/AsoboStudio/glTF-Blender-IO-MSFS" diff --git a/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py b/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py index f32926d..cb780c7 100644 --- a/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py +++ b/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py @@ -719,13 +719,17 @@ def updateColorLinks(self): def setCompTex(self, tex): self.nodeCompTex = self.getNode(MSFS_ShaderNodes.compTex.value) - self.nodeCompTex.image = tex - self.updateCompLinks() + if tex is not None: + self.nodeCompTex.image = tex + self.nodeCompTex.image.colorspace_settings.name = "Non-Color" + self.updateCompLinks() def setDetailCompTex(self, tex): self.nodeDetailCompTex = self.getNode(MSFS_ShaderNodes.detailCompTex.value) - self.nodeDetailCompTex.image = tex - self.updateCompLinks() + if tex is not None: + self.nodeDetailCompTex.image = tex + self.nodeDetailCompTex.image.colorspace_settings.name = "Non-Color" + self.updateCompLinks() def setRoughnessScale(self, scale): self.nodeRoughnessScale = self.getNode(MSFS_ShaderNodes.roughnessScale.value) @@ -746,15 +750,17 @@ def setNormalScale(self, scale): def setDetailNormalTex(self, tex): self.nodeDetailNormalTex = self.getNode(MSFS_ShaderNodes.detailNormalTex.value) - self.nodeDetailNormalTex.image = tex - self.nodeDetailNormalTex.image.colorspace_settings.name = "Non-Color" - self.updateNormalLinks() + if tex is not None: + self.nodeDetailNormalTex.image = tex + self.nodeDetailNormalTex.image.colorspace_settings.name = "Non-Color" + self.updateNormalLinks() def setNormalTex(self, tex): self.nodeNormalTex = self.getNode(MSFS_ShaderNodes.normalTex.value) - self.nodeNormalTex.image = tex - self.nodeNormalTex.image.colorspace_settings.name = "Non-Color" - self.updateNormalLinks() + if tex is not None: + self.nodeNormalTex.image = tex + self.nodeNormalTex.image.colorspace_settings.name = "Non-Color" + self.updateNormalLinks() def updateNormalLinks(self): self.nodeNormalTex = self.getNode(MSFS_ShaderNodes.normalTex.value) diff --git a/addons/io_scene_gltf2_msfs/com/msfs_material_props.py b/addons/io_scene_gltf2_msfs/com/msfs_material_props.py index 747f399..47eebe8 100644 --- a/addons/io_scene_gltf2_msfs/com/msfs_material_props.py +++ b/addons/io_scene_gltf2_msfs/com/msfs_material_props.py @@ -233,15 +233,10 @@ def from_dict( return assert isinstance(extensions, dict) - # If any Asobo extensions are present, set blender_material to standard. If the blender_material is another type, it will get changed later. This is the only way to see if it's a flight sim blender_material - for key in extensions.keys(): - if key.upper().startswith("ASOBO_"): - blender_material.msfs_material_type = "msfs_standard" - break + # Every flight sim asset has ASOBO_normal_map_convention, so we check if it's being used to set material. We set blender_material to standard. If the blender_material is another type, it will get changed later. + if "ASOBO_normal_map_convention" in import_settings.data.extensions_used: + blender_material.msfs_material_type = "msfs_standard" - if ( - blender_material.msfs_material_type == "msfs_standard" - ): # Only set properties if we are importing a flight sim blender_material if gltf2_material.pbr_metallic_roughness is not None: if gltf2_material.pbr_metallic_roughness.base_color_factor is not None: blender_material.msfs_base_color_factor = gltf2_material.pbr_metallic_roughness.base_color_factor @@ -341,8 +336,13 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialGeometryDecal.SerializedName, {} + AsoboMaterialGeometryDecal.SerializedName ) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_geo_decal" + if extension.get("baseColorBlendFactor"): blender_material.msfs_base_color_blend_factor = extension.get( "baseColorBlendFactor" @@ -365,6 +365,7 @@ def to_extension(blender_material, gltf2_material, export_settings): blender_material.msfs_material_type == "msfs_geo_decal" or blender_material.msfs_material_type == "msfs_geo_decal_frosted" ): + result["enabled"] = True result[ "baseColorBlendFactor" ] = blender_material.msfs_base_color_blend_factor @@ -426,8 +427,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialGhostEffect.SerializedName, {} + AsoboMaterialGhostEffect.SerializedName ) + if extension is None: + return + if extension.get("bias"): blender_material.msfs_ghost_bias = extension.get("bias") if extension.get("scale"): @@ -476,8 +480,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialDrawOrder.SerializedName, {} + AsoboMaterialDrawOrder.SerializedName ) + if extension is None: + return + if extension.get("drawOrderOffset"): blender_material.msfs_draw_order_offset = extension.get("drawOrderOffset") @@ -518,8 +525,10 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get(AsoboDayNightCycle.SerializedName) - if extension is not None: - blender_material.msfs_day_night_cycle = True + if extension is None: + return + + blender_material.msfs_day_night_cycle = True @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -550,9 +559,11 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboDisableMotionBlur.SerializedName, {}) - if extension.get("enabled"): - blender_material.msfs_disable_motion_blur = True + extension = extensions.get(AsoboDisableMotionBlur.SerializedName) + if extension is None: + return + + blender_material.msfs_disable_motion_blur = True @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -615,9 +626,12 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboPearlescent.SerializedName, {}) - if extension: - blender_material.msfs_use_pearl = True + extension = extensions.get(AsoboPearlescent.SerializedName) + if extension is None: + return + + blender_material.msfs_use_pearl = True + if extension.get("pearlShift"): blender_material.msfs_pearl_shift = extension.get("pearlShift") if extension.get("pearlRange"): @@ -653,10 +667,12 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboAlphaModeDither.SerializedName, {} + AsoboAlphaModeDither.SerializedName ) - if extension.get("enabled"): - blender_material.msfs_alpha_mode = "DITHER" + if extension is None: + return + + blender_material.msfs_alpha_mode = "DITHER" @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -683,10 +699,12 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialInvisible.SerializedName, {} + AsoboMaterialInvisible.SerializedName ) - if extension.get("enabled"): - blender_material.msfs_material_type = "msfs_invisible" + if extension is None: + return + + blender_material.msfs_material_type = "msfs_invisible" @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -715,10 +733,12 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialEnvironmentOccluder.SerializedName, {} + AsoboMaterialEnvironmentOccluder.SerializedName ) - if extension.get("enabled"): - blender_material.msfs_material_type = "msfs_environment_occluder" + if extension is None: + return + + blender_material.msfs_material_type = "msfs_environment_occluder" @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -814,8 +834,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialUVOptions.SerializedName, {} + AsoboMaterialUVOptions.SerializedName ) + if extension is None: + return + if extension.get("AOUseUV2"): blender_material.msfs_ao_use_uv2 = extension.get("AOUseUV2") if extension.get("clampUVX"): @@ -898,8 +921,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialShadowOptions.SerializedName, {} + AsoboMaterialShadowOptions.SerializedName ) + if extension is None: + return + if extension.get("noCastShadow"): blender_material.msfs_no_cast_shadow = extension.get("noCastShadow") @@ -939,8 +965,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialResponsiveAAOptions.SerializedName, {} + AsoboMaterialResponsiveAAOptions.SerializedName ) + if extension is None: + return + if extension.get("responsiveAA"): blender_material.msfs_responsive_aa = extension.get("responsiveAA") @@ -1019,8 +1048,11 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialDetail.SerializedName, {} + AsoboMaterialDetail.SerializedName ) + if extension is None: + return + if extension.get("UVScale"): blender_material.msfs_detail_uv_scale = extension.get("UVScale") if extension.get("UVOffset"): @@ -1135,10 +1167,12 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialFakeTerrain.SerializedName, {} + AsoboMaterialFakeTerrain.SerializedName ) - if extension.get("enabled"): - blender_material.msfs_material_type = "msfs_fake_terrain" + if extension is None: + return + + blender_material.msfs_material_type = "msfs_fake_terrain" @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1186,16 +1220,19 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboMaterialFresnelFade.SerializedName, {} + AsoboMaterialFresnelFade.SerializedName ) - if extension: - blender_material.msfs_material_type = "msfs_fresnel_fade" - if extension.get("fresnelFactor"): - blender_material.msfs_fresnel_factor = extension.get("fresnelFactor") - if extension.get("fresnelOpacityOffset"): - blender_material.msfs_fresnel_opacity_offset = extension.get( - "fresnelOpacityOffset" - ) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_fresnel_fade" + + if extension.get("fresnelFactor"): + blender_material.msfs_fresnel_factor = extension.get("fresnelFactor") + if extension.get("fresnelOpacityOffset"): + blender_material.msfs_fresnel_opacity_offset = extension.get( + "fresnelOpacityOffset" + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1243,15 +1280,18 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboSSS.SerializedName, {}) - if extension: - blender_material.msfs_material_type = "msfs_sss" - if extension.get("SSSColor"): - blender_material.msfs_sss_color = extension.get("SSSColor") - if extension.get("opacityTexture"): - blender_material.msfs_opacity_texture = MSFSMaterial.create_image( - extension.get("opacityTexture", {}).get("index"), import_settings - ) + extension = extensions.get(AsoboSSS.SerializedName) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_sss" + + if extension.get("SSSColor"): + blender_material.msfs_sss_color = extension.get("SSSColor") + if extension.get("opacityTexture"): + blender_material.msfs_opacity_texture = MSFSMaterial.create_image( + extension.get("opacityTexture", {}).get("index"), import_settings + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1289,17 +1329,19 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboAnisotropic.SerializedName, {}) - if extension: - # MUST BE CALLED AFTER SSS - if blender_material.msfs_material_type == "msfs_sss": - blender_material.msfs_material_type = "msfs_hair" # SSS and hair share identical properties, except for this. If present, switch from SSS to hair - else: - blender_material.msfs_material_type = "msfs_anisotropic" - if extension.get("anisotropicTexture"): - blender_material.msfs_extra_slot1_texture = MSFSMaterial.create_image( - extension.get("anisotropicTexture", {}).get("index"), import_settings - ) + extension = extensions.get(AsoboAnisotropic.SerializedName) + if extension is None: + return + + # MUST BE CALLED AFTER SSS + if blender_material.msfs_material_type == "msfs_sss": + blender_material.msfs_material_type = "msfs_hair" # SSS and hair share identical properties, except for this. If present, switch from SSS to hair + else: + blender_material.msfs_material_type = "msfs_anisotropic" + if extension.get("anisotropicTexture"): + blender_material.msfs_extra_slot1_texture = MSFSMaterial.create_image( + extension.get("anisotropicTexture", {}).get("index"), import_settings + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1325,6 +1367,7 @@ def to_extension(blender_material, gltf2_material, export_settings): class AsoboWindshield: SerializedName = "ASOBO_material_windshield_v2" + AlternateSerializedName = "ASOBO_material_windshield" class Defaults: rainDropScale = 1.0 @@ -1378,23 +1421,28 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboWindshield.SerializedName, {}) - if extension: - blender_material.msfs_material_type = "msfs_windshield" - if extension.get("rainDropScale"): - blender_material.msfs_rain_drop_scale = extension.get("rainDropScale") - if extension.get("wiper1State"): - blender_material.msfs_wiper_1_state = extension.get("wiper1State") - if extension.get("wiper2State"): - blender_material.msfs_wiper_2_state = extension.get("wiper2State") - if extension.get("wiper3State"): - blender_material.msfs_wiper_3_state = extension.get("wiper3State") - if extension.get("wiper4State"): - blender_material.msfs_wiper_4_state = extension.get("wiper4State") - if extension.get("wiperMaskTexture"): - blender_material.msfs_extra_slot1_texture = MSFSMaterial.create_image( - extension.get("wiperMaskTexture", {}).get("index"), import_settings - ) + extension = extensions.get(AsoboWindshield.SerializedName) + if not extension: + extension = extensions.get(AsoboWindshield.AlternateSerializedName) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_windshield" + + if extension.get("rainDropScale"): + blender_material.msfs_rain_drop_scale = extension.get("rainDropScale") + if extension.get("wiper1State"): + blender_material.msfs_wiper_1_state = extension.get("wiper1State") + if extension.get("wiper2State"): + blender_material.msfs_wiper_2_state = extension.get("wiper2State") + if extension.get("wiper3State"): + blender_material.msfs_wiper_3_state = extension.get("wiper3State") + if extension.get("wiper4State"): + blender_material.msfs_wiper_4_state = extension.get("wiper4State") + if extension.get("wiperMaskTexture"): + blender_material.msfs_extra_slot1_texture = MSFSMaterial.create_image( + extension.get("wiperMaskTexture", {}).get("index"), import_settings + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1433,13 +1481,16 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboClearCoat.SerializedName, {}) - if extension: - blender_material.msfs_material_type = "msfs_clearcoat" - if extension.get("dirtTexture"): - blender_material.msfs_dirt_texture = MSFSMaterial.create_image( - extension.get("dirtTexture", {}).get("index"), import_settings - ) + extension = extensions.get(AsoboClearCoat.SerializedName) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_clearcoat" + + if extension.get("dirtTexture"): + blender_material.msfs_dirt_texture = MSFSMaterial.create_image( + extension.get("dirtTexture", {}).get("index"), import_settings + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1517,24 +1568,26 @@ def from_dict(blender_material, gltf2_material, import_settings): assert isinstance(extensions, dict) extension = extensions.get( - AsoboParallaxWindow.SerializedName, {} + AsoboParallaxWindow.SerializedName ) - if extension: - blender_material.msfs_material_type = "msfs_parallax" - if extension.get("parallaxScale"): - blender_material.msfs_parallax_scale = extension.get("parallaxScale") - if extension.get("roomSizeXScale"): - blender_material.msfs_parallax_room_size_x = extension.get("roomSizeXScale") - if extension.get("roomSizeYScale"): - blender_material.msfs_parallax_room_size_y = extension.get("roomSizeYScale") - if extension.get("roomNumberXY"): - blender_material.msfs_parallax_room_number_xy = extension.get("roomNumberXY") - if extension.get("corridor"): - blender_material.msfs_parallax_corridor = extension.get("corridor") - if extension.get("behindWindowMapTexture"): - blender_material.msfs_detail_color_texture = MSFSMaterial.create_image( - extension.get("behindWindowMapTexture", {}).get("index"), import_settings - ) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_parallax" + if extension.get("parallaxScale"): + blender_material.msfs_parallax_scale = extension.get("parallaxScale") + if extension.get("roomSizeXScale"): + blender_material.msfs_parallax_room_size_x = extension.get("roomSizeXScale") + if extension.get("roomSizeYScale"): + blender_material.msfs_parallax_room_size_y = extension.get("roomSizeYScale") + if extension.get("roomNumberXY"): + blender_material.msfs_parallax_room_number_xy = extension.get("roomNumberXY") + if extension.get("corridor"): + blender_material.msfs_parallax_corridor = extension.get("corridor") + if extension.get("behindWindowMapTexture"): + blender_material.msfs_detail_color_texture = MSFSMaterial.create_image( + extension.get("behindWindowMapTexture", {}).get("index"), import_settings + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1566,6 +1619,7 @@ def to_extension(blender_material, gltf2_material, export_settings): class AsoboGlass: SerializedName = "ASOBO_material_glass" + AlternateSerializedName = "ASOBO_material_kitty_glass" class Defaults: glassReflectionMaskFactor = 0.0 @@ -1593,17 +1647,22 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboGlass.SerializedName, {}) - if extension: - blender_material.msfs_material_type = "msfs_glass" - if extension.get("glassReflectionMaskFactor"): - blender_material.msfs_glass_reflection_mask_factor = extension.get( - "glassReflectionMaskFactor" - ) - if extension.get("glassDeformationFactor"): - blender_material.msfs_glass_deformation_factor = extension.get( - "glassDeformationFactor" - ) + extension = extensions.get(AsoboGlass.SerializedName) + if not extension: + extension = extensions.get(AsoboGlass.AlternateSerializedName) + if extension is None: + return + + blender_material.msfs_material_type = "msfs_glass" + + if extension.get("glassReflectionMaskFactor"): + blender_material.msfs_glass_reflection_mask_factor = extension.get( + "glassReflectionMaskFactor" + ) + if extension.get("glassDeformationFactor"): + blender_material.msfs_glass_deformation_factor = extension.get( + "glassDeformationFactor" + ) @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1647,12 +1706,14 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extensions, dict) - extension = extensions.get(AsoboTags.SerializedName, []) - if extension: - if AsoboTags.AsoboTag.Collision in extension.get("tags"): - blender_material.msfs_collision_material = True - if AsoboTags.AsoboTag.Road in extension.get("tags"): - blender_material.msfs_road_collision_material = True + extension = extensions.get(AsoboTags.SerializedName) + if extension is None: + return + + if AsoboTags.AsoboTag.Collision in extension.get("tags"): + blender_material.msfs_collision_material = True + if AsoboTags.AsoboTag.Road in extension.get("tags"): + blender_material.msfs_road_collision_material = True @staticmethod def to_extension(blender_material, gltf2_material, export_settings): @@ -1689,16 +1750,18 @@ def from_dict(blender_material, gltf2_material, import_settings): return assert isinstance(extras, dict) - extension = extras.get(AsoboMaterialCode.SerializedName, []) - if extension: - if AsoboMaterialCode.MaterialCode.Windshield in extension: - blender_material.msfs_material_type = "msfs_windshield" - elif AsoboMaterialCode.MaterialCode.Porthole in extension: - blender_material.msfs_material_type = "msfs_porthole" - elif AsoboMaterialCode.MaterialCode.GeoDecalFrosted in extension: - blender_material.msfs_material_type = "msfs_geo_decal_frosted" - elif AsoboMaterialCode.MaterialCode.ClearCoat in extension: - blender_material.msfs_material_type = "msfs_clearcoat" + extension = extras.get(AsoboMaterialCode.SerializedName) + if extension is None: + return + + if extension == AsoboMaterialCode.MaterialCode.Windshield: + blender_material.msfs_material_type = "msfs_windshield" + elif extension == AsoboMaterialCode.MaterialCode.Porthole: + blender_material.msfs_material_type = "msfs_porthole" + elif extension == AsoboMaterialCode.MaterialCode.GeoDecalFrosted: + blender_material.msfs_material_type = "msfs_geo_decal_frosted" + elif extension == AsoboMaterialCode.MaterialCode.ClearCoat: + blender_material.msfs_material_type = "msfs_clearcoat" @staticmethod def to_extension(blender_material, gltf2_material, export_settings): diff --git a/addons/io_scene_gltf2_msfs/io/msfs_material.py b/addons/io_scene_gltf2_msfs/io/msfs_material.py index 018e993..9d31fe2 100644 --- a/addons/io_scene_gltf2_msfs/io/msfs_material.py +++ b/addons/io_scene_gltf2_msfs/io/msfs_material.py @@ -30,6 +30,33 @@ class MSFSMaterial: bl_options = {"UNDO"} + extensions = [ + MSFSMaterialExtensions.AsoboMaterialCommon, + MSFSMaterialExtensions.AsoboMaterialGeometryDecal, + MSFSMaterialExtensions.AsoboMaterialGhostEffect, + MSFSMaterialExtensions.AsoboMaterialDrawOrder, + MSFSMaterialExtensions.AsoboDayNightCycle, + MSFSMaterialExtensions.AsoboDisableMotionBlur, + MSFSMaterialExtensions.AsoboPearlescent, + MSFSMaterialExtensions.AsoboAlphaModeDither, + MSFSMaterialExtensions.AsoboMaterialInvisible, + MSFSMaterialExtensions.AsoboMaterialEnvironmentOccluder, + MSFSMaterialExtensions.AsoboMaterialUVOptions, + MSFSMaterialExtensions.AsoboMaterialShadowOptions, + MSFSMaterialExtensions.AsoboMaterialResponsiveAAOptions, + MSFSMaterialExtensions.AsoboMaterialDetail, + MSFSMaterialExtensions.AsoboMaterialFakeTerrain, + MSFSMaterialExtensions.AsoboMaterialFresnelFade, + MSFSMaterialExtensions.AsoboSSS, + MSFSMaterialExtensions.AsoboAnisotropic, + MSFSMaterialExtensions.AsoboWindshield, + MSFSMaterialExtensions.AsoboClearCoat, + MSFSMaterialExtensions.AsoboParallaxWindow, + MSFSMaterialExtensions.AsoboGlass, + MSFSMaterialExtensions.AsoboTags, + MSFSMaterialExtensions.AsoboMaterialCode, + ] + def __new__(cls, *args, **kwargs): raise RuntimeError("%s should not be instantiated" % cls) @@ -40,12 +67,9 @@ def create_image(index, import_settings): pyimg = import_settings.data.images[pytexture.source] # Find image created - if pyimg.name in bpy.data.images: - return bpy.data.images[pyimg.name] - elif os.path.basename(pyimg.uri) in bpy.data.images: - return bpy.data.images[pyimg.uri] - elif "Image_%d" % index in bpy.data.images: - return bpy.data.images["Image_%d" % index] + blender_image_name = pyimg.blender_image_name + if blender_image_name: + return bpy.data.images[blender_image_name] @staticmethod def export_image( @@ -99,68 +123,18 @@ def export_image( if type == "NORMAL": nodes.remove(normal_node) + # Some versions of the Khronos exporter have gather_texture_info return a tuple + if isinstance(texture_info, tuple): + texture_info = texture_info[0] + return texture_info @staticmethod def create(gltf2_material, blender_material, import_settings): - extensions = [ - MSFSMaterialExtensions.AsoboMaterialCommon, - MSFSMaterialExtensions.AsoboMaterialGeometryDecal, - MSFSMaterialExtensions.AsoboMaterialGhostEffect, - MSFSMaterialExtensions.AsoboMaterialDrawOrder, - MSFSMaterialExtensions.AsoboDayNightCycle, - MSFSMaterialExtensions.AsoboDisableMotionBlur, - MSFSMaterialExtensions.AsoboPearlescent, - MSFSMaterialExtensions.AsoboAlphaModeDither, - MSFSMaterialExtensions.AsoboMaterialInvisible, - MSFSMaterialExtensions.AsoboMaterialEnvironmentOccluder, - MSFSMaterialExtensions.AsoboMaterialUVOptions, - MSFSMaterialExtensions.AsoboMaterialShadowOptions, - MSFSMaterialExtensions.AsoboMaterialResponsiveAAOptions, - MSFSMaterialExtensions.AsoboMaterialDetail, - MSFSMaterialExtensions.AsoboMaterialFakeTerrain, - MSFSMaterialExtensions.AsoboMaterialFresnelFade, - MSFSMaterialExtensions.AsoboSSS, - MSFSMaterialExtensions.AsoboAnisotropic, - MSFSMaterialExtensions.AsoboWindshield, - MSFSMaterialExtensions.AsoboClearCoat, - MSFSMaterialExtensions.AsoboParallaxWindow, - MSFSMaterialExtensions.AsoboGlass, - MSFSMaterialExtensions.AsoboTags, - MSFSMaterialExtensions.AsoboMaterialCode, - ] - - for extension in extensions: + for extension in MSFSMaterial.extensions: extension.from_dict(blender_material, gltf2_material, import_settings) @staticmethod def export(gltf2_material, blender_material, export_settings): - extensions = [ - MSFSMaterialExtensions.AsoboMaterialCommon, - MSFSMaterialExtensions.AsoboMaterialGeometryDecal, - MSFSMaterialExtensions.AsoboMaterialGhostEffect, - MSFSMaterialExtensions.AsoboMaterialDrawOrder, - MSFSMaterialExtensions.AsoboDayNightCycle, - MSFSMaterialExtensions.AsoboDisableMotionBlur, - MSFSMaterialExtensions.AsoboPearlescent, - MSFSMaterialExtensions.AsoboAlphaModeDither, - MSFSMaterialExtensions.AsoboMaterialInvisible, - MSFSMaterialExtensions.AsoboMaterialEnvironmentOccluder, - MSFSMaterialExtensions.AsoboMaterialUVOptions, - MSFSMaterialExtensions.AsoboMaterialShadowOptions, - MSFSMaterialExtensions.AsoboMaterialResponsiveAAOptions, - MSFSMaterialExtensions.AsoboMaterialDetail, - MSFSMaterialExtensions.AsoboMaterialFakeTerrain, - MSFSMaterialExtensions.AsoboMaterialFresnelFade, - MSFSMaterialExtensions.AsoboSSS, - MSFSMaterialExtensions.AsoboAnisotropic, - MSFSMaterialExtensions.AsoboWindshield, - MSFSMaterialExtensions.AsoboClearCoat, - MSFSMaterialExtensions.AsoboParallaxWindow, - MSFSMaterialExtensions.AsoboGlass, - MSFSMaterialExtensions.AsoboTags, - MSFSMaterialExtensions.AsoboMaterialCode, - ] - - for extension in extensions: + for extension in MSFSMaterial.extensions: extension.to_extension(blender_material, gltf2_material, export_settings) diff --git a/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py b/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py index 517865b..2564779 100644 --- a/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py +++ b/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py @@ -87,9 +87,29 @@ def execute(self, context): for lod_group in lod_groups: # Generate XML if needed if lod_group.generate_xml: - root = etree.Element( - "ModelInfo", guid="{" + str(uuid.uuid4()) + "}", version="1.1" + xml_path = bpy.path.abspath( + os.path.join( + lod_group.folder_name, + lod_group.group_name + ".xml", + ) ) + + found_guid = None + if os.path.exists(xml_path): + tree = etree.parse(xml_path) + found_guid = tree.getroot().attrib.get("guid") + + if lod_group.overwrite_guid or found_guid is None: + root = etree.Element( + "ModelInfo", + guid="{" + str(uuid.uuid4()) + "}", + version="1.1", + ) + else: + root = etree.Element( + "ModelInfo", guid=found_guid, version="1.1" + ) + lods = etree.SubElement(root, "LODS") lod_files = {} @@ -101,14 +121,17 @@ def execute(self, context): if lod.enabled: lod_files[lod.file_name] = lod.lod_value - lod_files = sorted(lod_files.items(), reverse=True) + lod_files = sorted(lod_files.items()) + last_lod = list(lod_files)[-1:] for file_name, lod_value in lod_files: - etree.SubElement( - lods, - "LOD", - minSize=str(lod_value), - ModelFile=os.path.splitext(file_name)[0] + ".gltf", + lod_element = etree.SubElement(lods, "LOD") + + if file_name != last_lod[0]: + lod_element.set("minSize", str(lod_value)) + + lod_element.set( + "ModelFile", os.path.splitext(file_name)[0] + ".gltf" ) if lod_files: @@ -117,12 +140,7 @@ def execute(self, context): xml_string = dom.toprettyxml(encoding="utf-8") with open( - bpy.path.abspath( - os.path.join( - lod_group.folder_name, - lod_group.group_name + ".xml", - ) - ), + xml_path, "wb", ) as f: f.write(xml_string) diff --git a/addons/io_scene_gltf2_msfs/io/msfs_multi_export_objects.py b/addons/io_scene_gltf2_msfs/io/msfs_multi_export_objects.py index 1e24613..1c497e1 100644 --- a/addons/io_scene_gltf2_msfs/io/msfs_multi_export_objects.py +++ b/addons/io_scene_gltf2_msfs/io/msfs_multi_export_objects.py @@ -37,7 +37,8 @@ class MultiExporterLODGroup(bpy.types.PropertyGroup): expanded: bpy.props.BoolProperty(name="", default=True) lods: bpy.props.CollectionProperty(type=MultiExporterLOD) folder_name: bpy.props.StringProperty(name="", default="", subtype="DIR_PATH") - generate_xml: bpy.props.BoolProperty(name="", default=True) + generate_xml: bpy.props.BoolProperty(name="", default=False) + overwrite_guid: bpy.props.BoolProperty(name="", description="If an XML file already exists in the location to export to, the GUID will be overwritten", default=False) class MSFS_LODGroupUtility: @@ -218,7 +219,6 @@ def draw(self, context): box.label(text="No LODs found in scene") else: for lod_group in lod_groups: - row = layout.row() if ( len(lod_group.lods) == 1 ): # If we only have one LOD in the group, and it is hidden, then don't render the group @@ -228,6 +228,8 @@ def draw(self, context): continue if len(lod_group.lods) > 0: + row = layout.row() + box = row.box() box.prop( lod_group, @@ -239,6 +241,9 @@ def draw(self, context): ) if lod_group.expanded: box.prop(lod_group, "generate_xml", text="Generate XML") + if lod_group.generate_xml: + box.prop(lod_group, "overwrite_guid", text="Overwrite GUID") + box.prop(lod_group, "folder_name", text="Folder") col = box.column()