예제 #1
0
    def check_meshes_use_auto_smooth(cls, _context) -> CheckResult:
        mesh_count = 0
        use_auto_smooth_mesh_count = 0

        obj: bpy.types.Object
        for obj in bpy.data.objects:
            if obj.type != 'MESH':
                continue

            if obj.hide_render:
                continue

            mesh: bpy.types.Mesh = obj.data

            mesh_count += 1

            if not mesh.use_auto_smooth:
                continue

            use_auto_smooth_mesh_count += 1

        return CheckResult(
            _('Meshes Use Auto Smooth'),
            CheckResultStatus.GOOD if use_auto_smooth_mesh_count == 0 else CheckResultStatus.WARNING,
            min(use_auto_smooth_mesh_count * 0.7, 3),
            f'{use_auto_smooth_mesh_count} / {mesh_count}',
            _('= 0 is Good'),
            editable=False
        )
예제 #2
0
class PyramidClothAdjusterSettingsPropertyGroup(bpy.types.PropertyGroup):
    string_pin_weight: bpy.props.FloatProperty(
        name=_('String Pin Weight'), min=0.0, max=1.0, precision=3, step=10,
        get=lambda p: PyramidMeshEditor(p.id_data).string_pin_weight,
        set=lambda p, v: setattr(PyramidMeshEditor(p.id_data), 'string_pin_weight', v),
    )

    apex_pin_weight: bpy.props.FloatProperty(
        name=_('Apex Pin Weight'), min=0.0, max=1.0, precision=3, step=10,
        get=lambda p: PyramidMeshEditor(p.id_data).apex_pin_weight,
        set=lambda p, v: setattr(PyramidMeshEditor(p.id_data), 'apex_pin_weight', v),
    )

    base_pin_weight: bpy.props.FloatProperty(
        name=_('Base Pin Weight'), min=0.0, max=1.0, precision=3, step=10,
        get=lambda p: PyramidMeshEditor(p.id_data).base_pin_weight,
        set=lambda p, v: setattr(PyramidMeshEditor(p.id_data), 'base_pin_weight', v),
    )

    time_scale: bpy.props.FloatProperty(
        name=_('Speed Multiplier'), min=0.0, soft_max=10.0, precision=3, step=10,
        get=lambda p: PyramidMeshEditor(p.id_data).time_scale,
        set=lambda p, v: setattr(PyramidMeshEditor(p.id_data), 'time_scale', v),
    )

    @staticmethod
    def register():
        # pylint: disable=assignment-from-no-return
        bpy.types.Object.mmd_uuunyaa_tools_pyramid_cloth_settings = bpy.props.PointerProperty(type=PyramidClothAdjusterSettingsPropertyGroup)

    @staticmethod
    def unregister():
        del bpy.types.Object.mmd_uuunyaa_tools_pyramid_cloth_settings
예제 #3
0
    def import_vpd(vpd_file_path, scale=0.08, asset=None):
        asset_path, _ = _Utilities.resolve_path(asset)

        print(f'import_vpd({vpd_file_path},{scale},{asset_path})')
        try:
            bpy.ops.mmd_tools.import_vpd('INVOKE_DEFAULT',
                                         filepath=os.path.join(
                                             asset_path, vpd_file_path),
                                         scale=scale)
        except AttributeError as ex:
            if str(
                    ex
            ) != 'Calling operator "bpy.ops.mmd_tools.import_vpd" error, could not be found':
                raise
            raise MessageException(
                _('Failed to invoke mmd_tools\nPlease install mmd_tools.')
            ) from ex
        except RuntimeError as ex:
            if str(
                    ex
            ) != 'Operator bpy.ops.mmd_tools.import_vpd.poll() failed, context is incorrect':
                raise
            raise MessageException(
                _('Select an object.\nThe target object for pose import is not selected.'
                  )) from ex
