Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #6110 from ynput/enhancement/OP-7075_Validate-Came…
Browse files Browse the repository at this point in the history
…ra-Attributes
  • Loading branch information
mkolar authored Feb 22, 2024
2 parents 4c810af + 3c47798 commit 10ec40b
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 2 deletions.
42 changes: 42 additions & 0 deletions openpype/hosts/max/api/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pymxs import runtime as rt

import pyblish.api

from openpype.pipeline.publish import get_errored_instances_from_context


class SelectInvalidAction(pyblish.api.Action):
"""Select invalid objects in Blender when a publish plug-in failed."""
label = "Select Invalid"
on = "failed"
icon = "search"

def process(self, context, plugin):
errored_instances = get_errored_instances_from_context(context,
plugin=plugin)

# Get the invalid nodes for the plug-ins
self.log.info("Finding invalid nodes...")
invalid = list()
for instance in errored_instances:
invalid_nodes = plugin.get_invalid(instance)
if invalid_nodes:
if isinstance(invalid_nodes, (list, tuple)):
invalid.extend(invalid_nodes)
else:
self.log.warning(
"Failed plug-in doesn't have any selectable objects."
)

if not invalid:
self.log.info("No invalid nodes found.")
return
invalid_names = [obj.name for obj in invalid if isinstance(obj, str)]
if not invalid_names:
invalid_names = [obj.name for obj, _ in invalid]
invalid = [obj for obj, _ in invalid]
self.log.info(
"Selecting invalid objects: %s", ", ".join(invalid_names)
)

rt.Select(invalid)
88 changes: 88 additions & 0 deletions openpype/hosts/max/plugins/publish/validate_camera_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import pyblish.api
from pymxs import runtime as rt

from openpype.pipeline.publish import (
RepairAction,
OptionalPyblishPluginMixin,
PublishValidationError
)
from openpype.hosts.max.api.action import SelectInvalidAction


class ValidateCameraAttributes(OptionalPyblishPluginMixin,
pyblish.api.InstancePlugin):
"""Validates Camera has no invalid attribute properties
or values.(For 3dsMax Cameras only)
"""

order = pyblish.api.ValidatorOrder
families = ['camera']
hosts = ['max']
label = 'Validate Camera Attributes'
actions = [SelectInvalidAction, RepairAction]
optional = True

DEFAULTS = ["fov", "nearrange", "farrange",
"nearclip", "farclip"]
CAM_TYPE = ["Freecamera", "Targetcamera",
"Physical"]

@classmethod
def get_invalid(cls, instance):
invalid = []
if rt.units.DisplayType != rt.Name("Generic"):
cls.log.warning(
"Generic Type is not used as a scene unit\n\n"
"sure you tweak the settings with your own values\n\n"
"before validation.")
cameras = instance.data["members"]
project_settings = instance.context.data["project_settings"].get("max")
cam_attr_settings = (
project_settings["publish"]["ValidateCameraAttributes"]
)
for camera in cameras:
if str(rt.ClassOf(camera)) not in cls.CAM_TYPE:
cls.log.debug(
"Skipping camera created from external plugin..")
continue
for attr in cls.DEFAULTS:
default_value = cam_attr_settings.get(attr)
if default_value == float(0):
cls.log.debug(
f"the value of {attr} in setting set to"
" zero. Skipping the check.")
continue
if round(rt.getProperty(camera, attr), 1) != default_value:
cls.log.error(
f"Invalid attribute value for {camera.name}:{attr} "
f"(should be: {default_value}))")
invalid.append(camera)

return invalid

def process(self, instance):
if not self.is_active(instance.data):
self.log.debug("Skipping Validate Camera Attributes.")
return
invalid = self.get_invalid(instance)

if invalid:
raise PublishValidationError(
"Invalid camera attributes found. See log.")

