diff --git a/addons/io_scene_gltf2_msfs/__init__.py b/addons/io_scene_gltf2_msfs/__init__.py index 6bca4cc9..76eeea19 100644 --- a/addons/io_scene_gltf2_msfs/__init__.py +++ b/addons/io_scene_gltf2_msfs/__init__.py @@ -24,7 +24,7 @@ "author": "Luca Pierabella, Yasmine Khodja, Wing42, pepperoni505, ronh991, and others", "description": "This toolkit prepares your 3D assets to be used for Microsoft Flight Simulator", "blender": (3, 3, 0), - "version": (1, 3, 1), + "version": (1, 3, 2), "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/material/utils/msfs_material_enum.py b/addons/io_scene_gltf2_msfs/blender/material/utils/msfs_material_enum.py index 7ea921e3..15970fd2 100644 --- a/addons/io_scene_gltf2_msfs/blender/material/utils/msfs_material_enum.py +++ b/addons/io_scene_gltf2_msfs/blender/material/utils/msfs_material_enum.py @@ -101,6 +101,7 @@ class MSFS_ShaderNodes(Enum): emissiveMulScale = "Emissive Multiplier Scale" RGBCurves = "RGB Curves" emissiveMul = "Emissive Multiplier" + normalScale = "Normal Scale" normalMapSampler = "Normal Map Sampler" detailColorTex = "Detail Color(RGBA)" detailCompTex = "Detail Occlusion(R) Roughness(G) Metallic(B)" @@ -114,7 +115,7 @@ class MSFS_ShaderNodes(Enum): combineUVScale = "Combine UV Scale" combineUVOffset = "Combine UV Offset" mulUVScale = "Multiply UV Scale" - addUVOffset = "Multiply UV Offset" + addUVOffset = "Add UV Offset" detailNormalMapSampler = "Detail Normal Map Sampler" blendNormalMap = "Blend Normal Map" blendColorMap = "Blend Color Map" 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 bbf3f3c6..3bf5011a 100644 --- a/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py +++ b/addons/io_scene_gltf2_msfs/blender/msfs_material_function.py @@ -163,7 +163,7 @@ def defaultShadersTree(self): ) ## Comp Texture - # Out[0] : Blend Comp Occlusion Metalic Roughness -> In[1] + # Out[0] : Blend Comp Occlusion Metallic Roughness -> In[1] compTexNode = self.addNode( name = MSFS_ShaderNodes.compTex.value, typeNode = MSFS_ShaderNodesTypes.shaderNodeTexImage.value, @@ -508,20 +508,6 @@ def defaultShadersTree(self): ## Links self.link(splitOccMetalRoughNode.inputs[0], blendCompMapNode.outputs[0]) - ## Occlusion Multiplier - # In[1] : Split Occ Metal Rough -> Out[0] - occlusionMulNode = self.addNode( - name = MSFS_ShaderNodes.occlusionMul.value, - typeNode = MSFS_ShaderNodesTypes.shaderNodeMath.value, - operation = "MULTIPLY", - location = (500.0, 200.0), - width = 200.0, - frame = omrFrame - ) - occlusionMulNode.inputs[0].default_value = 1.0 - ## Links - self.link(occlusionMulNode.inputs[1], splitOccMetalRoughNode.outputs[0]) - ## Roughness Multiplier # In[1] : Split Occ Metal Rough -> Out[1] roughnessMulNode = self.addNode( @@ -601,12 +587,24 @@ def defaultShadersTree(self): color = (0.5, 0.25, 0.25) ) + ## Normal scale + # Out[0] : Normap Map Sampler -> In[0] + normalScaleNode = self.addNode( + name = MSFS_ShaderNodes.normalScale.value, + typeNode = MSFS_ShaderNodesTypes.shaderNodeValue.value, + location = (-300.0, -350.0), + frame = normalFrame + ) + + normalScaleNode.outputs[0].default_value = 1.0 + # Fix the normal view by reversing the green channel # since blender can only render openGL normal textures RGBCurvesNode = self.addNode( name = MSFS_ShaderNodes.RGBCurves.value, typeNode = MSFS_ShaderNodesTypes.shaderNodeRGBCurve.value, - location = (-300.0, -400.0) + location = (-300.0, -400.0), + frame = normalFrame ) curveMapping = RGBCurvesNode.mapping.curves[1] curveMapping.points[0].location = (0.0, 1.0) @@ -623,6 +621,7 @@ def defaultShadersTree(self): ) # Links + self.link(normalMapSamplerNode.inputs[0], normalScaleNode.outputs[0]) self.link(normalMapSamplerNode.inputs[1], normalTexNode.outputs[0]) ## Detail Normal Map Sampler @@ -754,8 +753,8 @@ def setEmissiveColor(self, color): self.updateEmissiveLinks() def setNormalScale(self, scale): - nodeNormalMapSampler = self.getNodeByName(MSFS_ShaderNodes.normalMapSampler.value) - nodeNormalMapSampler.inputs[0].default_value = scale + nodeNormalScale = self.getNodeByName(MSFS_ShaderNodes.normalScale.value) + nodeNormalScale.outputs[0].default_value = scale self.updateNormalLinks() def setDetailNormalTex(self, tex): @@ -845,7 +844,7 @@ def updateNormalLinks(self): nodeDetailNormalScale = self.getNodeByName(MSFS_ShaderNodes.detailNormalScale.value) nodePrincipledBSDF = self.getNodeByName(MSFS_ShaderNodes.principledBSDF.value) - # normal + # Normal self.link(nodeNormalTex.outputs[0], nodeRGBCurves.inputs[1]) self.link(nodeRGBCurves.outputs[0], nodeNormalMapSampler.inputs[1]) self.link(nodeNormalMapSampler.outputs[0], nodeBlendNormalMap.inputs[1]) @@ -855,10 +854,8 @@ def updateNormalLinks(self): if nodeNormalTex.image and not nodeDetailNormalTex.image: self.link(nodeNormalMapSampler.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.normal.value]) - elif nodeNormalTex.image and nodeDetailNormalTex.image: self.link(nodeBlendNormalMap.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.normal.value]) - else: self.unLinkNodeInput(nodePrincipledBSDF, MSFS_PrincipledBSDFInputs.normal.value) @@ -867,7 +864,6 @@ def updateEmissiveLinks(self): nodeEmissiveScale = self.getNodeByName(MSFS_ShaderNodes.emissiveScale.value) nodeEmissiveColor = self.getNodeByName(MSFS_ShaderNodes.emissiveColor.value) nodeMulEmissive = self.getNodeByName(MSFS_ShaderNodes.emissiveMul.value) - # nodeMulEmissiveScale = self.getNodeByName(MSFS_ShaderNodes.emissiveMulScale.value) nodePrincipledBSDF = self.getNodeByName(MSFS_ShaderNodes.principledBSDF.value) # emissive @@ -889,7 +885,6 @@ def updateCompLinks(self): nodeSeparateComp = self.getNodeByName(MSFS_ShaderNodes.compSeparate.value) nodeMulMetallic = self.getNodeByName(MSFS_ShaderNodes.metallicMul.value) nodeMulRoughness = self.getNodeByName(MSFS_ShaderNodes.roughnessMul.value) - nodeMulOcclusion = self.getNodeByName(MSFS_ShaderNodes.occlusionMul.value) nodeGltfSettings = self.getNodeByName(MSFS_ShaderNodes.glTFSettings.value) nodePrincipledBSDF = self.getNodeByName(MSFS_ShaderNodes.principledBSDF.value) @@ -902,7 +897,6 @@ def updateCompLinks(self): self.link(nodeBlendCompMap.outputs[0], nodeSeparateComp.inputs[0]) self.link(nodeMetallicScale.outputs[0], nodeMulMetallic.inputs[0]) self.link(nodeRoughnessScale.outputs[0], nodeMulRoughness.inputs[0]) - self.link(nodeSeparateComp.outputs[0], nodeMulOcclusion.inputs[1]) self.link(nodeSeparateComp.outputs[1], nodeMulRoughness.inputs[1]) self.link(nodeSeparateComp.outputs[2], nodeMulMetallic.inputs[1]) @@ -910,22 +904,18 @@ def updateCompLinks(self): self.link(nodeRoughnessScale.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.roughness.value]) self.link(nodeMetallicScale.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.metallic.value]) - elif nodeCompTex.image and not nodeDetailCompTex.image: - nodeBlendCompMap.blend_type = "ADD" - self.link(nodeRoughnessScale.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.roughness.value]) + self.unLinkNodeInput(nodeGltfSettings, 0) + else: # nodeCompTex.image or nodeDetailCompTex.image (if we have both images or only one of them) + self.link(nodeSeparateComp.outputs[0], nodeGltfSettings.inputs[0]) + self.link(nodeMulRoughness.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.roughness.value]) self.link(nodeMulMetallic.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.metallic.value]) - elif not nodeCompTex.image and nodeDetailCompTex.image: - nodeBlendCompMap.blend_type = "ADD" - self.link(nodeMulRoughness.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.roughness.value]) - self.link(nodeMetallicScale.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.metallic.value]) + if nodeCompTex.image and nodeDetailCompTex.image: + nodeBlendCompMap.blend_type = "MULTIPLY" + else: # we have only one of the two images + nodeBlendCompMap.blend_type = "ADD" - else: - nodeBlendCompMap.blend_type = "MULTIPLY" - self.link(nodeMulRoughness.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.roughness.value]) - self.link(nodeMulMetallic.outputs[0], nodePrincipledBSDF.inputs[MSFS_PrincipledBSDFInputs.metallic.value]) - self.link(nodeMulOcclusion.outputs[0], nodeGltfSettings.inputs[0]) def setBlendMode(self, blendMode): if blendMode == "BLEND": diff --git a/addons/io_scene_gltf2_msfs/blender/msfs_material_prop_update.py b/addons/io_scene_gltf2_msfs/blender/msfs_material_prop_update.py index 08f9d1a3..637b1d9a 100644 --- a/addons/io_scene_gltf2_msfs/blender/msfs_material_prop_update.py +++ b/addons/io_scene_gltf2_msfs/blender/msfs_material_prop_update.py @@ -135,14 +135,12 @@ def update_msfs_material_type(self, context): @staticmethod def reset_material_prop_object(self): self.msfs_alpha_cutoff = 0.5 - self.msfs_ao_use_uv2 = False self.msfs_base_color_blend_factor = 1.0 self.msfs_base_color_factor = [0.8, 0.8, 0.8, 1.0] self.msfs_base_color_texture = None self.msfs_blend_mask_texture = None self.msfs_clamp_uv_x = False self.msfs_clamp_uv_y = False - self.msfs_clamp_uv_z = False self.msfs_collision_material = False self.msfs_day_night_cycle = False self.msfs_detail_blend_threshold = 0.1 @@ -169,7 +167,7 @@ def reset_material_prop_object(self): self.msfs_glass_deformation_factor = 0.0 self.msfs_glass_reflection_mask_factor = 0.0 self.msfs_metallic_blend_factor = 0.0 - self.msfs_metallic_factor = 0.0 + self.msfs_metallic_factor = 1.0 self.msfs_no_cast_shadow = False self.msfs_normal_blend_factor = 1.0 self.msfs_normal_scale = 1.0 @@ -189,7 +187,7 @@ def reset_material_prop_object(self): self.msfs_responsive_aa = False self.msfs_road_collision_material = False self.msfs_roughness_blend_factor = 1.0 - self.msfs_roughness_factor = 0.5 + self.msfs_roughness_factor = 1.0 self.msfs_sss_color = [0.8, 0.8, 0.8, 1.0] self.msfs_use_pearl = False self.msfs_uv_offset_u = 0.0 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 ad3f4513..4f11019f 100644 --- a/addons/io_scene_gltf2_msfs/com/msfs_material_props.py +++ b/addons/io_scene_gltf2_msfs/com/msfs_material_props.py @@ -22,8 +22,8 @@ class AsoboMaterialCommon: class Defaults: BaseColorFactor = [0.8, 0.8, 0.8, 1.0] EmissiveFactor = [0.0, 0.0, 0.0] - MetallicFactor = 0.0 - RoughnessFactor = 0.5 + MetallicFactor = 1.0 + RoughnessFactor = 1.0 NormalScale = 1.0 EmissiveScale = 1.0 AlphaMode = "OPAQUE" @@ -287,6 +287,10 @@ def from_dict( @staticmethod def to_extension(blender_material, gltf2_material, export_settings): # All the properties here (besides some textures, which we handle elsewhere) are exported from the Khronos exporter + gltf2_material.emissive_factor = [f * blender_material.msfs_emissive_scale for f in blender_material.msfs_emissive_factor] + + if "KHR_materials_emissive_strength" in gltf2_material.extensions: + gltf2_material.extensions.pop("KHR_materials_emissive_strength") pass @@ -759,21 +763,14 @@ class AsoboMaterialUVOptions: SerializedName = "ASOBO_material_UV_options" class Defaults: - AOUseUV2 = False clampUVX = False clampUVY = False - clampUVZ = False UVOffsetU = 0.0 UVOffsetV = 0.0 UVTilingU = 1.0 UVTilingV = 1.0 UVRotation = 0.0 - bpy.types.Material.msfs_ao_use_uv2 = bpy.props.BoolProperty( - name="AO Use UV2", - default=Defaults.AOUseUV2, - options=set(), - ) bpy.types.Material.msfs_clamp_uv_x = bpy.props.BoolProperty( name="Clamp UV U", @@ -787,12 +784,6 @@ class Defaults: options=set(), ) - bpy.types.Material.msfs_clamp_uv_z = bpy.props.BoolProperty( # Doesn't seem to actually be used, which makes sense. Keeping just in case - name="Clamp UV Z", - default=Defaults.clampUVZ, - options=set(), - ) - bpy.types.Material.msfs_uv_offset_u = bpy.props.FloatProperty( name="UV Offset U", min=-10.0, @@ -844,13 +835,11 @@ def from_dict(blender_material, gltf2_material, import_settings): if extension is None: return - if extension.get("AOUseUV2"): - blender_material.msfs_ao_use_uv2 = extension.get("AOUseUV2") if extension.get("clampUVX"): blender_material.msfs_clamp_uv_x = extension.get("clampUVX") if extension.get("clampUVY"): blender_material.msfs_clamp_uv_y = extension.get("clampUVY") - if extension.get("clampUVZ"): + if extension.get("clampUVZ"): # Deprecated blender_material.msfs_clamp_uv_z = extension.get("clampUVZ") if extension.get("UVOffsetU"): blender_material.msfs_uv_offset_u = extension.get("UVOffsetU") @@ -867,10 +856,8 @@ def from_dict(blender_material, gltf2_material, import_settings): def to_extension(blender_material, gltf2_material, export_settings): result = {} if ( - (blender_material.msfs_ao_use_uv2 - or blender_material.msfs_clamp_uv_x + (blender_material.msfs_clamp_uv_x or blender_material.msfs_clamp_uv_y - or blender_material.msfs_clamp_uv_z or ( blender_material.msfs_uv_offset_u != AsoboMaterialUVOptions.Defaults.UVOffsetU or blender_material.msfs_uv_offset_v != AsoboMaterialUVOptions.Defaults.UVOffsetV @@ -883,10 +870,8 @@ def to_extension(blender_material, gltf2_material, export_settings): and blender_material.msfs_material_type != "msfs_invisible" and blender_material.msfs_material_type != "msfs_environment_occluder" ): - result["AOUseUV2"] = blender_material.msfs_ao_use_uv2 result["clampUVX"] = blender_material.msfs_clamp_uv_x result["clampUVY"] = blender_material.msfs_clamp_uv_y - result["clampUVZ"] = blender_material.msfs_clamp_uv_z result["UVOffsetU"] = blender_material.msfs_uv_offset_u result["UVOffsetV"] = blender_material.msfs_uv_offset_v result["UVTilingU"] = blender_material.msfs_uv_tiling_u 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 7699b69b..c6c4a103 100644 --- a/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py +++ b/addons/io_scene_gltf2_msfs/io/msfs_multi_export.py @@ -69,7 +69,6 @@ def export(file_path): export_frame_step=settings.export_frame_step, export_force_sampling=settings.export_force_sampling, export_nla_strips=settings.export_nla_strips, - export_nla_strips_merged_animation_name=settings.export_nla_strips_merged_animation_name, export_def_bones=settings.export_def_bones, export_current_frame=settings.export_current_frame, export_skins=settings.export_skins, @@ -214,7 +213,7 @@ def select_recursive(obj): for obj in lod.collection.all_objects: obj.select_set(True) else: - select_recursive(lod.object) + select_recursive(lod.objectLOD) if lod_group.folder_name != "": exportPath = bpy.path.ensure_ext(os.path.join(bpy.path.abspath(lod_group.folder_name), os.path.splitext(lod.file_name)[0]), ".gltf") 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 a69abec7..df4851aa 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 @@ -20,7 +20,7 @@ class MultiExporterLOD(bpy.types.PropertyGroup): - object: bpy.props.PointerProperty(name="", type=bpy.types.Object) + objectLOD: bpy.props.PointerProperty(name="", type=bpy.types.Object) collection: bpy.props.PointerProperty(name="", type=bpy.types.Collection) enabled: bpy.props.BoolProperty(name="", default=False) @@ -58,8 +58,8 @@ def lod_is_visible(context, lod): return False else: if ( - (not context.scene.multi_exporter_show_hidden_objects and lod.object.hide_get()) or - (lod.object is None or lod.object not in list(bpy.context.window.view_layer.objects)) + (not context.scene.multi_exporter_show_hidden_objects and lod.objectLOD.hide_get()) or + (lod.objectLOD is None or lod.objectLOD not in list(bpy.context.window.view_layer.objects)) ): return False @@ -77,7 +77,7 @@ def update_grouped_by(self, context): @staticmethod def get_group_from_name(name): - matches = re.findall("^(?i)x[0-9]_|_lod[0-9]+", name) + matches = re.findall("^x[0-9]_|_LOD[0-9]+", name) # If an object starts with xN_ or ends with _LODN, treat as an LOD if matches: # Get base object group name from object @@ -109,8 +109,8 @@ def reload_lod_groups(self, context): continue else: if ( - not lod.object in list(context.scene.objects) - or not MSFS_OT_ReloadLODGroups.get_group_from_name(lod.object.name) == lod_group.group_name + not lod.objectLOD in list(context.scene.objects) + or not MSFS_OT_ReloadLODGroups.get_group_from_name(lod.objectLOD.name) == lod_group.group_name ): lod_groups[i].lods.remove(j) continue @@ -151,9 +151,9 @@ def reload_lod_groups(self, context): lod.file_name = collection.name else: for obj in found_lod_groups[lod_group]: - if obj not in [lod.object for lod in lod_groups[lod_group_index].lods]: + if obj not in [lod.objectLOD for lod in lod_groups[lod_group_index].lods]: lod = lod_groups[lod_group_index].lods.add() - lod.object = obj + lod.objectLOD = obj lod.file_name = obj.name def execute(self, context): @@ -229,7 +229,7 @@ def draw(self, context): if sort_by_collection: row.prop(lod, "enabled", text=lod.collection.name) else: - row.prop(lod, "enabled", text=lod.object.name) + row.prop(lod, "enabled", text=lod.objectLOD.name) subrow = row.column() subrow.prop(lod, "lod_value", text="LOD Value") # subrow.prop(lod, "flatten_on_export", text="Flatten on Export") # Disable these two options for now as there's not a great way to implement them diff --git a/addons/io_scene_gltf2_msfs/io/msfs_multi_export_settings.py b/addons/io_scene_gltf2_msfs/io/msfs_multi_export_settings.py index d26818b4..c8a1b94a 100644 --- a/addons/io_scene_gltf2_msfs/io/msfs_multi_export_settings.py +++ b/addons/io_scene_gltf2_msfs/io/msfs_multi_export_settings.py @@ -81,7 +81,10 @@ def msfs_use_unique_id_extension_update(self, context): ## Export Selected Only Check - TODO : See if this works use_selected: bpy.props.BoolProperty( name="Selected Objects", - description="Export selected objects only", + description= ( + "Export selected objects only. " + "Disabled for the use of the MultiExporter (Needs to be always checked)" + ), default=True ) @@ -95,7 +98,7 @@ def msfs_use_unique_id_extension_update(self, context): ## Export Renderable Objects Check use_renderable: bpy.props.BoolProperty( name="Renderable Objects", - description="Export renderable objects only", + description="Export renderable objects only", default=False, ) @@ -129,8 +132,10 @@ def msfs_use_unique_id_extension_update(self, context): ## Export Punctual Lights Check export_lights: bpy.props.BoolProperty( name="Punctual Lights", - description="Export directional, point, and spot lights. " - 'Uses "KHR_lights_punctual" glTF extension', + description= ( + "Export directional, point, and spot lights. " + "Uses 'KHR_lights_punctual' glTF extension" + ), default=False, ) @@ -336,7 +341,7 @@ def msfs_use_unique_id_extension_update(self, context): export_force_sampling: bpy.props.BoolProperty( name="Always Sample Animations", description="Apply sampling to all animations", - default=True, + default=False, ) ## Group by NLA Track Check @@ -512,17 +517,19 @@ def draw(self, context): settings = context.scene.msfs_multi_exporter_settings - col = layout.column(heading="Limit to", align=True) - col.prop(settings, "use_selected") - col.prop(settings, "use_visible") - col.prop(settings, "use_renderable") - col.prop(settings, "use_active_collection") - col.prop(settings, "use_active_scene") - - col = layout.column(heading="Data", align=True) - col.prop(settings, "export_extras") - col.prop(settings, "export_cameras") - col.prop(settings, "export_lights") + col1 = layout.column(heading="", align=True) + col1.prop(settings, "use_selected") ## To use the MultiExporter panel, it's important to have use selected to True + col1.enabled = False + col2 = layout.column(heading="Limit to", align=True) + col2.prop(settings, "use_visible") + col2.prop(settings, "use_renderable") + col2.prop(settings, "use_active_collection") + col2.prop(settings, "use_active_scene") + + col2 = layout.column(heading="Data", align=True) + col2.prop(settings, "export_extras") + col2.prop(settings, "export_cameras") + col2.prop(settings, "export_lights") class MSFS_PT_export_transform(bpy.types.Panel): @@ -669,7 +676,10 @@ def draw(self, context): if settings.export_nla_strips is False: layout.prop(settings, 'export_nla_strips_merged_animation_name') layout.prop(settings, "optimize_animation_size") - layout.prop(settings, "export_all_armature_actions") + if (bpy.app.version > (3, 3, 0)): + layout.prop(settings, "export_all_armature_actions") + else: + layout.prop(settings, 'export_def_bones') class MSFS_PT_export_animation_shapekeys(bpy.types.Panel): @@ -727,11 +737,13 @@ def draw(self, context): layout.active = settings.export_skins layout.prop(settings, "export_all_influences") - row = layout.row() - row.active = settings.export_force_sampling - row.prop(settings, 'export_def_bones') - if settings.export_force_sampling is False and settings.export_def_bones is True: - layout.label(text="Export only deformation bones is not possible when not sampling animation") + if bpy.app.version > (3, 3, 0): + row = layout.row() + row.prop(settings, 'export_def_bones') + row.active = settings.export_force_sampling + if settings.export_force_sampling is False and settings.export_def_bones is True: + layout.label(text="Export only deformation bones is not possible when not sampling animation") + def register():