예제 #4
0
    def check_materials_method(cls, _context) -> CheckResult:
        active_materials: Set[bpy.types.Material] = set()

        obj: bpy.types.Object
        for obj in bpy.data.objects:
            if obj.type != 'MESH':
                continue

            if obj.hide_render:
                continue

            material_slot: bpy.types.MaterialSlot
            for material_slot in obj.material_slots:
                active_materials.add(material_slot.material)

        material_count = len(active_materials)
        alpha_hashed_material_count = 0

        for material in active_materials:
            if material.blend_method != 'HASHED' and material.shadow_method != 'HASHED':
                continue
            alpha_hashed_material_count += 1

        return CheckResult(
            _('Materials Use Alpha Hashed'),
            CheckResultStatus.GOOD if alpha_hashed_material_count == 0 else CheckResultStatus.WARNING,
            min(alpha_hashed_material_count * 0.4, 2),
            f'{alpha_hashed_material_count} / {material_count}',
            _('= 0 is Good'),
            editable=False
        )
예제 #5
0
    def draw(self, context: bpy.types.Context):
        world: bpy.types.World = context.scene.world

        utilities = MaterialEditor(world)

        layout = self.layout

        node_frame = utilities.find_node_frame()
        if node_frame is None:
            layout.label(text=_('UuuNyaa World not found.'))
            return

        scene_has_irradiance_volumes = self._scene_has_irradiance_volumes()
        if not scene_has_irradiance_volumes:
            layout.label(text=_('IrradianceVolume not found. Please add it.'),
                         icon='ERROR')

        utilities.draw_setting_shader_node_properties(
            layout, utilities.list_nodes(node_frame=node_frame))

        col = layout.column(align=True)
        col.label(text=_('for Eevee lighting, check Render Properties.'))

        if not scene_has_irradiance_volumes:
            return

        col.operator('scene.light_cache_bake',
                     text=_('Bake Indirect Lighting'),
                     icon='RENDER_STILL')
예제 #6
0
class EmissionAdjuster(MaterialAdjusterABC):
    @classmethod
    def get_id(cls) -> str:
        return 'MATERIAL_ADJUSTER_EMISSION'

    @classmethod
    def get_name(cls) -> str:
        return _('Emission Adjuster')

    translation_properties = [
        _('Min'),
        _('Max'),
        _('Blood Color'),
        _('Subsurface'),
        _('Subsurface Color'),
    ]

    def attach(self) -> ShaderNodeGroup:
        node_frame = self.get_adjusters_node_frame()
        node_emission_adjuster = self.find_node(ShaderNodeGroup,
                                                label=self.get_name(),
                                                node_frame=node_frame)

        node_shader = self.find_active_principled_shader_node()
        node_emission_adjuster = self.edit(
            self.get_emission_adjuster_node(), {
                'Min':
                self.to_link_or_value(node_shader.inputs['Subsurface']),
                'Max':
                0.300,
                'Blood Color':
                self.to_link_or_value(node_shader.inputs['Subsurface Color']),
            }, {
                'location': self.grid_to_position(-2, -8),
                'parent': node_frame
            })

        self.edit(node_shader, {
            'Subsurface':
            node_emission_adjuster.outputs['Subsurface'],
            'Subsurface Color':
            node_emission_adjuster.outputs['Subsurface Color'],
        },
                  force=True)

        return node_emission_adjuster

    def detach(self):
        node_emission_adjuster = self.get_emission_adjuster_node()

        self.edit(self.find_active_principled_shader_node(), {
            'Subsurface':
            self.to_link_or_value(node_emission_adjuster.inputs['Min']),
            'Subsurface Color':
            self.to_link_or_value(
                node_emission_adjuster.inputs['Blood Color']),
        },
                  force=True)

        self.nodes.remove(node_emission_adjuster)