@classmethod
def repair(cls, instance):
invalid_cameras = cls.get_invalid(instance)
project_settings = instance.context.data["project_settings"].get("max")
cam_attr_settings = (
project_settings["publish"]["ValidateCameraAttributes"]
)
for camera in invalid_cameras:
for attr in cls.DEFAULTS:
expected_value = cam_attr_settings.get(attr)
if expected_value == float(0):
cls.log.debug(
f"the value of {attr} in setting set to zero.")
continue
rt.setProperty(camera, attr, expected_value)
10 changes: 10 additions & 0 deletions openpype/settings/defaults/project_settings/max.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@
"enabled": false,
"attributes": {}
},
"ValidateCameraAttributes": {
"enabled": true,
"optional": true,
"active": false,
"fov": 45.0,
"nearrange": 0.0,
"farrange": 1000.0,
"nearclip": 1.0,
"farclip": 1000.0
},
"ValidateLoadedPlugin": {
"enabled": false,
"optional": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,76 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "ValidateCameraAttributes",
"label": "Validate Camera Attributes",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"type": "boolean",
"key": "active",
"label": "Active"
},
{
"type": "number",
"key": "fov",
"label": "Focal Length",
"decimal": 1,
"minimum": 0,
"maximum": 100.0
},
{
"type": "label",
"label": "If the value of the camera attributes set to 0, the system automatically skips checking it"
},
{
"type": "number",
"key": "nearrange",
"label": "Near Range",
"decimal": 1,
"minimum": 0,
"maximum": 100.0
},
{
"type": "number",
"key": "farrange",
"label": "Far Range",
"decimal": 1,
"minimum": 0,
"maximum": 2000.0
},
{
"type": "number",
"key": "nearclip",
"label": "Near Clip",
"decimal": 1,
"minimum": 0,
"maximum": 100.0
},
{
"type": "number",
"key": "farclip",
"label": "Far Clip",
"decimal": 1,
"minimum": 0,
"maximum": 2000.0
}
]
},

{
"type": "dict",
"collapsible": true,
Expand Down
30 changes: 29 additions & 1 deletion server_addon/max/server/settings/publishers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ def validate_json(cls, value):
return value


class ValidateCameraAttributesModel(BaseSettingsModel):
enabled: bool = SettingsField(title="Enabled")
optional: bool = SettingsField(title="Optional")
active: bool = SettingsField(title="Active")
fov: float = SettingsField(0.0, title="Focal Length")
nearrange: float = SettingsField(0.0, title="Near Range")
farrange: float = SettingsField(0.0, title="Far Range")
nearclip: float = SettingsField(0.0, title="Near Clip")
farclip: float = SettingsField(0.0, title="Far Clip")


class FamilyMappingItemModel(BaseSettingsModel):
product_types: list[str] = SettingsField(
default_factory=list,
Expand Down Expand Up @@ -63,7 +74,14 @@ class PublishersModel(BaseSettingsModel):
default_factory=ValidateAttributesModel,
title="Validate Attributes"
)

ValidateCameraAttributes: ValidateCameraAttributesModel = SettingsField(
default_factory=ValidateCameraAttributesModel,
title="Validate Camera Attributes",
description=(
"If the value of the camera attributes set to 0, "
"the system automatically skips checking it"
)
)
ValidateLoadedPlugin: ValidateLoadedPluginModel = SettingsField(
default_factory=ValidateLoadedPluginModel,
title="Validate Loaded Plugin"
Expand Down Expand Up @@ -101,6 +119,16 @@ class PublishersModel(BaseSettingsModel):
"enabled": False,
"attributes": "{}"
},
"ValidateCameraAttributes": {
"enabled": True,
"optional": True,
"active": False,
"fov": 45.0,
"nearrange": 0.0,
"farrange": 1000.0,
"nearclip": 1.0,
"farclip": 1000.0
},
"ValidateLoadedPlugin": {
"enabled": False,
"optional": True,
Expand Down
2 changes: 1 addition & 1 deletion server_addon/max/server/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.1.4"
__version__ = "0.1.5"

0 comments on commit 10ec40b

Please sign in to comment.