예제 #7
0
    def draw(self, context):
        layout = self.layout

        col = layout.column()
        box = col.box().column(align=True)
        box.label(text=_('Reload local asset JSON files'))
        box.operator(ReloadAssetJsons.bl_idname, icon='FILE_REFRESH')

        preferences = get_preferences()

        box = col.box().column(align=True)
        box.label(text=_('Download and Update to the latest assets'))
        operator = box.operator(UpdateAssetJson.bl_idname,
                                icon='TRIA_DOWN_BAR')
        operator.repo = preferences.asset_json_update_repo
        operator.query = preferences.asset_json_update_query

        props = context.scene.mmd_uuunyaa_tools_asset_operator

        row = col.row(align=True)
        row.prop(
            props,
            'debug_expanded',
            icon='TRIA_DOWN' if props.debug_expanded else 'TRIA_RIGHT',
            icon_only=True,
            emboss=False,
        )
        row.label(text=_('Debug'))

        if not props.debug_expanded:
            return

        box = col.box().column()
        box.label(text=_('Fetch an asset for debug'), icon='MODIFIER')
        box.column(align=True).prop(props,
                                    'debug_issue_number',
                                    text=_('issue #'))

        row = box.row(align=True)
        row.operator(DeleteDebugAssetJson.bl_idname, icon='CANCEL')
        row.operator(
            UpdateDebugAssetJson.bl_idname,
            icon='TRIA_DOWN_BAR').issue_number = props.debug_issue_number

        box = col.box().column()
        box.label(text=_(
            'Download and Update to the latest filtered assets for debug'),
                  icon='FILTER')

        box.prop(props, 'repo', text=_('Repository'))
        box.prop(props, 'query', text=_('Query'))
        box.prop(props, 'output_json', text=_('Write to'))

        operator = box.operator(UpdateAssetJson.bl_idname,
                                text=_('Update Assets JSON by query'),
                                icon='TRIA_DOWN_BAR')
        operator.repo = props.repo
        operator.query = props.query
        operator.output_json = props.output_json
예제 #8
0
class WetAdjuster(MaterialAdjusterABC):
    @classmethod
    def get_id(cls) -> str:
        return 'MATERIAL_ADJUSTER_WET'

    @classmethod
    def get_name(cls) -> str:
        return _('Wet Adjuster')

    translation_properties = [
        _('Specular'),
        _('Roughness'),
        _('Wet'),
    ]

    def attach(self):
        node_frame = self.get_adjusters_node_frame()
        node_wet_adjuster = self.find_node(ShaderNodeGroup,
                                           label=WetAdjuster.get_name(),
                                           node_frame=node_frame)

        node_shader = self.find_active_principled_shader_node()
        node_wet_adjuster = self.edit(
            self.get_wet_adjuster_node(), {
                'Specular':
                self.to_link_or_value(node_shader.inputs['Specular']),
                'Roughness':
                self.to_link_or_value(node_shader.inputs['Roughness']),
                'Wet':
                self.edit(self.get_vertex_color_node(), {}, {
                    'location': self.grid_to_position(-4, -10),
                    'parent': node_frame
                }).outputs['Color'],
            }, {
                'location': self.grid_to_position(-2, -10),
                'parent': node_frame
            })

        self.edit(node_shader, {
            'Specular': node_wet_adjuster.outputs['Specular'],
            'Roughness': node_wet_adjuster.outputs['Roughness'],
        },
                  force=True)

        return node_wet_adjuster

    def detach(self):
        node_wet_adjuster = self.get_wet_adjuster_node()

        self.edit(self.find_active_principled_shader_node(), {
            'Specular':
            self.to_link_or_value(node_wet_adjuster.inputs['Specular']),
            'Roughness':
            self.to_link_or_value(node_wet_adjuster.inputs['Roughness']),
        },
                  force=True)

        self.nodes.remove(node_wet_adjuster)
        self.nodes.remove(self.get_vertex_color_node())
예제 #9
0
 def check_use_ssr(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Screen Space Refraction'),
         CheckResultStatus.WARNING if context.scene.eevee.use_ssr else CheckResultStatus.GOOD,
         0 if context.scene.eevee.use_ssr else -11.4,
         'scene.eevee.use_ssr',
         _('= False is Good'),
     )
예제 #10
0
 def check_use_motion_blur(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Motion Blur'),
         CheckResultStatus.AVERAGE if context.scene.eevee.use_motion_blur else CheckResultStatus.GOOD,
         0 if context.scene.eevee.use_motion_blur else -3.4,
         'scene.eevee.use_motion_blur',
         _('= False is Good'),
     )
예제 #11
0
 def check_use_bloom(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Bloom'),
         CheckResultStatus.AVERAGE if context.scene.eevee.use_bloom else CheckResultStatus.GOOD,
         0 if context.scene.eevee.use_bloom else -2.9,
         'scene.eevee.use_bloom',
         _('= False is Good'),
     )
예제 #12
0
 def check_use_gtao(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Ambient Occlusion'),
         CheckResultStatus.AVERAGE if context.scene.eevee.use_gtao else CheckResultStatus.GOOD,
         0 if context.scene.eevee.use_gtao else -3.9,
         'scene.eevee.use_gtao',
         _('= False is Good'),
     )
예제 #13
0
 def check_use_compositing(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Compositing'),
         CheckResultStatus.WARNING if context.scene.render.use_compositing else CheckResultStatus.GOOD,
         -(0.6-1.7) if context.scene.render.use_compositing else 0,
         'scene.render.use_compositing',
         _('= False is Good'),
     )
예제 #14
0
 def check_use_pass_ambient_occlusion(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Ambient Occlusion'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_ambient_occlusion else CheckResultStatus.GOOD,
         -(-0.3-6.4) if context.view_layer.use_pass_ambient_occlusion else 0,
         'view_layer.use_pass_ambient_occlusion',
         _('= False is Good'),
     )
예제 #15
0
 def check_use_pass_diffuse_direct(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Diffuse Light'),
         CheckResultStatus.POOR if context.view_layer.use_pass_diffuse_direct else CheckResultStatus.GOOD,
         -(-0.7-26.8) if context.view_layer.use_pass_diffuse_direct else 0,
         'view_layer.use_pass_diffuse_direct',
         _('= False is Good'),
     )
예제 #16
0
 def check_render_engine(context: bpy.types.Context):
     return CheckResult(
         _('Render Engine'),
         CheckResultStatus.GOOD if context.scene.render.engine == 'BLENDER_EEVEE' else CheckResultStatus.BAD,
         0,
         'scene.render.engine',
         _('= Eevee is Good'),
     )
    def draw(self, context: bpy.types.Context):
        layout = self.layout

        col = layout.column()
        col.label(text=_('Batch Operation:'))
        col.operator('rigidbody.object_settings_copy',
                     text=_('Copy to Selected'),
                     icon='DUPLICATE')
예제 #18
0
 def check_use_sequencer(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Sequencer'),
         CheckResultStatus.WARNING if context.scene.render.use_sequencer else CheckResultStatus.GOOD,
         0,
         'scene.render.use_sequencer',
         _('= False is Good'),
     )
예제 #19
0
 def check_use_pass_z(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Z'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_z else CheckResultStatus.GOOD,
         -(-0.2-1.6) if context.view_layer.use_pass_z else 0,
         'view_layer.use_pass_z',
         _('= False is Good'),
     )
예제 #20
0
 def check_use_pass_environment(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Environment'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_environment else CheckResultStatus.GOOD,
         -(-0.6-2.3) if context.view_layer.use_pass_environment else 0,
         'view_layer.use_pass_environment',
         _('= False is Good'),
     )
예제 #21
0
 def check_use_pass_bloom(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Bloom'),
         CheckResultStatus.WARNING if context.view_layer.eevee.use_pass_bloom else CheckResultStatus.GOOD,
         -(-0.8-2.6) if context.view_layer.eevee.use_pass_bloom else 0,
         'view_layer.eevee.use_pass_bloom',
         _('= False is Good'),
     )
예제 #22
0
 def check_use_pass_normal(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Normal'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_normal else CheckResultStatus.GOOD,
         -(-0.6-4.4) if context.view_layer.use_pass_normal else 0,
         'view_layer.use_pass_normal',
         _('= False is Good'),
     )
예제 #23
0
 def check_use_pass_shadow(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Shadow'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_shadow else CheckResultStatus.GOOD,
         -(-0.4-8.6) if context.view_layer.use_pass_shadow else 0,
         'view_layer.use_pass_shadow',
         _('= False is Good'),
     )
예제 #24
0
 def check_use_pass_diffuse_color(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Pass Diffuse Color'),
         CheckResultStatus.WARNING if context.view_layer.use_pass_diffuse_color else CheckResultStatus.GOOD,
         -(-0.7-14.5) if context.view_layer.use_pass_diffuse_color else 0,
         'view_layer.use_pass_diffuse_color',
         _('= False is Good'),
     )
예제 #25
0
class SkyPanel(bpy.types.Panel):
    bl_idname = 'UUUNYAA_PT_sky_panel'
    bl_label = _('MMD UuuNyaa Sky')
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = 'world'

    @classmethod
    def poll(cls, context):
        return context.scene.world is not None

    translation_properties = [
        _('Light Strength'),
        _('Image Strength'),
    ]

    def draw(self, context: bpy.types.Context):
        world: bpy.types.World = context.scene.world

        utilities = MaterialEditor(world)

        layout = self.layout

        node_frame = utilities.find_node_frame()
        if node_frame is None:
            layout.label(text=_('UuuNyaa World not found.'))
            return

        scene_has_irradiance_volumes = self._scene_has_irradiance_volumes()
        if not scene_has_irradiance_volumes:
            layout.label(text=_('IrradianceVolume not found. Please add it.'),
                         icon='ERROR')

        utilities.draw_setting_shader_node_properties(
            layout, utilities.list_nodes(node_frame=node_frame))

        col = layout.column(align=True)
        col.label(text=_('for Eevee lighting, check Render Properties.'))

        if not scene_has_irradiance_volumes:
            return

        col.operator('scene.light_cache_bake',
                     text=_('Bake Indirect Lighting'),
                     icon='RENDER_STILL')

    @staticmethod
    def _scene_has_irradiance_volumes():
        obj: bpy.types.Object
        for obj in bpy.data.objects:
            if obj.type != 'LIGHT_PROBE':
                continue

            light_probe = obj.data
            if light_probe.type == 'GRID':
                return True

        return False
예제 #26
0
 def check_taa_render_samples(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Render Samples'),
         cls.sample_to_status(context.scene.eevee.taa_render_samples),
         0.0141 * context.scene.eevee.taa_render_samples + -0.439,
         'scene.eevee.taa_render_samples',
         _('<= 16 is Good'),
         1
     )
예제 #27
0
 def check_blender_version(_context: bpy.types.Context):
     return CheckResult(
         _('Blender Version'),
         CheckResultStatus.GOOD if bpy.app.version >= (2, 93, 0) else CheckResultStatus.BAD,
         0,
         bpy.app.version_string,
         _('>= 2.93 LTS is Good'),
         editable=False,
     )
예제 #28
0
 def check_taa_samples(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Viewport Samples'),
         cls.sample_to_status(context.scene.eevee.taa_samples),
         0,
         'scene.eevee.taa_samples',
         _('<= 16 is Good'),
         1
     )
예제 #29
0
 def check_use_ssr_halfres(cls, context: bpy.types.Context) -> CheckResult:
     return CheckResult(
         _('Use Half Res Trace'),
         CheckResultStatus.AVERAGE if not context.scene.eevee.use_ssr_halfres else CheckResultStatus.GOOD,
         -2.2 if context.scene.eevee.use_ssr_halfres else 0,
         'scene.eevee.use_ssr_halfres',
         _('= True is Good'),
         1
     )
예제 #30
0
    def check_use_pass_volume_direct(cls, context: bpy.types.Context) -> Union[CheckResult, None]:
        if not hasattr(context.view_layer.eevee, 'use_pass_volume_direct'):
            return None

        return CheckResult(
            _('Pass Volume Light'),
            CheckResultStatus.WARNING if context.view_layer.eevee.use_pass_volume_direct else CheckResultStatus.GOOD,
            -(-0.7-2.9) if context.view_layer.eevee.use_pass_volume_direct else 0,
            'view_layer.eevee.use_pass_volume_direct',
            _('= False is Good'),
        )